From e81025e6d2e01e38c5a5b656af5739ac9df5ff55 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> Date: Thu, 7 May 2026 19:01:11 +0300 Subject: [PATCH 001/818] Post 3.15.0b1 --- Include/patchlevel.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Include/patchlevel.h b/Include/patchlevel.h index 32c85792d550c3..cdca931566577f 100644 --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -27,7 +27,7 @@ #define PY_RELEASE_SERIAL 1 /* Version as a string */ -#define PY_VERSION "3.15.0b1" +#define PY_VERSION "3.15.0b1+" /*--end constants--*/ From 4caee143d2703f424ce66c3662a9f9a4fcdd0b54 Mon Sep 17 00:00:00 2001 From: Zachary Ware Date: Thu, 7 May 2026 17:15:06 -0500 Subject: [PATCH 002/818] [3.15] Forward-port 'check-abi' CI job from 3.14 (GH-149517) Also add the python3.15.abi file as generated by the new job and remove the 'main branch only' entry from .gitignore. (adapted from commit 0eb2291a7e85062dba387dfecaee94858db8a0a9) --- .github/workflows/build.yml | 47 + .gitignore | 4 - Doc/data/python3.15.abi | 33491 ++++++++++++++++++++++++++++++++++ 3 files changed, 33538 insertions(+), 4 deletions(-) create mode 100644 Doc/data/python3.15.abi diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1af3a0607f9ad2..12bf160178e3c7 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -49,6 +49,53 @@ jobs: if: fromJSON(needs.build-context.outputs.run-docs) uses: ./.github/workflows/reusable-docs.yml + check-abi: + name: 'Check if the ABI has changed' + runs-on: ubuntu-22.04 # 24.04 causes spurious errors + needs: build-context + if: needs.build-context.outputs.run-tests == 'true' + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 + with: + python-version: '3.x' + - name: Install dependencies + run: | + sudo ./.github/workflows/posix-deps-apt.sh + sudo apt-get install -yq --no-install-recommends abigail-tools + - name: Build CPython + env: + CFLAGS: -g3 -O0 + run: | + # Build Python with the libpython dynamic library + ./configure --enable-shared + make -j4 + - name: Check for changes in the ABI + id: check + run: | + if ! make check-abidump; then + echo "Generated ABI file is not up to date." + echo "Please add the release manager of this branch as a reviewer of this PR." + echo "" + echo "The up to date ABI file should be attached to this build as an artifact." + echo "" + echo "To learn more about this check: https://devguide.python.org/getting-started/setup-building/index.html#regenerate-the-abi-dump" + echo "" + exit 1 + fi + - name: Generate updated ABI files + if: ${{ failure() && steps.check.conclusion == 'failure' }} + run: | + make regen-abidump + - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 + name: Publish updated ABI files + if: ${{ failure() && steps.check.conclusion == 'failure' }} + with: + name: abi-data + path: ./Doc/data/*.abi + 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 diff --git a/.gitignore b/.gitignore index 118eb5ee76e805..78b6d4efb0e109 100644 --- a/.gitignore +++ b/.gitignore @@ -177,7 +177,3 @@ Python/frozen_modules/MANIFEST # People's custom https://docs.anthropic.com/en/docs/claude-code/memory configs. /.claude/ CLAUDE.local.md - -#### main branch only stuff below this line, things to backport go above. #### -# main branch only: ABI files are not checked/maintained. -Doc/data/python*.abi diff --git a/Doc/data/python3.15.abi b/Doc/data/python3.15.abi new file mode 100644 index 00000000000000..04211b6e4e274a --- /dev/null +++ b/Doc/data/python3.15.abi @@ -0,0 +1,33491 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From b311ea869141acff7985ba3b7ae304ec04e39229 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 8 May 2026 00:27:34 +0200 Subject: [PATCH 003/818] [3.15] Improve error messages when the WASI SDK can't be found (GH-149519) (cherry picked from commit b142878db1e54149feba62b08df1236432793bf0) Co-authored-by: Brett Cannon --- Platforms/WASI/_build.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/Platforms/WASI/_build.py b/Platforms/WASI/_build.py index 76d2853163baa9..c1a91a9c833b8e 100644 --- a/Platforms/WASI/_build.py +++ b/Platforms/WASI/_build.py @@ -222,10 +222,8 @@ def wasi_sdk(context): if wasi_sdk_path := context.wasi_sdk_path: if not wasi_sdk_path.exists(): raise ValueError( - "WASI SDK not found; " - "download from " - "https://github.com/WebAssembly/wasi-sdk and/or " - "specify via $WASI_SDK_PATH or --wasi-sdk" + "WASI SDK not found at " + f"{os.fsdecode(wasi_sdk_path)!r} (via --wasi-sdk)" ) return wasi_sdk_path @@ -237,7 +235,8 @@ def wasi_sdk(context): wasi_sdk_path = pathlib.Path(wasi_sdk_path_env_var) if not wasi_sdk_path.exists(): raise ValueError( - f"WASI SDK not found at $WASI_SDK_PATH ({wasi_sdk_path})" + f"WASI SDK not found at {os.fsdecode(wasi_sdk_path)!r} " + "(via $WASI_SDK_PATH)" ) else: opt_path = pathlib.Path("/opt") @@ -272,6 +271,14 @@ def wasi_sdk(context): f" Found WASI SDK {major_version}, " f"but WASI SDK {wasi_sdk_version} is the supported version", ) + elif not wasi_sdk_path: + raise ValueError( + f"WASI SDK {wasi_sdk_version} not found; " + "download from " + "https://github.com/WebAssembly/wasi-sdk and install in " + f"{os.fsdecode(opt_path)!r} or specify the SDK via " + "$WASI_SDK_PATH or --wasi-sdk" + ) # Cache the result. context.wasi_sdk_path = wasi_sdk_path From 5cb915da44642ceabac7a2d24a7cc2c5620f65ab Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 8 May 2026 04:08:12 +0200 Subject: [PATCH 004/818] [3.15] gh-149481: skip `FOR_ITER` inline specialization for Python `__next__` (GH-149491) (#149523) gh-149481: skip `FOR_ITER` inline specialization for Python `__next__` (GH-149491) (cherry picked from commit 49918f5b0ceb1950c3222fd4fd6be872d2e15c6f) Co-authored-by: Neko Asakura Co-authored-by: Savannah Ostrowski Co-authored-by: Stan Ulbrych --- Include/internal/pycore_typeobject.h | 2 ++ Lib/test/test_capi/test_opt.py | 3 ++- Objects/typeobject.c | 6 ++++++ Python/optimizer_bytecodes.c | 4 +++- Python/optimizer_cases.c.h | 3 ++- 5 files changed, 15 insertions(+), 3 deletions(-) diff --git a/Include/internal/pycore_typeobject.h b/Include/internal/pycore_typeobject.h index 8d48cf6605ca7e..785b77d3e3be81 100644 --- a/Include/internal/pycore_typeobject.h +++ b/Include/internal/pycore_typeobject.h @@ -122,6 +122,8 @@ extern PyObject* _Py_BaseObject_RichCompare(PyObject* self, PyObject* other, int extern PyObject* _Py_slot_tp_getattro(PyObject *self, PyObject *name); extern PyObject* _Py_slot_tp_getattr_hook(PyObject *self, PyObject *name); +extern int _PyType_HasSlotTpIternext(PyTypeObject *type); + extern PyTypeObject _PyBufferWrapper_Type; PyAPI_FUNC(PyObject*) _PySuper_Lookup(PyTypeObject *su_type, PyObject *su_obj, diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py index d80fec9a8a0d2b..aaa5050208ced9 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -598,7 +598,8 @@ def testfunc(n, m): ex = get_first_executor(testfunc) self.assertIsNotNone(ex) uops = get_opnames(ex) - self.assertIn("_ITER_NEXT_INLINE", uops) + self.assertIn("_FOR_ITER_TIER_TWO", uops) + self.assertNotIn("_ITER_NEXT_INLINE", uops) @requires_specialization diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 4f43747ba83fd9..9a18ca72516da7 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -11079,6 +11079,12 @@ slot_tp_iternext(PyObject *self) return vectorcall_method(&_Py_ID(__next__), stack, 1); } +int +_PyType_HasSlotTpIternext(PyTypeObject *type) +{ + return type->tp_iternext == slot_tp_iternext; +} + static PyObject * slot_tp_descr_get(PyObject *self, PyObject *obj, PyObject *type) { diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c index e10a096baa3318..39cc36ae79fead 100644 --- a/Python/optimizer_bytecodes.c +++ b/Python/optimizer_bytecodes.c @@ -2,6 +2,7 @@ #include "pycore_long.h" #include "pycore_opcode_utils.h" #include "pycore_optimizer.h" +#include "pycore_typeobject.h" #include "pycore_uops.h" #include "pycore_uop_ids.h" #include "internal/pycore_moduleobject.h" @@ -1459,7 +1460,8 @@ dummy_func(void) { type = sym_get_probable_type(iter); definite = false; } - if (type != NULL && type != &PyGen_Type && type->tp_iternext != NULL) { + if (type != NULL && type != &PyGen_Type && type->tp_iternext != NULL + && !_PyType_HasSlotTpIternext(type)) { PyType_Watch(TYPE_WATCHER_ID, (PyObject *)type); _Py_BloomFilter_Add(dependencies, type); if (!definite) { diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index 01ecb3790aa2cd..db3dcbb97b2645 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -3706,7 +3706,8 @@ type = sym_get_probable_type(iter); definite = false; } - if (type != NULL && type != &PyGen_Type && type->tp_iternext != NULL) { + if (type != NULL && type != &PyGen_Type && type->tp_iternext != NULL + && !_PyType_HasSlotTpIternext(type)) { PyType_Watch(TYPE_WATCHER_ID, (PyObject *)type); _Py_BloomFilter_Add(dependencies, type); if (!definite) { From 831dac8b518c9de262f84d3faca3443715902e07 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 8 May 2026 12:33:35 +0200 Subject: [PATCH 005/818] [3.15] gh-146445: Update CODEOWNERS for Android and iOS migration to Platforms directory (GH-149543) (#149545) gh-146445: Update CODEOWNERS for Android and iOS migration to Platforms directory (GH-149543) (cherry picked from commit 5b58fbc07c8173df98ce6d378ded1bc605997c3f) Co-authored-by: Malcolm Smith --- .github/CODEOWNERS | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index af904a567cfb7e..769d739a8057aa 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -156,7 +156,7 @@ Misc/libabigail.abignore @encukou # ---------------------------------------------------------------------------- # Android -Android/ @mhsmith @freakboy3742 +Platforms/Android/ @mhsmith @freakboy3742 Doc/using/android.rst @mhsmith @freakboy3742 Lib/_android_support.py @mhsmith @freakboy3742 Lib/test/test_android.py @mhsmith @freakboy3742 @@ -164,8 +164,7 @@ Lib/test/test_android.py @mhsmith @freakboy3742 # iOS Doc/using/ios.rst @freakboy3742 Lib/_ios_support.py @freakboy3742 -Apple/ @freakboy3742 -iOS/ @freakboy3742 +Platforms/Apple/ @freakboy3742 # macOS Mac/ @python/macos-team From 20e298bc37a48049244553862cc1918713494a23 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 8 May 2026 13:06:52 +0200 Subject: [PATCH 006/818] [3.15] docs: Clarify docs for error case of `PyDict_GetItemRef` (GH-149506) (#149546) docs: Clarify docs for error case of `PyDict_GetItemRef` (GH-149506) (cherry picked from commit 3565d31690d30a189933bce7b27d0bd2c6973f47) Co-authored-by: Nathan Goldbaum --- Doc/c-api/dict.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/c-api/dict.rst b/Doc/c-api/dict.rst index a2a0d0d80657eb..556113a97bf772 100644 --- a/Doc/c-api/dict.rst +++ b/Doc/c-api/dict.rst @@ -151,7 +151,7 @@ Dictionary objects * If the key is present, set *\*result* to a new :term:`strong reference` to the value and return ``1``. * If the key is missing, set *\*result* to ``NULL`` and return ``0``. - * On error, raise an exception and return ``-1``. + * On error, raise an exception, set *\*result* to ``NULL`` and return ``-1``. The first argument can be a :class:`dict` or a :class:`frozendict`. From b922b42be7c9bedd3ecf6f34a560fa692793a530 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 8 May 2026 13:09:06 +0200 Subject: [PATCH 007/818] [3.15] gh-145176: Update CODEOWNERS for Emscripten migration to Platforms directory (GH-149544) (#149550) gh-145176: Update CODEOWNERS for Emscripten migration to Platforms directory (GH-149544) (cherry picked from commit 52a05e8da71abcc83df54e465d0a4df50785e910) Co-authored-by: Malcolm Smith --- .github/CODEOWNERS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 769d739a8057aa..f4ffa24edca453 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -175,8 +175,8 @@ Lib/test/test__osx_support.py @python/macos-team Tools/wasm/README.md @brettcannon @freakboy3742 @emmatyping # WebAssembly (Emscripten) -Tools/wasm/config.site-wasm32-emscripten @freakboy3742 @emmatyping -Tools/wasm/emscripten @freakboy3742 @emmatyping +Platforms/emscripten @freakboy3742 @emmatyping +Tools/wasm/emscripten @freakboy3742 @emmatyping # WebAssembly (WASI) Platforms/WASI @brettcannon @emmatyping @savannahostrowski From f9e5975deb6b01c434eadff66f28bd53e0ca4c55 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 8 May 2026 13:48:04 +0200 Subject: [PATCH 008/818] [3.15] gh-149459: Fix segfault when `_LOAD_SPECIAL` guard deoptimizes (GH-149478) (#149552) gh-149459: Fix segfault when `_LOAD_SPECIAL` guard deoptimizes (GH-149478) (cherry picked from commit c341e341b25cec03d28d1b2c368bb871d76ca88b) Co-authored-by: Hai Zhu --- Lib/test/test_capi/test_opt.py | 14 ++++++++++++++ .../2026-05-07-03-18-59.gh-issue-149459.5fhAqP.rst | 1 + Python/optimizer_bytecodes.c | 11 ++++++++++- Python/optimizer_cases.c.h | 6 +++++- 4 files changed, 30 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-05-07-03-18-59.gh-issue-149459.5fhAqP.rst diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py index aaa5050208ced9..2f606c2c6eba2d 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -6138,6 +6138,20 @@ def __init__(self, x): C(0) if i else str(0) """)) + def test_load_special_type_guard_deopt(self): + script_helper.assert_python_ok("-s", "-c", textwrap.dedent(f""" + def f1(): + class Context: + def __enter__(self): ... + def __exit__(self, e, v, t): ... + + with Context(): + pass + + for _ in range({TIER2_THRESHOLD + 5}): + f1() + """), PYTHON_JIT="1") + def global_identity(x): return x diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-07-03-18-59.gh-issue-149459.5fhAqP.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-07-03-18-59.gh-issue-149459.5fhAqP.rst new file mode 100644 index 00000000000000..4cd0a148df3c70 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-07-03-18-59.gh-issue-149459.5fhAqP.rst @@ -0,0 +1 @@ +Fix a crash in the JIT optimizer when a specialized ``LOAD_SPECIAL`` guard deoptimized after inserting the synthetic ``NULL`` stack entry. diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c index 39cc36ae79fead..96dbaea5a5797e 100644 --- a/Python/optimizer_bytecodes.c +++ b/Python/optimizer_bytecodes.c @@ -2043,7 +2043,16 @@ dummy_func(void) { PyObject *name = _Py_SpecialMethods[oparg].name; PyObject *descr = _PyType_Lookup(type, name); if (descr != NULL && (Py_TYPE(descr)->tp_flags & Py_TPFLAGS_METHOD_DESCRIPTOR)) { - ADD_OP(_GUARD_TYPE_VERSION, 0, type->tp_version_tag); + /* LOAD_SPECIAL expands to _RECORD_TOS_TYPE + _INSERT_NULL + + * _LOAD_SPECIAL. Insert _GUARD_TYPE_VERSION before the + * already-emitted _INSERT_NULL so deopt sees the original + * stack shape.*/ + _PyUOpInstruction *insert_null = uop_buffer_last(&ctx->out_buffer); + assert(insert_null->opcode == _INSERT_NULL); + assert(insert_null->target == this_instr->target); + REPLACE_OP(insert_null, _GUARD_TYPE_VERSION, 0, type->tp_version_tag); + ADD_OP(_INSERT_NULL, 0, 0); + bool immortal = _Py_IsImmortal(descr) || (type->tp_flags & Py_TPFLAGS_IMMUTABLETYPE); ADD_OP(immortal ? _LOAD_CONST_INLINE_BORROW : _LOAD_CONST_INLINE, 0, (uintptr_t)descr); diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index db3dcbb97b2645..f336549d2ed244 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -3896,7 +3896,11 @@ PyObject *name = _Py_SpecialMethods[oparg].name; PyObject *descr = _PyType_Lookup(type, name); if (descr != NULL && (Py_TYPE(descr)->tp_flags & Py_TPFLAGS_METHOD_DESCRIPTOR)) { - ADD_OP(_GUARD_TYPE_VERSION, 0, type->tp_version_tag); + _PyUOpInstruction *insert_null = uop_buffer_last(&ctx->out_buffer); + assert(insert_null->opcode == _INSERT_NULL); + assert(insert_null->target == this_instr->target); + REPLACE_OP(insert_null, _GUARD_TYPE_VERSION, 0, type->tp_version_tag); + ADD_OP(_INSERT_NULL, 0, 0); bool immortal = _Py_IsImmortal(descr) || (type->tp_flags & Py_TPFLAGS_IMMUTABLETYPE); ADD_OP(immortal ? _LOAD_CONST_INLINE_BORROW : _LOAD_CONST_INLINE, 0, (uintptr_t)descr); From 333b7c54c01b2eb1aca9b4d0ffe35b45e833f18a Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 8 May 2026 15:06:08 +0200 Subject: [PATCH 009/818] [3.15] Add Diego as author of PEP 831 (GH-149551) (#149561) --- Doc/whatsnew/3.15.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst index 9e2f789334ff02..0f7782ba1813d1 100644 --- a/Doc/whatsnew/3.15.rst +++ b/Doc/whatsnew/3.15.rst @@ -411,8 +411,8 @@ embedding applications, and native libraries. unwinding for the whole Python process. (Contributed by Pablo Galindo Salgado and Savannah Ostrowski in -:gh:`149201`; PEP 831 written by Pablo Galindo Salgado, Ken Jin, and -Savannah Ostrowski.) +:gh:`149201`; PEP 831 written by Pablo Galindo Salgado, Ken Jin, +Savannah Ostrowski, and Diego Russo.) .. seealso:: :pep:`831` for further details. From 54a187d3b3ae11e37ae04fd91f3ea0cdfb6fe410 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 8 May 2026 15:32:59 +0200 Subject: [PATCH 010/818] [3.15] Skip GNU backtrace test on Arm 32-bit (GH-149493) (#149562) --- Lib/test/test_frame_pointer_unwind.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/Lib/test/test_frame_pointer_unwind.py b/Lib/test/test_frame_pointer_unwind.py index faa012c9c00d8f..1cf5083fd0fdcf 100644 --- a/Lib/test/test_frame_pointer_unwind.py +++ b/Lib/test/test_frame_pointer_unwind.py @@ -89,6 +89,21 @@ def _frame_pointers_expected(machine): return None +def _is_arm32_build(): + if sys.maxsize >= 2**32: + return False + + abi = " ".join( + value for value in ( + sysconfig.get_config_var("MULTIARCH"), + sysconfig.get_config_var("HOST_GNU_TYPE"), + sysconfig.get_config_var("SOABI"), + ) + if value + ).lower() + return "arm" in abi + + def _build_stack_and_unwind(unwinder): import operator @@ -295,6 +310,10 @@ def test_manual_unwind_respects_frame_pointers(self): @support.requires_gil_enabled("test requires the GIL enabled") @unittest.skipIf(support.is_wasi, "test not supported on WASI") @unittest.skipUnless(sys.platform == "linux", "GNU backtrace unwinding test requires Linux") +@unittest.skipIf( + _is_arm32_build(), + "GNU backtrace unwinding skipped on Arm 32-bit", +) class GnuBacktraceUnwindTests(unittest.TestCase): def setUp(self): From 0bdbc4810165bcbaefd16560d48e94a472557d23 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 8 May 2026 16:24:49 +0200 Subject: [PATCH 011/818] [3.15] Rename fp unwind test module to C stack unwind (GH-149563) (#149565) --- ...inter_unwind.py => test_c_stack_unwind.py} | 31 +++++++++++++------ 1 file changed, 22 insertions(+), 9 deletions(-) rename Lib/test/{test_frame_pointer_unwind.py => test_c_stack_unwind.py} (92%) diff --git a/Lib/test/test_frame_pointer_unwind.py b/Lib/test/test_c_stack_unwind.py similarity index 92% rename from Lib/test/test_frame_pointer_unwind.py rename to Lib/test/test_c_stack_unwind.py index 1cf5083fd0fdcf..91bf44e463473d 100644 --- a/Lib/test/test_frame_pointer_unwind.py +++ b/Lib/test/test_c_stack_unwind.py @@ -1,3 +1,12 @@ +"""Test in-process C stack unwinders against Python and JIT frames. + +The tests build a recursive Python call stack, ask each _testinternalcapi +unwinder for return addresses, and classify those addresses as Python, JIT, or +other frames. The backends include CPython's manual stack-chain unwinder and +GNU backtrace(), so this module is about in-process C stack unwinding rather +than a single unwind mechanism. GDB integration tests live in test_gdb. +""" + import json import os import platform @@ -20,7 +29,7 @@ STACK_DEPTH = 10 -def _frame_pointers_expected(machine): +def _manual_unwind_expected(machine): _Py_WITH_FRAME_POINTERS = getattr( _testinternalcapi, "_Py_WITH_FRAME_POINTERS", @@ -195,7 +204,7 @@ def _annotate_unwind_after_executor_free(unwinder_name="gnu_backtrace_unwind"): def _run_unwind_helper(helper_name, unwinder_name, **env): code = ( - f"from test.test_frame_pointer_unwind import {helper_name}; " + f"from test.test_c_stack_unwind import {helper_name}; " f"print({helper_name}({unwinder_name!r}));" ) run_env = os.environ.copy() @@ -235,15 +244,17 @@ def _unwind_after_executor_free_result(unwinder_name, **env): @support.requires_gil_enabled("test requires the GIL enabled") @unittest.skipIf(support.is_wasi, "test not supported on WASI") -class FramePointerUnwindTests(unittest.TestCase): +class ManualStackUnwindTests(unittest.TestCase): def setUp(self): super().setUp() machine = platform.machine().lower() - expected = _frame_pointers_expected(machine) + expected = _manual_unwind_expected(machine) if expected is None: - self.skipTest(f"unsupported architecture for frame pointer check: {machine}") + self.skipTest( + f"unsupported architecture for manual stack unwind check: {machine}" + ) if expected == "crash": self.skipTest(f"test does crash on {machine}") @@ -251,12 +262,14 @@ def setUp(self): _testinternalcapi.manual_frame_pointer_unwind() except RuntimeError as exc: if "not supported" in str(exc): - self.skipTest("manual frame pointer unwinding not supported on this platform") + self.skipTest( + "manual stack unwinding not supported on this platform" + ) raise self.machine = machine - self.frame_pointers_expected = expected + self.manual_unwind_expected = expected - def test_manual_unwind_respects_frame_pointers(self): + def test_manual_unwind_finds_expected_frames(self): jit_available = hasattr(sys, "_jit") and sys._jit.is_available() envs = [({"PYTHON_JIT": "0"}, False)] if jit_available: @@ -268,7 +281,7 @@ def test_manual_unwind_respects_frame_pointers(self): jit_frames = result["jit_frames"] python_frames = result.get("python_frames", 0) jit_backend = result.get("jit_backend") - if self.frame_pointers_expected: + if self.manual_unwind_expected: self.assertGreaterEqual( python_frames, STACK_DEPTH, From bb060b82f6723110b399431843e7de7d209c3a1d Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 8 May 2026 22:53:55 +0200 Subject: [PATCH 012/818] [3.15] gh-79638: Test other HTTP error codes besides 403 in test_robotparser (GH-149569) (GH-149580) Also, use urllib.request.urlcleanup() in NetworkTestCase. (cherry picked from commit 57ef2199503387617b8af3d719c74089fb70dbd4) Co-authored-by: Serhiy Storchaka --- Lib/test/test_robotparser.py | 83 +++++++++++++++++++++++++++--------- 1 file changed, 64 insertions(+), 19 deletions(-) diff --git a/Lib/test/test_robotparser.py b/Lib/test/test_robotparser.py index 3ea0ec66fbfbe9..cd1477037e94b7 100644 --- a/Lib/test/test_robotparser.py +++ b/Lib/test/test_robotparser.py @@ -646,26 +646,23 @@ def test_group_without_user_agent(self): ) class BaseLocalNetworkTestCase: - def setUp(self): + @classmethod + def setUpClass(cls): # clear _opener global variable - self.addCleanup(urllib.request.urlcleanup) + cls.addClassCleanup(urllib.request.urlcleanup) - self.server = HTTPServer((socket_helper.HOST, 0), self.RobotHandler) + cls.server = HTTPServer((socket_helper.HOST, 0), cls.RobotHandler) + cls.addClassCleanup(cls.server.server_close) - self.t = threading.Thread( + t = threading.Thread( name='HTTPServer serving', - target=self.server.serve_forever, + target=cls.server.serve_forever, # Short poll interval to make the test finish quickly. # Time between requests is short enough that we won't wake # up spuriously too many times. kwargs={'poll_interval':0.01}) - self.t.daemon = True # In case this function raises. - self.t.start() - - def tearDown(self): - self.server.shutdown() - self.t.join() - self.server.server_close() + cls.enterClassContext(threading_helper.start_threads([t])) + cls.addClassCleanup(cls.server.shutdown) SAMPLE_ROBOTS_TXT = b'''\ @@ -687,7 +684,6 @@ def do_GET(self): def log_message(self, format, *args): pass - @threading_helper.reap_threads def testRead(self): # Test that reading a weird robots.txt doesn't fail. addr = self.server.server_address @@ -702,31 +698,79 @@ def testRead(self): self.assertTrue(parser.can_fetch(agent, url + '/utf8/')) self.assertFalse(parser.can_fetch(agent, url + '/utf8/\U0001f40d')) self.assertFalse(parser.can_fetch(agent, url + '/utf8/%F0%9F%90%8D')) - self.assertFalse(parser.can_fetch(agent, url + '/utf8/\U0001f40d')) self.assertTrue(parser.can_fetch(agent, url + '/non-utf8/')) self.assertFalse(parser.can_fetch(agent, url + '/non-utf8/%F0')) self.assertFalse(parser.can_fetch(agent, url + '/non-utf8/\U0001f40d')) self.assertFalse(parser.can_fetch(agent, url + '/%2F[spam]/path')) -class PasswordProtectedSiteTestCase(BaseLocalNetworkTestCase, unittest.TestCase): +class HttpErrorsTestCase(BaseLocalNetworkTestCase, unittest.TestCase): class RobotHandler(BaseHTTPRequestHandler): def do_GET(self): - self.send_error(403, "Forbidden access") + self.send_error(self.server.return_code) def log_message(self, format, *args): pass - @threading_helper.reap_threads - def testPasswordProtectedSite(self): + def setUp(self): + # Make sure that a valid code is set in the test. + self.server.return_code = None + + def testUnauthorized(self): + self.server.return_code = 401 + addr = self.server.server_address + url = f'http://{socket_helper.HOST}:{addr[1]}' + robots_url = url + "/robots.txt" + parser = urllib.robotparser.RobotFileParser() + parser.set_url(url) + parser.read() + self.assertFalse(parser.can_fetch("*", robots_url)) + self.assertFalse(parser.can_fetch("*", url + '/some/file.html')) + + def testForbidden(self): + self.server.return_code = 403 + addr = self.server.server_address + url = f'http://{socket_helper.HOST}:{addr[1]}' + robots_url = url + "/robots.txt" + parser = urllib.robotparser.RobotFileParser() + parser.set_url(url) + parser.read() + self.assertFalse(parser.can_fetch("*", robots_url)) + self.assertFalse(parser.can_fetch("*", url + '/some/file.html')) + + def testNotFound(self): + self.server.return_code = 404 addr = self.server.server_address - url = 'http://' + socket_helper.HOST + ':' + str(addr[1]) + url = f'http://{socket_helper.HOST}:{addr[1]}' + robots_url = url + "/robots.txt" + parser = urllib.robotparser.RobotFileParser() + parser.set_url(url) + parser.read() + self.assertTrue(parser.can_fetch("*", robots_url)) + self.assertTrue(parser.can_fetch("*", url + '/path/file.html')) + + def testTeapot(self): + self.server.return_code = 418 + addr = self.server.server_address + url = f'http://{socket_helper.HOST}:{addr[1]}' + robots_url = url + "/robots.txt" + parser = urllib.robotparser.RobotFileParser() + parser.set_url(url) + parser.read() + self.assertTrue(parser.can_fetch("*", robots_url)) + self.assertTrue(parser.can_fetch("*", url + '/pot-1?milk-type=Cream')) + + def testServiceUnavailable(self): + self.server.return_code = 503 + addr = self.server.server_address + url = f'http://{socket_helper.HOST}:{addr[1]}' robots_url = url + "/robots.txt" parser = urllib.robotparser.RobotFileParser() parser.set_url(url) parser.read() self.assertFalse(parser.can_fetch("*", robots_url)) + self.assertFalse(parser.can_fetch("*", url + '/path/file.html')) @support.requires_working_socket() @@ -738,6 +782,7 @@ class NetworkTestCase(unittest.TestCase): @classmethod def setUpClass(cls): support.requires('network') + cls.addClassCleanup(urllib.request.urlcleanup) with socket_helper.transient_internet(cls.base_url): cls.parser = urllib.robotparser.RobotFileParser(cls.robots_txt) cls.parser.read() From 2b1eed460d598a30a5eab63f5f1f4d8ac8e43468 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 9 May 2026 02:28:21 +0200 Subject: [PATCH 013/818] [3.15] gh-149474: use `Py_fopen` in `Binary{Reader,Writer}` for audit hook and path-like support (GH-149524) (#149586) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gh-149474: use `Py_fopen` in `Binary{Reader,Writer}` for audit hook and path-like support (GH-149524) (cherry picked from commit 354ef336e4cd48cf0c02bc9a0c642adf5d543184) Co-authored-by: Maurycy Pawłowski-Wieroński --- Lib/test/audit-tests.py | 14 ++++++ .../test_binary_format.py | 30 +++++++++++++ ...-05-08-02-18-54.gh-issue-149474.ujQ-mu.rst | 3 ++ Modules/_remote_debugging/binary_io.h | 12 ++--- Modules/_remote_debugging/binary_io_reader.c | 45 +++++++------------ Modules/_remote_debugging/binary_io_writer.c | 18 ++------ Modules/_remote_debugging/clinic/module.c.h | 38 +++------------- Modules/_remote_debugging/module.c | 12 ++--- 8 files changed, 83 insertions(+), 89 deletions(-) create mode 100644 Misc/NEWS.d/next/Security/2026-05-08-02-18-54.gh-issue-149474.ujQ-mu.rst diff --git a/Lib/test/audit-tests.py b/Lib/test/audit-tests.py index a893932169a089..8be5bf8aa4f546 100644 --- a/Lib/test/audit-tests.py +++ b/Lib/test/audit-tests.py @@ -208,6 +208,16 @@ def rl(name): else: return None + try: + import _remote_debugging + except ImportError: + _remote_debugging = None + + def rd(name): + if _remote_debugging: + return getattr(_remote_debugging, name, None) + return None + # Try a range of "open" functions. # All of them should fail with TestHook(raise_on_events={"open"}) as hook: @@ -225,6 +235,8 @@ def rl(name): (rl("append_history_file"), 0, None), (rl("read_init_file"), testfn), (rl("read_init_file"), None), + (rd("BinaryWriter"), testfn, 1000, 0), + (rd("BinaryReader"), testfn), ]: if not fn: continue @@ -258,6 +270,8 @@ def rl(name): ("~/.history", "a") if rl("append_history_file") else None, (testfn, "r") if readline else None, ("", "r") if readline else None, + (testfn, "wb") if rd("BinaryWriter") else None, + (testfn, "rb") if rd("BinaryReader") else None, ] if i is not None ], diff --git a/Lib/test/test_profiling/test_sampling_profiler/test_binary_format.py b/Lib/test/test_profiling/test_sampling_profiler/test_binary_format.py index 9cf706aa2dafee..1fbb4e2d6c6fbb 100644 --- a/Lib/test/test_profiling/test_sampling_profiler/test_binary_format.py +++ b/Lib/test/test_profiling/test_sampling_profiler/test_binary_format.py @@ -2,6 +2,7 @@ import json import os +import pathlib import random import struct import tempfile @@ -814,6 +815,35 @@ def test_invalid_file_path(self): with BinaryReader("/nonexistent/path/file.bin") as reader: reader.replay_samples(RawCollector()) + def test_path_arguments_round_trip(self): + """Reader and writer accept str, bytes or os.PathLike.""" + with tempfile.NamedTemporaryFile(suffix=".bin", delete=False) as f: + filename = f.name + self.temp_files.append(filename) + + for path_arg in (filename, os.fsencode(filename), pathlib.Path(filename)): + with self.subTest(path_type=type(path_arg).__name__): + writer = _remote_debugging.BinaryWriter(path_arg, 1000, 0) + writer.finalize() + reader = _remote_debugging.BinaryReader(path_arg) + info = reader.get_info() + reader.close() + self.assertEqual(info["sample_count"], 0) + + def test_rejects_non_pathlike(self): + """Reader and writer raise TypeError on non-path-like filenames.""" + with self.assertRaises(TypeError): + _remote_debugging.BinaryWriter(123, 1000, 0) + with self.assertRaises(TypeError): + _remote_debugging.BinaryReader(123) + + def test_invalid_path_error_preserves_pathlib(self): + """Missing path: OSError carries the original path object, not a string.""" + missing = pathlib.Path("/i/do/not/exist") + with self.assertRaises(FileNotFoundError) as cm: + _remote_debugging.BinaryReader(missing) + self.assertEqual(os.fspath(cm.exception.filename), os.fspath(missing)) + def test_writer_handles_empty_stack_first_sample(self): """BinaryWriter.write_sample tolerates an empty stack on a fresh thread. diff --git a/Misc/NEWS.d/next/Security/2026-05-08-02-18-54.gh-issue-149474.ujQ-mu.rst b/Misc/NEWS.d/next/Security/2026-05-08-02-18-54.gh-issue-149474.ujQ-mu.rst new file mode 100644 index 00000000000000..48e718b95ebe3a --- /dev/null +++ b/Misc/NEWS.d/next/Security/2026-05-08-02-18-54.gh-issue-149474.ujQ-mu.rst @@ -0,0 +1,3 @@ +Fix the binary writer in :mod:`profiling.sampling` not firing the audit +(:pep:`578`) when creating the output file. The writer and the reader now +accept any path-like object. Patch by Maurycy Pawłowski-Wieroński. diff --git a/Modules/_remote_debugging/binary_io.h b/Modules/_remote_debugging/binary_io.h index 87a54371c774f1..d4188335c0b6d0 100644 --- a/Modules/_remote_debugging/binary_io.h +++ b/Modules/_remote_debugging/binary_io.h @@ -253,7 +253,6 @@ typedef struct { /* Main binary writer structure */ typedef struct { FILE *fp; - char *filename; /* Write buffer for batched I/O */ uint8_t *write_buffer; @@ -311,10 +310,7 @@ typedef struct { /* Main binary reader structure */ typedef struct { - char *filename; - #if USE_MMAP - int fd; uint8_t *mapped_data; size_t mapped_size; #else @@ -522,7 +518,7 @@ grow_array_inplace(void **ptr_addr, size_t count, size_t *capacity, size_t elem_ * Create a new binary writer. * * Arguments: - * filename: Path to output file + * path: Path to output file * sample_interval_us: Sampling interval in microseconds * compression_type: COMPRESSION_NONE or COMPRESSION_ZSTD * start_time_us: Start timestamp in microseconds (from time.monotonic() * 1e6) @@ -531,7 +527,7 @@ grow_array_inplace(void **ptr_addr, size_t count, size_t *capacity, size_t elem_ * New BinaryWriter* on success, NULL on failure (PyErr set) */ BinaryWriter *binary_writer_create( - const char *filename, + PyObject *path, uint64_t sample_interval_us, int compression_type, uint64_t start_time_us @@ -583,12 +579,12 @@ void binary_writer_destroy(BinaryWriter *writer); * Open a binary file for reading. * * Arguments: - * filename: Path to input file + * path: Path to input file * * Returns: * New BinaryReader* on success, NULL on failure (PyErr set) */ -BinaryReader *binary_reader_open(const char *filename); +BinaryReader *binary_reader_open(PyObject *path); /* * Replay samples from binary file through a collector. diff --git a/Modules/_remote_debugging/binary_io_reader.c b/Modules/_remote_debugging/binary_io_reader.c index 551530b519952c..972b197cfbad86 100644 --- a/Modules/_remote_debugging/binary_io_reader.c +++ b/Modules/_remote_debugging/binary_io_reader.c @@ -358,7 +358,7 @@ reader_parse_frame_table(BinaryReader *reader, const uint8_t *data, size_t file_ } BinaryReader * -binary_reader_open(const char *filename) +binary_reader_open(PyObject *path) { BinaryReader *reader = PyMem_Calloc(1, sizeof(BinaryReader)); if (!reader) { @@ -366,29 +366,18 @@ binary_reader_open(const char *filename) return NULL; } -#if USE_MMAP - reader->fd = -1; /* Explicit initialization for cleanup safety */ -#endif - - reader->filename = PyMem_Malloc(strlen(filename) + 1); - if (!reader->filename) { - PyMem_Free(reader); - PyErr_NoMemory(); - return NULL; - } - strcpy(reader->filename, filename); - #if USE_MMAP /* Open with mmap on Unix */ - reader->fd = open(filename, O_RDONLY); - if (reader->fd < 0) { - PyErr_SetFromErrnoWithFilename(PyExc_IOError, filename); + FILE *fp = Py_fopen(path, "rb"); + if (!fp) { goto error; } + int fd = fileno(fp); struct stat st; - if (fstat(reader->fd, &st) < 0) { + if (fstat(fd, &st) < 0) { PyErr_SetFromErrno(PyExc_IOError); + Py_fclose(fp); goto error; } reader->mapped_size = st.st_size; @@ -400,14 +389,15 @@ binary_reader_open(const char *filename) */ #ifdef __linux__ reader->mapped_data = mmap(NULL, reader->mapped_size, PROT_READ, - MAP_PRIVATE | MAP_POPULATE, reader->fd, 0); + MAP_PRIVATE | MAP_POPULATE, fd, 0); #else reader->mapped_data = mmap(NULL, reader->mapped_size, PROT_READ, - MAP_PRIVATE, reader->fd, 0); + MAP_PRIVATE, fd, 0); #endif if (reader->mapped_data == MAP_FAILED) { reader->mapped_data = NULL; PyErr_SetFromErrno(PyExc_IOError); + Py_fclose(fp); goto error; } @@ -428,19 +418,20 @@ binary_reader_open(const char *filename) /* Add file descriptor-level hints for better kernel I/O scheduling */ #if defined(__linux__) && defined(POSIX_FADV_SEQUENTIAL) - (void)posix_fadvise(reader->fd, 0, 0, POSIX_FADV_SEQUENTIAL); + (void)posix_fadvise(fd, 0, 0, POSIX_FADV_SEQUENTIAL); if (reader->mapped_size > (64 * 1024 * 1024)) { - (void)posix_fadvise(reader->fd, 0, 0, POSIX_FADV_WILLNEED); + (void)posix_fadvise(fd, 0, 0, POSIX_FADV_WILLNEED); } #endif + (void)Py_fclose(fp); + uint8_t *data = reader->mapped_data; size_t file_size = reader->mapped_size; #else /* Use stdio on Windows */ - reader->fp = fopen(filename, "rb"); + reader->fp = Py_fopen(path, "rb"); if (!reader->fp) { - PyErr_SetFromErrnoWithFilename(PyExc_IOError, filename); goto error; } @@ -1263,8 +1254,6 @@ binary_reader_close(BinaryReader *reader) return; } - PyMem_Free(reader->filename); - #if USE_MMAP if (reader->mapped_data) { munmap(reader->mapped_data, reader->mapped_size); @@ -1274,13 +1263,9 @@ binary_reader_close(BinaryReader *reader) /* Clear sample_data which may point into the now-unmapped region */ reader->sample_data = NULL; reader->sample_data_size = 0; - if (reader->fd >= 0) { - close(reader->fd); - reader->fd = -1; /* Mark as closed */ - } #else if (reader->fp) { - fclose(reader->fp); + Py_fclose(reader->fp); reader->fp = NULL; } if (reader->file_data) { diff --git a/Modules/_remote_debugging/binary_io_writer.c b/Modules/_remote_debugging/binary_io_writer.c index 4cfed7300ac5ab..c31ed7d746466f 100644 --- a/Modules/_remote_debugging/binary_io_writer.c +++ b/Modules/_remote_debugging/binary_io_writer.c @@ -717,7 +717,7 @@ write_sample_with_encoding(BinaryWriter *writer, ThreadEntry *entry, } BinaryWriter * -binary_writer_create(const char *filename, uint64_t sample_interval_us, int compression_type, +binary_writer_create(PyObject *path, uint64_t sample_interval_us, int compression_type, uint64_t start_time_us) { BinaryWriter *writer = PyMem_Calloc(1, sizeof(BinaryWriter)); @@ -726,14 +726,6 @@ binary_writer_create(const char *filename, uint64_t sample_interval_us, int comp return NULL; } - writer->filename = PyMem_Malloc(strlen(filename) + 1); - if (!writer->filename) { - PyMem_Free(writer); - PyErr_NoMemory(); - return NULL; - } - strcpy(writer->filename, filename); - writer->start_time_us = start_time_us; writer->sample_interval_us = sample_interval_us; writer->compression_type = compression_type; @@ -799,9 +791,8 @@ binary_writer_create(const char *filename, uint64_t sample_interval_us, int comp } } - writer->fp = fopen(filename, "wb"); + writer->fp = Py_fopen(path, "wb"); if (!writer->fp) { - PyErr_SetFromErrnoWithFilename(PyExc_IOError, filename); goto error; } @@ -1193,7 +1184,7 @@ binary_writer_finalize(BinaryWriter *writer) return -1; } - if (fclose(writer->fp) != 0) { + if (Py_fclose(writer->fp) != 0) { writer->fp = NULL; PyErr_SetFromErrno(PyExc_IOError); return -1; @@ -1211,10 +1202,9 @@ binary_writer_destroy(BinaryWriter *writer) } if (writer->fp) { - fclose(writer->fp); + Py_fclose(writer->fp); } - PyMem_Free(writer->filename); PyMem_Free(writer->write_buffer); #ifdef HAVE_ZSTD diff --git a/Modules/_remote_debugging/clinic/module.c.h b/Modules/_remote_debugging/clinic/module.c.h index 1133db808efaec..d56622fb82ab56 100644 --- a/Modules/_remote_debugging/clinic/module.c.h +++ b/Modules/_remote_debugging/clinic/module.c.h @@ -688,7 +688,7 @@ PyDoc_STRVAR(_remote_debugging_BinaryWriter___init____doc__, static int _remote_debugging_BinaryWriter___init___impl(BinaryWriterObject *self, - const char *filename, + PyObject *filename, unsigned long long sample_interval_us, unsigned long long start_time_us, int compression); @@ -728,7 +728,7 @@ _remote_debugging_BinaryWriter___init__(PyObject *self, PyObject *args, PyObject PyObject * const *fastargs; Py_ssize_t nargs = PyTuple_GET_SIZE(args); Py_ssize_t noptargs = nargs + (kwargs ? PyDict_GET_SIZE(kwargs) : 0) - 3; - const char *filename; + PyObject *filename; unsigned long long sample_interval_us; unsigned long long start_time_us; int compression = 0; @@ -738,19 +738,7 @@ _remote_debugging_BinaryWriter___init__(PyObject *self, PyObject *args, PyObject if (!fastargs) { goto exit; } - if (!PyUnicode_Check(fastargs[0])) { - _PyArg_BadArgument("BinaryWriter", "argument 'filename'", "str", fastargs[0]); - goto exit; - } - Py_ssize_t filename_length; - filename = PyUnicode_AsUTF8AndSize(fastargs[0], &filename_length); - if (filename == NULL) { - goto exit; - } - if (strlen(filename) != (size_t)filename_length) { - PyErr_SetString(PyExc_ValueError, "embedded null character"); - goto exit; - } + filename = fastargs[0]; if (!_PyLong_UnsignedLongLong_Converter(fastargs[1], &sample_interval_us)) { goto exit; } @@ -1009,7 +997,7 @@ PyDoc_STRVAR(_remote_debugging_BinaryReader___init____doc__, static int _remote_debugging_BinaryReader___init___impl(BinaryReaderObject *self, - const char *filename); + PyObject *filename); static int _remote_debugging_BinaryReader___init__(PyObject *self, PyObject *args, PyObject *kwargs) @@ -1045,26 +1033,14 @@ _remote_debugging_BinaryReader___init__(PyObject *self, PyObject *args, PyObject PyObject *argsbuf[1]; PyObject * const *fastargs; Py_ssize_t nargs = PyTuple_GET_SIZE(args); - const char *filename; + PyObject *filename; fastargs = _PyArg_UnpackKeywords(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser, /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); if (!fastargs) { goto exit; } - if (!PyUnicode_Check(fastargs[0])) { - _PyArg_BadArgument("BinaryReader", "argument 'filename'", "str", fastargs[0]); - goto exit; - } - Py_ssize_t filename_length; - filename = PyUnicode_AsUTF8AndSize(fastargs[0], &filename_length); - if (filename == NULL) { - goto exit; - } - if (strlen(filename) != (size_t)filename_length) { - PyErr_SetString(PyExc_ValueError, "embedded null character"); - goto exit; - } + filename = fastargs[0]; return_value = _remote_debugging_BinaryReader___init___impl((BinaryReaderObject *)self, filename); exit: @@ -1564,4 +1540,4 @@ _remote_debugging_get_gc_stats(PyObject *module, PyObject *const *args, Py_ssize exit: return return_value; } -/*[clinic end generated code: output=36674f4cb8a653f3 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=5e2a29746a0c5d65 input=a9049054013a1b77]*/ diff --git a/Modules/_remote_debugging/module.c b/Modules/_remote_debugging/module.c index 172f8711a2a2a0..efdd2e1a2d7b7a 100644 --- a/Modules/_remote_debugging/module.c +++ b/Modules/_remote_debugging/module.c @@ -1476,7 +1476,7 @@ class _remote_debugging.BinaryWriter "BinaryWriterObject *" "&PyBinaryWriter_Typ /*[clinic input] @permit_long_docstring_body _remote_debugging.BinaryWriter.__init__ - filename: str + filename: object sample_interval_us: unsigned_long_long start_time_us: unsigned_long_long * @@ -1495,11 +1495,11 @@ Use as a context manager or call finalize() when done. static int _remote_debugging_BinaryWriter___init___impl(BinaryWriterObject *self, - const char *filename, + PyObject *filename, unsigned long long sample_interval_us, unsigned long long start_time_us, int compression) -/*[clinic end generated code: output=014c0306f1bacf4b input=3bdf01c1cc2f5a1d]*/ +/*[clinic end generated code: output=00446656ea2e5986 input=b92f0c77ba4cd274]*/ { if (self->writer) { binary_writer_destroy(self->writer); @@ -1742,7 +1742,7 @@ class _remote_debugging.BinaryReader "BinaryReaderObject *" "&PyBinaryReader_Typ /*[clinic input] _remote_debugging.BinaryReader.__init__ - filename: str + filename: object High-performance binary reader for profiling data. @@ -1754,8 +1754,8 @@ Use as a context manager or call close() when done. static int _remote_debugging_BinaryReader___init___impl(BinaryReaderObject *self, - const char *filename) -/*[clinic end generated code: output=9699226f7ae052bb input=4201f9cc500ef2f6]*/ + PyObject *filename) +/*[clinic end generated code: output=f04b33ee5c5e6dbf input=9d7cbe8b4f1a97c9]*/ { if (self->reader) { binary_reader_close(self->reader); From 915b6c1572285f2bd469be177fe523eca52951f1 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 9 May 2026 10:27:29 +0200 Subject: [PATCH 014/818] [3.15] gh-149083: Convert `_initial_missing` for pure py `reduce` to `sentinel` (GH-149536) (#149592) gh-149083: Convert `_initial_missing` for pure py `reduce` to `sentinel` (GH-149536) (cherry picked from commit bc8cf07d8dbb4341955dc85d9b2bf273ec5852c7) Co-authored-by: sobolevn --- Lib/functools.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/functools.py b/Lib/functools.py index cd374631f16792..e03a77f204b544 100644 --- a/Lib/functools.py +++ b/Lib/functools.py @@ -232,7 +232,7 @@ def __ge__(self, other): ### reduce() sequence to a single item ################################################################################ -_initial_missing = object() +_initial_missing = sentinel('_initial_missing') def reduce(function, sequence, initial=_initial_missing): """ From dc8c32e59d1ae4163b04b015f48dd54a6d6a11a2 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 9 May 2026 15:33:05 +0200 Subject: [PATCH 015/818] [3.15] gh-149430: Fix edge-cases in `profiling.sampling` outputs (GH-149431) (#149602) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gh-149430: Fix edge-cases in `profiling.sampling` outputs (GH-149431) The line highlights on the heatmap are driven by the URL hash and the `:target` selector. When clicking a caller/callee link for the line that was already selected, the hash doesn't change, so the browser keeps the existing target state and doesn't restart the animation. Due to this the highlight only works the first time. With this fix, line navigation goes through JavaScript. If the target URL already points to the current location, the highlight is replayed by clearing the animation, forcing style recalculation, and restoring it. The `baseline_self` variable isn't initialized for structural elided roots. This variable is accessed later unconditionally and leads to a crash. The child process ends up being invoked with `--diff_flamegraph` instead of the correct argument. (cherry picked from commit 9587726a3ebbcdb780e3f15c9e016e3a28c646e3) Co-authored-by: László Kiss Kollár --- .../sampling/_heatmap_assets/heatmap.js | 22 ++++++++- Lib/profiling/sampling/cli.py | 4 +- Lib/profiling/sampling/stack_collector.py | 2 + .../test_sampling_profiler/test_children.py | 33 +++++++++++++ .../test_sampling_profiler/test_collectors.py | 46 +++++++++++++++++++ 5 files changed, 104 insertions(+), 3 deletions(-) diff --git a/Lib/profiling/sampling/_heatmap_assets/heatmap.js b/Lib/profiling/sampling/_heatmap_assets/heatmap.js index 2da1103b82a52a..1f698779f3a46e 100644 --- a/Lib/profiling/sampling/_heatmap_assets/heatmap.js +++ b/Lib/profiling/sampling/_heatmap_assets/heatmap.js @@ -84,7 +84,7 @@ function showNavigationMenu(button, items, title) { item.appendChild(funcDiv); item.appendChild(createElement('div', 'callee-menu-file', linkData.file)); - item.addEventListener('click', () => window.location.href = linkData.link); + item.addEventListener('click', () => navigateToLine(linkData.link)); menu.appendChild(item); }); @@ -105,7 +105,7 @@ function handleNavigationClick(button, e) { const navData = button.getAttribute('data-nav'); if (navData) { - window.location.href = JSON.parse(navData).link; + navigateToLine(JSON.parse(navData).link); return; } @@ -117,11 +117,29 @@ function handleNavigationClick(button, e) { } } +function restartLineHighlight(target) { + target.style.animation = 'none'; + // Force style recalculation so restoring the animation restarts it. + void target.offsetWidth; + target.style.animation = ''; +} + +function navigateToLine(link) { + const url = new URL(link, window.location.href); + + if (url.href === window.location.href) { + scrollToTargetLine(); + } else { + window.location.href = link; + } +} + function scrollToTargetLine() { if (!window.location.hash) return; const target = document.querySelector(window.location.hash); if (target) { target.scrollIntoView({ behavior: 'smooth', block: 'start' }); + restartLineHighlight(target); } } diff --git a/Lib/profiling/sampling/cli.py b/Lib/profiling/sampling/cli.py index 0648713edc52af..a5d9573ae6b6dd 100644 --- a/Lib/profiling/sampling/cli.py +++ b/Lib/profiling/sampling/cli.py @@ -167,7 +167,9 @@ def _build_child_profiler_args(args): child_args.extend(["--mode", mode]) # Format options (skip pstats as it's the default) - if args.format != "pstats": + if args.format == "diff_flamegraph": + child_args.extend(["--diff-flamegraph", args.diff_baseline]) + elif args.format != "pstats": child_args.append(f"--{args.format}") return child_args diff --git a/Lib/profiling/sampling/stack_collector.py b/Lib/profiling/sampling/stack_collector.py index 04622a8c1e89ef..60df026ed76a6c 100644 --- a/Lib/profiling/sampling/stack_collector.py +++ b/Lib/profiling/sampling/stack_collector.py @@ -698,6 +698,8 @@ def _add_elided_metadata(self, node, baseline_stats, scale, path): func_key = self._extract_func_key(node, self._baseline_collector._string_table) current_path = path + (func_key,) if func_key else path + baseline_self = 0 + baseline_total = 0 if func_key and current_path in baseline_stats: baseline_data = baseline_stats[current_path] baseline_self = baseline_data["self"] * scale diff --git a/Lib/test/test_profiling/test_sampling_profiler/test_children.py b/Lib/test/test_profiling/test_sampling_profiler/test_children.py index bb49faa890f348..e64d917eedde56 100644 --- a/Lib/test/test_profiling/test_sampling_profiler/test_children.py +++ b/Lib/test/test_profiling/test_sampling_profiler/test_children.py @@ -109,6 +109,39 @@ def _wait_for_process_ready(proc, timeout): return proc.poll() is None +@unittest.skipIf( + _build_child_profiler_args is None, + "profiling.sampling.cli unavailable", +) +class TestChildProfilerArgBuilder(unittest.TestCase): + """Tests for child profiler CLI argument construction.""" + + def test_build_child_profiler_args_diff_flamegraph(self): + """Test child args use the real --diff-flamegraph flag.""" + args = argparse.Namespace( + sample_interval_usec=1000, + duration=None, + all_threads=False, + realtime_stats=False, + native=False, + gc=True, + opcodes=False, + async_aware=False, + mode="wall", + format="diff_flamegraph", + diff_baseline="baseline.bin", + ) + + child_args = _build_child_profiler_args(args) + + self.assertIn("--diff-flamegraph", child_args) + self.assertNotIn("--diff_flamegraph", child_args) + + flag_index = child_args.index("--diff-flamegraph") + self.assertGreater(len(child_args), flag_index + 1) + self.assertEqual(child_args[flag_index + 1], "baseline.bin") + + @requires_remote_subprocess_debugging() class TestGetChildPids(unittest.TestCase): """Tests for the get_child_pids function.""" diff --git a/Lib/test/test_profiling/test_sampling_profiler/test_collectors.py b/Lib/test/test_profiling/test_sampling_profiler/test_collectors.py index b42e7aa579f40c..390a1479fdd297 100644 --- a/Lib/test/test_profiling/test_sampling_profiler/test_collectors.py +++ b/Lib/test/test_profiling/test_sampling_profiler/test_collectors.py @@ -18,6 +18,7 @@ ) from profiling.sampling.jsonl_collector import JsonlCollector from profiling.sampling.gecko_collector import GeckoCollector + from profiling.sampling.heatmap_collector import _TemplateLoader from profiling.sampling.collector import extract_lineno, normalize_location from profiling.sampling.opcode_utils import get_opcode_info, format_opcode from profiling.sampling.constants import ( @@ -82,6 +83,18 @@ def test_mock_frame_info_with_empty_and_unicode_values(self): self.assertEqual(frame.location.lineno, 999999) self.assertEqual(frame.funcname, long_funcname) + def test_heatmap_navigation_restarts_line_highlight(self): + """Test heatmap navigation can replay target line highlights.""" + loader = _TemplateLoader() + + self.assertIn(".code-line:target", loader.file_css) + self.assertIn("function restartLineHighlight(target)", loader.file_js) + self.assertIn("target.style.animation = 'none'", loader.file_js) + self.assertIn("void target.offsetWidth", loader.file_js) + self.assertIn("url.href === window.location.href", loader.file_js) + self.assertIn("navigateToLine(JSON.parse(navData).link)", loader.file_js) + self.assertIn("navigateToLine(linkData.link)", loader.file_js) + def test_pstats_collector_with_extreme_intervals_and_empty_data(self): """Test PstatsCollector handles zero/large intervals, empty frames, None thread IDs, and duplicate frames.""" # Test with zero interval @@ -1403,6 +1416,39 @@ def test_diff_flamegraph_elided_stacks(self): self.assertGreater(child["baseline"], 0) self.assertAlmostEqual(child["diff"], -child["baseline"]) + def test_diff_flamegraph_elided_top_level_root(self): + """Elided top-level roots do not crash metadata generation.""" + baseline_frames_1 = [ + MockInterpreterInfo(0, [ + MockThreadInfo(1, [ + MockFrameInfo("file.py", 10, "kept_leaf"), + MockFrameInfo("file.py", 20, "kept_root"), + ]) + ]) + ] + baseline_frames_2 = [ + MockInterpreterInfo(0, [ + MockThreadInfo(1, [ + MockFrameInfo("file.py", 30, "old_leaf"), + MockFrameInfo("file.py", 40, "old_root"), + ]) + ]) + ] + + diff = make_diff_collector_with_mock_baseline([ + baseline_frames_1, + baseline_frames_2, + ]) + diff.collect(baseline_frames_1) + + data = diff._convert_to_flamegraph_format() + elided = data["stats"]["elided_flamegraph"] + elided_strings = elided.get("strings", []) + children = elided.get("children", []) + + self.assertEqual(len(children), 1) + self.assertIn("old_root", resolve_name(children[0], elided_strings)) + def test_diff_flamegraph_function_matched_despite_line_change(self): """Functions match by (filename, funcname), ignoring lineno.""" baseline_frames = [ From 212e996cba9224ae8ba7cb03d018774e818fef33 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 9 May 2026 17:08:34 +0200 Subject: [PATCH 016/818] [3.15] gh-149388: Make asyncio `PipeHandle.close` idempotent (GH-149518) (#149605) gh-149388: Make asyncio `PipeHandle.close` idempotent (GH-149518) (cherry picked from commit 7241f2739c4bbdf4519238689e5e4ea9268b411e) Co-authored-by: Max Schmitt --- Lib/asyncio/windows_utils.py | 3 ++- Lib/test/test_asyncio/test_windows_utils.py | 24 +++++++++++++++++++ ...-05-07-21-58-17.gh-issue-149388.DDBPeA.rst | 1 + 3 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2026-05-07-21-58-17.gh-issue-149388.DDBPeA.rst diff --git a/Lib/asyncio/windows_utils.py b/Lib/asyncio/windows_utils.py index acd49441131b04..d6393f0b1ffee5 100644 --- a/Lib/asyncio/windows_utils.py +++ b/Lib/asyncio/windows_utils.py @@ -111,8 +111,9 @@ def fileno(self): def close(self, *, CloseHandle=_winapi.CloseHandle): if self._handle is not None: - CloseHandle(self._handle) + handle = self._handle self._handle = None + CloseHandle(handle) def __del__(self, _warn=warnings.warn): if self._handle is not None: diff --git a/Lib/test/test_asyncio/test_windows_utils.py b/Lib/test/test_asyncio/test_windows_utils.py index f9ee2f4f68150a..50969761347595 100644 --- a/Lib/test/test_asyncio/test_windows_utils.py +++ b/Lib/test/test_asyncio/test_windows_utils.py @@ -77,6 +77,30 @@ def test_pipe_handle(self): else: raise RuntimeError('expected ERROR_INVALID_HANDLE') + def test_pipe_handle_close_after_external_close(self): + # gh-149388: PipeHandle.close() must clear ``_handle`` before calling + # CloseHandle so that if CloseHandle raises on a stale handle the + # PipeHandle is still marked closed and __del__ / subsequent close() + # calls are silent no-ops. + h1, h2 = windows_utils.pipe(overlapped=(False, False)) + try: + p = windows_utils.PipeHandle(h1) + # Simulate an external close of the underlying handle (e.g. + # a finalizer race or a concurrent close on the same object). + _winapi.CloseHandle(p.handle) + # First close() still propagates the OSError from CloseHandle, + # but must clear ``_handle`` first. + with self.assertRaises(OSError): + p.close() + self.assertIsNone(p.handle) + # Second close() is a no-op. + p.close() + # __del__ through GC is also a silent no-op — no unraisable. + del p + support.gc_collect() + finally: + _winapi.CloseHandle(h2) + class PopenTests(unittest.TestCase): diff --git a/Misc/NEWS.d/next/Library/2026-05-07-21-58-17.gh-issue-149388.DDBPeA.rst b/Misc/NEWS.d/next/Library/2026-05-07-21-58-17.gh-issue-149388.DDBPeA.rst new file mode 100644 index 00000000000000..4a1c6f3f5b4e57 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-05-07-21-58-17.gh-issue-149388.DDBPeA.rst @@ -0,0 +1 @@ +Make :class:`!asyncio.windows_utils.PipeHandle` closing idempotent. From f488c7d45f5186be2bb52054b4dd3bc59a45fde5 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 9 May 2026 23:39:35 +0200 Subject: [PATCH 017/818] [3.15] Fix minor typos in unicode.rst (GH-149587) (#149620) Fix minor typos in unicode.rst (GH-149587) (cherry picked from commit 4e97ff3351f381a61b238bd8e805e4e8dd3ea5cf) Co-authored-by: Manoj K M --- Doc/c-api/unicode.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/c-api/unicode.rst b/Doc/c-api/unicode.rst index 059a7ef399ae0f..401c99ebeb0fec 100644 --- a/Doc/c-api/unicode.rst +++ b/Doc/c-api/unicode.rst @@ -762,7 +762,7 @@ APIs: 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 + Return the number of written characters, or return ``-1`` and raise an exception on error. .. versionadded:: 3.3 @@ -1174,7 +1174,7 @@ These are the UTF-8 codec APIs: .. versionadded:: 3.3 .. versionchanged:: 3.7 - The return type is now ``const char *`` rather of ``char *``. + The return type is now ``const char *`` rather than ``char *``. .. versionchanged:: 3.10 This function is a part of the :ref:`limited API `. @@ -1196,7 +1196,7 @@ These are the UTF-8 codec APIs: .. versionadded:: 3.3 .. versionchanged:: 3.7 - The return type is now ``const char *`` rather of ``char *``. + The return type is now ``const char *`` rather than ``char *``. UTF-32 Codecs From 6ba3ea43a032ceedaf917fd0f1952afb238756eb Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 9 May 2026 23:47:21 +0200 Subject: [PATCH 018/818] [3.15] gh-139871: Fix 3.15 bytearray.take_bytes example (GH-149520) (#149622) gh-139871: Fix 3.15 bytearray.take_bytes example (GH-149520) Currently: ```python buffer = bytearray(b'abc\ndef') n = buffer.find(b'\n') data = bytes(buffer[:n + 1]) del buffer[:n + 1] assert data == b'abc' Traceback (most recent call last): File "", line 1, in assert data == b'abc' ^^^^^^^^^^^^^^ AssertionError ``` Adding in the `\n` makes the two match: ```python buffer = bytearray(b'abc\ndef') n = buffer.find(b'\n') data = bytes(buffer[:n + 1]) del buffer[:n + 1] assert data == b'abc\n' assert buffer == bytearray(b'def') buffer = bytearray(b'abc\ndef') n = buffer.find(b'\n') data = buffer.take_bytes(n + 1) assert data == b'abc\n' assert buffer == bytearray(b'def') ``` (cherry picked from commit cc5cf14ae0a3665ba9d192cc4152c0a46a9dab2f) Co-authored-by: Cody Maloney --- Doc/whatsnew/3.15.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst index 0f7782ba1813d1..fb0755e8ffec5b 100644 --- a/Doc/whatsnew/3.15.rst +++ b/Doc/whatsnew/3.15.rst @@ -798,7 +798,7 @@ Other language changes n = buffer.find(b'\n') data = bytes(buffer[:n + 1]) del buffer[:n + 1] - assert data == b'abc' + assert data == b'abc\n' assert buffer == bytearray(b'def') - .. code:: python From 46a54ea5b0e4658db6bc40706ac3d4d86734e599 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 10 May 2026 16:11:57 +0200 Subject: [PATCH 019/818] [3.15] gh-148441: Avoid integer overflow in Expat's CharacterDataHandler (GH-148904) (#149639) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gh-148441: Avoid integer overflow in Expat's CharacterDataHandler (GH-148904) (cherry picked from commit bc1be4f6174086b4a46e3fe656552f5bb4e6e7b2) Co-authored-by: ByteFlow Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com> --- Lib/test/test_pyexpat.py | 14 ++++++++++++++ .../2026-04-23-12-50-15.gh-issue-148441.zvpCkR.rst | 4 ++++ Modules/pyexpat.c | 2 +- 3 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2026-04-23-12-50-15.gh-issue-148441.zvpCkR.rst diff --git a/Lib/test/test_pyexpat.py b/Lib/test/test_pyexpat.py index aaa91aca36e3c4..9a1620029c6da9 100644 --- a/Lib/test/test_pyexpat.py +++ b/Lib/test/test_pyexpat.py @@ -712,6 +712,20 @@ def test_change_size_2(self): parser.Parse(xml2, True) self.assertEqual(self.n, 4) + @support.requires_resource('cpu') + @support.requires_resource('walltime') + @support.bigmemtest(size=2**31, memuse=4, dry_run=False) + def test_large_character_data_does_not_crash(self): + # See https://github.com/python/cpython/issues/148441 + parser = expat.ParserCreate() + parser.buffer_text = True + parser.buffer_size = 2**31 - 1 # INT_MAX + N = 2049 * (1 << 20) - 3 # Character data greater than INT_MAX + self.assertGreater(N, parser.buffer_size) + parser.CharacterDataHandler = lambda text: None + xml_data = b"" + b"A" * N + b"" + self.assertEqual(parser.Parse(xml_data, True), 1) + class ElementDeclHandlerTest(unittest.TestCase): def test_trigger_leak(self): # Unfixed, this test would leak the memory of the so-called diff --git a/Misc/NEWS.d/next/Library/2026-04-23-12-50-15.gh-issue-148441.zvpCkR.rst b/Misc/NEWS.d/next/Library/2026-04-23-12-50-15.gh-issue-148441.zvpCkR.rst new file mode 100644 index 00000000000000..762815270e4d40 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-04-23-12-50-15.gh-issue-148441.zvpCkR.rst @@ -0,0 +1,4 @@ +:mod:`xml.parsers.expat`: prevent a crash in +:meth:`~xml.parsers.expat.xmlparser.CharacterDataHandler` +when the character data size exceeds the parser's +:attr:`buffer size `. diff --git a/Modules/pyexpat.c b/Modules/pyexpat.c index 0f0afe17513ef1..c01f7babe74527 100644 --- a/Modules/pyexpat.c +++ b/Modules/pyexpat.c @@ -393,7 +393,7 @@ my_CharacterDataHandler(void *userData, const XML_Char *data, int len) if (self->buffer == NULL) call_character_handler(self, data, len); else { - if ((self->buffer_used + len) > self->buffer_size) { + if (len > (self->buffer_size - self->buffer_used)) { if (flush_character_buffer(self) < 0) return; /* handler might have changed; drop the rest on the floor From 1162834c0ee310f7497b4f9d18d17a998e26831c Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 10 May 2026 23:11:04 +0200 Subject: [PATCH 020/818] [3.15] gh-139489: Add is_valid_text to xml.__all__ (GH-149641) (#149652) gh-139489: Add is_valid_text to xml.__all__ (GH-149641) (cherry picked from commit b45319e13273ee17e84e6b8c459f03b141518289) Co-authored-by: Jelle Zijlstra --- Lib/xml/__init__.py | 2 +- .../next/Library/2026-05-10-07-21-51.gh-issue-139489.rS7LTA.rst | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2026-05-10-07-21-51.gh-issue-139489.rS7LTA.rst diff --git a/Lib/xml/__init__.py b/Lib/xml/__init__.py index 002d6d3e0e8267..ecfce1c6ae52cf 100644 --- a/Lib/xml/__init__.py +++ b/Lib/xml/__init__.py @@ -18,4 +18,4 @@ from .utils import * -__all__ = ["dom", "parsers", "sax", "etree", "is_valid_name"] +__all__ = ["dom", "parsers", "sax", "etree", "is_valid_name", "is_valid_text"] diff --git a/Misc/NEWS.d/next/Library/2026-05-10-07-21-51.gh-issue-139489.rS7LTA.rst b/Misc/NEWS.d/next/Library/2026-05-10-07-21-51.gh-issue-139489.rS7LTA.rst new file mode 100644 index 00000000000000..40fe7e9fd6a008 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-05-10-07-21-51.gh-issue-139489.rS7LTA.rst @@ -0,0 +1 @@ +Add :func:`xml.is_valid_text` to ``xml.__all__``. From 73c80cb859589ef9e5871c30b17c951a44a26e33 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 11 May 2026 01:32:35 +0200 Subject: [PATCH 021/818] [3.15] gh-149083: use sentinel to fix _functools.reduce() signature (GH-149591) (#149653) gh-149083: use sentinel to fix _functools.reduce() signature (GH-149591) (cherry picked from commit c6fd7de64ac7591a9708c14a34737eb9baf050bc) Co-authored-by: Sergey B Kirpichev --- Lib/inspect.py | 3 ++- Lib/test/test_inspect/test_inspect.py | 3 +-- Modules/_functoolsmodule.c | 4 ++-- Modules/clinic/_functoolsmodule.c.h | 5 +++-- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/Lib/inspect.py b/Lib/inspect.py index a96b3dc954ef0c..dc5a6e3be883bb 100644 --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -2200,7 +2200,8 @@ def wrap_value(s): except NameError: raise ValueError - if isinstance(value, (str, int, float, bytes, bool, type(None))): + if isinstance(value, (str, int, float, bytes, bool, type(None), + sentinel)): return ast.Constant(value) raise ValueError diff --git a/Lib/test/test_inspect/test_inspect.py b/Lib/test/test_inspect/test_inspect.py index 9028d42c617fb4..7351f97fd9a4b5 100644 --- a/Lib/test/test_inspect/test_inspect.py +++ b/Lib/test/test_inspect/test_inspect.py @@ -6255,8 +6255,7 @@ def test_faulthandler_module_has_signatures(self): self._test_module_has_signatures(faulthandler, unsupported_signature=unsupported_signature) def test_functools_module_has_signatures(self): - unsupported_signature = {"reduce"} - self._test_module_has_signatures(functools, unsupported_signature=unsupported_signature) + self._test_module_has_signatures(functools) def test_gc_module_has_signatures(self): import gc diff --git a/Modules/_functoolsmodule.c b/Modules/_functoolsmodule.c index 19bdf3d47c2fad..c702eecc700ac8 100644 --- a/Modules/_functoolsmodule.c +++ b/Modules/_functoolsmodule.c @@ -1066,7 +1066,7 @@ _functools.reduce function as func: object iterable as seq: object / - initial as result: object = NULL + initial as result: object(c_default="NULL") = functools._initial_missing Apply a function of two arguments cumulatively to the items of an iterable, from left to right. @@ -1081,7 +1081,7 @@ calculates ((((1 + 2) + 3) + 4) + 5). static PyObject * _functools_reduce_impl(PyObject *module, PyObject *func, PyObject *seq, PyObject *result) -/*[clinic end generated code: output=30d898fe1267c79d input=4ccfb74548ce5170]*/ +/*[clinic end generated code: output=30d898fe1267c79d input=5c9088c98ffe2793]*/ { PyObject *args, *it; diff --git a/Modules/clinic/_functoolsmodule.c.h b/Modules/clinic/_functoolsmodule.c.h index 23f66631085031..87cdef2ad3cff3 100644 --- a/Modules/clinic/_functoolsmodule.c.h +++ b/Modules/clinic/_functoolsmodule.c.h @@ -71,7 +71,8 @@ _functools_cmp_to_key(PyObject *module, PyObject *const *args, Py_ssize_t nargs, } PyDoc_STRVAR(_functools_reduce__doc__, -"reduce($module, function, iterable, /, initial=)\n" +"reduce($module, function, iterable, /,\n" +" initial=functools._initial_missing)\n" "--\n" "\n" "Apply a function of two arguments cumulatively to the items of an iterable, from left to right.\n" @@ -192,4 +193,4 @@ _functools__lru_cache_wrapper_cache_clear(PyObject *self, PyObject *Py_UNUSED(ig return return_value; } -/*[clinic end generated code: output=7f2abc718fcc35d5 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=ac9e26d0a5a23d40 input=a9049054013a1b77]*/ From 5cf47a248c35c375d610b87b2f72fd1ed454b558 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 11 May 2026 11:57:32 +0200 Subject: [PATCH 022/818] [3.15] gh-149486: tarfile.data_filter: validate written link target (GH-149487) (GH-149553) gh-149486: tarfile.data_filter: validate written link target (GH-149487) The data filter rewrote linknames with normpath() but ran the containment check against the un-normalised value, and computed a symlink's directory before stripping trailing slashes. Both let a crafted archive create links pointing outside the destination. Also reject link members that resolve to the destination directory itself, which could otherwise replace it with a symlink and redirect all subsequent members. (cherry picked from commit 578411982c16f753f4893532510099ef665117da) Co-authored-by: Gregory P. Smith --- Lib/tarfile.py | 16 ++-- Lib/test/test_tarfile.py | 87 ++++++++++++++++++- ...-05-03-21-00-00.gh-issue-149486.tarflt.rst | 5 ++ 3 files changed, 99 insertions(+), 9 deletions(-) create mode 100644 Misc/NEWS.d/next/Security/2026-05-03-21-00-00.gh-issue-149486.tarflt.rst diff --git a/Lib/tarfile.py b/Lib/tarfile.py index d0e7dec5575047..1394a26f2096ff 100644 --- a/Lib/tarfile.py +++ b/Lib/tarfile.py @@ -830,16 +830,22 @@ def _get_filtered_attrs(member, dest_path, for_data=True): if member.islnk() or member.issym(): if os.path.isabs(member.linkname): raise AbsoluteLinkError(member) + # A link member that resolves to the destination directory itself + # would replace it with a (sym)link, redirecting the destination + # for all subsequent members. + if target_path == dest_path: + raise OutsideDestinationError(member, target_path) normalized = os.path.normpath(member.linkname) if normalized != member.linkname: new_attrs['linkname'] = normalized if member.issym(): - target_path = os.path.join(dest_path, - os.path.dirname(name), - member.linkname) + # The symlink is created at `name` with trailing separators + # stripped, so its target is relative to the directory + # containing that path. + link_dir = os.path.dirname(name.rstrip('/' + os.sep)) + target_path = os.path.join(dest_path, link_dir, normalized) else: - target_path = os.path.join(dest_path, - member.linkname) + target_path = os.path.join(dest_path, normalized) target_path = os.path.realpath(target_path, strict=os.path.ALLOW_MISSING) if os.path.commonpath([target_path, dest_path]) != dest_path: diff --git a/Lib/test/test_tarfile.py b/Lib/test/test_tarfile.py index e270cbb22e2d1a..192c948edc6056 100644 --- a/Lib/test/test_tarfile.py +++ b/Lib/test/test_tarfile.py @@ -3911,10 +3911,19 @@ def test_parent_symlink(self): + "which is outside the destination") with self.check_context(arc.open(), 'data'): - self.expect_exception( - tarfile.LinkOutsideDestinationError, - """'parent' would link to ['"].*outerdir['"], """ - + "which is outside the destination") + if self.dotdot_resolves_early: + # 'current/../..' normalises to '..', which is rejected. + self.expect_exception( + tarfile.LinkOutsideDestinationError, + """'parent' would link to ['"].*outerdir['"], """ + + "which is outside the destination") + else: + # 'current/..' normalises to '.'; the rewritten link is + # created and 'parent/evil' lands harmlessly inside the + # destination. + self.expect_file('current', symlink_to='.') + self.expect_file('parent', symlink_to='.') + self.expect_file('evil') else: # No symlink support. The symlinks are ignored. @@ -4174,6 +4183,76 @@ def test_sly_relative2(self): + """['"].*moo['"], which is outside the """ + "destination") + @symlink_test + @os_helper.skip_unless_symlink + def test_normpath_realpath_mismatch(self): + # The link-target check must validate the value that will actually + # be written to disk (the normalised linkname), not the original. + # Here 'a' is a symlink to a deep nonexistent path, so realpath() + # of 'a/../../...' stays inside the destination while normpath() + # collapses 'a/..' lexically and escapes. + depth = len(self.destdir.parts) + 5 + deep = '/'.join(f'p{i}' for i in range(depth)) + sneaky = 'a/' + '../' * depth + 'flag' + for kind in 'symlink_to', 'hardlink_to': + with self.subTest(kind): + with ArchiveMaker() as arc: + arc.add('a', symlink_to=deep) + arc.add('escape', **{kind: sneaky}) + with self.check_context(arc.open(), 'data'): + self.expect_exception( + tarfile.LinkOutsideDestinationError) + + @symlink_test + @os_helper.skip_unless_symlink + def test_symlink_trailing_slash(self): + # A trailing slash on a symlink member's name must not cause the + # link target to be resolved relative to the wrong directory. + with ArchiveMaker() as arc: + t = tarfile.TarInfo('x/') + t.type = tarfile.SYMTYPE + t.linkname = '..' + arc.tar_w.addfile(t) + arc.add('x/escaped', content='hi') + + with self.check_context(arc.open(), 'data'): + self.expect_exception(tarfile.LinkOutsideDestinationError) + + @symlink_test + @os_helper.skip_unless_symlink + def test_link_at_destination(self): + # A link member whose name resolves to the destination directory + # itself must be rejected: otherwise the destination is replaced + # by a symlink and later members can be redirected through it. + for name in '', '.', './': + with ArchiveMaker() as arc: + t = tarfile.TarInfo(name) + t.type = tarfile.SYMTYPE + t.linkname = '.' + arc.tar_w.addfile(t) + + with self.check_context(arc.open(), 'data'): + self.expect_exception(tarfile.OutsideDestinationError) + + @symlink_test + @os_helper.skip_unless_symlink + def test_empty_name_symlink_chain(self): + # Regression test for a chain of empty-named symlinks that + # incrementally redirects the destination outwards. + with ArchiveMaker() as arc: + for name, target in [('', ''), ('a/', '..'), + ('', 'dummy'), ('', 'a'), + ('b/', '..'), + ('', 'dummy'), ('', 'a/b')]: + t = tarfile.TarInfo(name) + t.type = tarfile.SYMTYPE + t.linkname = target + arc.tar_w.addfile(t) + arc.add('escaped', content='hi') + + with self.check_context(arc.open(), 'data'): + self.expect_exception(tarfile.FilterError) + @symlink_test def test_deep_symlink(self): # Test that symlinks and hardlinks inside a directory diff --git a/Misc/NEWS.d/next/Security/2026-05-03-21-00-00.gh-issue-149486.tarflt.rst b/Misc/NEWS.d/next/Security/2026-05-03-21-00-00.gh-issue-149486.tarflt.rst new file mode 100644 index 00000000000000..7c69edb683cf80 --- /dev/null +++ b/Misc/NEWS.d/next/Security/2026-05-03-21-00-00.gh-issue-149486.tarflt.rst @@ -0,0 +1,5 @@ +:func:`tarfile.data_filter` now validates link targets using the same +normalised value that is written to disk, strips trailing separators from +the member name when resolving a symlink's directory, and rejects link +members that would replace the destination directory itself. This closes +several path-traversal bypasses of the ``data`` extraction filter. From 4277df2421bc5b39ce5a133c032f8ef5428d3718 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 11 May 2026 13:44:11 +0200 Subject: [PATCH 023/818] [3.15] gh-146061: Clarify indent=None in json docs (GH-146095) (GH-149667) (cherry picked from commit 833dae7c1fdc556200cbfc3e76bad4d54628042c) Co-authored-by: Jonathan Dung --- Doc/library/json.rst | 2 +- Lib/json/__init__.py | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Doc/library/json.rst b/Doc/library/json.rst index b354e7ba534835..383ccad9df041b 100644 --- a/Doc/library/json.rst +++ b/Doc/library/json.rst @@ -211,7 +211,7 @@ Basic Usage a string (such as ``"\t"``) is used to indent each level. If zero, negative, or ``""`` (the empty string), only newlines are inserted. - If ``None`` (the default), the most compact representation is used. + If ``None`` (the default), no newlines are inserted. :type indent: int | str | None :param separators: diff --git a/Lib/json/__init__.py b/Lib/json/__init__.py index 251025efac14b8..94c177cafa0294 100644 --- a/Lib/json/__init__.py +++ b/Lib/json/__init__.py @@ -142,8 +142,8 @@ def dump(obj, fp, *, skipkeys=False, ensure_ascii=True, check_circular=True, If ``indent`` is a non-negative integer, then JSON array elements and object members will be pretty-printed with that indent level. An indent - level of 0 will only insert newlines. ``None`` is the most compact - representation. + level of 0 will only insert newlines. ``None`` is the default and gives + a representation with no newlines inserted. If specified, ``separators`` should be an ``(item_separator, key_separator)`` tuple. The default is ``(', ', ': ')`` if *indent* is @@ -206,8 +206,8 @@ def dumps(obj, *, skipkeys=False, ensure_ascii=True, check_circular=True, If ``indent`` is a non-negative integer, then JSON array elements and object members will be pretty-printed with that indent level. An indent - level of 0 will only insert newlines. ``None`` is the most compact - representation. + level of 0 will only insert newlines. ``None`` is the default and gives + a representation with no newlines inserted. If specified, ``separators`` should be an ``(item_separator, key_separator)`` tuple. The default is ``(', ', ': ')`` if *indent* is From 592a356fb5250c83c1dcd4df47d2ea9f7c58cca3 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 11 May 2026 14:02:28 +0200 Subject: [PATCH 024/818] [3.15] gh-149663: fix typo in `unittest` docs (GH-149670) (#149672) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gh-149663: fix typo in `unittest` docs (GH-149670) `hastattr` -> `hasattr` (cherry picked from commit 4956d2be9d5e555f2cf64faed9ef39e6a797c360) Co-authored-by: Árni Már Jónsson --- Doc/library/unittest.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/unittest.rst b/Doc/library/unittest.rst index c54f3e2792c388..ff619f97923325 100644 --- a/Doc/library/unittest.rst +++ b/Doc/library/unittest.rst @@ -1262,10 +1262,10 @@ Test cases | :meth:`assertNotEndsWith(a, b) | ``not a.endswith(b)`` | 3.14 | | ` | | | +---------------------------------------+--------------------------------+--------------+ - | :meth:`assertHasAttr(a, b) | ``hastattr(a, b)`` | 3.14 | + | :meth:`assertHasAttr(a, b) | ``hasattr(a, b)`` | 3.14 | | ` | | | +---------------------------------------+--------------------------------+--------------+ - | :meth:`assertNotHasAttr(a, b) | ``not hastattr(a, b)`` | 3.14 | + | :meth:`assertNotHasAttr(a, b) | ``not hasattr(a, b)`` | 3.14 | | ` | | | +---------------------------------------+--------------------------------+--------------+ From 8fdeb2dd3a2392669e7bbb75e3bd7142d15e00fb Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 11 May 2026 15:36:35 +0200 Subject: [PATCH 025/818] [3.15] gh-144957: Fix lazy imports + module __getattr__ (GH-149624) (#149678) gh-144957: Fix lazy imports + module __getattr__ (GH-149624) (cherry picked from commit 56171da3417bc14fded2f42033d72f63e1bf7cd9) Co-authored-by: Jelle Zijlstra --- Lib/test/test_lazy_import/__init__.py | 31 +++++++++++++++++++ .../data/module_with_getattr.py | 4 +++ .../test_lazy_import/data/pkg/__init__.py | 5 +++ ...-05-09-15-22-32.gh-issue-144957.u1F2aQ.rst | 2 ++ Objects/moduleobject.c | 19 ++++++++++++ 5 files changed, 61 insertions(+) create mode 100644 Lib/test/test_lazy_import/data/module_with_getattr.py create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-05-09-15-22-32.gh-issue-144957.u1F2aQ.rst diff --git a/Lib/test/test_lazy_import/__init__.py b/Lib/test/test_lazy_import/__init__.py index 1d1d2e00bd733f..ea534a8ee5b981 100644 --- a/Lib/test/test_lazy_import/__init__.py +++ b/Lib/test/test_lazy_import/__init__.py @@ -88,6 +88,26 @@ def test_basic_used(self): import test.test_lazy_import.data.basic_used self.assertIn("test.test_lazy_import.data.basic2", sys.modules) + @support.requires_subprocess() + def test_from_import_with_module_getattr(self): + """Lazy from import should respect module-level __getattr__.""" + code = textwrap.dedent(""" + lazy from test.test_lazy_import.data.module_with_getattr import dynamic_attr + assert dynamic_attr == "from_getattr" + """) + assert_python_ok("-c", code) + + @support.requires_subprocess() + def test_from_import_with_imported_module_getattr(self): + """Lazy from import should not shadow an imported module's __getattr__.""" + code = textwrap.dedent(""" + import test.test_lazy_import.data.module_with_getattr as mod + lazy from test.test_lazy_import.data.module_with_getattr import dynamic_attr + assert dynamic_attr == "from_getattr" + assert mod.dynamic_attr == "from_getattr" + """) + assert_python_ok("-c", code) + class GlobalLazyImportModeTests(unittest.TestCase): """Tests for sys.set_lazy_imports() global mode control.""" @@ -385,6 +405,17 @@ def test_lazy_import_pkg_cross_import(self): self.assertEqual(type(g["x"]), int) self.assertEqual(type(g["b"]), types.LazyImportType) + @support.requires_subprocess() + def test_package_from_import_with_module_getattr(self): + """Lazy from import should respect a package's __getattr__.""" + code = textwrap.dedent(""" + import test.test_lazy_import.data.pkg as pkg + lazy from test.test_lazy_import.data.pkg import dynamic_attr + assert dynamic_attr == "from_getattr" + assert pkg.dynamic_attr == "from_getattr" + """) + assert_python_ok("-c", code) + class DunderLazyImportTests(unittest.TestCase): """Tests for __lazy_import__ builtin function.""" diff --git a/Lib/test/test_lazy_import/data/module_with_getattr.py b/Lib/test/test_lazy_import/data/module_with_getattr.py new file mode 100644 index 00000000000000..2ac01a90d76e62 --- /dev/null +++ b/Lib/test/test_lazy_import/data/module_with_getattr.py @@ -0,0 +1,4 @@ +def __getattr__(name): + if name == "dynamic_attr": + return "from_getattr" + raise AttributeError(name) diff --git a/Lib/test/test_lazy_import/data/pkg/__init__.py b/Lib/test/test_lazy_import/data/pkg/__init__.py index 2d76abaa89f893..e526aab94131b8 100644 --- a/Lib/test/test_lazy_import/data/pkg/__init__.py +++ b/Lib/test/test_lazy_import/data/pkg/__init__.py @@ -1 +1,6 @@ x = 42 + +def __getattr__(name): + if name == "dynamic_attr": + return "from_getattr" + raise AttributeError(name) diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-09-15-22-32.gh-issue-144957.u1F2aQ.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-09-15-22-32.gh-issue-144957.u1F2aQ.rst new file mode 100644 index 00000000000000..3063f1a3c0e6d3 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-09-15-22-32.gh-issue-144957.u1F2aQ.rst @@ -0,0 +1,2 @@ +Fix lazy ``from`` imports of module attributes provided by module-level +``__getattr__``. diff --git a/Objects/moduleobject.c b/Objects/moduleobject.c index b7d2e5ffde4fe7..f7b83c1d111cde 100644 --- a/Objects/moduleobject.c +++ b/Objects/moduleobject.c @@ -1307,6 +1307,25 @@ _Py_module_getattro_impl(PyModuleObject *m, PyObject *name, int suppress) attr = _PyObject_GenericGetAttrWithDict((PyObject *)m, name, NULL, suppress); if (attr) { if (PyLazyImport_CheckExact(attr)) { + // gh-144957: Module __getattr__ should get a chance to provide + // the attribute before resolving a lazy import placeholder. + if (PyDict_GetItemRef(m->md_dict, &_Py_ID(__getattr__), &getattr) < 0) { + Py_DECREF(attr); + return NULL; + } + if (getattr) { + PyObject *result = PyObject_CallOneArg(getattr, name); + Py_DECREF(getattr); + if (result != NULL) { + Py_DECREF(attr); + return result; + } + if (!PyErr_ExceptionMatches(PyExc_AttributeError)) { + Py_DECREF(attr); + return NULL; + } + PyErr_Clear(); + } PyObject *new_value = _PyImport_LoadLazyImportTstate( PyThreadState_GET(), attr); if (new_value == NULL) { From b4f2e882032d71b2c60d74befdc2615d5596f2fe Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 11 May 2026 18:07:50 +0200 Subject: [PATCH 026/818] [3.15] gh-112821: Fix rlcompleter failures on objects with descriptors (GH-149577) (#149656) gh-112821: Fix rlcompleter failures on objects with descriptors (GH-149577) * gh-112821: Fix rlcompleter failures on objects with descriptors * Confirm no accesses (cherry picked from commit f23a1837d7156c4c478528321a423eae2b31e4bf) Co-authored-by: Michael Droettboom --- Lib/rlcompleter.py | 16 +++--- Lib/test/test_rlcompleter.py | 52 +++++++++++++++++++ ...-05-08-15-08-35.gh-issue-112821.t9T1YD.rst | 4 ++ 3 files changed, 64 insertions(+), 8 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-05-08-15-08-35.gh-issue-112821.t9T1YD.rst diff --git a/Lib/rlcompleter.py b/Lib/rlcompleter.py index e8cef29d00467f..6c6d9bb6b34244 100644 --- a/Lib/rlcompleter.py +++ b/Lib/rlcompleter.py @@ -179,14 +179,14 @@ def attr_matches(self, text): if (word[:n] == attr and not (noprefix and word[:n+1] == noprefix)): match = "%s.%s" % (expr, word) - if isinstance(getattr(type(thisobject), word, None), - property): - # bpo-44752: thisobject.word is a method decorated by - # `@property`. What follows applies a postfix if - # thisobject.word is callable, but know we know that - # this is not callable (because it is a property). - # Also, getattr(thisobject, word) will evaluate the - # property method, which is not desirable. + + class_attr = getattr(type(thisobject), word, None) + if isinstance( + class_attr, + (property, types.GetSetDescriptorType, types.MemberDescriptorType) + ) or (hasattr(class_attr, '__get__') and not callable(class_attr)): + # Avoid evaluating descriptors, which could run + # arbitrary code or raise exceptions. matches.append(match) continue diff --git a/Lib/test/test_rlcompleter.py b/Lib/test/test_rlcompleter.py index a8914953ce9eb4..e6d727d417b298 100644 --- a/Lib/test/test_rlcompleter.py +++ b/Lib/test/test_rlcompleter.py @@ -1,6 +1,7 @@ import unittest from unittest.mock import patch import builtins +import types import rlcompleter from test.support import MISSING_C_DOCSTRINGS @@ -135,6 +136,57 @@ def bar(self): self.assertEqual(completer.complete('f.b', 0), 'f.bar') self.assertFalse(f.property_called) + def test_released_memoryview_completion_works(self): + mv = memoryview(b"abc") + mv.release() + + self.assertIsInstance(type(mv).shape, types.GetSetDescriptorType) + self.assertIsInstance(type(mv).strides, types.GetSetDescriptorType) + + completer = rlcompleter.Completer(dict(mv=mv)) + matches = completer.attr_matches('mv.') + + # These are getset descriptors on memoryview and should be completed + # without evaluating the released-memoryview getters. + self.assertIn('mv.shape', matches) + self.assertIn('mv.strides', matches) + + def test_member_descriptor_not_evaluated(self): + class Foo: + __slots__ = ("boom",) + boom_accesses = 0 + + def __getattribute__(self, name): + if name == "boom": + type(self).boom_accesses += 1 + raise RuntimeError("boom access should be skipped") + return super().__getattribute__(name) + + self.assertIsInstance(Foo.boom, types.MemberDescriptorType) + + completer = rlcompleter.Completer(dict(f=Foo())) + matches = completer.attr_matches('f.') + self.assertIn('f.boom', matches) + self.assertEqual(Foo.boom_accesses, 0) + + def test_raising_descriptor_completion_works(self): + class ExplodingDescriptor: + def __init__(self): + self.instance_get_calls = 0 + + def __get__(self, obj, owner): + if obj is None: + return self + self.instance_get_calls += 1 + raise RuntimeError("descriptor getter exploded") + + class Foo: + boom = ExplodingDescriptor() + + completer = rlcompleter.Completer(dict(f=Foo())) + matches = completer.attr_matches('f.') + self.assertIn('f.boom', matches) + self.assertEqual(Foo.boom.instance_get_calls, 0) def test_uncreated_attr(self): # Attributes like properties and slots should be completed even when diff --git a/Misc/NEWS.d/next/Library/2026-05-08-15-08-35.gh-issue-112821.t9T1YD.rst b/Misc/NEWS.d/next/Library/2026-05-08-15-08-35.gh-issue-112821.t9T1YD.rst new file mode 100644 index 00000000000000..cfbcde81493e22 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-05-08-15-08-35.gh-issue-112821.t9T1YD.rst @@ -0,0 +1,4 @@ +In the REPL, autocompletion might run arbitrary code in the getter of a +descriptor. If that getter raised an exception, autocompletion would fail to +present any options for the entire object. Autocompletion now works as +expected for these objects. From 8297d50a63906757a92f86fc7f1eb5064c816b93 Mon Sep 17 00:00:00 2001 From: Sam Gross Date: Mon, 11 May 2026 18:23:39 +0000 Subject: [PATCH 027/818] [3.15] gh-145235: Make dict watcher API thread-safe for free-threaded builds (gh-145233) (#149690) In free-threaded builds, concurrent calls to PyDict_AddWatcher, PyDict_ClearWatcher, PyDict_Watch, and PyDict_Unwatch can race on the shared callback array and the per-dict watcher tags. This change adds a mutex to serialize watcher registration and removal, atomic operations for tag updates, and atomic acquire/release synchronization for callback dispatch in _PyDict_SendEvent. (cherry picked from commit 8a4895985f42282504d83b9bd0c77b129f95a5d5) Co-authored-by: Alper --- Include/internal/pycore_dict_state.h | 2 + .../internal/pycore_pyatomic_ft_wrappers.h | 2 + .../test_free_threading/test_dict_watcher.py | 89 +++++++++++++++++++ ...-02-25-13-37-10.gh-issue-145235.-1ySNR.rst | 3 + Modules/_testcapi/watchers.c | 26 +++--- Objects/dictobject.c | 42 ++++++--- Python/optimizer_analysis.c | 20 +++-- Python/pystate.c | 1 + Tools/c-analyzer/cpython/ignored.tsv | 1 + 9 files changed, 159 insertions(+), 27 deletions(-) create mode 100644 Lib/test/test_free_threading/test_dict_watcher.py create mode 100644 Misc/NEWS.d/next/C_API/2026-02-25-13-37-10.gh-issue-145235.-1ySNR.rst diff --git a/Include/internal/pycore_dict_state.h b/Include/internal/pycore_dict_state.h index 11932b8d1e1ab6..bb6fe262597559 100644 --- a/Include/internal/pycore_dict_state.h +++ b/Include/internal/pycore_dict_state.h @@ -13,6 +13,8 @@ extern "C" { struct _Py_dict_state { uint32_t next_keys_version; + PyMutex watcher_mutex; // Protects the watchers array (free-threaded builds) + _PyOnceFlag watcher_setup_once; // One-time optimizer watcher setup PyDict_WatchCallback watchers[DICT_MAX_WATCHERS]; }; diff --git a/Include/internal/pycore_pyatomic_ft_wrappers.h b/Include/internal/pycore_pyatomic_ft_wrappers.h index fafdd728a8229a..d8ec306a0dae3f 100644 --- a/Include/internal/pycore_pyatomic_ft_wrappers.h +++ b/Include/internal/pycore_pyatomic_ft_wrappers.h @@ -138,6 +138,7 @@ extern "C" { #define FT_ATOMIC_ADD_SSIZE(value, new_value) \ (void)_Py_atomic_add_ssize(&value, new_value) #define FT_MUTEX_LOCK(lock) PyMutex_Lock(lock) +#define FT_MUTEX_LOCK_FLAGS(lock, flags) PyMutex_LockFlags(lock, flags) #define FT_MUTEX_UNLOCK(lock) PyMutex_Unlock(lock) #else @@ -201,6 +202,7 @@ extern "C" { #define FT_ATOMIC_STORE_ULLONG_RELAXED(value, new_value) value = new_value #define FT_ATOMIC_ADD_SSIZE(value, new_value) (void)(value += new_value) #define FT_MUTEX_LOCK(lock) do {} while (0) +#define FT_MUTEX_LOCK_FLAGS(lock, flags) do {} while (0) #define FT_MUTEX_UNLOCK(lock) do {} while (0) #endif diff --git a/Lib/test/test_free_threading/test_dict_watcher.py b/Lib/test/test_free_threading/test_dict_watcher.py new file mode 100644 index 00000000000000..6a6843f9344f64 --- /dev/null +++ b/Lib/test/test_free_threading/test_dict_watcher.py @@ -0,0 +1,89 @@ +import unittest + +from test.support import import_helper, threading_helper + +_testcapi = import_helper.import_module("_testcapi") + +ITERS = 100 +NTHREADS = 20 + + +@threading_helper.requires_working_threading() +class TestDictWatcherThreadSafety(unittest.TestCase): + # Watcher kinds from _testcapi + EVENTS = 0 # appends dict events as strings to global event list + + def test_concurrent_add_clear_watchers(self): + """Race AddWatcher and ClearWatcher from multiple threads. + + Uses more threads than available watcher slots (5 user slots out + of DICT_MAX_WATCHERS=8). + """ + results = [] + + def worker(): + for _ in range(ITERS): + try: + wid = _testcapi.add_dict_watcher(self.EVENTS) + except RuntimeError: + continue # All slots taken + self.assertGreaterEqual(wid, 0) + results.append(wid) + _testcapi.clear_dict_watcher(wid) + + threading_helper.run_concurrently(worker, NTHREADS) + + # Verify at least some watchers were successfully added + self.assertGreater(len(results), 0) + + def test_concurrent_watch_unwatch(self): + """Race Watch and Unwatch on the same dict from multiple threads.""" + wid = _testcapi.add_dict_watcher(self.EVENTS) + dicts = [{} for _ in range(10)] + + def worker(): + for _ in range(ITERS): + for d in dicts: + _testcapi.watch_dict(wid, d) + for d in dicts: + _testcapi.unwatch_dict(wid, d) + + try: + threading_helper.run_concurrently(worker, NTHREADS) + + # Verify watching still works after concurrent watch/unwatch + _testcapi.watch_dict(wid, dicts[0]) + dicts[0]["key"] = "value" + events = _testcapi.get_dict_watcher_events() + self.assertIn("new:key:value", events) + finally: + _testcapi.clear_dict_watcher(wid) + + def test_concurrent_modify_watched_dict(self): + """Race dict mutations (triggering callbacks) with watch/unwatch.""" + wid = _testcapi.add_dict_watcher(self.EVENTS) + d = {} + _testcapi.watch_dict(wid, d) + + def mutator(): + for i in range(ITERS): + d[f"key_{i}"] = i + d.pop(f"key_{i}", None) + + def toggler(): + for i in range(ITERS): + _testcapi.watch_dict(wid, d) + d[f"toggler_{i}"] = i + _testcapi.unwatch_dict(wid, d) + + workers = [mutator, toggler] * (NTHREADS // 2) + try: + threading_helper.run_concurrently(workers) + events = _testcapi.get_dict_watcher_events() + self.assertGreater(len(events), 0) + finally: + _testcapi.clear_dict_watcher(wid) + + +if __name__ == "__main__": + unittest.main() diff --git a/Misc/NEWS.d/next/C_API/2026-02-25-13-37-10.gh-issue-145235.-1ySNR.rst b/Misc/NEWS.d/next/C_API/2026-02-25-13-37-10.gh-issue-145235.-1ySNR.rst new file mode 100644 index 00000000000000..98a8c268735726 --- /dev/null +++ b/Misc/NEWS.d/next/C_API/2026-02-25-13-37-10.gh-issue-145235.-1ySNR.rst @@ -0,0 +1,3 @@ +Made :c:func:`PyDict_AddWatcher`, :c:func:`PyDict_ClearWatcher`, +:c:func:`PyDict_Watch`, and :c:func:`PyDict_Unwatch` thread-safe on the +:term:`free threaded ` build. diff --git a/Modules/_testcapi/watchers.c b/Modules/_testcapi/watchers.c index e0abf6b1845d8e..71cdc54009017a 100644 --- a/Modules/_testcapi/watchers.c +++ b/Modules/_testcapi/watchers.c @@ -9,6 +9,7 @@ #include "pycore_function.h" // FUNC_MAX_WATCHERS #include "pycore_interp_structs.h" // CODE_MAX_WATCHERS #include "pycore_context.h" // CONTEXT_MAX_WATCHERS +#include "pycore_lock.h" // _PyOnceFlag /*[clinic input] module _testcapi @@ -18,6 +19,14 @@ module _testcapi // Test dict watching static PyObject *g_dict_watch_events = NULL; static int g_dict_watchers_installed = 0; +static _PyOnceFlag g_dict_watch_once = {0}; + +static int +_init_dict_watch_events(void *arg) +{ + g_dict_watch_events = PyList_New(0); + return g_dict_watch_events ? 0 : -1; +} static int dict_watch_callback(PyDict_WatchEvent event, @@ -106,13 +115,10 @@ add_dict_watcher(PyObject *self, PyObject *kind) if (watcher_id < 0) { return NULL; } - if (!g_dict_watchers_installed) { - assert(!g_dict_watch_events); - if (!(g_dict_watch_events = PyList_New(0))) { - return NULL; - } + if (_PyOnceFlag_CallOnce(&g_dict_watch_once, _init_dict_watch_events, NULL) < 0) { + return NULL; } - g_dict_watchers_installed++; + _Py_atomic_add_int(&g_dict_watchers_installed, 1); return PyLong_FromLong(watcher_id); } @@ -122,10 +128,8 @@ clear_dict_watcher(PyObject *self, PyObject *watcher_id) if (PyDict_ClearWatcher(PyLong_AsLong(watcher_id))) { return NULL; } - g_dict_watchers_installed--; - if (!g_dict_watchers_installed) { - assert(g_dict_watch_events); - Py_CLEAR(g_dict_watch_events); + if (_Py_atomic_add_int(&g_dict_watchers_installed, -1) == 1) { + PyList_Clear(g_dict_watch_events); } Py_RETURN_NONE; } @@ -164,7 +168,7 @@ _testcapi_unwatch_dict_impl(PyObject *module, int watcher_id, PyObject *dict) static PyObject * get_dict_watcher_events(PyObject *self, PyObject *Py_UNUSED(args)) { - if (!g_dict_watch_events) { + if (_Py_atomic_load_int(&g_dict_watchers_installed) <= 0) { PyErr_SetString(PyExc_RuntimeError, "no watchers active"); return NULL; } diff --git a/Objects/dictobject.c b/Objects/dictobject.c index 42bc63acd9049c..09135e031e6fc7 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -8015,13 +8015,19 @@ validate_watcher_id(PyInterpreterState *interp, int watcher_id) PyErr_Format(PyExc_ValueError, "Invalid dict watcher ID %d", watcher_id); return -1; } - if (!interp->dict_state.watchers[watcher_id]) { + PyDict_WatchCallback cb = FT_ATOMIC_LOAD_PTR_RELAXED( + interp->dict_state.watchers[watcher_id]); + if (cb == NULL) { PyErr_Format(PyExc_ValueError, "No dict watcher set for ID %d", watcher_id); return -1; } return 0; } +// In free-threaded builds, Add/Clear serialize on watcher_mutex and publish +// callbacks with release stores. SendEvent reads them lock-free using +// acquire loads. + int PyDict_Watch(int watcher_id, PyObject* dict) { @@ -8033,7 +8039,8 @@ PyDict_Watch(int watcher_id, PyObject* dict) if (validate_watcher_id(interp, watcher_id)) { return -1; } - FT_ATOMIC_OR_UINT64(((PyDictObject*)dict)->_ma_watcher_tag, (1LL << watcher_id)); + FT_ATOMIC_OR_UINT64(((PyDictObject*)dict)->_ma_watcher_tag, + 1ULL << watcher_id); return 0; } @@ -8048,36 +8055,48 @@ PyDict_Unwatch(int watcher_id, PyObject* dict) if (validate_watcher_id(interp, watcher_id)) { return -1; } - FT_ATOMIC_AND_UINT64(((PyDictObject*)dict)->_ma_watcher_tag, ~(1LL << watcher_id)); + FT_ATOMIC_AND_UINT64(((PyDictObject*)dict)->_ma_watcher_tag, + ~(1ULL << watcher_id)); return 0; } int PyDict_AddWatcher(PyDict_WatchCallback callback) { + int watcher_id = -1; PyInterpreterState *interp = _PyInterpreterState_GET(); + FT_MUTEX_LOCK_FLAGS(&interp->dict_state.watcher_mutex, + _Py_LOCK_DONT_DETACH); /* Some watchers are reserved for CPython, start at the first available one */ for (int i = FIRST_AVAILABLE_WATCHER; i < DICT_MAX_WATCHERS; i++) { if (!interp->dict_state.watchers[i]) { - interp->dict_state.watchers[i] = callback; - return i; + FT_ATOMIC_STORE_PTR_RELEASE(interp->dict_state.watchers[i], callback); + watcher_id = i; + goto done; } } - PyErr_SetString(PyExc_RuntimeError, "no more dict watcher IDs available"); - return -1; +done: + FT_MUTEX_UNLOCK(&interp->dict_state.watcher_mutex); + return watcher_id; } int PyDict_ClearWatcher(int watcher_id) { + int res = 0; PyInterpreterState *interp = _PyInterpreterState_GET(); + FT_MUTEX_LOCK_FLAGS(&interp->dict_state.watcher_mutex, + _Py_LOCK_DONT_DETACH); if (validate_watcher_id(interp, watcher_id)) { - return -1; + res = -1; + goto done; } - interp->dict_state.watchers[watcher_id] = NULL; - return 0; + FT_ATOMIC_STORE_PTR_RELEASE(interp->dict_state.watchers[watcher_id], NULL); +done: + FT_MUTEX_UNLOCK(&interp->dict_state.watcher_mutex); + return res; } static const char * @@ -8102,7 +8121,8 @@ _PyDict_SendEvent(int watcher_bits, PyInterpreterState *interp = _PyInterpreterState_GET(); for (int i = 0; i < DICT_MAX_WATCHERS; i++) { if (watcher_bits & 1) { - PyDict_WatchCallback cb = interp->dict_state.watchers[i]; + PyDict_WatchCallback cb = FT_ATOMIC_LOAD_PTR_ACQUIRE( + interp->dict_state.watchers[i]); if (cb && (cb(event, (PyObject*)mp, key, value) < 0)) { // We don't want to resurrect the dict by potentially having an // unraisablehook keep a reference to it, so we don't pass the diff --git a/Python/optimizer_analysis.c b/Python/optimizer_analysis.c index 1dc3a248f45f0c..e726dc0e6fd111 100644 --- a/Python/optimizer_analysis.c +++ b/Python/optimizer_analysis.c @@ -18,6 +18,7 @@ #include "pycore_opcode_metadata.h" #include "pycore_opcode_utils.h" #include "pycore_pystate.h" // _PyInterpreterState_GET() +#include "pycore_pyatomic_ft_wrappers.h" // FT_ATOMIC_* #include "pycore_tstate.h" // _PyThreadStateImpl #include "pycore_uop_metadata.h" #include "pycore_long.h" @@ -127,7 +128,7 @@ static void increment_mutations(PyObject* dict) { assert(PyDict_CheckExact(dict)); PyDictObject *d = (PyDictObject *)dict; - FT_ATOMIC_ADD_UINT64(d->_ma_watcher_tag, (1 << DICT_MAX_WATCHERS)); + FT_ATOMIC_ADD_UINT64(d->_ma_watcher_tag, 1ULL << DICT_MAX_WATCHERS); } /* The first two dict watcher IDs are reserved for CPython, @@ -156,6 +157,17 @@ type_watcher_callback(PyTypeObject* type) return 0; } +static int +_setup_optimizer_watchers(void *Py_UNUSED(arg)) +{ + PyInterpreterState *interp = _PyInterpreterState_GET(); + FT_ATOMIC_STORE_PTR_RELEASE( + interp->dict_state.watchers[GLOBALS_WATCHER_ID], + globals_watcher_callback); + interp->type_watchers[TYPE_WATCHER_ID] = type_watcher_callback; + return 0; +} + static void watch_type(PyTypeObject *type, _PyBloomFilter *filter) { @@ -580,10 +592,8 @@ optimize_uops( // Make sure that watchers are set up PyInterpreterState *interp = _PyInterpreterState_GET(); - if (interp->dict_state.watchers[GLOBALS_WATCHER_ID] == NULL) { - interp->dict_state.watchers[GLOBALS_WATCHER_ID] = globals_watcher_callback; - interp->type_watchers[TYPE_WATCHER_ID] = type_watcher_callback; - } + _PyOnceFlag_CallOnce(&interp->dict_state.watcher_setup_once, + _setup_optimizer_watchers, NULL); _Py_uop_abstractcontext_init(ctx, dependencies); _Py_UOpsAbstractFrame *frame = _Py_uop_frame_new(ctx, (PyCodeObject *)func->func_code, NULL, 0); diff --git a/Python/pystate.c b/Python/pystate.c index bf2616a49148a7..ff712019affbf9 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -320,6 +320,7 @@ _Py_COMP_DIAG_POP &(runtime)->allocators.mutex, \ &(runtime)->_main_interpreter.types.mutex, \ &(runtime)->_main_interpreter.code_state.mutex, \ + &(runtime)->_main_interpreter.dict_state.watcher_mutex, \ } static void diff --git a/Tools/c-analyzer/cpython/ignored.tsv b/Tools/c-analyzer/cpython/ignored.tsv index 7af64ed017ba73..ddfb93a424c018 100644 --- a/Tools/c-analyzer/cpython/ignored.tsv +++ b/Tools/c-analyzer/cpython/ignored.tsv @@ -467,6 +467,7 @@ Modules/_testcapi/object.c - MyObject_dealloc_called - Modules/_testcapi/object.c - MyType - Modules/_testcapi/structmember.c - test_structmembersType_OldAPI - Modules/_testcapi/watchers.c - g_dict_watch_events - +Modules/_testcapi/watchers.c - g_dict_watch_once - Modules/_testcapi/watchers.c - g_dict_watchers_installed - Modules/_testcapi/watchers.c - g_type_modified_events - Modules/_testcapi/watchers.c - g_type_watchers_installed - From a8c420879e344a365ec4542107db5c4830ef2520 Mon Sep 17 00:00:00 2001 From: Savannah Ostrowski Date: Mon, 11 May 2026 11:25:40 -0700 Subject: [PATCH 028/818] =?UTF-8?q?[3.15]=20gh-149614=20-=20Restore=20deep?= =?UTF-8?q?copiability=20of=20argparse.ArgumentParser=E2=80=A6=20(#149693)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [3.15] gh-149614 - Restore deepcopiability of argparse.ArgumentParser instances (GH-149617) (cherry picked from commit fadd9bc14e43041c84bb8d06824990264fe1434a) Co-authored-by: David Ellis Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com> --- Lib/argparse.py | 2 + Lib/test/test_argparse.py | 55 +++++++++++++++++++ ...-05-09-21-02-08.gh-issue-149614.U4snj3.rst | 1 + 3 files changed, 58 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2026-05-09-21-02-08.gh-issue-149614.U4snj3.rst diff --git a/Lib/argparse.py b/Lib/argparse.py index 6d21823e652429..29e6ebb9634261 100644 --- a/Lib/argparse.py +++ b/Lib/argparse.py @@ -163,6 +163,8 @@ class _ColorlessTheme: def __getattr__(self, name): # _colorize's no_color themes are just all empty strings # by directly using empty strings the import is avoided + if name.startswith("_"): + raise AttributeError(name) return "" _colorless_theme = _ColorlessTheme() diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py index 4ea5b6f53a0426..1dc3f538f4ad8b 100644 --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -140,6 +140,48 @@ def test_parse_args(self): ) +class TestArgumentParserCopiable(unittest.TestCase): + def _get_parser(self): + parser = argparse.ArgumentParser(exit_on_error=False) + parser.add_argument('--foo', type=int, default=42) + parser.add_argument('bar', nargs='?', default='baz') + return parser + + @force_not_colorized + def test_copiable(self): + import copy + parser = self._get_parser() + parser2 = copy.copy(parser) + ns = parser2.parse_args(['--foo', '123', 'quux']) + self.assertEqual(ns.foo, 123) + self.assertEqual(ns.bar, 'quux') + ns2 = parser2.parse_args([]) + self.assertEqual(ns2.foo, 42) + self.assertEqual(ns2.bar, 'baz') + + # Test shallow copy also gets new arguments + parser.add_argument("--extra") + ns3 = parser2.parse_args(["--extra", "bar"]) + self.assertEqual(ns3.extra, "bar") + + @force_not_colorized + def test_deepcopiable(self): + import copy + parser = self._get_parser() + parser2 = copy.deepcopy(parser) + ns = parser2.parse_args(['--foo', '123', 'quux']) + self.assertEqual(ns.foo, 123) + self.assertEqual(ns.bar, 'quux') + ns2 = parser2.parse_args([]) + self.assertEqual(ns2.foo, 42) + self.assertEqual(ns2.bar, 'baz') + + # Test deep copy does not get new arguments + parser.add_argument("--extra") + with self.assertRaises(argparse.ArgumentError): + parser2.parse_args(["--extra", "bar"]) + + class TestArgumentParserPickleable(unittest.TestCase): @force_not_colorized @@ -7863,12 +7905,25 @@ def fake_can_colorize(*, file=None): def test_fake_color_theme_matches_real(self): from argparse import _colorless_theme + + # Check the attributes match those of the 'real' theme _colorize_nocolor = _colorize.get_theme(force_no_color=True).argparse for k in _colorize_nocolor: self.assertEqual( getattr(_colorless_theme, k), getattr(_colorize_nocolor, k) ) + def test_fake_color_theme_raises(self): + from argparse import _colorless_theme + + # Make sure the _colorless_theme doesn't return empty strings + # for magic methods or private attributes + with self.assertRaises(AttributeError): + _colorless_theme.__unknown_dunder__ + + with self.assertRaises(AttributeError): + _colorless_theme._private_attribute + class TestModule(unittest.TestCase): def test_deprecated__version__(self): diff --git a/Misc/NEWS.d/next/Library/2026-05-09-21-02-08.gh-issue-149614.U4snj3.rst b/Misc/NEWS.d/next/Library/2026-05-09-21-02-08.gh-issue-149614.U4snj3.rst new file mode 100644 index 00000000000000..5169c6c203fc1b --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-05-09-21-02-08.gh-issue-149614.U4snj3.rst @@ -0,0 +1 @@ +Fix a regression that broke the ability to deepcopy :class:`argparse.ArgumentParser` instances. From 9138bf2612730f8d6bca46e08f645072c7bf32fa Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 12 May 2026 04:54:10 +0200 Subject: [PATCH 029/818] [3.15] gh-148669: Clarify `__reduce__()` module lookup behavior (GH-148670) (#149703) gh-148669: Clarify `__reduce__()` module lookup behavior (GH-148670) (cherry picked from commit 54a5fd4126df74f7b84d1f8a6a36ef79803f66f9) Co-authored-by: Victorien <65306057+Viicos@users.noreply.github.com> --- Doc/library/pickle.rst | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Doc/library/pickle.rst b/Doc/library/pickle.rst index f8975c2f4281d4..8eadc2cf2b1ef0 100644 --- a/Doc/library/pickle.rst +++ b/Doc/library/pickle.rst @@ -56,7 +56,7 @@ The :mod:`!pickle` module differs from :mod:`marshal` in several significant way * :mod:`marshal` cannot be used to serialize user-defined classes and their instances. :mod:`!pickle` can save and restore class instances transparently, however the class definition must be importable and live in the same module as - when the object was stored. + when the object was pickled. * The :mod:`marshal` serialization format is not guaranteed to be portable across Python versions. Because its primary job in life is to support @@ -693,7 +693,10 @@ or both. If a string is returned, the string should be interpreted as the name of a global variable. It should be the object's local name relative to its module; the pickle module searches the module namespace to determine the - object's module. This behaviour is typically useful for singletons. + object's module: for a given ``obj`` to be pickled, the ``__module__`` + attribute is looked up on ``obj`` directly, which falls back to a lookup + on the type of ``obj`` if no ``__module__`` instance attribute is set. + This behaviour is typically useful for singletons. When a tuple is returned, it must be between two and six items long. Optional items can either be omitted, or ``None`` can be provided as their From 45c431a55db2b05bb21b76cd95f6775cc13ce9fb Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 12 May 2026 11:09:52 +0200 Subject: [PATCH 030/818] [3.15] Update mypy to 2.1.0 (GH-149709) (#149711) Update mypy to 2.1.0 (GH-149709) (cherry picked from commit b546cc10f5c659344ce3cf49db6d9c92307ed1fc) Co-authored-by: sobolevn --- Lib/test/libregrtest/single.py | 2 +- Lib/tomllib/mypy.ini | 2 -- Tools/build/check_extension_modules.py | 2 +- Tools/build/mypy.ini | 2 -- Tools/requirements-dev.txt | 6 +++--- 5 files changed, 5 insertions(+), 9 deletions(-) diff --git a/Lib/test/libregrtest/single.py b/Lib/test/libregrtest/single.py index 958a915626ad24..d0759d2626989d 100644 --- a/Lib/test/libregrtest/single.py +++ b/Lib/test/libregrtest/single.py @@ -145,7 +145,7 @@ def regrtest_runner(result: TestResult, test_func, runtests: RunTests) -> None: # Storage of uncollectable GC objects (gc.garbage) -GC_GARBAGE = [] +GC_GARBAGE: list[object] = [] def _load_run_test(result: TestResult, runtests: RunTests) -> None: diff --git a/Lib/tomllib/mypy.ini b/Lib/tomllib/mypy.ini index 1761dce45562a6..f7eeffd575c1c7 100644 --- a/Lib/tomllib/mypy.ini +++ b/Lib/tomllib/mypy.ini @@ -12,6 +12,4 @@ pretty = True # Enable most stricter settings enable_error_code = ignore-without-code strict = True -strict_bytes = True -local_partial_types = True warn_unreachable = True diff --git a/Tools/build/check_extension_modules.py b/Tools/build/check_extension_modules.py index f23c1d5286f92a..c619a9a0c1c5a1 100644 --- a/Tools/build/check_extension_modules.py +++ b/Tools/build/check_extension_modules.py @@ -463,7 +463,7 @@ def get_location(self, modinfo: ModuleInfo) -> pathlib.Path | None: def _check_file(self, modinfo: ModuleInfo, spec: ModuleSpec) -> None: """Check that the module file is present and not empty""" if spec.loader is BuiltinImporter: # type: ignore[comparison-overlap] - return + return # type: ignore[unreachable] try: assert spec.origin is not None st = os.stat(spec.origin) diff --git a/Tools/build/mypy.ini b/Tools/build/mypy.ini index 5465e2d4b6171f..485c9314cf7001 100644 --- a/Tools/build/mypy.ini +++ b/Tools/build/mypy.ini @@ -24,8 +24,6 @@ python_version = 3.10 # ...And be strict: strict = True -strict_bytes = True -local_partial_types = True extra_checks = True enable_error_code = ignore-without-code,redundant-expr,truthy-bool,possibly-undefined warn_unreachable = True diff --git a/Tools/requirements-dev.txt b/Tools/requirements-dev.txt index af5cbaa7689f33..46381ea58a1238 100644 --- a/Tools/requirements-dev.txt +++ b/Tools/requirements-dev.txt @@ -1,7 +1,7 @@ # Requirements file for external linters and checks we run on # Tools/clinic, Tools/cases_generator/, and Tools/peg_generator/ in CI -mypy==1.19.1 +mypy==2.1.0 # needed for peg_generator: -types-psutil==7.2.2.20260130 -types-setuptools==82.0.0.20260210 +types-psutil==7.2.2.20260508 +types-setuptools==82.0.0.20260508 From d3b86111ef7913077394c40fff1eb8941b30be51 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 12 May 2026 15:57:02 +0200 Subject: [PATCH 031/818] [3.15] gh-149676: Fix hash(frozendict | frozendict) (GH-149675) (#149717) gh-149676: Fix hash(frozendict | frozendict) (GH-149675) Fix new_dict_impl() to properly initialize ma_hash on frozendict. (cherry picked from commit f5fb491341e566bbaf17d9bf3e4ec3af4a56bb3f) Co-authored-by: Thomas Kowalski Co-authored-by: Victor Stinner --- Lib/test/test_dict.py | 5 +++++ .../2026-05-11-14-48-56.gh-issue-149676.6aTrw1.rst | 1 + Objects/dictobject.c | 9 ++++++--- 3 files changed, 12 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-05-11-14-48-56.gh-issue-149676.6aTrw1.rst diff --git a/Lib/test/test_dict.py b/Lib/test/test_dict.py index b2f4363b23e748..4efb066d4fd01c 100644 --- a/Lib/test/test_dict.py +++ b/Lib/test/test_dict.py @@ -1868,6 +1868,11 @@ def test_merge(self): self.assertEqual(fd | {}, fd) self.assertEqual(frozendict() | fd, fd) + # gh-149676: Test hash(frozendict | frozendict) + a = frozendict({"a": 1}) + b = frozendict({"b": 2}) + self.assertEqual(hash(a | b), hash(frozendict({"a": 1, "b": 2}))) + def test_update(self): # test "a |= b" operator d = frozendict(x=1) diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-11-14-48-56.gh-issue-149676.6aTrw1.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-11-14-48-56.gh-issue-149676.6aTrw1.rst new file mode 100644 index 00000000000000..96f407cf5ad25a --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-11-14-48-56.gh-issue-149676.6aTrw1.rst @@ -0,0 +1 @@ +Fix ``frozendict | frozendict`` hash. diff --git a/Objects/dictobject.c b/Objects/dictobject.c index 09135e031e6fc7..b33a273dac3b95 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -900,7 +900,7 @@ free_values(PyDictValues *values, bool use_qsbr) static inline PyObject * new_dict_impl(PyDictObject *mp, PyDictKeysObject *keys, PyDictValues *values, Py_ssize_t used, - int free_values_on_failure) + int free_values_on_failure, int frozendict) { assert(keys != NULL); if (mp == NULL) { @@ -915,6 +915,9 @@ new_dict_impl(PyDictObject *mp, PyDictKeysObject *keys, mp->ma_values = values; mp->ma_used = used; mp->_ma_watcher_tag = 0; + if (frozendict) { + ((PyFrozenDictObject *)mp)->ma_hash = -1; + } ASSERT_CONSISTENT(mp); _PyObject_GC_TRACK(mp); return (PyObject *)mp; @@ -931,7 +934,7 @@ new_dict(PyDictKeysObject *keys, PyDictValues *values, } assert(mp == NULL || Py_IS_TYPE(mp, &PyDict_Type)); - return new_dict_impl(mp, keys, values, used, free_values_on_failure); + return new_dict_impl(mp, keys, values, used, free_values_on_failure, 0); } /* Consumes a reference to the keys object */ @@ -940,7 +943,7 @@ new_frozendict(PyDictKeysObject *keys, PyDictValues *values, Py_ssize_t used, int free_values_on_failure) { PyDictObject *mp = PyObject_GC_New(PyDictObject, &PyFrozenDict_Type); - return new_dict_impl(mp, keys, values, used, free_values_on_failure); + return new_dict_impl(mp, keys, values, used, free_values_on_failure, 1); } static PyObject * From 5f9d0d0b866d2d1275b2aefaf9f70b6333e03947 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 12 May 2026 18:09:41 +0200 Subject: [PATCH 032/818] [3.15] Remove myself from CODEOWNERS (GH-149727) (#149732) Remove myself from CODEOWNERS (GH-149727) (cherry picked from commit 058c12528d98954c44d6f92f2eea48b881c1967f) Co-authored-by: Berker Peksag --- .github/CODEOWNERS | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index f4ffa24edca453..b4b3b1013e3095 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -586,10 +586,10 @@ Lib/test/test_string/test_templatelib.py @lysnikolaou @AA-Turner **/*sysconfig* @FFY00 # SQLite 3 -Doc/library/sqlite3.rst @berkerpeksag @erlend-aasland -Lib/sqlite3/ @berkerpeksag @erlend-aasland -Lib/test/test_sqlite3/ @berkerpeksag @erlend-aasland -Modules/_sqlite/ @berkerpeksag @erlend-aasland +Doc/library/sqlite3.rst @erlend-aasland +Lib/sqlite3/ @erlend-aasland +Lib/test/test_sqlite3/ @erlend-aasland +Modules/_sqlite/ @erlend-aasland # Subprocess Lib/subprocess.py @gpshead @@ -622,9 +622,6 @@ Modules/_typesmodule.c @AA-Turner Lib/unittest/mock.py @cjw296 Lib/test/test_unittest/testmock/ @cjw296 -# Urllib -**/*robotparser* @berkerpeksag - # Venv **/*venv* @vsajip @FFY00 From 6a6600569985e4006900bae16812f2d19c8ab97b Mon Sep 17 00:00:00 2001 From: deadlovelll <128279579+deadlovelll@users.noreply.github.com> Date: Tue, 12 May 2026 20:22:36 +0300 Subject: [PATCH 033/818] [3.15] gh-149694: Fix missing docstring on `asyncio.iscoroutinefunction` (#149696) --- Lib/asyncio/coroutines.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/asyncio/coroutines.py b/Lib/asyncio/coroutines.py index a51319cb72a6a9..6727065bbe323f 100644 --- a/Lib/asyncio/coroutines.py +++ b/Lib/asyncio/coroutines.py @@ -18,8 +18,8 @@ def _is_debug_mode(): def iscoroutinefunction(func): - import warnings """Return True if func is a decorated coroutine function.""" + import warnings warnings._deprecated("asyncio.iscoroutinefunction", f"{warnings._DEPRECATED_MSG}; " "use inspect.iscoroutinefunction() instead", From e2e9cea7692fdb0ac3e34fd38a25d9025035769f Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 12 May 2026 19:58:31 +0200 Subject: [PATCH 034/818] [3.15] GH-149501: Fix compilation warning in `_YIELD_VALUE` uop (GH-149502) (#149737) GH-149501: Fix compilation warning in `_YIELD_VALUE` uop (GH-149502) (cherry picked from commit 1a79fd0ad650f0a0f21f653cc46a89bc1741d253) Co-authored-by: Sergey Miryanov --- Modules/_testinternalcapi/test_cases.c.h | 10 ++++++---- Python/bytecodes.c | 5 +++-- Python/executor_cases.c.h | 5 +++-- Python/generated_cases.c.h | 10 ++++++---- 4 files changed, 18 insertions(+), 12 deletions(-) diff --git a/Modules/_testinternalcapi/test_cases.c.h b/Modules/_testinternalcapi/test_cases.c.h index 238e17bea303d3..a2506524f0bb6d 100644 --- a/Modules/_testinternalcapi/test_cases.c.h +++ b/Modules/_testinternalcapi/test_cases.c.h @@ -7946,8 +7946,9 @@ assert(INLINE_CACHE_ENTRIES_SEND == INLINE_CACHE_ENTRIES_FOR_ITER); #if TIER_ONE && defined(Py_DEBUG) if (!PyStackRef_IsNone(frame->f_executable)) { - int i = frame->instr_ptr - _PyFrame_GetBytecode(frame); - int opcode = _Py_GetBaseCodeUnit(_PyFrame_GetCode(frame), i).op.code; + Py_ssize_t i = frame->instr_ptr - _PyFrame_GetBytecode(frame); + assert(i >= 0 && i <= INT_MAX); + int opcode = _Py_GetBaseCodeUnit(_PyFrame_GetCode(frame), (int)i).op.code; assert(opcode == SEND || opcode == FOR_ITER); } #endif @@ -13056,8 +13057,9 @@ assert(INLINE_CACHE_ENTRIES_SEND == INLINE_CACHE_ENTRIES_FOR_ITER); #if TIER_ONE && defined(Py_DEBUG) if (!PyStackRef_IsNone(frame->f_executable)) { - int i = frame->instr_ptr - _PyFrame_GetBytecode(frame); - int opcode = _Py_GetBaseCodeUnit(_PyFrame_GetCode(frame), i).op.code; + Py_ssize_t i = frame->instr_ptr - _PyFrame_GetBytecode(frame); + assert(i >= 0 && i <= INT_MAX); + int opcode = _Py_GetBaseCodeUnit(_PyFrame_GetCode(frame), (int)i).op.code; assert(opcode == SEND || opcode == FOR_ITER); } #endif diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 3bd489122da9d4..f7487c7136962f 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -1867,8 +1867,9 @@ dummy_func( assert(INLINE_CACHE_ENTRIES_SEND == INLINE_CACHE_ENTRIES_FOR_ITER); #if TIER_ONE && defined(Py_DEBUG) if (!PyStackRef_IsNone(frame->f_executable)) { - int i = frame->instr_ptr - _PyFrame_GetBytecode(frame); - int opcode = _Py_GetBaseCodeUnit(_PyFrame_GetCode(frame), i).op.code; + Py_ssize_t i = frame->instr_ptr - _PyFrame_GetBytecode(frame); + assert(i >= 0 && i <= INT_MAX); + int opcode = _Py_GetBaseCodeUnit(_PyFrame_GetCode(frame), (int)i).op.code; assert(opcode == SEND || opcode == FOR_ITER); } #endif diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index b6a2821db3007e..efa61d7de74e88 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -9346,8 +9346,9 @@ assert(INLINE_CACHE_ENTRIES_SEND == INLINE_CACHE_ENTRIES_FOR_ITER); #if TIER_ONE && defined(Py_DEBUG) if (!PyStackRef_IsNone(frame->f_executable)) { - int i = frame->instr_ptr - _PyFrame_GetBytecode(frame); - int opcode = _Py_GetBaseCodeUnit(_PyFrame_GetCode(frame), i).op.code; + Py_ssize_t i = frame->instr_ptr - _PyFrame_GetBytecode(frame); + assert(i >= 0 && i <= INT_MAX); + int opcode = _Py_GetBaseCodeUnit(_PyFrame_GetCode(frame), (int)i).op.code; assert(opcode == SEND || opcode == FOR_ITER); } #endif diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 2623105656c90c..53e09a8f4523c7 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -7945,8 +7945,9 @@ assert(INLINE_CACHE_ENTRIES_SEND == INLINE_CACHE_ENTRIES_FOR_ITER); #if TIER_ONE && defined(Py_DEBUG) if (!PyStackRef_IsNone(frame->f_executable)) { - int i = frame->instr_ptr - _PyFrame_GetBytecode(frame); - int opcode = _Py_GetBaseCodeUnit(_PyFrame_GetCode(frame), i).op.code; + Py_ssize_t i = frame->instr_ptr - _PyFrame_GetBytecode(frame); + assert(i >= 0 && i <= INT_MAX); + int opcode = _Py_GetBaseCodeUnit(_PyFrame_GetCode(frame), (int)i).op.code; assert(opcode == SEND || opcode == FOR_ITER); } #endif @@ -13053,8 +13054,9 @@ assert(INLINE_CACHE_ENTRIES_SEND == INLINE_CACHE_ENTRIES_FOR_ITER); #if TIER_ONE && defined(Py_DEBUG) if (!PyStackRef_IsNone(frame->f_executable)) { - int i = frame->instr_ptr - _PyFrame_GetBytecode(frame); - int opcode = _Py_GetBaseCodeUnit(_PyFrame_GetCode(frame), i).op.code; + Py_ssize_t i = frame->instr_ptr - _PyFrame_GetBytecode(frame); + assert(i >= 0 && i <= INT_MAX); + int opcode = _Py_GetBaseCodeUnit(_PyFrame_GetCode(frame), (int)i).op.code; assert(opcode == SEND || opcode == FOR_ITER); } #endif From 564902ea8ae409d46a8ff9c06f3f9d58f754cf59 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 12 May 2026 22:10:24 +0200 Subject: [PATCH 035/818] [3.15] gh-139808: Add branch protections for aarch64 in asm_trampoline.S (GH-130864) (#149730) gh-139808: Add branch protections for aarch64 in asm_trampoline.S (GH-130864) Apply protection against ROP/JOP attacks for aarch64 on asm_trampoline.S. The BTI flag must be applied in assembler sources for this class of attacks to be mitigated on newer aarch64 processors. See also: https://sourceware.org/annobin/annobin.html/Test-branch-protection.html and https://community.arm.com/arm-community-blogs/b/architectures-and-processors-blog/posts/enabling-pac-and-bti-on-aarch64 (cherry picked from commit da8477b25c6124c961306d4d7cd5ec7dafda6be4) Co-authored-by: stratakis Co-authored-by: Victor Stinner --- ...-05-12-16-47-23.gh-issue-139808.iIs7_E.rst | 2 + Python/asm_trampoline.S | 4 ++ Python/asm_trampoline_aarch64.h | 56 +++++++++++++++++++ Python/jit_unwind.c | 13 +++++ 4 files changed, 75 insertions(+) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-05-12-16-47-23.gh-issue-139808.iIs7_E.rst create mode 100644 Python/asm_trampoline_aarch64.h diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-12-16-47-23.gh-issue-139808.iIs7_E.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-12-16-47-23.gh-issue-139808.iIs7_E.rst new file mode 100644 index 00000000000000..3e9d930bf1de89 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-12-16-47-23.gh-issue-139808.iIs7_E.rst @@ -0,0 +1,2 @@ +Add branch protections for AArch64 (BTI/PAC) in assembly code used by +:option:`-X perf_jit <-X>` (Linux perf profiler integration). diff --git a/Python/asm_trampoline.S b/Python/asm_trampoline.S index 93adae3d99038f..9f3ca909ab7d85 100644 --- a/Python/asm_trampoline.S +++ b/Python/asm_trampoline.S @@ -1,3 +1,5 @@ +#include "asm_trampoline_aarch64.h" + .text #if defined(__APPLE__) .globl __Py_trampoline_func_start @@ -29,10 +31,12 @@ _Py_trampoline_func_start: #if defined(__aarch64__) && defined(__AARCH64EL__) && !defined(__ILP32__) // ARM64 little endian, 64bit ABI // generate with aarch64-linux-gnu-gcc 12.1 + SIGN_LR stp x29, x30, [sp, -16]! mov x29, sp blr x3 ldp x29, x30, [sp], 16 + VERIFY_LR ret #endif #ifdef __riscv diff --git a/Python/asm_trampoline_aarch64.h b/Python/asm_trampoline_aarch64.h new file mode 100644 index 00000000000000..bc83aa460b6860 --- /dev/null +++ b/Python/asm_trampoline_aarch64.h @@ -0,0 +1,56 @@ +#ifndef ASM_TRAMPOLINE_AARCH_64_H_ +#define ASM_TRAMPOLINE_AARCH_64_H_ + +/* + * References: + * - https://developer.arm.com/documentation/101028/0012/5--Feature-test-macros + * - https://github.com/ARM-software/abi-aa/blob/main/aaelf64/aaelf64.rst + */ + +#if defined(__ARM_FEATURE_BTI_DEFAULT) && __ARM_FEATURE_BTI_DEFAULT == 1 + #define BTI_J hint 36 /* bti j: for jumps, IE br instructions */ + #define BTI_C hint 34 /* bti c: for calls, IE bl instructions */ + #define GNU_PROPERTY_AARCH64_BTI 1 /* bit 0 GNU Notes is for BTI support */ +#else + #define BTI_J + #define BTI_C + #define GNU_PROPERTY_AARCH64_BTI 0 +#endif + +#if defined(__ARM_FEATURE_PAC_DEFAULT) + #if __ARM_FEATURE_PAC_DEFAULT & 1 + #define SIGN_LR hint 25 /* paciasp: sign with the A key */ + #define VERIFY_LR hint 29 /* autiasp: verify with the A key */ + #elif __ARM_FEATURE_PAC_DEFAULT & 2 + #define SIGN_LR hint 27 /* pacibsp: sign with the b key */ + #define VERIFY_LR hint 31 /* autibsp: verify with the b key */ + #endif + #define GNU_PROPERTY_AARCH64_POINTER_AUTH 2 /* bit 1 GNU Notes is for PAC support */ +#else + #define SIGN_LR BTI_C + #define VERIFY_LR + #define GNU_PROPERTY_AARCH64_POINTER_AUTH 0 +#endif + +#if defined(__ARM_FEATURE_GCS_DEFAULT) && __ARM_FEATURE_GCS_DEFAULT == 1 + #define GNU_PROPERTY_AARCH64_GCS 4 /* bit 2 GNU Notes is for GCS support */ +#else + #define GNU_PROPERTY_AARCH64_GCS 0 +#endif + +/* Add the BTI, PAC and GCS support to GNU Notes section */ +#if GNU_PROPERTY_AARCH64_BTI != 0 || GNU_PROPERTY_AARCH64_POINTER_AUTH != 0 || GNU_PROPERTY_AARCH64_GCS != 0 + .pushsection .note.gnu.property, "a"; /* Start a new allocatable section */ + .balign 8; /* align it on a byte boundry */ + .long 4; /* size of "GNU\0" */ + .long 0x10; /* size of descriptor */ + .long 0x5; /* NT_GNU_PROPERTY_TYPE_0 */ + .asciz "GNU"; + .long 0xc0000000; /* GNU_PROPERTY_AARCH64_FEATURE_1_AND */ + .long 4; /* Four bytes of data */ + .long (GNU_PROPERTY_AARCH64_BTI|GNU_PROPERTY_AARCH64_POINTER_AUTH|GNU_PROPERTY_AARCH64_GCS); /* BTI, PAC or GCS is enabled */ + .long 0; /* padding for 8 byte alignment */ + .popsection; /* end the section */ +#endif + +#endif diff --git a/Python/jit_unwind.c b/Python/jit_unwind.c index 646106f0a9655c..0941ed593ff7d1 100644 --- a/Python/jit_unwind.c +++ b/Python/jit_unwind.c @@ -60,6 +60,9 @@ enum { DWRF_CFA_offset_extended_sf = 0x11, // Extended signed offset DWRF_CFA_advance_loc = 0x40, // Advance location counter DWRF_CFA_offset = 0x80, // Simple offset instruction +#if defined(__aarch64__) + DWRF_CFA_AARCH64_negate_ra_state = 0x2d, // Toggle return address signing state +#endif DWRF_CFA_restore = 0xc0 // Restore register }; @@ -562,6 +565,13 @@ static void elf_init_ehframe_perf(ELFObjectContext* ctx) { DWRF_UV(8); // New offset: SP + 8 #elif defined(__aarch64__) && defined(__AARCH64EL__) && !defined(__ILP32__) /* AArch64 calling convention unwinding rules */ +#if defined(__ARM_FEATURE_PAC_DEFAULT) || \ + (defined(__ARM_FEATURE_BTI_DEFAULT) && __ARM_FEATURE_BTI_DEFAULT == 1) + DWRF_U8(DWRF_CFA_advance_loc | 1); // Advance past SIGN_LR (4 bytes) +#endif +#if defined(__ARM_FEATURE_PAC_DEFAULT) + DWRF_U8(DWRF_CFA_AARCH64_negate_ra_state); // Saved LR is PAC-signed from here +#endif DWRF_U8(DWRF_CFA_advance_loc | 1); // Advance by 1 instruction (4 bytes) DWRF_U8(DWRF_CFA_def_cfa_offset); // CFA = SP + 16 DWRF_UV(16); // Stack pointer moved by 16 bytes @@ -570,6 +580,9 @@ static void elf_init_ehframe_perf(ELFObjectContext* ctx) { DWRF_U8(DWRF_CFA_offset | DWRF_REG_RA); // x30 (link register) saved DWRF_UV(1); // At CFA-8 (1 * 8 = 8 bytes from CFA) DWRF_U8(DWRF_CFA_advance_loc | 3); // Advance by 3 instructions (12 bytes) +#if defined(__ARM_FEATURE_PAC_DEFAULT) + DWRF_U8(DWRF_CFA_AARCH64_negate_ra_state); // LR is authenticated, no longer PAC-signed +#endif DWRF_U8(DWRF_CFA_def_cfa_register); // CFA = FP (x29) + 16 DWRF_UV(DWRF_REG_FP); DWRF_U8(DWRF_CFA_restore | DWRF_REG_RA); // Restore x30 - NO DWRF_UV() after this! From 670f982fbd6b8655e9d3ff832aac4bdbb0d89d34 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 12 May 2026 22:25:28 +0200 Subject: [PATCH 036/818] [3.15] gh-134837: Correct and improve base85 documentation for base64 and binascii modules (GH-145843) (GH-149742) (cherry picked from commit e667d62f114b54dcba17bdfad3835b9c91fda348) Co-authored-by: David Huggins-Daines --- Doc/library/base64.rst | 89 ++++++++++++++++++++++++------------- Doc/library/binascii.rst | 27 +++++++---- Lib/base64.py | 38 ++++++++++------ Modules/binascii.c | 13 +++--- Modules/clinic/binascii.c.h | 9 ++-- 5 files changed, 112 insertions(+), 64 deletions(-) diff --git a/Doc/library/base64.rst b/Doc/library/base64.rst index a722607b2c1f19..8af40a2f8a65e3 100644 --- a/Doc/library/base64.rst +++ b/Doc/library/base64.rst @@ -16,8 +16,10 @@ This module provides functions for encoding binary data to printable ASCII characters and decoding such encodings back to binary data. This includes the :ref:`encodings specified in ` -:rfc:`4648` (Base64, Base32 and Base16) -and the non-standard :ref:`Base85 encodings `. +:rfc:`4648` (Base64, Base32 and Base16), the :ref:`Base85 encoding +` specified in `PDF 2.0 +`_, and non-standard variants +of Base85 used elsewhere. There are two interfaces provided by this module. The modern interface supports encoding :term:`bytes-like objects ` to ASCII @@ -284,19 +286,28 @@ POST request. Base85 Encodings ----------------- -Base85 encoding is not formally specified but rather a de facto standard, -thus different systems perform the encoding differently. +Base85 encoding is a family of algorithms which represent four bytes +using five ASCII characters. Originally implemented in the Unix +``btoa(1)`` utility, a version of it was later adopted by Adobe in the +PostScript language and is standardized in PDF 2.0 (ISO 32000-2). +This version, in both its ``btoa`` and PDF variants, is implemented by +:func:`a85encode`. -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. +A separate version, using a different output character set, was +defined as an April Fool's joke in :rfc:`1924` but is now used by Git +and other software. This version is implemented by :func:`b85encode`. -The two functions present in this module differ in how they handle the following: +Finally, a third version, using yet another output character set +designed for safe inclusion in programming language strings, is +defined by ZeroMQ and implemented here by :func:`z85encode`. -* Whether to include enclosing ``<~`` and ``~>`` markers -* Whether to include newline characters -* The set of ASCII characters used for encoding -* Handling of null bytes +The functions present in this module differ in how they handle the following: + +* Whether to include and expect enclosing ``<~`` and ``~>`` markers. +* Whether to fold the input into multiple lines. +* The set of ASCII characters used for encoding. +* Compact encodings of sequences of spaces and null bytes. +* The encoding of zero-padding bytes applied to the input. Refer to the documentation of the individual functions for more information. @@ -307,18 +318,22 @@ Refer to the documentation of the individual functions for more information. *foldspaces* is an optional flag that uses the special short sequence 'y' instead of 4 consecutive spaces (ASCII 0x20) as supported by 'btoa'. This - feature is not supported by the "standard" Ascii85 encoding. + feature is not supported by the standard encoding used in PDF. If *wrapcol* is non-zero, insert a newline (``b'\n'``) character after at most every *wrapcol* characters. If *wrapcol* is zero (default), do not insert any newlines. - If *pad* is true, the input is padded with ``b'\0'`` so its length is a - multiple of 4 bytes before encoding. - Note that the ``btoa`` implementation always pads. + *pad* controls whether zero-padding applied to the end of the input + is fully retained in the output encoding, as done by ``btoa``, + producing an exact multiple of 5 bytes of output. This is not part + of the standard encoding used in PDF, as it does not preserve the + length of the data. - *adobe* controls whether the encoded byte sequence is framed with ``<~`` - and ``~>``, which is used by the Adobe implementation. + *adobe* controls whether the encoded byte sequence is framed with + ``<~`` and ``~>``, as in a PostScript base-85 string literal. Note + that while ASCII85Decode streams in PDF documents *must* be + terminated with ``~>``, they *must not* use a leading ``<~``. .. versionadded:: 3.4 @@ -330,10 +345,12 @@ Refer to the documentation of the individual functions for more information. *foldspaces* is a flag that specifies whether the 'y' short sequence should be accepted as shorthand for 4 consecutive spaces (ASCII 0x20). - This feature is not supported by the "standard" Ascii85 encoding. + This feature is not supported by the standard Ascii85 encoding used in + PDF and PostScript. - *adobe* controls whether the input sequence is in Adobe Ascii85 format - (i.e. is framed with <~ and ~>). + *adobe* controls whether the ``<~`` and ``~>`` markers are + present. While the leading ``<~`` is not required, the input must + end with ``~>``, or a :exc:`ValueError` is raised. *ignorechars* should be a :term:`bytes-like object` containing characters to ignore from the input. @@ -356,8 +373,11 @@ Refer to the documentation of the individual functions for more information. Encode the :term:`bytes-like object` *b* using base85 (as used in e.g. git-style binary diffs) and return the encoded :class:`bytes`. - If *pad* is true, the input is padded with ``b'\0'`` so its length is a - multiple of 4 bytes before encoding. + The input is padded with ``b'\0'`` so its length is a multiple of 4 + bytes before encoding. If *pad* is true, all the resulting + characters are retained in the output, which will always be a + multiple of 5 bytes, and thus the length of the data may not be + preserved on decoding. If *wrapcol* is non-zero, insert a newline (``b'\n'``) character after at most every *wrapcol* characters. @@ -372,8 +392,7 @@ Refer to the documentation of the individual functions for more information. .. function:: b85decode(b, *, ignorechars=b'', canonical=False) Decode the base85-encoded :term:`bytes-like object` or ASCII string *b* and - return the decoded :class:`bytes`. Padding is implicitly removed, if - necessary. + return the decoded :class:`bytes`. *ignorechars* should be a :term:`bytes-like object` containing characters to ignore from the input. @@ -392,11 +411,12 @@ Refer to the documentation of the individual functions for more information. .. function:: z85encode(s, pad=False, *, wrapcol=0) Encode the :term:`bytes-like object` *s* using Z85 (as used in ZeroMQ) - and return the encoded :class:`bytes`. See `Z85 specification - `_ for more information. + and return the encoded :class:`bytes`. - If *pad* is true, the input is padded with ``b'\0'`` so its length is a - multiple of 4 bytes before encoding. + The input is padded with ``b'\0'`` so its length is a multiple of 4 + bytes before encoding. If *pad* is true, all the resulting + characters are retained in the output, which will always be a + multiple of 5 bytes, as required by the ZeroMQ standard. If *wrapcol* is non-zero, insert a newline (``b'\n'``) character after at most every *wrapcol* characters. @@ -414,8 +434,7 @@ Refer to the documentation of the individual functions for more information. .. function:: z85decode(s, *, ignorechars=b'', canonical=False) Decode the Z85-encoded :term:`bytes-like object` or ASCII string *s* and - return the decoded :class:`bytes`. See `Z85 specification - `_ for more information. + return the decoded :class:`bytes`. *ignorechars* should be a :term:`bytes-like object` containing characters to ignore from the input. @@ -499,3 +518,11 @@ recommended to review the security section for any code deployed to production. Section 5.2, "Base64 Content-Transfer-Encoding," provides the definition of the base64 encoding. + `ISO 32000-2 Portable document format - Part 2: PDF 2.0 `_ + Section 7.4.3, "ASCII85Decode Filter," provides the definition + of the Ascii85 encoding used in PDF and PostScript, including + the output character set and the details of data length preservation + using zero-padding and partial output groups. + + `ZeroMQ RFC 32/Z85 `_ + The "Formal Specification" section provides the character set used in Z85. diff --git a/Doc/library/binascii.rst b/Doc/library/binascii.rst index 8b4ba6ae9fb254..60afe9261d51fa 100644 --- a/Doc/library/binascii.rst +++ b/Doc/library/binascii.rst @@ -133,8 +133,11 @@ The :mod:`!binascii` module defines the following functions: should be accepted as shorthand for 4 consecutive spaces (ASCII 0x20). This feature is not supported by the "standard" Ascii85 encoding. - *adobe* controls whether the input sequence is in Adobe Ascii85 format - (i.e. is framed with <~ and ~>). + *adobe* controls whether the encoded byte sequence is framed with + ``<~`` and ``~>``, as in a PostScript base-85 string literal. If + *adobe* is true, a leading ``<~`` is optionally accepted, while a + trailing ``~>`` is *required*, and :exc:`binascii.Error` is raised + if it is not found. *ignorechars* should be a :term:`bytes-like object` containing characters to ignore from the input. @@ -164,12 +167,16 @@ The :mod:`!binascii` module defines the following functions: after at most every *wrapcol* characters. If *wrapcol* is zero (default), do not insert any newlines. - If *pad* is true, the input is padded with ``b'\0'`` so its length is a - multiple of 4 bytes before encoding. - Note that the ``btoa`` implementation always pads. + If *pad* is true, the zero-padding applied to the end of the input + is fully retained in the output encoding, as done by ``btoa``, + producing an exact multiple of 5 bytes of output. This is not part + of the standard encoding used in PDF, as it does not preserve the + length of the data. - *adobe* controls whether the encoded byte sequence is framed with ``<~`` - and ``~>``, which is used by the Adobe implementation. + *adobe* controls whether the encoded byte sequence is framed with + ``<~`` and ``~>``, as in a PostScript base-85 string literal. Note + that while ASCII85Decode streams in PDF documents *must* be + terminated with ``~>``, they *must not* use a leading ``<~``. .. versionadded:: 3.15 @@ -213,8 +220,10 @@ The :mod:`!binascii` module defines the following functions: after at most every *wrapcol* characters. If *wrapcol* is zero (default), do not insert any newlines. - If *pad* is true, the input is padded with ``b'\0'`` so its length is a - multiple of 4 bytes before encoding. + If *pad* is true, the zero-padding applied to the end of the input + is retained in the output, which will always be a multiple of 5 + bytes, and thus the length of the data may not be preserved on + decoding. .. versionadded:: 3.15 diff --git a/Lib/base64.py b/Lib/base64.py index 4b810e08569e5b..4a0e9d446edb0b 100644 --- a/Lib/base64.py +++ b/Lib/base64.py @@ -315,16 +315,20 @@ def a85encode(b, *, foldspaces=False, wrapcol=0, pad=False, adobe=False): foldspaces is an optional flag that uses the special short sequence 'y' instead of 4 consecutive spaces (ASCII 0x20) as supported by 'btoa'. This - feature is not supported by the "standard" Adobe encoding. + feature is not supported by the standard encoding used in PDF. If wrapcol is non-zero, insert a newline (b'\\n') character after at most every wrapcol characters. - pad controls whether the input is padded to a multiple of 4 before - encoding. Note that the btoa implementation always pads. + pad controls whether zero-padding applied to the end of the input + is fully retained in the output encoding, as done by btoa, + producing an exact multiple of 5 bytes of output. + + adobe controls whether the encoded byte sequence is framed with <~ + and ~>, as in a PostScript base-85 string literal. Note that + while ASCII85Decode streams in PDF documents must be terminated + with ~>, they must not use a leading <~. - adobe controls whether the encoded byte sequence is framed with <~ and ~>, - which is used by the Adobe implementation. """ return binascii.b2a_ascii85(b, foldspaces=foldspaces, adobe=adobe, wrapcol=wrapcol, pad=pad) @@ -333,12 +337,14 @@ def a85decode(b, *, foldspaces=False, adobe=False, ignorechars=b' \t\n\r\v', canonical=False): """Decode the Ascii85 encoded bytes-like object or ASCII string b. - foldspaces is a flag that specifies whether the 'y' short sequence should be - accepted as shorthand for 4 consecutive spaces (ASCII 0x20). This feature is - not supported by the "standard" Adobe encoding. + foldspaces is a flag that specifies whether the 'y' short sequence + should be accepted as shorthand for 4 consecutive spaces (ASCII + 0x20). This feature is not supported by the standard Ascii85 + encoding used in PDF and PostScript. - adobe controls whether the input sequence is in Adobe Ascii85 format (i.e. - is framed with <~ and ~>). + adobe controls whether the <~ and ~> markers are present. While + the leading <~ is not required, the input must end with ~>, or a + ValueError is raised. ignorechars should be a byte string containing characters to ignore from the input. This should only contain whitespace characters, and by default @@ -358,8 +364,10 @@ def b85encode(b, pad=False, *, wrapcol=0): If wrapcol is non-zero, insert a newline (b'\\n') character after at most every wrapcol characters. - If pad is true, the input is padded with b'\\0' so its length is a multiple of - 4 bytes before encoding. + The input is padded with b'\0' so its length is a multiple of 4 + bytes before encoding. If pad is true, all the resulting + characters are retained in the output, which will always be a + multiple of 5 bytes. """ return binascii.b2a_base85(b, wrapcol=wrapcol, pad=pad) @@ -379,8 +387,10 @@ def z85encode(s, pad=False, *, wrapcol=0): If wrapcol is non-zero, insert a newline (b'\\n') character after at most every wrapcol characters. - If pad is true, the input is padded with b'\\0' so its length is a multiple of - 4 bytes before encoding. + The input is padded with b'\0' so its length is a multiple of + bytes before encoding. If pad is true, all the resulting + characters are retained in the output, which will always be a + multiple of 5 bytes, as required by the ZeroMQ standard. """ return binascii.b2a_base85(s, wrapcol=wrapcol, pad=pad, alphabet=binascii.Z85_ALPHABET) diff --git a/Modules/binascii.c b/Modules/binascii.c index 673dca6ee134bd..0e7af135a6f6ce 100644 --- a/Modules/binascii.c +++ b/Modules/binascii.c @@ -1057,7 +1057,8 @@ binascii.a2b_ascii85 foldspaces: bool = False Allow 'y' as a short form encoding four spaces. adobe: bool = False - Expect data to be wrapped in '<~' and '~>' as in Adobe Ascii85. + Expect data to be terminated with '~>' as in Adobe Ascii85, and + optionally accept leading '<~'. ignorechars: Py_buffer = b'' A byte string containing characters to ignore from the input. canonical: bool = False @@ -1069,7 +1070,7 @@ Decode Ascii85 data. static PyObject * binascii_a2b_ascii85_impl(PyObject *module, Py_buffer *data, int foldspaces, int adobe, Py_buffer *ignorechars, int canonical) -/*[clinic end generated code: output=09b35f1eac531357 input=dd050604ed30199e]*/ +/*[clinic end generated code: output=09b35f1eac531357 input=08eab2e53c62f1a8]*/ { const unsigned char *ascii_data = data->buf; Py_ssize_t ascii_len = data->len; @@ -1264,7 +1265,7 @@ binascii.b2a_ascii85 wrapcol: size_t = 0 Split result into lines of provided width. pad: bool = False - Pad input to a multiple of 4 before encoding. + Retain zero-padding bytes at end of output. adobe: bool = False Wrap result in '<~' and '~>' as in Adobe Ascii85. @@ -1274,7 +1275,7 @@ Ascii85-encode data. static PyObject * binascii_b2a_ascii85_impl(PyObject *module, Py_buffer *data, int foldspaces, size_t wrapcol, int pad, int adobe) -/*[clinic end generated code: output=5ce8fdee843073f4 input=791da754508c7d17]*/ +/*[clinic end generated code: output=5ce8fdee843073f4 input=a77e31d63517bf19]*/ { const unsigned char *bin_data = data->buf; Py_ssize_t bin_len = data->len; @@ -1539,7 +1540,7 @@ binascii.b2a_base85 / * pad: bool = False - Pad input to a multiple of 4 before encoding. + Retain zero-padding bytes at end of output. wrapcol: size_t = 0 alphabet: Py_buffer(c_default="{NULL, NULL}") = BASE85_ALPHABET @@ -1549,7 +1550,7 @@ Base85-code line of data. static PyObject * binascii_b2a_base85_impl(PyObject *module, Py_buffer *data, int pad, size_t wrapcol, Py_buffer *alphabet) -/*[clinic end generated code: output=98b962ed52c776a4 input=1b20b0bd6572691b]*/ +/*[clinic end generated code: output=98b962ed52c776a4 input=54886d05128d41a8]*/ { const unsigned char *bin_data = data->buf; Py_ssize_t bin_len = data->len; diff --git a/Modules/clinic/binascii.c.h b/Modules/clinic/binascii.c.h index ed695758ef998c..29fa9e87de87c7 100644 --- a/Modules/clinic/binascii.c.h +++ b/Modules/clinic/binascii.c.h @@ -372,7 +372,8 @@ PyDoc_STRVAR(binascii_a2b_ascii85__doc__, " foldspaces\n" " Allow \'y\' as a short form encoding four spaces.\n" " adobe\n" -" Expect data to be wrapped in \'<~\' and \'~>\' as in Adobe Ascii85.\n" +" Expect data to be terminated with \'~>\' as in Adobe Ascii85, and\n" +" optionally accept leading \'<~\'.\n" " ignorechars\n" " A byte string containing characters to ignore from the input.\n" " canonical\n" @@ -492,7 +493,7 @@ PyDoc_STRVAR(binascii_b2a_ascii85__doc__, " wrapcol\n" " Split result into lines of provided width.\n" " pad\n" -" Pad input to a multiple of 4 before encoding.\n" +" Retain zero-padding bytes at end of output.\n" " adobe\n" " Wrap result in \'<~\' and \'~>\' as in Adobe Ascii85."); @@ -709,7 +710,7 @@ PyDoc_STRVAR(binascii_b2a_base85__doc__, "Base85-code line of data.\n" "\n" " pad\n" -" Pad input to a multiple of 4 before encoding."); +" Retain zero-padding bytes at end of output."); #define BINASCII_B2A_BASE85_METHODDEF \ {"b2a_base85", _PyCFunction_CAST(binascii_b2a_base85), METH_FASTCALL|METH_KEYWORDS, binascii_b2a_base85__doc__}, @@ -1684,4 +1685,4 @@ binascii_b2a_qp(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObj return return_value; } -/*[clinic end generated code: output=b41544f39b0ef681 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=42dd48f323cbb118 input=a9049054013a1b77]*/ From e3fbcc3eac2527a0f1eda039bcbd4cc3eab708f9 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 12 May 2026 23:25:21 +0200 Subject: [PATCH 037/818] [3.15] gh-149496: Fix MacOSTest.test_default regression when BROWSER env var is set (GH-149579) (#149745) gh-149496: Fix MacOSTest.test_default regression when BROWSER env var is set (GH-149579) gh-149496: Fix MacOSTest.test_default failing when BROWSER env var is set MacOSTest.test_default calls webbrowser.get() and asserts it returns a MacOS instance. When BROWSER is set in the environment (e.g. BROWSER=open, a common macOS workaround for the old osascript-based implementation), register_standard_browsers() registers a GenericBrowser as the preferred browser instead, causing the assertion to fail. This is a regression introduced in gh-137586, which added MacOSTest and moved test_default into it from MacOSXOSAScriptTest. MacOSXOSAScriptTest had an identical setUp() guard added in gh-131254 specifically to fix this same failure. The guard was not carried over to MacOSTest. Add setUp() to MacOSTest to unset BROWSER for the duration of each test, restoring the isolation that was already established as the correct pattern for macOS webbrowser tests. (cherry picked from commit 45c47d26c230086163ac1ef0aa9f955f794fb69c) Co-authored-by: Jeff Lyon <146767590+secengjeff@users.noreply.github.com> --- Lib/test/test_webbrowser.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Lib/test/test_webbrowser.py b/Lib/test/test_webbrowser.py index 51d627d24c5a8a..82f14ca968f266 100644 --- a/Lib/test/test_webbrowser.py +++ b/Lib/test/test_webbrowser.py @@ -340,6 +340,10 @@ def close(self): @requires_subprocess() class MacOSTest(unittest.TestCase): + def setUp(self): + env = self.enterContext(os_helper.EnvironmentVarGuard()) + env.unset("BROWSER") + def test_default(self): browser = webbrowser.get() self.assertIsInstance(browser, webbrowser.MacOS) From 8b73ce9ab86a0048a4e9a74ce71397b41f4da3f0 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 13 May 2026 02:30:22 +0200 Subject: [PATCH 038/818] [3.15] gh-149718: Aggregate same stack frames in Tachyon in some collectors (GH-149719) (#149747) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gh-149718: Aggregate same stack frames in Tachyon in some collectors (GH-149719) (cherry picked from commit 76f22853410d3ded872cbfe1430852cf8c048962) Co-authored-by: Maurycy Pawłowski-Wieroński --- Lib/profiling/sampling/collector.py | 2 + Lib/profiling/sampling/gecko_collector.py | 2 + Lib/profiling/sampling/heatmap_collector.py | 7 +- Lib/profiling/sampling/pstats_collector.py | 2 + Lib/profiling/sampling/sample.py | 33 +++++++- Lib/profiling/sampling/stack_collector.py | 2 + Lib/test/test_profiling/test_heatmap.py | 15 ++++ .../test_sampling_profiler/test_profiler.py | 79 ++++++++++++++++++- ...-05-12-13-03-45.gh-issue-149718.SaM1NJ.rst | 4 + 9 files changed, 140 insertions(+), 6 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-05-12-13-03-45.gh-issue-149718.SaM1NJ.rst diff --git a/Lib/profiling/sampling/collector.py b/Lib/profiling/sampling/collector.py index 81ec6344ebdea4..8e0f0c44c4f8f3 100644 --- a/Lib/profiling/sampling/collector.py +++ b/Lib/profiling/sampling/collector.py @@ -143,6 +143,8 @@ def iter_async_frames(awaited_info_list): class Collector(ABC): + aggregating = False + @abstractmethod def collect(self, stack_frames, timestamps_us=None): """Collect profiling data from stack frames. diff --git a/Lib/profiling/sampling/gecko_collector.py b/Lib/profiling/sampling/gecko_collector.py index 8986194268b3ce..54392af9500008 100644 --- a/Lib/profiling/sampling/gecko_collector.py +++ b/Lib/profiling/sampling/gecko_collector.py @@ -63,6 +63,8 @@ class GeckoCollector(Collector): + aggregating = True + def __init__(self, sample_interval_usec, *, skip_idle=False, opcodes=False): self.sample_interval_usec = sample_interval_usec self.skip_idle = skip_idle diff --git a/Lib/profiling/sampling/heatmap_collector.py b/Lib/profiling/sampling/heatmap_collector.py index 5c36d78f5535e7..6e650ec08f410b 100644 --- a/Lib/profiling/sampling/heatmap_collector.py +++ b/Lib/profiling/sampling/heatmap_collector.py @@ -452,7 +452,8 @@ def process_frames(self, frames, thread_id, weight=1): next_lineno = extract_lineno(next_frame[1]) self._record_call_relationship( (filename, lineno, funcname), - (next_frame[0], next_lineno, next_frame[2]) + (next_frame[0], next_lineno, next_frame[2]), + weight=weight, ) def _is_valid_frame(self, filename, lineno): @@ -561,7 +562,7 @@ def _get_bytecode_data_for_line(self, filename, lineno): result.sort(key=lambda x: (-x['samples'], x['opcode'])) return result - def _record_call_relationship(self, callee_frame, caller_frame): + def _record_call_relationship(self, callee_frame, caller_frame, weight=1): """Record caller/callee relationship between adjacent frames.""" callee_filename, callee_lineno, callee_funcname = callee_frame caller_filename, caller_lineno, caller_funcname = caller_frame @@ -587,7 +588,7 @@ def _record_call_relationship(self, callee_frame, caller_frame): # Count this call edge for path analysis edge_key = (caller_key, callee_key) - self.edge_samples[edge_key] += 1 + self.edge_samples[edge_key] += weight def export(self, output_path): """Export heatmap data as HTML files in a directory. diff --git a/Lib/profiling/sampling/pstats_collector.py b/Lib/profiling/sampling/pstats_collector.py index 50500296c15acc..43b1daf2a119d4 100644 --- a/Lib/profiling/sampling/pstats_collector.py +++ b/Lib/profiling/sampling/pstats_collector.py @@ -8,6 +8,8 @@ class PstatsCollector(Collector): + aggregating = True + def __init__(self, sample_interval_usec, *, skip_idle=False): self.result = collections.defaultdict( lambda: dict(total_rec_calls=0, direct_calls=0, cumulative_calls=0) diff --git a/Lib/profiling/sampling/sample.py b/Lib/profiling/sampling/sample.py index 5bbe2483581333..b9e7e2625d09e4 100644 --- a/Lib/profiling/sampling/sample.py +++ b/Lib/profiling/sampling/sample.py @@ -47,6 +47,9 @@ def _pause_threads(unwinder, blocking): # If fewer samples are collected, we skip the TUI and just print a message MIN_SAMPLES_FOR_TUI = 200 +# Maximum number of consecutive identical samples to keep before flushing. +MAX_PENDING_SAMPLES = 8192 + class SampleProfiler: def __init__(self, pid, sample_interval_usec, all_threads, *, mode=PROFILING_MODE_WALL, native=False, gc=True, opcodes=False, skip_non_matching_threads=True, collect_stats=False, blocking=False): self.pid = pid @@ -109,6 +112,20 @@ def sample(self, collector, duration_sec=None, *, async_aware=False): last_sample_time = start_time realtime_update_interval = 1.0 # Update every second last_realtime_update = start_time + aggregating = getattr(collector, 'aggregating', False) is True + prev_stack = None + pending_count = 0 + pending_timestamps = [] if aggregating else None + + def flush_pending(): + nonlocal pending_count, pending_timestamps + if pending_count == 0: + return + pending_count = 0 + ts = pending_timestamps + pending_timestamps = [] + collector.collect(prev_stack, timestamps_us=ts) + try: while duration_sec is None or running_time_sec < duration_sec: # Check if live collector wants to stop @@ -116,6 +133,7 @@ def sample(self, collector, duration_sec=None, *, async_aware=False): break current_time = time.perf_counter() + current_time_us = int(current_time * 1_000_000) if next_time > current_time: sleep_time = (next_time - current_time) * 0.9 if sleep_time > 0.0001: @@ -125,13 +143,24 @@ def sample(self, collector, duration_sec=None, *, async_aware=False): stack_frames = self._get_stack_trace( async_aware=async_aware ) - collector.collect(stack_frames) + if aggregating: + if stack_frames != prev_stack: + flush_pending() + prev_stack = stack_frames + pending_count += 1 + pending_timestamps.append(current_time_us) + if pending_count >= MAX_PENDING_SAMPLES: + flush_pending() + else: + collector.collect(stack_frames) except ProcessLookupError as e: running_time_sec = current_time - start_time break except (RuntimeError, UnicodeDecodeError, MemoryError, OSError): + flush_pending() collector.collect_failed_sample() errors += 1 + prev_stack = None except Exception as e: if not _is_process_running(self.pid): break @@ -163,6 +192,8 @@ def sample(self, collector, duration_sec=None, *, async_aware=False): interrupted = True running_time_sec = time.perf_counter() - start_time print("Interrupted by user.") + finally: + flush_pending() # Clear real-time stats line if it was being displayed if self.realtime_stats and len(self.sample_intervals) > 0: diff --git a/Lib/profiling/sampling/stack_collector.py b/Lib/profiling/sampling/stack_collector.py index 60df026ed76a6c..42281dc6454c83 100644 --- a/Lib/profiling/sampling/stack_collector.py +++ b/Lib/profiling/sampling/stack_collector.py @@ -16,6 +16,8 @@ class StackTraceCollector(Collector): + aggregating = True + def __init__(self, sample_interval_usec, *, skip_idle=False): self.sample_interval_usec = sample_interval_usec self.skip_idle = skip_idle diff --git a/Lib/test/test_profiling/test_heatmap.py b/Lib/test/test_profiling/test_heatmap.py index b2acb1cf577341..ee27fdd3fa3053 100644 --- a/Lib/test/test_profiling/test_heatmap.py +++ b/Lib/test/test_profiling/test_heatmap.py @@ -345,6 +345,21 @@ def test_process_frames_tracks_edge_samples(self): # Check that edge count is tracked self.assertGreater(len(collector.edge_samples), 0) + def test_process_frames_weight_applies_to_identical_samples(self): + collector = HeatmapCollector(sample_interval_usec=100) + + frames = [ + ('callee.py', (5, 5, -1, -1), 'callee', None), + ('caller.py', (10, 10, -1, -1), 'caller', None), + ] + + collector.process_frames(frames, thread_id=1, weight=5) + + edge_key = (('caller.py', 10), ('callee.py', 5)) + self.assertEqual(collector.edge_samples[edge_key], 5) + self.assertEqual(collector.line_samples[('callee.py', 5)], 5) + self.assertEqual(collector.line_samples[('caller.py', 10)], 5) + def test_process_frames_handles_empty_frames(self): """Test that process_frames handles empty frame list.""" collector = HeatmapCollector(sample_interval_usec=100) diff --git a/Lib/test/test_profiling/test_sampling_profiler/test_profiler.py b/Lib/test/test_profiling/test_sampling_profiler/test_profiler.py index 68bc59a5414a05..2f5a5e27328659 100644 --- a/Lib/test/test_profiling/test_sampling_profiler/test_profiler.py +++ b/Lib/test/test_profiling/test_sampling_profiler/test_profiler.py @@ -198,8 +198,83 @@ def test_sample_profiler_sample_method_timing(self): self.assertIn("samples", result) # Verify collector was called multiple times - self.assertGreaterEqual(mock_collector.collect.call_count, 5) - self.assertLessEqual(mock_collector.collect.call_count, 11) + total_weight = sum( + len(c.kwargs.get("timestamps_us") or [None]) + for c in mock_collector.collect.call_args_list + ) + self.assertGreaterEqual(total_weight, 5) + self.assertLessEqual(total_weight, 11) + + def test_sample_profiler_does_not_buffer_non_aggregating_collectors(self): + """Test that non-aggregating collectors get each sample immediately.""" + + stack_frames = [mock.sentinel.stack_frames] + mock_collector = mock.MagicMock() + mock_collector.aggregating = False + + with self._patched_unwinder() as u: + u.instance.get_stack_trace.return_value = stack_frames + + manager = mock.Mock() + manager.attach_mock(u.instance.get_stack_trace, "unwind") + manager.attach_mock(mock_collector.collect, "collect") + + profiler = SampleProfiler( + pid=12345, sample_interval_usec=10000, all_threads=False + ) + + times = [0.0, 0.01, 0.011, 0.02, 0.03] + with mock.patch("time.perf_counter", side_effect=times): + with io.StringIO() as output: + with mock.patch("sys.stdout", output): + profiler.sample(mock_collector, duration_sec=0.025) + + self.assertEqual( + manager.mock_calls, + [ + mock.call.unwind(), + mock.call.collect(stack_frames), + mock.call.unwind(), + mock.call.collect(stack_frames), + ], + ) + + def test_sample_profiler_flushes_aggregated_batches_at_limit(self): + """Test that aggregating collectors flush after MAX_PENDING_SAMPLES samples.""" + + stack_frames = [mock.sentinel.stack_frames] + mock_collector = mock.MagicMock() + mock_collector.aggregating = True + + with self._patched_unwinder() as u: + u.instance.get_stack_trace.return_value = stack_frames + + profiler = SampleProfiler( + pid=12345, sample_interval_usec=10000, all_threads=False + ) + + times = [ + 0.0, + 0.01, 0.011, + 0.02, 0.021, + 0.03, 0.031, + 0.04, 0.041, + 0.05, 0.051, + ] + with mock.patch("profiling.sampling.sample.MAX_PENDING_SAMPLES", 2): + with mock.patch("time.perf_counter", side_effect=times): + with io.StringIO() as output: + with mock.patch("sys.stdout", output): + profiler.sample(mock_collector, duration_sec=0.045) + + batches = [ + (c.args[0], len(c.kwargs["timestamps_us"])) + for c in mock_collector.collect.call_args_list + ] + self.assertEqual( + batches, + [(stack_frames, 2), (stack_frames, 2), (stack_frames, 1)], + ) def test_sample_profiler_error_handling(self): """Test that the sample method handles errors gracefully.""" diff --git a/Misc/NEWS.d/next/Library/2026-05-12-13-03-45.gh-issue-149718.SaM1NJ.rst b/Misc/NEWS.d/next/Library/2026-05-12-13-03-45.gh-issue-149718.SaM1NJ.rst new file mode 100644 index 00000000000000..25344e5a90f022 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-05-12-13-03-45.gh-issue-149718.SaM1NJ.rst @@ -0,0 +1,4 @@ +Coalesce consecutive identical stack frames in Tachyon, so aggregating +collectors (pstats, collapsed, flamegraph, gecko) receive one collect. +Improves sample rate 3x, error rate and missed rate drop by 70%. Patch by +Maurycy Pawłowski-Wieroński. From bc20c2b14604f934d598835e6528211785a4b703 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 13 May 2026 05:08:49 +0200 Subject: [PATCH 039/818] [3.15] gh-149574: Document that is_typeddict, is_protocol, is_dataclass, isclass return False for generic aliases (GH-149604) (#149750) gh-149574: Document that is_typeddict, is_protocol, is_dataclass, isclass return False for generic aliases (GH-149604) (cherry picked from commit a4e51c8dac9fdd49ae26ff8c6cd3c808fd8ba15e) Co-authored-by: Jelle Zijlstra --- Doc/library/dataclasses.rst | 3 ++- Doc/library/inspect.rst | 3 +++ Doc/library/stdtypes.rst | 3 ++- Doc/library/typing.rst | 30 +++++++++++++++++++++++++++--- 4 files changed, 34 insertions(+), 5 deletions(-) diff --git a/Doc/library/dataclasses.rst b/Doc/library/dataclasses.rst index 0bce3e5b762b8b..a09c28ad979158 100644 --- a/Doc/library/dataclasses.rst +++ b/Doc/library/dataclasses.rst @@ -498,7 +498,8 @@ Module contents .. function:: is_dataclass(obj) Return ``True`` if its parameter is a dataclass (including subclasses of a - dataclass) or an instance of one, otherwise return ``False``. + dataclass, but not including :ref:`generic aliases `) + or an instance of one, otherwise return ``False``. If you need to know if a class is an instance of a dataclass (and not a dataclass itself), then add a further check for ``not diff --git a/Doc/library/inspect.rst b/Doc/library/inspect.rst index 8713765b8aebfb..48ae9147587c64 100644 --- a/Doc/library/inspect.rst +++ b/Doc/library/inspect.rst @@ -416,6 +416,9 @@ attributes (see :ref:`import-mod-attrs` for module attributes): Return ``True`` if the object is a class, whether built-in or created in Python code. + This function returns ``False`` for :ref:`generic aliases ` of classes, + such as ``list[int]``. + .. function:: ismethod(object) diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index 3d943566be34ff..e3bd1a46891adc 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -5858,7 +5858,8 @@ type and the :class:`bytes` data type: ``GenericAlias`` objects are instances of the class :class:`types.GenericAlias`, which can also be used to create ``GenericAlias`` -objects directly. +objects directly. Specializations of user-defined :ref:`generic classes ` +may not be instances of :class:`types.GenericAlias`, but they provide similar functionality. .. describe:: T[X, Y, ...] diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index dca51b8014da5a..71b395c80166cc 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -3633,14 +3633,27 @@ Introspection helpers Determine if a type is a :class:`Protocol`. - For example:: + For example: + + .. testcode:: class P(Protocol): def a(self) -> str: ... b: int - is_protocol(P) # => True - is_protocol(int) # => False + assert is_protocol(P) + assert not is_protocol(int) + + This function only returns true for ``Protocol`` classes, not for + :ref:`generic aliases ` of them: + + .. testcode:: + + class GenericP[T](Protocol): + def a(self) -> T: ... + b: int + + assert not is_protocol(GenericP[int]) .. versionadded:: 3.13 @@ -3663,6 +3676,17 @@ Introspection helpers # not a typed dict itself assert not is_typeddict(TypedDict) + This function only returns true for ``TypedDict`` classes, not for + :ref:`generic aliases ` of them: + + .. testcode:: + + class GenericFilm[T](TypedDict): + title: str + year: T + + assert not is_typeddict(GenericFilm[int]) + .. versionadded:: 3.10 .. class:: ForwardRef From 15a597e9ba0dd79bf953e181251788782fff6164 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 13 May 2026 05:36:32 +0200 Subject: [PATCH 040/818] [3.15] gh-149642: Fix interaction between exec and lazy_imports=all (GH-149643) (#149749) gh-149642: Fix interaction between exec and lazy_imports=all (GH-149643) (cherry picked from commit 4087ff859958abc897711b501bb66dc308890ba5) Co-authored-by: Jelle Zijlstra --- Lib/test/test_lazy_import/__init__.py | 53 +++++++++++++++++++ ...-05-10-07-42-36.gh-issue-149642.6ZksML.rst | 2 + Python/ceval.c | 16 ++++-- 3 files changed, 68 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-05-10-07-42-36.gh-issue-149642.6ZksML.rst diff --git a/Lib/test/test_lazy_import/__init__.py b/Lib/test/test_lazy_import/__init__.py index ea534a8ee5b981..5d770eeae07a15 100644 --- a/Lib/test/test_lazy_import/__init__.py +++ b/Lib/test/test_lazy_import/__init__.py @@ -301,6 +301,15 @@ def f(): f() self.assertIn("only allowed at module level", str(cm.exception)) + def test_lazy_import_exec_in_class(self): + """lazy import via exec() inside a class should raise SyntaxError.""" + # exec() inside a class body also has non-module-level locals. + with self.assertRaises(SyntaxError) as cm: + class C: + exec("lazy import json") + + self.assertIn("only allowed at module level", str(cm.exception)) + @support.requires_subprocess() def test_lazy_import_exec_at_module_level(self): """lazy import via exec() at module level should work.""" @@ -352,6 +361,50 @@ def test_eager_import_func(self): f = test.test_lazy_import.data.eager_import_func.f self.assertEqual(type(f()), type(sys)) + def test_exec_import_func(self): + """Implicit lazy imports via exec() inside functions should be eager.""" + sys.set_lazy_imports("all") + + def f(): + exec("import test.test_lazy_import.data.basic2") + + f() + self.assertIn("test.test_lazy_import.data.basic2", sys.modules) + + def test_exec_import_func_with_lazy_modules(self): + """__lazy_modules__ should not make exec() imports lazy inside functions.""" + globals()["__lazy_modules__"] = ["test.test_lazy_import.data.basic2"] + try: + def f(): + exec("import test.test_lazy_import.data.basic2") + + f() + self.assertIn("test.test_lazy_import.data.basic2", sys.modules) + finally: + del globals()["__lazy_modules__"] + + def test_exec_import_class(self): + """Implicit lazy imports via exec() inside classes should be eager.""" + sys.set_lazy_imports("all") + + class C: + exec("import test.test_lazy_import.data.basic2") + + self.assertIsNotNone(C) + self.assertIn("test.test_lazy_import.data.basic2", sys.modules) + + def test_exec_import_class_with_lazy_modules(self): + """__lazy_modules__ should not make exec() imports lazy inside classes.""" + globals()["__lazy_modules__"] = ["test.test_lazy_import.data.basic2"] + try: + class C: + exec("import test.test_lazy_import.data.basic2") + + self.assertIsNotNone(C) + self.assertIn("test.test_lazy_import.data.basic2", sys.modules) + finally: + del globals()["__lazy_modules__"] + class WithStatementTests(unittest.TestCase): """Tests for lazy imports in with statement context.""" diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-10-07-42-36.gh-issue-149642.6ZksML.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-10-07-42-36.gh-issue-149642.6ZksML.rst new file mode 100644 index 00000000000000..815a084db69d8d --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-10-07-42-36.gh-issue-149642.6ZksML.rst @@ -0,0 +1,2 @@ +Allow imports inside ``exec()`` calls within functions under +``PYTHON_LAZY_IMPORTS=all``. diff --git a/Python/ceval.c b/Python/ceval.c index 060e948e6b01c9..a080ae42b93766 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -3059,25 +3059,35 @@ check_lazy_import_compatibility(PyThreadState *tstate, PyObject *globals, return res; } +static int +is_lazy_import_module_level(void) +{ + _PyInterpreterFrame *frame = _PyEval_GetFrame(); + return frame != NULL && frame->f_globals == frame->f_locals; +} + PyObject * _PyEval_LazyImportName(PyThreadState *tstate, PyObject *builtins, PyObject *globals, PyObject *locals, PyObject *name, PyObject *fromlist, PyObject *level, int lazy) { PyObject *res = NULL; + PyImport_LazyImportsMode mode = PyImport_GetLazyImportsMode(); // Check if global policy overrides the local syntax - switch (PyImport_GetLazyImportsMode()) { + switch (mode) { case PyImport_LAZY_NONE: lazy = 0; break; case PyImport_LAZY_ALL: - lazy = 1; + if (!lazy) { + lazy = is_lazy_import_module_level(); + } break; case PyImport_LAZY_NORMAL: break; } - if (!lazy && PyImport_GetLazyImportsMode() != PyImport_LAZY_NONE) { + if (!lazy && mode != PyImport_LAZY_NONE && is_lazy_import_module_level()) { // See if __lazy_modules__ forces this to be lazy. lazy = check_lazy_import_compatibility(tstate, globals, name, level); if (lazy < 0) { From 4e369c1deaea5843d08f83c0dadcb4f2cc4de3a9 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 13 May 2026 11:28:27 +0200 Subject: [PATCH 041/818] [3.15] gh-149701: Fully silence potential `hash -r` error (GH-149702) (GH-149757) (cherry picked from commit cd6096887e22cdb6d6365ad0eb5b0ffac50d4791) --- Lib/test/test_venv.py | 20 +++++++++++++++++++ Lib/venv/scripts/common/activate | 4 ++-- ...-05-12-06-24-54.gh-issue-149701.8v9RTm.rst | 1 + 3 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-05-12-06-24-54.gh-issue-149701.8v9RTm.rst diff --git a/Lib/test/test_venv.py b/Lib/test/test_venv.py index 78461abcd69f33..a42787f261bfe8 100644 --- a/Lib/test/test_venv.py +++ b/Lib/test/test_venv.py @@ -656,6 +656,26 @@ def test_deactivate_with_strict_bash_opts(self): self.assertEqual(out, "".encode()) self.assertEqual(err, "".encode()) + # gh-149701: Test exit code is zero even when hashing is disabled + @unittest.skipIf(os.name == 'nt', 'not relevant on Windows') + def test_deactivate_with_strict_bash_opts_and_hashing_disabled(self): + bash = shutil.which("bash") + if bash is None: + self.skipTest("bash required for this test") + rmtree(self.env_dir) + builder = venv.EnvBuilder(clear=True) + builder.create(self.env_dir) + activate = os.path.join(self.env_dir, self.bindir, "activate") + test_script = os.path.join(self.env_dir, "test_hash_disabled.sh") + with open(test_script, "w") as f: + f.write("set -euo pipefail\n" + "set +h\n" # disable hashing + f"source {activate}\n" + "deactivate") + out, err = check_output([bash, test_script]) + self.assertEqual(out, "".encode()) + self.assertEqual(err, "".encode()) + @unittest.skipUnless(sys.platform == 'darwin', 'only relevant on macOS') def test_macos_env(self): diff --git a/Lib/venv/scripts/common/activate b/Lib/venv/scripts/common/activate index 70673a265d41f8..241a8650bda33a 100644 --- a/Lib/venv/scripts/common/activate +++ b/Lib/venv/scripts/common/activate @@ -17,7 +17,7 @@ deactivate () { # Call hash to forget past locations. Without forgetting # past locations the $PATH changes we made may not be respected. # See "man bash" for more details. hash is usually a builtin of your shell - hash -r 2> /dev/null + hash -r 2> /dev/null || true if [ -n "${_OLD_VIRTUAL_PS1:-}" ] ; then PS1="${_OLD_VIRTUAL_PS1:-}" @@ -73,4 +73,4 @@ fi # Call hash to forget past commands. Without forgetting # past commands the $PATH changes we made may not be respected -hash -r 2> /dev/null +hash -r 2> /dev/null || true diff --git a/Misc/NEWS.d/next/Library/2026-05-12-06-24-54.gh-issue-149701.8v9RTm.rst b/Misc/NEWS.d/next/Library/2026-05-12-06-24-54.gh-issue-149701.8v9RTm.rst new file mode 100644 index 00000000000000..676d788cbce62a --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-05-12-06-24-54.gh-issue-149701.8v9RTm.rst @@ -0,0 +1 @@ +Fix bad return code from Lib/venv/bin/activate if hashing is disabled From a5f77a13fdce49bcc6699ab4e7ec8b88e1d261af Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 13 May 2026 12:39:38 +0200 Subject: [PATCH 042/818] [3.15] gh-148829: Add PySentinel_CheckExact() (GH-149725) (#149766) gh-148829: Add PySentinel_CheckExact() (GH-149725) (cherry picked from commit 94df62542cdf1c9eb082abab1534cbd1fd425062) Co-authored-by: scoder --- Doc/c-api/sentinel.rst | 16 ++++++++++++++-- Include/cpython/sentinelobject.h | 5 ++++- Lib/test/test_capi/test_object.py | 2 ++ ...026-05-12-16-47-21.gh-issue-149725.HZLBTZ.rst | 2 ++ Modules/_testcapi/object.c | 7 +++++++ 5 files changed, 29 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/C_API/2026-05-12-16-47-21.gh-issue-149725.HZLBTZ.rst diff --git a/Doc/c-api/sentinel.rst b/Doc/c-api/sentinel.rst index 89e0a28bf3b835..937cae18e86f50 100644 --- a/Doc/c-api/sentinel.rst +++ b/Doc/c-api/sentinel.rst @@ -14,8 +14,20 @@ Sentinel objects .. c:function:: int PySentinel_Check(PyObject *o) - Return true if *o* is a :class:`sentinel` object. The :class:`sentinel` type - does not allow subclasses, so this check is exact. + Return true if *o* is a :class:`sentinel` object or a subtype. + The :class:`sentinel` type does not currently allow subclasses, + so this check is exact. + Future Python versions may choose to allow subtyping. + This function always succeeds. + + .. versionadded:: 3.15 + +.. c:function:: int PySentinel_CheckExact(PyObject *o) + + Return true if *o* is a :class:`sentinel` object, but not a subtype. + The :class:`sentinel` type does not currently allow subclasses. + Future Python versions may choose to allow subtyping. + This function always succeeds. .. versionadded:: 3.15 diff --git a/Include/cpython/sentinelobject.h b/Include/cpython/sentinelobject.h index 0b6ff0f17e6f8c..8d5b1886ce5436 100644 --- a/Include/cpython/sentinelobject.h +++ b/Include/cpython/sentinelobject.h @@ -9,7 +9,10 @@ extern "C" { PyAPI_DATA(PyTypeObject) PySentinel_Type; -#define PySentinel_Check(op) Py_IS_TYPE((op), &PySentinel_Type) +#define PySentinel_CheckExact(op) Py_IS_TYPE((op), &PySentinel_Type) + +/* Alias as long as subclasses are not allowed. */ +#define PySentinel_Check(op) PySentinel_CheckExact(op) PyAPI_FUNC(PyObject *) PySentinel_New( const char *name, diff --git a/Lib/test/test_capi/test_object.py b/Lib/test/test_capi/test_object.py index 635deaa73f7efa..e6fd068dc20d8d 100644 --- a/Lib/test/test_capi/test_object.py +++ b/Lib/test/test_capi/test_object.py @@ -71,6 +71,8 @@ def test_pysentinel_new(self): self.assertIs(type(marker), sentinel) self.assertTrue(_testcapi.pysentinel_check(marker)) self.assertFalse(_testcapi.pysentinel_check(object())) + self.assertTrue(_testcapi.pysentinel_checkexact(marker)) + self.assertFalse(_testcapi.pysentinel_checkexact(object())) self.assertEqual(marker.__name__, "CAPI_SENTINEL") self.assertEqual(marker.__module__, __name__) self.assertEqual(repr(marker), "CAPI_SENTINEL") diff --git a/Misc/NEWS.d/next/C_API/2026-05-12-16-47-21.gh-issue-149725.HZLBTZ.rst b/Misc/NEWS.d/next/C_API/2026-05-12-16-47-21.gh-issue-149725.HZLBTZ.rst new file mode 100644 index 00000000000000..97721430edbd69 --- /dev/null +++ b/Misc/NEWS.d/next/C_API/2026-05-12-16-47-21.gh-issue-149725.HZLBTZ.rst @@ -0,0 +1,2 @@ +Add :c:func:`PySentinel_CheckExact` for exact :class:`sentinel` type tests +to accompany the existing :c:func:`PySentinel_Check`. diff --git a/Modules/_testcapi/object.c b/Modules/_testcapi/object.c index 6e5c8dcbb725fa..c62dc1144df688 100644 --- a/Modules/_testcapi/object.c +++ b/Modules/_testcapi/object.c @@ -572,6 +572,12 @@ pysentinel_check(PyObject *self, PyObject *obj) return PyBool_FromLong(PySentinel_Check(obj)); } +static PyObject * +pysentinel_checkexact(PyObject *self, PyObject *obj) +{ + return PyBool_FromLong(PySentinel_CheckExact(obj)); +} + static PyMethodDef test_methods[] = { {"call_pyobject_print", call_pyobject_print, METH_VARARGS}, @@ -604,6 +610,7 @@ static PyMethodDef test_methods[] = { {"pyobject_dump", pyobject_dump, METH_VARARGS}, {"pysentinel_new", pysentinel_new, METH_VARARGS}, {"pysentinel_check", pysentinel_check, METH_O}, + {"pysentinel_checkexact", pysentinel_checkexact, METH_O}, {NULL}, }; From 37f3deb571c02eccd8edc1457fcfc0eeeac909ce Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 13 May 2026 12:54:10 +0200 Subject: [PATCH 043/818] [3.15] bpo-45509: Check gzip headers for corrupted fields (GH-29028) (GH-149769) Check the header checksum it the HCRC field is present. (cherry picked from commit dd94457893a1dd2c99c2405e197f54a7692cbe09) Co-authored-by: Ruben Vorderman --- Lib/gzip.py | 51 ++++++++++++++----- Lib/test/test_gzip.py | 29 +++++++++++ .../2021-10-18-13-46-55.bpo-45509.Upwb60.rst | 1 + 3 files changed, 67 insertions(+), 14 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2021-10-18-13-46-55.bpo-45509.Upwb60.rst diff --git a/Lib/gzip.py b/Lib/gzip.py index 971063aa24f871..a89ebf806c8572 100644 --- a/Lib/gzip.py +++ b/Lib/gzip.py @@ -484,40 +484,63 @@ def _read_exact(fp, n): return data +def _read_until_null(fp, append_to): + '''Read until the first encountered null byte in fp. + Append to given byte array object''' + while True: + s = fp.read(1) + append_to += s + if not s or s == b'\000': + break + + def _read_gzip_header(fp): '''Read a gzip header from `fp` and progress to the end of the header. Returns last mtime if header was present or None otherwise. ''' magic = fp.read(2) - if magic == b'': + if not magic: return None if magic != b'\037\213': raise BadGzipFile('Not a gzipped file (%r)' % magic) - - (method, flag, last_mtime) = struct.unpack(" Date: Wed, 13 May 2026 13:10:30 +0200 Subject: [PATCH 044/818] [3.15] gh-148821: Add more strict tests for XML encodings (GH-149765) (GH-149770) Exclude encodings like 'utf-8-sig', 'iso2022-jp' and 'hz' from the list of supported encodings. (cherry picked from commit fa2afa64d9467fb7362672ed603d29d8e246d240) Co-authored-by: Serhiy Storchaka --- Lib/test/test_pyexpat.py | 76 +++++++++++++++++++++++++++++++++++++- Lib/test/test_xml_etree.py | 27 ++++++++------ 2 files changed, 89 insertions(+), 14 deletions(-) diff --git a/Lib/test/test_pyexpat.py b/Lib/test/test_pyexpat.py index 9a1620029c6da9..4fe2e02326f04f 100644 --- a/Lib/test/test_pyexpat.py +++ b/Lib/test/test_pyexpat.py @@ -227,8 +227,7 @@ def _verify_parse_output(self, operations): "Character data: '\xb5'", "End element: 'root'", ] - for operation, expected_operation in zip(operations, expected_operations): - self.assertEqual(operation, expected_operation) + self.assertEqual(operations, expected_operations) def test_parse_bytes(self): out = self.Outputter() @@ -276,6 +275,79 @@ def test_parse_again(self): self.assertEqual(expat.ErrorString(cm.exception.code), expat.errors.XML_ERROR_FINISHED) + @support.subTests('encoding', [ + 'utf-8', 'utf-16', 'utf-16be', 'utf-16le', + 'iso8859-1', 'iso8859-2', 'iso8859-3', 'iso8859-4', 'iso8859-5', + 'iso8859-6', 'iso8859-7', 'iso8859-8', 'iso8859-9', 'iso8859-10', + 'iso8859-13', 'iso8859-14', 'iso8859-15', 'iso8859-16', + 'cp437', 'cp720', 'cp737', 'cp775', 'cp850', 'cp852', + 'cp855', 'cp856', 'cp857', 'cp858', 'cp860', 'cp861', 'cp862', + 'cp863', 'cp865', 'cp866', 'cp869', 'cp874', 'cp1006', 'cp1125', + 'cp1250', 'cp1251', 'cp1252', 'cp1253', 'cp1254', 'cp1255', + 'cp1256', 'cp1257', 'cp1258', + 'mac-cyrillic', 'mac-greek', 'mac-iceland', 'mac-latin2', + 'mac-roman', 'mac-turkish', + 'koi8-r', 'koi8-t', 'koi8-u', 'kz1048', 'ptcp154', + ]) + def test_supported_ecodings(self, encoding): + out = self.Outputter() + parser = expat.ParserCreate() + self._hookup_callbacks(parser, out) + c = 'éπя\u05d0\u060c€'.encode(encoding, 'ignore').decode(encoding)[0] + data = (f'\n' + f'{c}').encode(encoding) + parser.Parse(data, True) + self.assertEqual(out.out, [ + ('XML declaration', ('1.0', encoding, -1)), + "Start element: 'root' {}", + f'Character data: {c!r}', + "End element: 'root'", + ]) + + @support.subTests('encoding', [ + 'UTF-8', 'utf-8', 'utf-16', 'utf-16le', 'utf-16be', + 'koi8-u', 'cp1125', 'cp1251', 'iso8859-5', 'mac-cyrillic', + ]) + def test_supported_ecodings2(self, encoding): + out = self.Outputter() + parser = expat.ParserCreate() + self._hookup_callbacks(parser, out) + data = (f'\n' + '' + '<корінь атрибут="значення">зміст').encode(encoding) + parser.Parse(data, True) + self.assertEqual(out.out, [ + ('XML declaration', ('1.0', encoding, -1)), + "Comment: ' коментар '", + "Start element: 'корінь' {'атрибут': 'значення'}", + "Character data: 'зміст'", + "End element: 'корінь'", + ]) + + @support.subTests('encoding', [ + 'UTF-7', + "Big5-HKSCS", "Big5", + "cp932", "cp949", "cp950", + "EUC_JIS-2004", "EUC_JISX0213", "EUC-JP", "EUC-KR", + "GB18030", "GB2312", "GBK", + "ISO-2022-KR", + "johab", + "Shift_JIS", "Shift_JIS-2004", "Shift_JISX0213", + ]) + def test_unsupportes_ecodings(self, encoding): + parser = expat.ParserCreate() + data = (f'\n' + '').encode(encoding) + with self.assertRaises(ValueError): + parser.Parse(data, True) + + def test_unknown_ecoding(self): + parser = expat.ParserCreate() + data = b'\n' + with self.assertRaises(LookupError): + parser.Parse(data, True) + + class NamespaceSeparatorTest(unittest.TestCase): def test_legal(self): # Tests that make sure we get errors when the namespace_separator value diff --git a/Lib/test/test_xml_etree.py b/Lib/test/test_xml_etree.py index 8f3efe9fc90794..3a41ea97a2e0a2 100644 --- a/Lib/test/test_xml_etree.py +++ b/Lib/test/test_xml_etree.py @@ -1009,12 +1009,12 @@ def check(encoding, body=''): check("cp437", '\u221a') check("mac-roman", '\u02da') - def xml(encoding): - return "" % encoding - def bxml(encoding): - return xml(encoding).encode(encoding) + def xml(encoding, body=''): + return "%s" % (encoding, body) + def bxml(encoding, body=''): + return xml(encoding, body).encode(encoding) supported_encodings = [ - 'ascii', 'utf-8', 'utf-8-sig', 'utf-16', 'utf-16be', 'utf-16le', + 'utf-8', 'utf-16', 'utf-16be', 'utf-16le', 'iso8859-1', 'iso8859-2', 'iso8859-3', 'iso8859-4', 'iso8859-5', 'iso8859-6', 'iso8859-7', 'iso8859-8', 'iso8859-9', 'iso8859-10', 'iso8859-13', 'iso8859-14', 'iso8859-15', 'iso8859-16', @@ -1025,13 +1025,14 @@ def bxml(encoding): 'cp1256', 'cp1257', 'cp1258', 'mac-cyrillic', 'mac-greek', 'mac-iceland', 'mac-latin2', 'mac-roman', 'mac-turkish', - 'iso2022-jp', 'iso2022-jp-1', 'iso2022-jp-2', 'iso2022-jp-2004', - 'iso2022-jp-3', 'iso2022-jp-ext', - 'koi8-r', 'koi8-t', 'koi8-u', 'kz1048', - 'hz', 'ptcp154', + 'koi8-r', 'koi8-t', 'koi8-u', 'kz1048', 'ptcp154', ] for encoding in supported_encodings: - self.assertEqual(ET.tostring(ET.XML(bxml(encoding))), b'') + with self.subTest(encoding=encoding): + self.assertEqual(ET.tostring(ET.XML(bxml(encoding))), b'') + c = 'éπя\u05d0\u060c€'.encode(encoding, 'ignore').decode(encoding)[0] + self.assertEqual(ET.tostring(ET.XML(bxml(encoding, c))), + ('&#%d;' % ord(c)).encode()) unsupported_ascii_compatible_encodings = [ 'big5', 'big5hkscs', @@ -1043,14 +1044,16 @@ def bxml(encoding): 'utf-7', ] for encoding in unsupported_ascii_compatible_encodings: - self.assertRaises(ValueError, ET.XML, bxml(encoding)) + with self.subTest(encoding=encoding): + self.assertRaises(ValueError, ET.XML, bxml(encoding)) unsupported_ascii_incompatible_encodings = [ 'cp037', 'cp424', 'cp500', 'cp864', 'cp875', 'cp1026', 'cp1140', 'utf_32', 'utf_32_be', 'utf_32_le', ] for encoding in unsupported_ascii_incompatible_encodings: - self.assertRaises(ET.ParseError, ET.XML, bxml(encoding)) + with self.subTest(encoding=encoding): + self.assertRaises(ET.ParseError, ET.XML, bxml(encoding)) self.assertRaises(ValueError, ET.XML, xml('undefined').encode('ascii')) self.assertRaises(LookupError, ET.XML, xml('xxx').encode('ascii')) From b37e91f6cfc6bd3f51a0f020cdf9368b24489087 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 13 May 2026 13:33:31 +0200 Subject: [PATCH 045/818] [3.15] Run mypy with four worker processes and uv (GH-149726) (#149773) Run mypy with four worker processes and uv (GH-149726) (cherry picked from commit 6304eb1f5b93f682bff558befe4a7b9585f4601e) Co-authored-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> --- .github/workflows/mypy.yml | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/.github/workflows/mypy.yml b/.github/workflows/mypy.yml index 490c32ecfc9a62..d748b6ff63e68a 100644 --- a/.github/workflows/mypy.yml +++ b/.github/workflows/mypy.yml @@ -69,12 +69,11 @@ jobs: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 + - uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0 with: python-version: "3.15" - allow-prereleases: true - cache: pip - cache-dependency-path: Tools/requirements-dev.txt - - run: pip install -r Tools/requirements-dev.txt + activate-environment: true + cache-dependency-glob: Tools/requirements-dev.txt + - run: uv pip install -r Tools/requirements-dev.txt - run: python3 Misc/mypy/make_symlinks.py --symlink - - run: mypy --config-file ${{ matrix.target }}/mypy.ini + - run: mypy --num-workers 4 --config-file ${{ matrix.target }}/mypy.ini From bb7a539da2fdd81724ecf8d899aa369a247709b9 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 13 May 2026 17:36:27 +0200 Subject: [PATCH 046/818] [3.15] gh-149776: Skip UDP Lite tests if it's not supported (GH-149777) (#149780) gh-149776: Skip UDP Lite tests if it's not supported (GH-149777) Fix test_socket on Linux kernel 7.1 and newer: skip UDP Lite tests if it's not supported. (cherry picked from commit 3cfc249e11a132dc69624150843779aa96c72b2b) Co-authored-by: Victor Stinner --- Lib/test/test_socket.py | 24 +++++++++++++++---- ...-05-13-14-53-23.gh-issue-149776.orqgsn.rst | 2 ++ 2 files changed, 22 insertions(+), 4 deletions(-) create mode 100644 Misc/NEWS.d/next/Tests/2026-05-13-14-53-23.gh-issue-149776.orqgsn.rst diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py index 9e03069494345b..47830d0e9645ef 100644 --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -205,6 +205,25 @@ def _have_socket_hyperv(): return True +def _have_udp_lite(): + if not hasattr(socket, "IPPROTO_UDPLITE"): + return False + # Older Android versions block UDPLITE with SELinux. + if support.is_android and platform.android_ver().api_level < 29: + return False + + try: + sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDPLITE) + except OSError as exc: + # Linux 7.1 removed UDP Lite support + if exc.errno == errno.EPROTONOSUPPORT: + return False + raise + sock.close() + + return True + + @contextlib.contextmanager def socket_setdefaulttimeout(timeout): old_timeout = socket.getdefaulttimeout() @@ -247,10 +266,7 @@ def downgrade_malformed_data_warning(): HAVE_SOCKET_VSOCK = _have_socket_vsock() -# Older Android versions block UDPLITE with SELinux. -HAVE_SOCKET_UDPLITE = ( - hasattr(socket, "IPPROTO_UDPLITE") - and not (support.is_android and platform.android_ver().api_level < 29)) +HAVE_SOCKET_UDPLITE = _have_udp_lite() HAVE_SOCKET_BLUETOOTH = _have_socket_bluetooth() diff --git a/Misc/NEWS.d/next/Tests/2026-05-13-14-53-23.gh-issue-149776.orqgsn.rst b/Misc/NEWS.d/next/Tests/2026-05-13-14-53-23.gh-issue-149776.orqgsn.rst new file mode 100644 index 00000000000000..e86a9130ff9bfb --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2026-05-13-14-53-23.gh-issue-149776.orqgsn.rst @@ -0,0 +1,2 @@ +Fix test_socket on Linux kernel 7.1 and newer: skip UDP Lite tests if it's +not supported. Patch by Victor Stinner. From 166c56b31162924ddbb594b67169004882dd1c07 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 13 May 2026 20:09:33 +0200 Subject: [PATCH 047/818] [3.15] gh-148906: fix performance scaling of descriptors on free-threading (GH-148915) (#149798) gh-148906: fix performance scaling of descriptors on free-threading (GH-148915) (cherry picked from commit 94bca40ff09c20f6168d6a27e3aa42bf8a8077b8) Co-authored-by: Kumar Aditya --- Objects/typeobject.c | 36 ++++++++++++++++++-------- Tools/ftscalingbench/ftscalingbench.py | 17 ++++++++++++ 2 files changed, 42 insertions(+), 11 deletions(-) diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 9a18ca72516da7..7cca137f74be58 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -4841,6 +4841,18 @@ type_new_set_attrs(const type_new_ctx *ctx, PyTypeObject *type) if (type_new_set_classdictcell(dict) < 0) { return -1; } + +#ifdef Py_GIL_DISABLED + // enable deferred reference counting on functions and descriptors + Py_ssize_t pos = 0; + PyObject *key, *value; + while (PyDict_Next(dict, &pos, &key, &value)) { + if (PyFunction_Check(value) || Py_TYPE(value)->tp_descr_get != NULL) { + PyUnstable_Object_EnableDeferredRefcount(value); + } + } +#endif + return 0; } @@ -6746,12 +6758,11 @@ type_setattro(PyObject *self, PyObject *name, PyObject *value) assert(!_PyType_HasFeature(metatype, Py_TPFLAGS_MANAGED_DICT)); #ifdef Py_GIL_DISABLED - // gh-139103: Enable deferred refcounting for functions assigned - // to type objects. This is important for `dataclass.__init__`, - // which is generated dynamically. - if (value != NULL && - PyFunction_Check(value) && - !_PyObject_HasDeferredRefcount(value)) + // gh-139103: Enable deferred refcounting for functions and descriptors + // assigned to type objects. This is important for `dataclass.__init__`, + // which is generated dynamically, and for descriptor scaling on + // free-threaded builds. + if (value != NULL && (PyFunction_Check(value) || Py_TYPE(value)->tp_descr_get != NULL)) { PyUnstable_Object_EnableDeferredRefcount(value); } @@ -11089,10 +11100,12 @@ static PyObject * slot_tp_descr_get(PyObject *self, PyObject *obj, PyObject *type) { PyTypeObject *tp = Py_TYPE(self); - PyObject *get; - - get = _PyType_LookupRef(tp, &_Py_ID(__get__)); - if (get == NULL) { + PyThreadState *tstate = _PyThreadState_GET(); + _PyCStackRef cref; + _PyThreadState_PushCStackRef(tstate, &cref); + _PyType_LookupStackRefAndVersion(tp, &_Py_ID(__get__), &cref.ref); + if (PyStackRef_IsNull(cref.ref)) { + _PyThreadState_PopCStackRef(tstate, &cref); #ifndef Py_GIL_DISABLED /* Avoid further slowdowns */ if (tp->tp_descr_get == slot_tp_descr_get) @@ -11104,9 +11117,10 @@ slot_tp_descr_get(PyObject *self, PyObject *obj, PyObject *type) obj = Py_None; if (type == NULL) type = Py_None; + PyObject *get = PyStackRef_AsPyObjectBorrow(cref.ref); PyObject *stack[3] = {self, obj, type}; PyObject *res = PyObject_Vectorcall(get, stack, 3, NULL); - Py_DECREF(get); + _PyThreadState_PopCStackRef(tstate, &cref); return res; } diff --git a/Tools/ftscalingbench/ftscalingbench.py b/Tools/ftscalingbench/ftscalingbench.py index 60f43b99c0f69d..c8a914c22a9e13 100644 --- a/Tools/ftscalingbench/ftscalingbench.py +++ b/Tools/ftscalingbench/ftscalingbench.py @@ -279,6 +279,23 @@ def staticmethod_call(): for _ in range(1000 * WORK_SCALE): obj.my_staticmethod() + +class MyDescriptor: + def __get__(self, obj, objtype=None): + return 42 + + def __set__(self, obj, value): + pass + +class MyClassWithDescriptor: + attr = MyDescriptor() + +@register_benchmark +def descriptor(): + obj = MyClassWithDescriptor() + for _ in range(1000 * WORK_SCALE): + obj.attr + @register_benchmark def deepcopy(): x = {'list': [1, 2], 'tuple': (1, None)} From fb3500466d1fa0f79f7db3b06ce966e79707e952 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 13 May 2026 22:26:42 +0200 Subject: [PATCH 048/818] [3.15] gh-128110: Fix rfc2047 whitespace handling in email parser address headers (GH-130749) (#149787) RFC 2047 Section 6.2 requires that "any 'linear-white-space' that separates a pair of adjacent 'encoded-word's is ignored." The modern header value parser correctly implements that for unstructured headers, but had missed a case in structured headers. This could cause a parsed address header to include extraneous spaces in a display-name. Switch to @bitdancer's fix from review feedback. Recharacterize space between ews as fws after parsing in get_phrase. RDM: This fix is dependent on the fact that "subsequent" atoms will never have leading whitespace because that's been consumed already. I don't think it's worth adding extra code for the possibility of leading whitespace because the parser won't produce it. It's a bit of parser fragility in the face of code changes, but I think that's a minor concern given the parser design (which is that it consumes whitespace greedily) (cherry picked from commit 7a4c6dfb8839eb05fb87baf70364680e45001dd4) Co-authored-by: Mike Edmunds Co-authored-by: R David Murray --- Lib/email/_header_value_parser.py | 10 +++ .../test_email/test__header_value_parser.py | 88 +++++++++++++++++++ ...-03-01-13-36-02.gh-issue-128110.9wx_G0.rst | 5 ++ 3 files changed, 103 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2025-03-01-13-36-02.gh-issue-128110.9wx_G0.rst diff --git a/Lib/email/_header_value_parser.py b/Lib/email/_header_value_parser.py index 9873958f5c2790..792072ab9f6128 100644 --- a/Lib/email/_header_value_parser.py +++ b/Lib/email/_header_value_parser.py @@ -1461,6 +1461,16 @@ def get_phrase(value): else: try: token, value = get_word(value) + if (token[0].token_type == 'encoded-word' + and phrase + and phrase[-1].token_type == 'atom' + and len(phrase[-1]) > 1 + and phrase[-1][-2].token_type == 'encoded-word' + and phrase[-1][-1].token_type == 'cfws' + and not phrase[-1][-1].comments + ): + # linear ws between ews needs special handing... + phrase[-1][-1] = EWWhiteSpaceTerminal(phrase[-1], 'fws') except errors.HeaderParseError: if value[0] in CFWS_LEADER: token, value = get_cfws(value) diff --git a/Lib/test/test_email/test__header_value_parser.py b/Lib/test/test_email/test__header_value_parser.py index aded44e85ee336..9d9fe418ee4d06 100644 --- a/Lib/test/test_email/test__header_value_parser.py +++ b/Lib/test/test_email/test__header_value_parser.py @@ -1060,6 +1060,78 @@ def get_phrase_cfws_only_raises(self): with self.assertRaises(errors.HeaderParseError): parser.get_phrase(' (foo) ') + def test_get_phrase_adjacent_ew(self): + # "'linear-white-space' that separates a pair of adjacent + # 'encoded-word's is ignored" (rfc2047 section 6.2) + self._test_get_x(parser.get_phrase, '=?ascii?q?Joi?= \t =?ascii?q?ned?=', 'Joined', 'Joined', [], '') + + def test_get_phrase_adjacent_ew_different_encodings(self): + self._test_get_x( + parser.get_phrase, + '=?utf-8?q?B=C3=A9r?= =?iso-8859-1?q?=E9nice?=', 'Bérénice', 'Bérénice', [], '' + ) + + def test_get_phrase_adjacent_ew_encoded_spaces(self): + self._test_get_x( + parser.get_phrase, + '=?ascii?q?Encoded?= =?ascii?q?_spaces_?= =?ascii?q?preserved?=', + 'Encoded spaces preserved', + 'Encoded spaces preserved', + [], + '' + ) + + def test_get_phrase_adjacent_ew_comment_is_not_linear_white_space(self): + self._test_get_x( + parser.get_phrase, + '=?ascii?q?Comment?= (is not) =?ascii?q?linear-white-space?=', + 'Comment (is not) linear-white-space', + 'Comment linear-white-space', + [], + '', + comments=['is not'], + ) + + def test_get_phrase_adjacent_ew_no_error_on_defects(self): + self._test_get_x( + parser.get_phrase, + '=?ascii?q?Def?= =?ascii?q?ect still joins?=', + 'Defect still joins', + 'Defect still joins', + [errors.InvalidHeaderDefect], # whitespace inside encoded word + '' + ) + + def test_get_phrase_adjacent_ew_ignore_non_ew(self): + self._test_get_x( + parser.get_phrase, + '=?ascii?q?No?= =?join?= for non-ew', + 'No =?join?= for non-ew', + 'No =?join?= for non-ew', + [], + '' + ) + + def test_get_phrase_adjacent_ew_ignore_invalid_ew(self): + self._test_get_x( + parser.get_phrase, + '=?ascii?q?No?= =?ascii?rot13?wbva= for invalid ew', + 'No =?ascii?rot13?wbva= for invalid ew', + 'No =?ascii?rot13?wbva= for invalid ew', + [], + '' + ) + + def test_get_phrase_adjacent_ew_missing_space(self): + self._test_get_x( + parser.get_phrase, + '=?ascii?q?Joi?==?ascii?q?ned?=', + 'Joined', + 'Joined', + [errors.InvalidHeaderDefect], # missing trailing whitespace + '' + ) + # get_local_part def test_get_local_part_simple(self): @@ -2387,6 +2459,22 @@ def test_get_address_rfc2047_display_name(self): self.assertEqual(address[0].token_type, 'mailbox') + def test_get_address_rfc2047_display_name_adjacent_ews(self): + address = self._test_get_x(parser.get_address, + '=?utf-8?q?B=C3=A9r?= =?utf-8?q?=C3=A9nice?= ', + 'Bérénice ', + 'Bérénice ', + [], + '') + self.assertEqual(address.token_type, 'address') + self.assertEqual(len(address.mailboxes), 1) + self.assertEqual(address.mailboxes, + address.all_mailboxes) + self.assertEqual(address.mailboxes[0].display_name, + 'Bérénice') + self.assertEqual(address[0].token_type, + 'mailbox') + def test_get_address_empty_group(self): address = self._test_get_x(parser.get_address, 'Monty Python:;', diff --git a/Misc/NEWS.d/next/Library/2025-03-01-13-36-02.gh-issue-128110.9wx_G0.rst b/Misc/NEWS.d/next/Library/2025-03-01-13-36-02.gh-issue-128110.9wx_G0.rst new file mode 100644 index 00000000000000..b08b1886cff9cf --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-03-01-13-36-02.gh-issue-128110.9wx_G0.rst @@ -0,0 +1,5 @@ +Fix bug in the parsing of :mod:`email` address headers that could result in +extraneous spaces in the decoded text when using a modern email policy. +Space between pairs of adjacent :rfc:`2047` encoded-words is now ignored, per +section 6.2 (and consistent with existing parsing of unstructured +headers like *Subject*). From 63a4007d25160cf200c8710a641412f4de328482 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 13 May 2026 23:29:08 +0200 Subject: [PATCH 049/818] [3.15] gh-149685: Use the _Py prefix for private C macros (GH-149686) (GH-149790) (cherry picked from commit 125f26358ac7ecab98095fa85490e5465bdad698) Co-authored-by: Petr Viktorin --- Include/cpython/sentinelobject.h | 6 +++--- Include/cpython/sliceobject.h | 2 +- Include/cpython/structseq.h | 2 +- Include/internal/pycore_jit_unwind.h | 2 +- Include/internal/pycore_mmap.h | 4 ++-- Include/sliceobject.h | 4 ++-- Include/structseq.h | 4 ++-- Python/pystrhex.c | 6 +++--- configure | 6 +++--- configure.ac | 6 +++--- pyconfig.h.in | 22 +++++++++++----------- 11 files changed, 32 insertions(+), 32 deletions(-) diff --git a/Include/cpython/sentinelobject.h b/Include/cpython/sentinelobject.h index 8d5b1886ce5436..15643ef966af86 100644 --- a/Include/cpython/sentinelobject.h +++ b/Include/cpython/sentinelobject.h @@ -1,8 +1,8 @@ /* Sentinel object interface */ #ifndef Py_LIMITED_API -#ifndef Py_SENTINELOBJECT_H -#define Py_SENTINELOBJECT_H +#ifndef _Py_SENTINELOBJECT_H +#define _Py_SENTINELOBJECT_H #ifdef __cplusplus extern "C" { #endif @@ -21,5 +21,5 @@ PyAPI_FUNC(PyObject *) PySentinel_New( #ifdef __cplusplus } #endif -#endif /* !Py_SENTINELOBJECT_H */ +#endif /* !_Py_SENTINELOBJECT_H */ #endif /* !Py_LIMITED_API */ diff --git a/Include/cpython/sliceobject.h b/Include/cpython/sliceobject.h index 4c3ea1facebc4e..137206eff15b33 100644 --- a/Include/cpython/sliceobject.h +++ b/Include/cpython/sliceobject.h @@ -1,4 +1,4 @@ -#ifndef Py_CPYTHON_SLICEOBJECT_H +#ifndef _Py_CPYTHON_SLICEOBJECT_H # error "this header file must not be included directly" #endif diff --git a/Include/cpython/structseq.h b/Include/cpython/structseq.h index 328fbe86143b02..83a1abcd6f3b34 100644 --- a/Include/cpython/structseq.h +++ b/Include/cpython/structseq.h @@ -1,4 +1,4 @@ -#ifndef Py_CPYTHON_STRUCTSEQ_H +#ifndef _Py_CPYTHON_STRUCTSEQ_H # error "this header file must not be included directly" #endif diff --git a/Include/internal/pycore_jit_unwind.h b/Include/internal/pycore_jit_unwind.h index 508caee97c43ab..7099b88812ce7b 100644 --- a/Include/internal/pycore_jit_unwind.h +++ b/Include/internal/pycore_jit_unwind.h @@ -11,7 +11,7 @@ #if defined(_Py_JIT) && defined(__linux__) && defined(__ELF__) # define PY_HAVE_JIT_GDB_UNWIND # if defined(HAVE_EXECINFO_H) && defined(HAVE_BACKTRACE) && \ - defined(HAVE_LIBGCC_EH_FRAME_REGISTRATION) + defined(_Py_HAVE_LIBGCC_EH_FRAME_REGISTRATION) # define PY_HAVE_JIT_GNU_BACKTRACE_UNWIND # endif #endif diff --git a/Include/internal/pycore_mmap.h b/Include/internal/pycore_mmap.h index 897816db01077f..c117cbd16283da 100644 --- a/Include/internal/pycore_mmap.h +++ b/Include/internal/pycore_mmap.h @@ -11,12 +11,12 @@ extern "C" { #include "pycore_pystate.h" -#if defined(HAVE_PR_SET_VMA_ANON_NAME) && defined(__linux__) +#if defined(_Py_HAVE_PR_SET_VMA_ANON_NAME) && defined(__linux__) # include # include #endif -#if defined(HAVE_PR_SET_VMA_ANON_NAME) && defined(__linux__) +#if defined(_Py_HAVE_PR_SET_VMA_ANON_NAME) && defined(__linux__) static inline int _PyAnnotateMemoryMap(void *addr, size_t size, const char *name) { diff --git a/Include/sliceobject.h b/Include/sliceobject.h index 00c70a6e911b41..9d6a16da95fe2f 100644 --- a/Include/sliceobject.h +++ b/Include/sliceobject.h @@ -45,9 +45,9 @@ PyAPI_FUNC(Py_ssize_t) PySlice_AdjustIndices(Py_ssize_t length, #endif #ifndef Py_LIMITED_API -# define Py_CPYTHON_SLICEOBJECT_H +# define _Py_CPYTHON_SLICEOBJECT_H # include "cpython/sliceobject.h" -# undef Py_CPYTHON_SLICEOBJECT_H +# undef _Py_CPYTHON_SLICEOBJECT_H #endif #ifdef __cplusplus diff --git a/Include/structseq.h b/Include/structseq.h index e52d6188030af9..e5da785f13d46b 100644 --- a/Include/structseq.h +++ b/Include/structseq.h @@ -29,9 +29,9 @@ PyAPI_FUNC(void) PyStructSequence_SetItem(PyObject*, Py_ssize_t, PyObject*); PyAPI_FUNC(PyObject*) PyStructSequence_GetItem(PyObject*, Py_ssize_t); #ifndef Py_LIMITED_API -# define Py_CPYTHON_STRUCTSEQ_H +# define _Py_CPYTHON_STRUCTSEQ_H # include "cpython/structseq.h" -# undef Py_CPYTHON_STRUCTSEQ_H +# undef _Py_CPYTHON_STRUCTSEQ_H #endif #ifdef __cplusplus diff --git a/Python/pystrhex.c b/Python/pystrhex.c index 645bb013581288..8fb1fa36f85e73 100644 --- a/Python/pystrhex.c +++ b/Python/pystrhex.c @@ -36,7 +36,7 @@ _Py_hexlify_scalar(const unsigned char *src, Py_UCS1 *dst, Py_ssize_t len) adds a ton of complication. Who ever really hexes huge data? The 16-64 byte boosts align nicely with md5 - sha512 hexdigests. */ -#ifdef HAVE_EFFICIENT_BUILTIN_SHUFFLEVECTOR +#ifdef _Py_HAVE_EFFICIENT_BUILTIN_SHUFFLEVECTOR /* 128-bit vector of 16 unsigned bytes */ typedef unsigned char v16u8 __attribute__((vector_size(16))); @@ -110,7 +110,7 @@ _Py_hexlify_simd(const unsigned char *src, Py_UCS1 *dst, Py_ssize_t len) _Py_hexlify_scalar(src + i, dst, len - i); } -#endif /* HAVE_EFFICIENT_BUILTIN_SHUFFLEVECTOR */ +#endif /* _Py_HAVE_EFFICIENT_BUILTIN_SHUFFLEVECTOR */ static PyObject * _Py_strhex_impl(const char* argbuf, Py_ssize_t arglen, @@ -191,7 +191,7 @@ _Py_strhex_impl(const char* argbuf, Py_ssize_t arglen, unsigned char c; if (bytes_per_sep_group == 0) { -#ifdef HAVE_EFFICIENT_BUILTIN_SHUFFLEVECTOR +#ifdef _Py_HAVE_EFFICIENT_BUILTIN_SHUFFLEVECTOR if (arglen >= 16) { _Py_hexlify_simd((const unsigned char *)argbuf, retbuf, arglen); } diff --git a/configure b/configure index cff7dfbfba8b9a..e9672d74c52a36 100755 --- a/configure +++ b/configure @@ -14619,7 +14619,7 @@ if test "x$ac_cv_have_libgcc_eh_frame_registration" = xyes then : -printf "%s\n" "#define HAVE_LIBGCC_EH_FRAME_REGISTRATION 1" >>confdefs.h +printf "%s\n" "#define _Py_HAVE_LIBGCC_EH_FRAME_REGISTRATION 1" >>confdefs.h fi @@ -19483,7 +19483,7 @@ if test "x$ac_cv_efficient_builtin_shufflevector" = xyes then : -printf "%s\n" "#define HAVE_EFFICIENT_BUILTIN_SHUFFLEVECTOR 1" >>confdefs.h +printf "%s\n" "#define _Py_HAVE_EFFICIENT_BUILTIN_SHUFFLEVECTOR 1" >>confdefs.h fi @@ -24582,7 +24582,7 @@ printf "%s\n" "#define HAVE_DECL_PR_SET_VMA_ANON_NAME $ac_have_decl" >>confdefs. if test $ac_have_decl = 1 then : -printf "%s\n" "#define HAVE_PR_SET_VMA_ANON_NAME 1" >>confdefs.h +printf "%s\n" "#define _Py_HAVE_PR_SET_VMA_ANON_NAME 1" >>confdefs.h fi diff --git a/configure.ac b/configure.ac index ac3269ab765c0d..7f97db73ad807d 100644 --- a/configure.ac +++ b/configure.ac @@ -3863,7 +3863,7 @@ __deregister_frame(0); [ac_cv_have_libgcc_eh_frame_registration=no]) ]) AS_VAR_IF([ac_cv_have_libgcc_eh_frame_registration], [yes], [ - AC_DEFINE([HAVE_LIBGCC_EH_FRAME_REGISTRATION], [1], + AC_DEFINE([_Py_HAVE_LIBGCC_EH_FRAME_REGISTRATION], [1], [Define to 1 if libgcc __register_frame and __deregister_frame are linkable.]) ]) @@ -5163,7 +5163,7 @@ AC_LINK_IFELSE([ ]) AS_VAR_IF([ac_cv_efficient_builtin_shufflevector], [yes], [ - AC_DEFINE([HAVE_EFFICIENT_BUILTIN_SHUFFLEVECTOR], [1], + AC_DEFINE([_Py_HAVE_EFFICIENT_BUILTIN_SHUFFLEVECTOR], [1], [Define if compiler supports __builtin_shufflevector with 128-bit vectors AND the target architecture has native SIMD (not just API availability)]) @@ -5788,7 +5788,7 @@ AC_CHECK_DECLS([UT_NAMESIZE], # musl libc redefines struct prctl_mm_map and conflicts with linux/prctl.h AS_IF([test "$ac_cv_libc" != musl], [ AC_CHECK_DECLS([PR_SET_VMA_ANON_NAME], - [AC_DEFINE([HAVE_PR_SET_VMA_ANON_NAME], [1], + [AC_DEFINE([_Py_HAVE_PR_SET_VMA_ANON_NAME], [1], [Define if you have the 'PR_SET_VMA_ANON_NAME' constant.])], [], [@%:@include diff --git a/pyconfig.h.in b/pyconfig.h.in index ad372255445d13..7ef83fcd0b9e0b 100644 --- a/pyconfig.h.in +++ b/pyconfig.h.in @@ -320,10 +320,6 @@ /* Define to 1 if you have the header file. */ #undef HAVE_EDITLINE_READLINE_H -/* Define if compiler supports __builtin_shufflevector with 128-bit vectors - AND the target architecture has native SIMD (not just API availability) */ -#undef HAVE_EFFICIENT_BUILTIN_SHUFFLEVECTOR - /* Define to 1 if you have the header file. */ #undef HAVE_ENDIAN_H @@ -701,10 +697,6 @@ /* Define to 1 if you have the 'dld' library (-ldld). */ #undef HAVE_LIBDLD -/* Define to 1 if libgcc __register_frame and __deregister_frame are linkable. - */ -#undef HAVE_LIBGCC_EH_FRAME_REGISTRATION - /* Define to 1 if you have the 'ieee' library (-lieee). */ #undef HAVE_LIBIEEE @@ -1007,9 +999,6 @@ /* Define if your compiler supports function prototype */ #undef HAVE_PROTOTYPES -/* Define if you have the 'PR_SET_VMA_ANON_NAME' constant. */ -#undef HAVE_PR_SET_VMA_ANON_NAME - /* Define to 1 if you have the 'pthread_condattr_setclock' function. */ #undef HAVE_PTHREAD_CONDATTR_SETCLOCK @@ -2067,6 +2056,17 @@ /* HACL* library can compile SIMD256 implementations */ #undef _Py_HACL_CAN_COMPILE_VEC256 +/* Define if compiler supports __builtin_shufflevector with 128-bit vectors + AND the target architecture has native SIMD (not just API availability) */ +#undef _Py_HAVE_EFFICIENT_BUILTIN_SHUFFLEVECTOR + +/* Define to 1 if libgcc __register_frame and __deregister_frame are linkable. + */ +#undef _Py_HAVE_LIBGCC_EH_FRAME_REGISTRATION + +/* Define if you have the 'PR_SET_VMA_ANON_NAME' constant. */ +#undef _Py_HAVE_PR_SET_VMA_ANON_NAME + /* Define to 1 if the machine stack grows down (default); 0 if it grows up. */ #undef _Py_STACK_GROWS_DOWN From b6503057b2ac5aa8b976965dc6ccf16bbd13b50d Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 14 May 2026 00:00:29 +0200 Subject: [PATCH 050/818] [3.15] gh-140550: Update xxlimited with 3.15 limited API (GH-142827) (GH-149785) (cherry picked from commit fa81cd976ad88e022839a37501d75d8716e22e3b) Co-authored-by: Petr Viktorin --- Lib/test/test_xxlimited.py | 119 +++-- Modules/Setup | 1 + Modules/Setup.stdlib.in | 1 + Modules/xxlimited.c | 419 +++++++++++---- Modules/xxlimited_35.c | 2 +- Modules/xxlimited_3_13.c | 499 ++++++++++++++++++ PC/layout/main.py | 3 +- PCbuild/pcbuild.proj | 1 + PCbuild/readme.txt | 5 +- PCbuild/xxlimited_3_13.vcxproj | 111 ++++ PCbuild/xxlimited_3_13.vcxproj.filters | 13 + Tools/build/generate_stdlib_module_names.py | 1 + Tools/c-analyzer/c_parser/preprocessor/gcc.py | 1 + Tools/c-analyzer/cpython/_analyzer.py | 1 + configure | 47 ++ configure.ac | 2 + 16 files changed, 1062 insertions(+), 164 deletions(-) create mode 100644 Modules/xxlimited_3_13.c create mode 100644 PCbuild/xxlimited_3_13.vcxproj create mode 100644 PCbuild/xxlimited_3_13.vcxproj.filters diff --git a/Lib/test/test_xxlimited.py b/Lib/test/test_xxlimited.py index b52e78bc4fb7e0..c6e9dc375d9a67 100644 --- a/Lib/test/test_xxlimited.py +++ b/Lib/test/test_xxlimited.py @@ -1,19 +1,39 @@ import unittest from test.support import import_helper -import types xxlimited = import_helper.import_module('xxlimited') -xxlimited_35 = import_helper.import_module('xxlimited_35') - -class CommonTests: - module: types.ModuleType - - def test_xxo_new(self): - xxo = self.module.Xxo() - - def test_xxo_attributes(self): - xxo = self.module.Xxo() +# if import of xxlimited succeeded, the other ones should be importable. +import xxlimited_3_13 +import xxlimited_35 + +MODULES = { + (3, 15): xxlimited, + (3, 13): xxlimited_3_13, + (3, 5): xxlimited_35, +} + +def test_with_xxlimited_modules(since=None, until=None): + def _decorator(func): + def _wrapper(self, *args, **kwargs): + for version, module in MODULES.items(): + if since and version < since: + continue + if until and version >= until: + continue + with self.subTest(version=version): + func(self, module, *args, **kwargs) + return _wrapper + return _decorator + +class XXLimitedTests(unittest.TestCase): + @test_with_xxlimited_modules() + def test_xxo_new(self, module): + xxo = module.Xxo() + + @test_with_xxlimited_modules() + def test_xxo_attributes(self, module): + xxo = module.Xxo() with self.assertRaises(AttributeError): xxo.foo with self.assertRaises(AttributeError): @@ -26,40 +46,61 @@ def test_xxo_attributes(self): with self.assertRaises(AttributeError): xxo.foo - def test_foo(self): + @test_with_xxlimited_modules() + def test_foo(self, module): # the foo function adds 2 numbers - self.assertEqual(self.module.foo(1, 2), 3) + self.assertEqual(module.foo(1, 2), 3) - def test_str(self): - self.assertIsSubclass(self.module.Str, str) - self.assertIsNot(self.module.Str, str) + @test_with_xxlimited_modules() + def test_str(self, module): + self.assertIsSubclass(module.Str, str) + self.assertIsNot(module.Str, str) - custom_string = self.module.Str("abcd") + custom_string = module.Str("abcd") self.assertEqual(custom_string, "abcd") self.assertEqual(custom_string.upper(), "ABCD") - def test_new(self): - xxo = self.module.new() + @test_with_xxlimited_modules() + def test_new(self, module): + xxo = module.new() self.assertEqual(xxo.demo("abc"), "abc") - -class TestXXLimited(CommonTests, unittest.TestCase): - module = xxlimited - - def test_xxo_demo(self): - xxo = self.module.Xxo() - other = self.module.Xxo() + @test_with_xxlimited_modules() + def test_xxo_demo(self, module): + xxo = module.Xxo() self.assertEqual(xxo.demo("abc"), "abc") + self.assertEqual(xxo.demo(0), None) + self.assertEqual(xxo.__module__, module.__name__) + with self.assertRaises(TypeError): + module.Xxo('arg') + with self.assertRaises(TypeError): + module.Xxo(kwarg='arg') + + @test_with_xxlimited_modules(since=(3, 13)) + def test_xxo_demo_extra(self, module): + xxo = module.Xxo() + other = module.Xxo() self.assertEqual(xxo.demo(xxo), xxo) self.assertEqual(xxo.demo(other), other) - self.assertEqual(xxo.demo(0), None) - def test_error(self): - with self.assertRaises(self.module.Error): - raise self.module.Error - - def test_buffer(self): - xxo = self.module.Xxo() + @test_with_xxlimited_modules(since=(3, 15)) + def test_xxo_subclass(self, module): + class Sub(module.Xxo): + pass + sub = Sub() + sub.a = 123 + self.assertEqual(sub.a, 123) + with self.assertRaisesRegex(AttributeError, "cannot set 'reserved'"): + sub.reserved = 123 + + @test_with_xxlimited_modules(since=(3, 13)) + def test_error(self, module): + with self.assertRaises(module.Error): + raise module.Error + + @test_with_xxlimited_modules(since=(3, 13)) + def test_buffer(self, module): + xxo = module.Xxo() self.assertEqual(xxo.x_exports, 0) b1 = memoryview(xxo) self.assertEqual(xxo.x_exports, 1) @@ -69,21 +110,13 @@ def test_buffer(self): self.assertEqual(b1[0], 1) self.assertEqual(b2[0], 1) - -class TestXXLimited35(CommonTests, unittest.TestCase): - module = xxlimited_35 - - def test_xxo_demo(self): - xxo = self.module.Xxo() - other = self.module.Xxo() - self.assertEqual(xxo.demo("abc"), "abc") - self.assertEqual(xxo.demo(0), None) - + @test_with_xxlimited_modules(until=(3, 5)) def test_roj(self): # the roj function always fails with self.assertRaises(SystemError): self.module.roj(0) + @test_with_xxlimited_modules(until=(3, 5)) def test_null(self): null1 = self.module.Null() null2 = self.module.Null() diff --git a/Modules/Setup b/Modules/Setup index 33737c21cb4066..e97a78e628693d 100644 --- a/Modules/Setup +++ b/Modules/Setup @@ -273,6 +273,7 @@ PYTHONPATH=$(COREPYTHONPATH) #xx xxmodule.c #xxlimited xxlimited.c #xxlimited_35 xxlimited_35.c +#xxlimited_3_13 xxlimited_3_13.c #xxsubtype xxsubtype.c # Testing diff --git a/Modules/Setup.stdlib.in b/Modules/Setup.stdlib.in index 19765bc313555b..5f8b0cf482472d 100644 --- a/Modules/Setup.stdlib.in +++ b/Modules/Setup.stdlib.in @@ -190,6 +190,7 @@ # Limited API template modules; must be built as shared modules. @MODULE_XXLIMITED_TRUE@xxlimited xxlimited.c @MODULE_XXLIMITED_35_TRUE@xxlimited_35 xxlimited_35.c +@MODULE_XXLIMITED_3_13_TRUE@xxlimited_3_13 xxlimited_3_13.c # for performance diff --git a/Modules/xxlimited.c b/Modules/xxlimited.c index 09c8d9487f5426..96454ee5e83eab 100644 --- a/Modules/xxlimited.c +++ b/Modules/xxlimited.c @@ -11,7 +11,13 @@ other files, you'll have to create a file "foobarobject.h"; see floatobject.h for an example. - This module roughly corresponds to:: + This module uses Limited API 3.15. + See ``xxlimited_3_13.c`` if you want to support older CPython versions. + + This module roughly corresponds to the following. + (All underscore-prefixed attributes are not accessible from Python.) + + :: class Xxo: """A class that explicitly stores attributes in an internal dict @@ -27,6 +33,8 @@ return self._x_attr[name] def __setattr__(self, name, value): + if name == "reserved": + raise AttributeError("cannot set 'reserved'") self._x_attr[name] = value def __delattr__(self, name): @@ -64,11 +72,13 @@ pass */ -// Need limited C API version 3.13 for Py_mod_gil -#include "pyconfig.h" // Py_GIL_DISABLED -#ifndef Py_GIL_DISABLED -# define Py_LIMITED_API 0x030d0000 -#endif +// Target both flavors of the Stable ABI. +// Both are set to version 3.15, which adds PyModExport +// (When using a build tool, check if it has an option to set these +// so they do not need to be defined in the source.) +#define Py_LIMITED_API 0x030f0000 // abi3 (GIL-enabled builds) +#define Py_TARGET_ABI3T 0x030f0000 // abi3t (free-threaded builds) + #include "Python.h" #include @@ -77,43 +87,135 @@ // Module state typedef struct { - PyObject *Xxo_Type; // Xxo class + PyTypeObject *Xxo_Type; // Xxo class PyObject *Error_Type; // Error class } xx_state; -/* Xxo objects */ +/* Xxo objects. + * + * A non-trivial extension type, intentionally showing a number of features + * that aren't easy to implement in the Limited API. + */ + +// Forward declaration +static PyType_Spec Xxo_Type_spec; + +// Get the module state (xx_state*) from a given type object 'type', which +// must be a subclass of Xxo (the type we're defining). +// This is complicated by the fact that the Xxo type is dynamically allocated, +// and there may be several such types in a given Python process -- for +// example, in different subinterpreters, or through loading this +// extension module several times. +// So, we don't have a "global" pointer to the type, or to the module, etc.; +// instead we search based on `Xxo_Type_spec` (which is static, immutable, +// and process-global). +// +// When possible, it's better to avoid `PyType_GetBaseByToken` -- for an +// example, see the `demo` method (Xxo_demo C function), which uses a +// "defining class". But, in many cases it's the best solution. +static xx_state * +Xxo_state_from_type(PyTypeObject *type) +{ + PyTypeObject *base; + // Search all superclasses of 'type' for one that was defined using + // "Xxo_Type_spec". That must be our 'Xxo' class. + if (PyType_GetBaseByToken(type, &Xxo_Type_spec, &base) < 0) { + return NULL; + } + if (base == NULL) { + PyErr_SetString(PyExc_TypeError, "need Xxo subclass"); + return NULL; + } + // From this type, get the associated module. That must be the + // relevant `xxlimited` module. + xx_state *state = PyType_GetModuleState(base); + Py_DECREF(base); + return state; +} -// Instance state +// Structure for data needed by the XxoObject type. +// Since the object may be shared across threads, access to the fields +// usually needs to be synchronized (using Py_BEGIN_CRITICAL_SECTION). typedef struct { - PyObject_HEAD - PyObject *x_attr; /* Attributes dictionary. - * May be NULL, which acts as an - * empty dict. - */ - char x_buffer[BUFSIZE]; /* buffer for Py_buffer */ - Py_ssize_t x_exports; /* how many buffer are exported */ -} XxoObject; - -#define XxoObject_CAST(op) ((XxoObject *)(op)) -// TODO: full support for type-checking was added in 3.14 (Py_tp_token) -// #define XxoObject_Check(v) Py_IS_TYPE(v, Xxo_Type) - -static XxoObject * -newXxoObject(PyObject *module) + PyObject *x_attr; /* Attributes dictionary. + * May be NULL, which acts as an + * empty dict. + */ + Py_ssize_t x_exports; /* how many buffers are exported */ + char x_buffer[BUFSIZE]; /* buffer for Py_buffer (for simplicity, + * this is constant, so does not need + * synchronization) + */ +} XxoObject_Data; + +// Get the `XxoObject_Data` structure for a given instance of our type. +static XxoObject_Data * +Xxo_get_data(PyObject *self) { - xx_state *state = PyModule_GetState(module); + xx_state *state = Xxo_state_from_type(Py_TYPE(self)); + if (!state) { + return NULL; + } + XxoObject_Data *data = PyObject_GetTypeData(self, state->Xxo_Type); + return data; +} + +// A variant of Xxo_get_data to be used in the tp_traverse handler. +// This function cannot have side effects (including reference count +// manipulation, creating objects, and raising exceptions), and must not +// call API functions that might have side effects. +// See: https://docs.python.org/3.15/c-api/gcsupport.html#traversal +static XxoObject_Data * +Xxo_get_data_DuringGC(PyObject *self) +{ + PyTypeObject *base; + PyType_GetBaseByToken_DuringGC(Py_TYPE(self), &Xxo_Type_spec, &base); + if (base == NULL) { + return NULL; + } + xx_state *state = PyType_GetModuleState_DuringGC(base); if (state == NULL) { return NULL; } - XxoObject *self; - self = PyObject_GC_New(XxoObject, (PyTypeObject*)state->Xxo_Type); + XxoObject_Data *data = PyObject_GetTypeData_DuringGC(self, state->Xxo_Type); + return data; +} + +// Xxo initialization +// This is the implementation of Xxo.__new__ +static PyObject * +Xxo_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) +{ + // Validate that we did not get any arguments. + if ((args != NULL && PyObject_Length(args)) + || (kwargs != NULL && PyObject_Length(kwargs))) + { + PyErr_SetString(PyExc_TypeError, "Xxo.__new__() takes no arguments"); + return NULL; + } + // Create an instance of *type* (which may be a subclass) + allocfunc alloc = PyType_GetSlot(type, Py_tp_alloc); + PyObject *self = alloc(type, 0); if (self == NULL) { return NULL; } - self->x_attr = NULL; - memset(self->x_buffer, 0, BUFSIZE); - self->x_exports = 0; + + // Initialize the C members on the instance. + // This is only included for the sake of example. The default alloc + // function zeroes instance memory; we don't need to do it again. + // Note that we during initialization (and finalization), we hold the only + // reference to the object, so we don't need to synchronize with + // other threads. + XxoObject_Data *xxo_data = Xxo_get_data(self); + if (xxo_data == NULL) { + Py_DECREF(self); + return NULL; + } + + xxo_data->x_attr = NULL; + memset(xxo_data->x_buffer, 0, BUFSIZE); + xxo_data->x_exports = 0; return self; } @@ -125,45 +227,63 @@ newXxoObject(PyObject *module) // traverse: Visit all references from an object, including its type static int -Xxo_traverse(PyObject *op, visitproc visit, void *arg) +Xxo_traverse(PyObject *self, visitproc visit, void *arg) { // Visit the type - Py_VISIT(Py_TYPE(op)); + Py_VISIT(Py_TYPE(self)); // Visit the attribute dict - XxoObject *self = XxoObject_CAST(op); - Py_VISIT(self->x_attr); + XxoObject_Data *data = Xxo_get_data_DuringGC(self); + if (data == NULL) { + return 0; + } + Py_VISIT(data->x_attr); return 0; } // clear: drop references in order to break all reference cycles static int -Xxo_clear(PyObject *op) +Xxo_clear(PyObject *self) { - XxoObject *self = XxoObject_CAST(op); - Py_CLEAR(self->x_attr); + XxoObject_Data *data = Xxo_get_data(self); + if (data == NULL) { + return 0; + } + Py_CLEAR(data->x_attr); return 0; } // finalize: like clear, but should leave the object in a consistent state. // Equivalent to `__del__` in Python. static void -Xxo_finalize(PyObject *op) +Xxo_finalize(PyObject *self) { - XxoObject *self = XxoObject_CAST(op); - Py_CLEAR(self->x_attr); + XxoObject_Data *data = Xxo_get_data(self); + if (data == NULL) { + return; + } + Py_CLEAR(data->x_attr); } // dealloc: drop all remaining references and free memory static void Xxo_dealloc(PyObject *self) { + // This function must preserve currently raised exception, if any. + PyObject *exc = PyErr_GetRaisedException(); + PyObject_GC_UnTrack(self); Xxo_finalize(self); + PyTypeObject *tp = Py_TYPE(self); freefunc free = PyType_GetSlot(tp, Py_tp_free); free(self); Py_DECREF(tp); + + if (PyErr_Occurred()) { + PyErr_WriteUnraisable(NULL); + } + PyErr_SetRaisedException(exc); } @@ -171,11 +291,20 @@ Xxo_dealloc(PyObject *self) // Get an attribute. static PyObject * -Xxo_getattro(PyObject *op, PyObject *name) +Xxo_getattro(PyObject *self, PyObject *name) { - XxoObject *self = XxoObject_CAST(op); - if (self->x_attr != NULL) { - PyObject *v = PyDict_GetItemWithError(self->x_attr, name); + XxoObject_Data *data = Xxo_get_data(self); + if (data == NULL) { + return 0; + } + + PyObject *x_attr; + Py_BEGIN_CRITICAL_SECTION(self); + x_attr = data->x_attr; + Py_END_CRITICAL_SECTION(); + + if (x_attr != NULL) { + PyObject *v = PyDict_GetItemWithError(x_attr, name); if (v != NULL) { return Py_NewRef(v); } @@ -185,24 +314,42 @@ Xxo_getattro(PyObject *op, PyObject *name) } // Fall back to generic implementation (this handles special attributes, // raising AttributeError, etc.) - return PyObject_GenericGetAttr(op, name); + return PyObject_GenericGetAttr(self, name); } // Set or delete an attribute. static int -Xxo_setattro(PyObject *op, PyObject *name, PyObject *v) +Xxo_setattro(PyObject *self, PyObject *name, PyObject *v) { - XxoObject *self = XxoObject_CAST(op); - if (self->x_attr == NULL) { + // filter a specific attribute name + if (PyUnicode_Check(name) && PyUnicode_EqualToUTF8(name, "reserved")) { + PyErr_Format(PyExc_AttributeError, "cannot set %R", name); + return -1; + } + + XxoObject_Data *data = Xxo_get_data(self); + if (data == NULL) { + return -1; + } + + // If the attribute dict is not created yet, make one. + // This needs to be protected by a critical section to avoid another thread + // creating a duplicate dict. + PyObject *x_attr; + Py_BEGIN_CRITICAL_SECTION(self); + x_attr = data->x_attr; + if (x_attr == NULL) { // prepare the attribute dict - self->x_attr = PyDict_New(); - if (self->x_attr == NULL) { - return -1; - } + data->x_attr = x_attr = PyDict_New(); } + Py_END_CRITICAL_SECTION(); + if (x_attr == NULL) { + return -1; + } + if (v == NULL) { // delete an attribute - int rv = PyDict_DelItem(self->x_attr, name); + int rv = PyDict_DelItem(x_attr, name); if (rv < 0 && PyErr_ExceptionMatches(PyExc_KeyError)) { PyErr_SetString(PyExc_AttributeError, "delete non-existing Xxo attribute"); @@ -212,7 +359,7 @@ Xxo_setattro(PyObject *op, PyObject *name, PyObject *v) } else { // set an attribute - return PyDict_SetItem(self->x_attr, name, v); + return PyDict_SetItem(x_attr, name, v); } } @@ -221,7 +368,7 @@ Xxo_setattro(PyObject *op, PyObject *name, PyObject *v) */ static PyObject * -Xxo_demo(PyObject *op, PyTypeObject *defining_class, +Xxo_demo(PyObject *self, PyTypeObject *defining_class, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { if (kwnames != NULL && PyObject_Length(kwnames)) { @@ -260,30 +407,49 @@ static PyMethodDef Xxo_methods[] = { */ static int -Xxo_getbuffer(PyObject *op, Py_buffer *view, int flags) +Xxo_getbuffer(PyObject *self, Py_buffer *view, int flags) { - XxoObject *self = XxoObject_CAST(op); - int res = PyBuffer_FillInfo(view, op, - (void *)self->x_buffer, BUFSIZE, + XxoObject_Data *data = Xxo_get_data(self); + if (data == NULL) { + return -1; + } + int res = PyBuffer_FillInfo(view, self, + (void *)data->x_buffer, BUFSIZE, 0, flags); if (res == 0) { - self->x_exports++; + Py_BEGIN_CRITICAL_SECTION(self); + data->x_exports++; + Py_END_CRITICAL_SECTION(); } return res; } static void -Xxo_releasebuffer(PyObject *op, Py_buffer *Py_UNUSED(view)) +Xxo_releasebuffer(PyObject *self, Py_buffer *Py_UNUSED(view)) { - XxoObject *self = XxoObject_CAST(op); - self->x_exports--; + XxoObject_Data *data = Xxo_get_data(self); + if (data == NULL) { + return; + } + Py_BEGIN_CRITICAL_SECTION(self); + data->x_exports--; + Py_END_CRITICAL_SECTION(); } static PyObject * -Xxo_get_x_exports(PyObject *op, void *Py_UNUSED(closure)) +Xxo_get_x_exports(PyObject *self, void *Py_UNUSED(closure)) { - XxoObject *self = XxoObject_CAST(op); - return PyLong_FromSsize_t(self->x_exports); + XxoObject_Data *data = Xxo_get_data(self); + if (data == NULL) { + return NULL; + } + Py_ssize_t result; + + Py_BEGIN_CRITICAL_SECTION(self); + result = data->x_exports; + Py_END_CRITICAL_SECTION(); + + return PyLong_FromSsize_t(result); } /* Xxo type definition */ @@ -299,6 +465,7 @@ static PyGetSetDef Xxo_getsetlist[] = { static PyType_Slot Xxo_Type_slots[] = { {Py_tp_doc, (char *)Xxo_doc}, + {Py_tp_new, Xxo_new}, {Py_tp_traverse, Xxo_traverse}, {Py_tp_clear, Xxo_clear}, {Py_tp_finalize, Xxo_finalize}, @@ -309,13 +476,14 @@ static PyType_Slot Xxo_Type_slots[] = { {Py_bf_getbuffer, Xxo_getbuffer}, {Py_bf_releasebuffer, Xxo_releasebuffer}, {Py_tp_getset, Xxo_getsetlist}, + {Py_tp_token, Py_TP_USE_SPEC}, {0, 0}, /* sentinel */ }; static PyType_Spec Xxo_Type_spec = { .name = "xxlimited.Xxo", - .basicsize = sizeof(XxoObject), - .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, + .basicsize = -(Py_ssize_t)sizeof(XxoObject_Data), + .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE, .slots = Xxo_Type_slots, }; @@ -354,17 +522,17 @@ xx_foo(PyObject *module, PyObject *args) } -/* Function of no arguments returning new Xxo object */ +/* Function of no arguments returning new Xxo object. + * Note that a function exposed to Python with METH_NOARGS requires an unused + * second argument, so we cannot use newXxoObject directly. + */ static PyObject * xx_new(PyObject *module, PyObject *Py_UNUSED(unused)) { - XxoObject *rv; + xx_state *state = PyModule_GetState(module); - rv = newXxoObject(module); - if (rv == NULL) - return NULL; - return (PyObject *)rv; + return Xxo_new(state->Xxo_Type, NULL, NULL); } @@ -398,11 +566,12 @@ xx_modexec(PyObject *m) return -1; } - state->Xxo_Type = PyType_FromModuleAndSpec(m, &Xxo_Type_spec, NULL); + state->Xxo_Type = (PyTypeObject*)PyType_FromModuleAndSpec( + m, &Xxo_Type_spec, NULL); if (state->Xxo_Type == NULL) { return -1; } - if (PyModule_AddType(m, (PyTypeObject*)state->Xxo_Type) < 0) { + if (PyModule_AddType(m, state->Xxo_Type) < 0) { return -1; } @@ -410,12 +579,13 @@ xx_modexec(PyObject *m) // added to the module dict. // It does not inherit from "object" (PyObject_Type), but from "str" // (PyUnincode_Type). - PyObject *Str_Type = PyType_FromModuleAndSpec( + PyTypeObject *Str_Type = (PyTypeObject*)PyType_FromModuleAndSpec( m, &Str_Type_spec, (PyObject *)&PyUnicode_Type); if (Str_Type == NULL) { return -1; } - if (PyModule_AddType(m, (PyTypeObject*)Str_Type) < 0) { + if (PyModule_AddType(m, Str_Type) < 0) { + Py_DECREF(Str_Type); return -1; } Py_DECREF(Str_Type); @@ -423,29 +593,6 @@ xx_modexec(PyObject *m) return 0; } -static PyModuleDef_Slot xx_slots[] = { - - /* exec function to initialize the module (called as part of import - * after the object was added to sys.modules) - */ - {Py_mod_exec, xx_modexec}, - - /* Signal that this module supports being loaded in multiple interpreters - * with separate GILs (global interpreter locks). - * See "Isolating Extension Modules" on how to prepare a module for this: - * https://docs.python.org/3/howto/isolating-extensions.html - */ - {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, - - /* Signal that this module does not rely on the GIL for its own needs. - * Without this slot, free-threaded builds of CPython will enable - * the GIL when this module is loaded. - */ - {Py_mod_gil, Py_MOD_GIL_NOT_USED}, - - {0, NULL} -}; - // Module finalization: modules that hold references in their module state // need to implement the fullowing GC hooks. They're similar to the ones for // types (see "Xxo finalization"). @@ -453,7 +600,10 @@ static PyModuleDef_Slot xx_slots[] = { static int xx_traverse(PyObject *module, visitproc visit, void *arg) { - xx_state *state = PyModule_GetState(module); + xx_state *state = PyModule_GetState_DuringGC(module); + if (state == NULL) { + return 0; + } Py_VISIT(state->Xxo_Type); Py_VISIT(state->Error_Type); return 0; @@ -463,6 +613,9 @@ static int xx_clear(PyObject *module) { xx_state *state = PyModule_GetState(module); + if (state == NULL) { + return 0; + } Py_CLEAR(state->Xxo_Type); Py_CLEAR(state->Error_Type); return 0; @@ -473,27 +626,59 @@ xx_free(void *module) { // allow xx_modexec to omit calling xx_clear on error (void)xx_clear((PyObject *)module); + + xx_state *state = PyModule_GetState(module); + if (state == NULL) { + return; + } } -static struct PyModuleDef xxmodule = { - PyModuleDef_HEAD_INIT, - .m_name = "xxlimited", - .m_doc = module_doc, - .m_size = sizeof(xx_state), - .m_methods = xx_methods, - .m_slots = xx_slots, - .m_traverse = xx_traverse, - .m_clear = xx_clear, - .m_free = xx_free, +// Information that CPython uses to prevent loading incompatible extenstions +PyABIInfo_VAR(abi_info); + +static PySlot xx_slots[] = { + /* Basic metadata */ + PySlot_STATIC_DATA(Py_mod_name, "xxlimited"), + PySlot_STATIC_DATA(Py_mod_doc, (void*)module_doc), + PySlot_DATA(Py_mod_abi, &abi_info), + + /* The method table */ + PySlot_STATIC_DATA(Py_mod_methods, xx_methods), + + /* exec function to initialize the module (called as part of import + * after the object was added to sys.modules) + */ + PySlot_FUNC(Py_mod_exec, xx_modexec), + + /* Module state and associated functions */ + PySlot_SIZE(Py_mod_state_size, sizeof(xx_state)), + PySlot_FUNC(Py_mod_state_traverse, xx_traverse), + PySlot_FUNC(Py_mod_state_clear, xx_clear), + PySlot_FUNC(Py_mod_state_free, xx_free), + + /* Signal that this module supports being loaded in multiple interpreters + * with separate GILs (global interpreter locks). + * See "Isolating Extension Modules" on how to prepare a module for this: + * https://docs.python.org/3/howto/isolating-extensions.html + */ + PySlot_DATA(Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED), + + /* Signal that this module does not rely on the GIL for its own needs. + * Without this slot, free-threaded builds of CPython will enable + * the GIL when this module is loaded. + */ + PySlot_DATA(Py_mod_gil, Py_MOD_GIL_NOT_USED), + + PySlot_END }; -/* Export function for the module. *Must* be called PyInit_xx; usually it is - * the only non-`static` object in a module definition. +/* Export function for the module. *Must* be called PyModExport_xx; usually + * it is the only non-`static` object in a module definition. */ -PyMODINIT_FUNC -PyInit_xxlimited(void) +PyMODEXPORT_FUNC +PyModExport_xxlimited(void) { - return PyModuleDef_Init(&xxmodule); + return xx_slots; } diff --git a/Modules/xxlimited_35.c b/Modules/xxlimited_35.c index b0a682ac4e6bb6..9ef0eac9a924e6 100644 --- a/Modules/xxlimited_35.c +++ b/Modules/xxlimited_35.c @@ -305,7 +305,7 @@ xx_modexec(PyObject *m) static PyModuleDef_Slot xx_slots[] = { {Py_mod_exec, xx_modexec}, #ifdef Py_GIL_DISABLED - // These definitions are in the limited API, but not until 3.13. + // In a free-threaded build, we don't use Limited API. {Py_mod_gil, Py_MOD_GIL_NOT_USED}, #endif {0, NULL} diff --git a/Modules/xxlimited_3_13.c b/Modules/xxlimited_3_13.c new file mode 100644 index 00000000000000..4f100f9150fc2a --- /dev/null +++ b/Modules/xxlimited_3_13.c @@ -0,0 +1,499 @@ +/* Use this file as a template to start implementing a module that + also declares object types. All occurrences of 'Xxo' should be changed + to something reasonable for your objects. After that, all other + occurrences of 'xx' should be changed to something reasonable for your + module. If your module is named foo your source file should be named + foo.c or foomodule.c. + + You will probably want to delete all references to 'x_attr' and add + your own types of attributes instead. Maybe you want to name your + local variables other than 'self'. If your object type is needed in + other files, you'll have to create a file "foobarobject.h"; see + floatobject.h for an example. + + This module roughly corresponds to:: + + class Xxo: + """A class that explicitly stores attributes in an internal dict + (to simulate custom attribute handling). + """ + + def __init__(self): + # In the C class, "_x_attr" is not accessible from Python code + self._x_attr = {} + self._x_exports = 0 + + def __getattr__(self, name): + return self._x_attr[name] + + def __setattr__(self, name, value): + self._x_attr[name] = value + + def __delattr__(self, name): + del self._x_attr[name] + + @property + def x_exports(self): + """Return the number of times an internal buffer is exported.""" + # Each Xxo instance has a 10-byte buffer that can be + # accessed via the buffer interface (e.g. `memoryview`). + return self._x_exports + + def demo(o, /): + if isinstance(o, str): + return o + elif isinstance(o, Xxo): + return o + else: + raise Error('argument must be str or Xxo') + + class Error(Exception): + """Exception raised by the xxlimited module""" + + def foo(i: int, j: int, /): + """Return the sum of i and j.""" + # Unlike this pseudocode, the C function will *only* work with + # integers and perform C long int arithmetic + return i + j + + def new(): + return Xxo() + + def Str(str): + # A trivial subclass of a built-in type + pass + */ + +// Need limited C API version 3.13 for Py_mod_gil +#include "pyconfig.h" // Py_GIL_DISABLED +#ifndef Py_GIL_DISABLED +# define Py_LIMITED_API 0x030d0000 +#endif + +#include "Python.h" +#include + +#define BUFSIZE 10 + +// Module state +typedef struct { + PyObject *Xxo_Type; // Xxo class + PyObject *Error_Type; // Error class +} xx_state; + + +/* Xxo objects */ + +// Instance state +typedef struct { + PyObject_HEAD + PyObject *x_attr; /* Attributes dictionary. + * May be NULL, which acts as an + * empty dict. + */ + char x_buffer[BUFSIZE]; /* buffer for Py_buffer */ + Py_ssize_t x_exports; /* how many buffer are exported */ +} XxoObject; + +#define XxoObject_CAST(op) ((XxoObject *)(op)) +// TODO: full support for type-checking was added in 3.14 (Py_tp_token) +// #define XxoObject_Check(v) Py_IS_TYPE(v, Xxo_Type) + +static XxoObject * +newXxoObject(PyObject *module) +{ + xx_state *state = PyModule_GetState(module); + if (state == NULL) { + return NULL; + } + XxoObject *self; + self = PyObject_GC_New(XxoObject, (PyTypeObject*)state->Xxo_Type); + if (self == NULL) { + return NULL; + } + self->x_attr = NULL; + memset(self->x_buffer, 0, BUFSIZE); + self->x_exports = 0; + return self; +} + +/* Xxo finalization. + * + * Types that store references to other PyObjects generally need to implement + * the GC slots: traverse, clear, dealloc, and (optionally) finalize. + */ + +// traverse: Visit all references from an object, including its type +static int +Xxo_traverse(PyObject *op, visitproc visit, void *arg) +{ + // Visit the type + Py_VISIT(Py_TYPE(op)); + + // Visit the attribute dict + XxoObject *self = XxoObject_CAST(op); + Py_VISIT(self->x_attr); + return 0; +} + +// clear: drop references in order to break all reference cycles +static int +Xxo_clear(PyObject *op) +{ + XxoObject *self = XxoObject_CAST(op); + Py_CLEAR(self->x_attr); + return 0; +} + +// finalize: like clear, but should leave the object in a consistent state. +// Equivalent to `__del__` in Python. +static void +Xxo_finalize(PyObject *op) +{ + XxoObject *self = XxoObject_CAST(op); + Py_CLEAR(self->x_attr); +} + +// dealloc: drop all remaining references and free memory +static void +Xxo_dealloc(PyObject *self) +{ + PyObject_GC_UnTrack(self); + Xxo_finalize(self); + PyTypeObject *tp = Py_TYPE(self); + freefunc free = PyType_GetSlot(tp, Py_tp_free); + free(self); + Py_DECREF(tp); +} + + +/* Xxo attribute handling */ + +// Get an attribute. +static PyObject * +Xxo_getattro(PyObject *op, PyObject *name) +{ + XxoObject *self = XxoObject_CAST(op); + if (self->x_attr != NULL) { + PyObject *v = PyDict_GetItemWithError(self->x_attr, name); + if (v != NULL) { + return Py_NewRef(v); + } + else if (PyErr_Occurred()) { + return NULL; + } + } + // Fall back to generic implementation (this handles special attributes, + // raising AttributeError, etc.) + return PyObject_GenericGetAttr(op, name); +} + +// Set or delete an attribute. +static int +Xxo_setattro(PyObject *op, PyObject *name, PyObject *v) +{ + XxoObject *self = XxoObject_CAST(op); + if (self->x_attr == NULL) { + // prepare the attribute dict + self->x_attr = PyDict_New(); + if (self->x_attr == NULL) { + return -1; + } + } + if (v == NULL) { + // delete an attribute + int rv = PyDict_DelItem(self->x_attr, name); + if (rv < 0 && PyErr_ExceptionMatches(PyExc_KeyError)) { + PyErr_SetString(PyExc_AttributeError, + "delete non-existing Xxo attribute"); + return -1; + } + return rv; + } + else { + // set an attribute + return PyDict_SetItem(self->x_attr, name, v); + } +} + +/* Xxo methods: C functions plus a PyMethodDef array that lists them and + * specifies metadata. + */ + +static PyObject * +Xxo_demo(PyObject *op, PyTypeObject *defining_class, + PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + if (kwnames != NULL && PyObject_Length(kwnames)) { + PyErr_SetString(PyExc_TypeError, "demo() takes no keyword arguments"); + return NULL; + } + if (nargs != 1) { + PyErr_SetString(PyExc_TypeError, "demo() takes exactly 1 argument"); + return NULL; + } + + PyObject *o = args[0]; + + /* Test if the argument is "str" */ + if (PyUnicode_Check(o)) { + return Py_NewRef(o); + } + + /* test if the argument is of the Xxo class */ + if (PyObject_TypeCheck(o, defining_class)) { + return Py_NewRef(o); + } + + return Py_NewRef(Py_None); +} + +static PyMethodDef Xxo_methods[] = { + {"demo", _PyCFunction_CAST(Xxo_demo), + METH_METHOD | METH_FASTCALL | METH_KEYWORDS, PyDoc_STR("demo(o) -> o")}, + {NULL, NULL} /* sentinel */ +}; + +/* Xxo buffer interface: C functions later referenced from PyType_Slot array. + * Other interfaces (e.g. for sequence-like or number-like types) are defined + * similarly. + */ + +static int +Xxo_getbuffer(PyObject *op, Py_buffer *view, int flags) +{ + XxoObject *self = XxoObject_CAST(op); + int res = PyBuffer_FillInfo(view, op, + (void *)self->x_buffer, BUFSIZE, + 0, flags); + if (res == 0) { + self->x_exports++; + } + return res; +} + +static void +Xxo_releasebuffer(PyObject *op, Py_buffer *Py_UNUSED(view)) +{ + XxoObject *self = XxoObject_CAST(op); + self->x_exports--; +} + +static PyObject * +Xxo_get_x_exports(PyObject *op, void *Py_UNUSED(closure)) +{ + XxoObject *self = XxoObject_CAST(op); + return PyLong_FromSsize_t(self->x_exports); +} + +/* Xxo type definition */ + +PyDoc_STRVAR(Xxo_doc, + "A class that explicitly stores attributes in an internal dict"); + +static PyGetSetDef Xxo_getsetlist[] = { + {"x_exports", Xxo_get_x_exports, NULL, NULL}, + {NULL}, +}; + + +static PyType_Slot Xxo_Type_slots[] = { + {Py_tp_doc, (char *)Xxo_doc}, + {Py_tp_traverse, Xxo_traverse}, + {Py_tp_clear, Xxo_clear}, + {Py_tp_finalize, Xxo_finalize}, + {Py_tp_dealloc, Xxo_dealloc}, + {Py_tp_getattro, Xxo_getattro}, + {Py_tp_setattro, Xxo_setattro}, + {Py_tp_methods, Xxo_methods}, + {Py_bf_getbuffer, Xxo_getbuffer}, + {Py_bf_releasebuffer, Xxo_releasebuffer}, + {Py_tp_getset, Xxo_getsetlist}, + {0, 0}, /* sentinel */ +}; + +static PyType_Spec Xxo_Type_spec = { + .name = "xxlimited_3_13.Xxo", + .basicsize = sizeof(XxoObject), + .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, + .slots = Xxo_Type_slots, +}; + + +/* Str type definition*/ + +static PyType_Slot Str_Type_slots[] = { + // slots array intentionally kept empty + {0, 0}, /* sentinel */ +}; + +static PyType_Spec Str_Type_spec = { + .name = "xxlimited_3_13.Str", + .basicsize = 0, + .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + .slots = Str_Type_slots, +}; + + +/* Function of two integers returning integer (with C "long int" arithmetic) */ + +PyDoc_STRVAR(xx_foo_doc, +"foo(i,j)\n\ +\n\ +Return the sum of i and j."); + +static PyObject * +xx_foo(PyObject *module, PyObject *args) +{ + long i, j; + long res; + if (!PyArg_ParseTuple(args, "ll:foo", &i, &j)) + return NULL; + res = i+j; /* XXX Do something here */ + return PyLong_FromLong(res); +} + + +/* Function of no arguments returning new Xxo object */ + +static PyObject * +xx_new(PyObject *module, PyObject *Py_UNUSED(unused)) +{ + XxoObject *rv; + + rv = newXxoObject(module); + if (rv == NULL) + return NULL; + return (PyObject *)rv; +} + + + +/* List of functions defined in the module */ + +static PyMethodDef xx_methods[] = { + {"foo", xx_foo, METH_VARARGS, + xx_foo_doc}, + {"new", xx_new, METH_NOARGS, + PyDoc_STR("new() -> new Xx object")}, + {NULL, NULL} /* sentinel */ +}; + + +/* The module itself */ + +PyDoc_STRVAR(module_doc, +"This is a template module just for instruction."); + +static int +xx_modexec(PyObject *m) +{ + xx_state *state = PyModule_GetState(m); + + state->Error_Type = PyErr_NewException("xxlimited_3_13.Error", NULL, NULL); + if (state->Error_Type == NULL) { + return -1; + } + if (PyModule_AddType(m, (PyTypeObject*)state->Error_Type) < 0) { + return -1; + } + + state->Xxo_Type = PyType_FromModuleAndSpec(m, &Xxo_Type_spec, NULL); + if (state->Xxo_Type == NULL) { + return -1; + } + if (PyModule_AddType(m, (PyTypeObject*)state->Xxo_Type) < 0) { + return -1; + } + + // Add the Str type. It is not needed from C code, so it is only + // added to the module dict. + // It does not inherit from "object" (PyObject_Type), but from "str" + // (PyUnincode_Type). + PyObject *Str_Type = PyType_FromModuleAndSpec( + m, &Str_Type_spec, (PyObject *)&PyUnicode_Type); + if (Str_Type == NULL) { + return -1; + } + if (PyModule_AddType(m, (PyTypeObject*)Str_Type) < 0) { + return -1; + } + Py_DECREF(Str_Type); + + return 0; +} + +static PyModuleDef_Slot xx_slots[] = { + + /* exec function to initialize the module (called as part of import + * after the object was added to sys.modules) + */ + {Py_mod_exec, xx_modexec}, + + /* Signal that this module supports being loaded in multiple interpreters + * with separate GILs (global interpreter locks). + * See "Isolating Extension Modules" on how to prepare a module for this: + * https://docs.python.org/3/howto/isolating-extensions.html + */ + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + + /* Signal that this module does not rely on the GIL for its own needs. + * Without this slot, free-threaded builds of CPython will enable + * the GIL when this module is loaded. + */ + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, + + {0, NULL} +}; + +// Module finalization: modules that hold references in their module state +// need to implement the fullowing GC hooks. They're similar to the ones for +// types (see "Xxo finalization"). + +static int +xx_traverse(PyObject *module, visitproc visit, void *arg) +{ + xx_state *state = PyModule_GetState(module); + Py_VISIT(state->Xxo_Type); + Py_VISIT(state->Error_Type); + return 0; +} + +static int +xx_clear(PyObject *module) +{ + xx_state *state = PyModule_GetState(module); + Py_CLEAR(state->Xxo_Type); + Py_CLEAR(state->Error_Type); + return 0; +} + +static void +xx_free(void *module) +{ + // allow xx_modexec to omit calling xx_clear on error + (void)xx_clear((PyObject *)module); +} + +static struct PyModuleDef xxmodule = { + PyModuleDef_HEAD_INIT, + .m_name = "xxlimited_3_13", + .m_doc = module_doc, + .m_size = sizeof(xx_state), + .m_methods = xx_methods, + .m_slots = xx_slots, + .m_traverse = xx_traverse, + .m_clear = xx_clear, + .m_free = xx_free, +}; + + +/* Export function for the module. *Must* be called PyInit_xx; usually it is + * the only non-`static` object in a module definition. + */ + +PyMODINIT_FUNC +PyInit_xxlimited_3_13(void) +{ + return PyModuleDef_Init(&xxmodule); +} diff --git a/PC/layout/main.py b/PC/layout/main.py index 3566b8bd873874..3a62ea91420c9e 100644 --- a/PC/layout/main.py +++ b/PC/layout/main.py @@ -32,7 +32,8 @@ from .support.pymanager import * from .support.nuspec import * -TEST_PYDS_ONLY = FileStemSet("xxlimited", "xxlimited_35", "_ctypes_test", "_test*") +TEST_PYDS_ONLY = FileStemSet("xxlimited", "xxlimited_3_13", "xxlimited_35", + "_ctypes_test", "_test*") TEST_DLLS_ONLY = set() TEST_DIRS_ONLY = FileNameSet("test", "tests") diff --git a/PCbuild/pcbuild.proj b/PCbuild/pcbuild.proj index bb7d8042176d8f..9d077bbd3f0ba2 100644 --- a/PCbuild/pcbuild.proj +++ b/PCbuild/pcbuild.proj @@ -84,6 +84,7 @@ + false diff --git a/PCbuild/readme.txt b/PCbuild/readme.txt index c291b7f86325f2..14aac0b0dc84b6 100644 --- a/PCbuild/readme.txt +++ b/PCbuild/readme.txt @@ -168,8 +168,9 @@ xxlimited builds an example module that makes use of the PEP 384 Stable ABI, see Modules\xxlimited.c xxlimited_35 - ditto for testing the Python 3.5 stable ABI, see - Modules\xxlimited_35.c +xxlimited_3_13 + ditto for testing older Limited API, see + Modules\xxlimited_*.c The following sub-projects are for individual modules of the standard library which are implemented in C; each one builds a DLL (renamed to diff --git a/PCbuild/xxlimited_3_13.vcxproj b/PCbuild/xxlimited_3_13.vcxproj new file mode 100644 index 00000000000000..7a9760fd43121e --- /dev/null +++ b/PCbuild/xxlimited_3_13.vcxproj @@ -0,0 +1,111 @@ + + + + + Debug + ARM + + + Debug + ARM64 + + + Debug + Win32 + + + Debug + x64 + + + PGInstrument + ARM + + + PGInstrument + ARM64 + + + PGInstrument + Win32 + + + PGInstrument + x64 + + + PGUpdate + ARM + + + PGUpdate + ARM64 + + + PGUpdate + Win32 + + + PGUpdate + x64 + + + Release + ARM + + + Release + ARM64 + + + Release + Win32 + + + Release + x64 + + + + {fb868ea7-f93a-4d9b-be78-ca4e9ba14fff} + xxlimited_3_13 + Win32Proj + + + + + DynamicLibrary + NotSet + false + + + + $(PyStdlibPydExt) + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + + + + wsock32.lib;%(AdditionalDependencies) + + + + + + + + {885d4898-d08d-4091-9c40-c700cfe3fc5a} + + + + + + diff --git a/PCbuild/xxlimited_3_13.vcxproj.filters b/PCbuild/xxlimited_3_13.vcxproj.filters new file mode 100644 index 00000000000000..3dfb7800edc441 --- /dev/null +++ b/PCbuild/xxlimited_3_13.vcxproj.filters @@ -0,0 +1,13 @@ + + + + + {5be27194-6530-452d-8d86-3767b991fa83} + + + + + Source Files + + + diff --git a/Tools/build/generate_stdlib_module_names.py b/Tools/build/generate_stdlib_module_names.py index bda72539640611..f8828a56b4c7da 100644 --- a/Tools/build/generate_stdlib_module_names.py +++ b/Tools/build/generate_stdlib_module_names.py @@ -42,6 +42,7 @@ 'test', 'xxlimited', 'xxlimited_35', + 'xxlimited_3_13', 'xxsubtype', } diff --git a/Tools/c-analyzer/c_parser/preprocessor/gcc.py b/Tools/c-analyzer/c_parser/preprocessor/gcc.py index 4a55a1a24ee1be..92134bc1321e1b 100644 --- a/Tools/c-analyzer/c_parser/preprocessor/gcc.py +++ b/Tools/c-analyzer/c_parser/preprocessor/gcc.py @@ -11,6 +11,7 @@ '_testclinic_limited.c', 'xxlimited.c', 'xxlimited_35.c', + 'xxlimited_3_13.c', )) # C files in the fhe following directories must not be built with diff --git a/Tools/c-analyzer/cpython/_analyzer.py b/Tools/c-analyzer/cpython/_analyzer.py index 43ed552fcf75d9..404a81af11e39f 100644 --- a/Tools/c-analyzer/cpython/_analyzer.py +++ b/Tools/c-analyzer/cpython/_analyzer.py @@ -77,6 +77,7 @@ 'PyStructSequence_Field[]', 'PyStructSequence_Desc', 'PyABIInfo', + 'PySlot[]', } # XXX We should normalize all cases to a single name, diff --git a/configure b/configure index e9672d74c52a36..8979ec294bcdf0 100755 --- a/configure +++ b/configure @@ -647,6 +647,8 @@ MODULE_BLOCK JIT_SHIM_BUILD_O JIT_SHIM_O JIT_STENCILS_H +MODULE_XXLIMITED_3_13_FALSE +MODULE_XXLIMITED_3_13_TRUE MODULE_XXLIMITED_35_FALSE MODULE_XXLIMITED_35_TRUE MODULE_XXLIMITED_FALSE @@ -31944,6 +31946,7 @@ case $ac_sys_system in #( py_cv_module_termios=n/a py_cv_module_xxlimited=n/a py_cv_module_xxlimited_35=n/a + py_cv_module_xxlimited_3_13=n/a py_cv_module_=n/a ;; #( @@ -35005,6 +35008,46 @@ fi printf "%s\n" "$py_cv_module_xxlimited_35" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module xxlimited_3_13" >&5 +printf %s "checking for stdlib extension module xxlimited_3_13... " >&6; } + if test "$py_cv_module_xxlimited_3_13" != "n/a" +then : + + if test "$TEST_MODULES" = yes +then : + if test "$ac_cv_func_dlopen" = yes +then : + py_cv_module_xxlimited_3_13=yes +else case e in #( + e) py_cv_module_xxlimited_3_13=missing ;; +esac +fi +else case e in #( + e) py_cv_module_xxlimited_3_13=disabled ;; +esac +fi + +fi + as_fn_append MODULE_BLOCK "MODULE_XXLIMITED_3_13_STATE=$py_cv_module_xxlimited_3_13$as_nl" + if test "x$py_cv_module_xxlimited_3_13" = xyes +then : + + + + +fi + if test "$py_cv_module_xxlimited_3_13" = yes; then + MODULE_XXLIMITED_3_13_TRUE= + MODULE_XXLIMITED_3_13_FALSE='#' +else + MODULE_XXLIMITED_3_13_TRUE='#' + MODULE_XXLIMITED_3_13_FALSE= +fi + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $py_cv_module_xxlimited_3_13" >&5 +printf "%s\n" "$py_cv_module_xxlimited_3_13" >&6; } + + # Determine JIT stencils header files based on target platform JIT_STENCILS_H="" JIT_SHIM_O="" @@ -35518,6 +35561,10 @@ if test -z "${MODULE_XXLIMITED_35_TRUE}" && test -z "${MODULE_XXLIMITED_35_FALSE as_fn_error $? "conditional \"MODULE_XXLIMITED_35\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi +if test -z "${MODULE_XXLIMITED_3_13_TRUE}" && test -z "${MODULE_XXLIMITED_3_13_FALSE}"; then + as_fn_error $? "conditional \"MODULE_XXLIMITED_3_13\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi : "${CONFIG_STATUS=./config.status}" ac_write_fail=0 diff --git a/configure.ac b/configure.ac index 7f97db73ad807d..842e010f20cb74 100644 --- a/configure.ac +++ b/configure.ac @@ -8047,6 +8047,7 @@ AS_CASE([$ac_sys_system], [termios], [xxlimited], [xxlimited_35], + [xxlimited_3_13], ) ], [PY_STDLIB_MOD_SET_NA([_scproxy])] @@ -8438,6 +8439,7 @@ dnl Limited API template modules. dnl Emscripten does not support shared libraries yet. PY_STDLIB_MOD([xxlimited], [test "$TEST_MODULES" = yes], [test "$ac_cv_func_dlopen" = yes]) PY_STDLIB_MOD([xxlimited_35], [test "$TEST_MODULES" = yes], [test "$ac_cv_func_dlopen" = yes]) +PY_STDLIB_MOD([xxlimited_3_13], [test "$TEST_MODULES" = yes], [test "$ac_cv_func_dlopen" = yes]) # Determine JIT stencils header files based on target platform JIT_STENCILS_H="" From 45fc9acb8cffd4009aedb8fdf2fce2add89f38bb Mon Sep 17 00:00:00 2001 From: Barry Warsaw Date: Wed, 13 May 2026 15:45:39 -0700 Subject: [PATCH 051/818] [3.15] gh-149504: Fix re-entrancy bug when .pth/.start file invokes site.add sitedir() (#149659) (#149799) * gh-149504: Fix re-entrancy bug when .pth/.start file invokes site.addsitedir() (#149659) * Add re-entrant tests for gh-149504 * Add end-to-end integration test coverage This ensures that future whitebox internal test changes do not regress the public surface semantics. * Implement a state class to process .pth and .start files By using this state class and managing implicit and explicit batching, we make it structurally impossible to get bitten by re-entrant site startup processing. Fixes #149504 (cherry picked from commit b162307d7f216e87976d76c9b8f4a932961cb2d4) * Add myself back to CODEOWNERS --- .github/CODEOWNERS | 6 +- Lib/site.py | 500 ++++++++----- Lib/test/test_site.py | 665 +++++++++++------- ...-05-10-23-51-23.gh-issue-149504.pDSCbn.rst | 5 + 4 files changed, 753 insertions(+), 423 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-05-10-23-51-23.gh-issue-149504.pDSCbn.rst diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index b4b3b1013e3095..bdf134254121e5 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -573,9 +573,9 @@ Lib/shutil.py @giampaolo Lib/test/test_shutil.py @giampaolo # Site -Lib/site.py @FFY00 -Lib/test/test_site.py @FFY00 -Doc/library/site.rst @FFY00 +Lib/site.py @FFY00 @warsaw +Lib/test/test_site.py @FFY00 @warsaw +Doc/library/site.rst @FFY00 @warsaw # string.templatelib Doc/library/string.templatelib.rst @lysnikolaou @AA-Turner diff --git a/Lib/site.py b/Lib/site.py index 52dd9648734c3e..64e8192a9ac81a 100644 --- a/Lib/site.py +++ b/Lib/site.py @@ -154,13 +154,37 @@ def _init_pathinfo(): return d -# Accumulated entry points from .start files across all site-packages -# directories. Execution is deferred until all paths in .pth files have been -# appended to sys.path. Map the .pth/.start file the data is found in to the -# data. -_pending_entrypoints = {} -_pending_syspaths = {} -_pending_importexecs = {} +# PEP 829 implementation notes. +# +# Startup information (.pth and .start file information) can be processed in +# implicit or explicit batches. Implicit batches are handled by the site.py +# machinery automatically, while explicit batches are driven by user code and +# processed on boundaries defined by that code. +# +# addsitedir() calls which use the default defer_processing_start_files=False +# are self-contained: they create a per-call _StartupState, populate it from +# the site directory's .pth/.start files, run process() on it, and then throw +# the state away. This is implicit batching and in that case the +# _startup_state global variable stays None. +# +# main() needs different semantics: it accumulates state across multiple +# addsitedir() calls (user-site plus all global site-packages) so that +# every sys.path extension is visible *before* any startup code (.pth +# import lines and .start entry points) runs. Callers opt into this by +# passing defer_processing_start_files=True, which preserves the _StartupState +# into the global _startup_state. Subsequent addsitedir() calls (with +# or without defer_processing_start_files=True) then write into that +# same shared state, and a later process_startup_files() call flushes +# all the state and resets the global to None. +# +# Here's the CRITICAL reentrancy invariant: process_startup_files() must clear +# the global _startup_state *before* calling state.process(), so that any +# reentrant site.addsitedir() calls reached from an exec'd .pth import line or +# a .start entry point falls into the per-call branch and gets its own fresh +# state. Otherwise the recursive addsitedir() would mutate the very dicts +# that the outer state.process() is iterating. This is the bug reported in +# gh-149504. +_startup_state = None def _read_pthstart_file(sitedir, name, suffix): @@ -194,13 +218,13 @@ def _read_pthstart_file(sitedir, name, suffix): return None, filename try: - # Accept BOM markers in .start and .pth files as we do in source files (Windows PowerShell - # 5.1 makes it hard to emit UTF-8 files without a BOM). + # Accept BOM markers in .start and .pth files as we do in source files + # (Windows PowerShell 5.1 makes it hard to emit UTF-8 files without a BOM). content = raw_content.decode("utf-8-sig") except UnicodeDecodeError: _trace(f"Cannot read {filename!r} as UTF-8.") - # For .pth files only, and then only until Python 3.20, fallback to locale encoding for - # backward compatibility. + # For .pth files only, and then only until Python 3.20, fall back to + # locale encoding for backward compatibility. _warn_future_us( ".pth files decoded to locale encoding as a fallback", remove=(3, 20) @@ -214,153 +238,221 @@ def _read_pthstart_file(sitedir, name, suffix): return content.splitlines(), filename -def _read_pth_file(sitedir, name, known_paths): - """Parse a .pth file, accumulating sys.path extensions and import lines. - - Errors on individual lines do not abort processing of the rest of the - file (PEP 829). - """ - lines, filename = _read_pthstart_file(sitedir, name, ".pth") - if lines is None: - return - - for n, line in enumerate(lines, 1): - line = line.strip() - if not line or line.startswith("#"): - continue - - # In Python 3.18 and 3.19, `import` lines are silently ignored. In - # Python 3.20 and beyond, issue a warning when `import` lines in .pth - # files are detected. - if line.startswith(("import ", "import\t")): - _warn_future_us( - "import lines in .pth files are silently ignored", - remove=(3, 18) - ) - _warn_future_us( - "import lines in .pth files are noisily ignored", - remove=(3, 20) - ) - _pending_importexecs.setdefault(filename, []).append(line) - continue - - try: - dir_, dircase = makepath(sitedir, line) - except Exception as exc: - _trace(f"Error in {filename!r}, line {n:d}: {line!r}", exc) - continue - - if dircase in known_paths: - _trace(f"In {filename!r}, line {n:d}: " - f"skipping duplicate sys.path entry: {dir_}") - else: - _pending_syspaths.setdefault(filename, []).append(dir_) - known_paths.add(dircase) - +class _StartupState: + """Per-batch accumulator for .pth and .start file processing. -def _read_start_file(sitedir, name): - """Parse a .start file for a list of entry point strings.""" - lines, filename = _read_pthstart_file(sitedir, name, ".start") - if lines is None: - return + A _StartupState collects sys.path extensions, deprecated .pth import + lines, and .start entry points read from one or more site-packages + directories. Calling process() applies them in PEP 829 order: paths + are added to sys.path first, then import lines from .pth files (skipping + any with a matching .start), then entry points from .start files. - # PEP 829: the *presence* of a matching .start file disables `import` - # line processing in the matched .pth file, regardless of whether the - # .start file produced any entry points. Register the filename as a - # key now so an empty (or comment-only) .start file still suppresses. - entrypoints = _pending_entrypoints.setdefault(filename, []) + State lives entirely on the instance; there is no module-level pending + state. This is what makes the module reentrancy-safe: a site.addsitedir() + call reached recursively from an exec'd import line or a .start entry + point operates on a different _StartupState than the one being processed + by the outer call. - for n, line in enumerate(lines, 1): - line = line.strip() - if not line or line.startswith("#"): - continue - # Syntax validation is deferred to entry-point execution time, - # where pkgutil.resolve_name(strict=True) enforces the - # pkg.mod:callable form. - entrypoints.append(line) - - -def _extend_syspath(): - # We've already filtered out duplicates, either in the existing sys.path - # or in all the .pth files we've seen. We've also abspath/normpath'd all - # the entries, so all that's left to do is to ensure that the path exists. - for filename, dirs in _pending_syspaths.items(): - for dir_ in dirs: - if os.path.exists(dir_): - _trace(f"Extending sys.path with {dir_} from {filename}") - sys.path.append(dir_) - else: - _print_error( - f"In {filename}: {dir_} does not exist; " - f"skipping sys.path append") - - -def _exec_imports(): - # For all the `import` lines we've seen in .pth files, exec() them in - # order. However, if they come from a file with a matching .start, then - # we ignore these import lines. For the ones we do process, print a - # warning but only when -v was given. - for filename, imports in _pending_importexecs.items(): - name, dot, pth = filename.rpartition(".") - assert dot == "." and pth == "pth", f"Bad startup filename: {filename}" - - if f"{name}.start" in _pending_entrypoints: - # Skip import lines in favor of entry points. - continue + The internal data is intentionally private; the public methods + (read_pth_file, read_start_file, process) are the only supported write + APIs. + """ + __slots__ = ('_syspaths', '_importexecs', '_entrypoints') + + def __init__(self): + # All three dicts map "" -> list + # of items collected from that file. Mapping by filename lets us + # cross-reference a .pth and its matching .start (PEP 829 import + # suppression rule) and lets _print_error report the source file + # when an entry fails. + self._syspaths = {} + self._importexecs = {} + self._entrypoints = {} + + def read_pth_file(self, sitedir, name, known_paths): + """Parse a .pth file, accumulating sys.path extensions and import lines. + + Errors on individual lines do not abort processing of the rest of + the file (PEP 829). ``known_paths`` is the per-batch dedup + ledger: any path already in it is skipped, and newly accepted + paths are added to it so that subsequent .pth files in the same + batch don't add them more than once. + """ + lines, filename = _read_pthstart_file(sitedir, name, ".pth") + if lines is None: + return + + for n, line in enumerate(lines, 1): + line = line.strip() + if not line or line.startswith("#"): + continue - _trace( - f"import lines in {filename} are deprecated, " - f"use entry points in a {name}.start file instead." - ) + # In Python 3.18 and 3.19, `import` lines are silently + # ignored. In Python 3.20 and beyond, issue a warning when + # `import` lines in .pth files are detected. + if line.startswith(("import ", "import\t")): + _warn_future_us( + "import lines in .pth files are silently ignored", + remove=(3, 18), + ) + _warn_future_us( + "import lines in .pth files are noisily ignored", + remove=(3, 20), + ) + self._importexecs.setdefault(filename, []).append(line) + continue - for line in imports: try: - _trace(f"Exec'ing from {filename}: {line}") - exec(line) + dir_, dircase = makepath(sitedir, line) except Exception as exc: - _print_error( - f"Error in import line from {filename}: {line}", exc) - - -def _execute_start_entrypoints(): - """Execute all accumulated .start file entry points. + _trace(f"Error in {filename!r}, line {n:d}: {line!r}", exc) + continue - Called after all site-packages directories have been processed so that - sys.path is fully populated before any entry point code runs. Uses - pkgutil.resolve_name(strict=True) which both validates the strict - pkg.mod:callable form and resolves the entry point in one step. - """ - for filename, entrypoints in _pending_entrypoints.items(): - for entrypoint in entrypoints: - try: - _trace(f"Executing entry point: {entrypoint} from {filename}") - callable_ = pkgutil.resolve_name(entrypoint, strict=True) - except ValueError as exc: - _print_error( - f"Invalid entry point syntax in {filename}: " - f"{entrypoint!r}", exc) + # PEP 829 dedup: skip paths already seen in this batch. See + # _startup_state docstring above for batch lifetimes. + if dircase in known_paths: + _trace( + f"In {filename!r}, line {n:d}: " + f"skipping duplicate sys.path entry: {dir_}" + ) + else: + self._syspaths.setdefault(filename, []).append(dir_) + known_paths.add(dircase) + + def read_start_file(self, sitedir, name): + """Parse a .start file for a list of entry point strings.""" + lines, filename = _read_pthstart_file(sitedir, name, ".start") + if lines is None: + return + + # PEP 829: the *presence* of a matching .start file disables `import` + # line processing in the matched .pth file, regardless of whether this + # .start file contains any entry points. Register the filename as a + # key now so an empty (or comment-only) .start file still suppresses. + entrypoints = self._entrypoints.setdefault(filename, []) + + for n, line in enumerate(lines, 1): + line = line.strip() + if not line or line.startswith("#"): continue - except Exception as exc: - _print_error( - f"Error resolving entry point {entrypoint} " - f"from {filename}", exc) + # Syntax validation is deferred to entry point execution + # time, where pkgutil.resolve_name(strict=True) enforces the + # pkg.mod:callable form. + entrypoints.append(line) + + def process(self): + """Apply accumulated state in PEP 829 order. + + Phase order matters: all .pth path extensions are applied to + sys.path *before* any import line or .start entry point runs, so + that an entry point may live in a module reachable only via a + .pth-extended path. + """ + self._extend_syspath() + self._exec_imports() + self._execute_start_entrypoints() + + def _extend_syspath(self): + # Duplicates have already been filtered (in existing sys.path or + # across .pth files via known_paths), and entries are already + # abspath/normpath'd, so all that remains is to confirm the path + # exists. + for filename, dirs in self._syspaths.items(): + for dir_ in dirs: + if os.path.exists(dir_): + _trace(f"Extending sys.path with {dir_} from {filename}") + sys.path.append(dir_) + else: + _print_error( + f"In {filename}: {dir_} does not exist; " + f"skipping sys.path append" + ) + + def _exec_imports(self): + # For each `import` line we've seen in a .pth file, exec() it in + # order, unless the .pth has a matching .start file in this same + # batch. In that case, PEP 829 says the import lines are + # suppressed in favor of the .start's entry points. + for filename, imports in self._importexecs.items(): + # Given "/path/to/foo.pth", check whether "/path/to/foo.start" was + # registered in this same batch. + name, dot, pth = filename.rpartition(".") + assert dot == "." and pth == "pth", ( + f"Bad startup filename: {filename}" + ) + if f"{name}.start" in self._entrypoints: + _trace( + f"import lines in {filename} are suppressed " + f"due to matching {name}.start file." + ) continue - try: - callable_() - except Exception as exc: - _print_error( - f"Error in entry point {entrypoint} from {filename}", - exc) + + _trace( + f"import lines in {filename} are deprecated, " + f"use entry points in a {name}.start file instead." + ) + for line in imports: + try: + _trace(f"Exec'ing from {filename}: {line}") + exec(line) + except Exception as exc: + _print_error( + f"Error in import line from {filename}: {line}", + exc, + ) + + def _execute_start_entrypoints(self): + # Resolve each entry point string to a callable via + # pkgutil.resolve_name(strict=True), which both validates the + # required pkg.mod:callable form and performs the import in one + # step, then call it with no arguments. + for filename, entrypoints in self._entrypoints.items(): + for entrypoint in entrypoints: + try: + _trace( + f"Executing entry point: {entrypoint} from {filename}" + ) + callable_ = pkgutil.resolve_name(entrypoint, strict=True) + except ValueError as exc: + _print_error( + f"Invalid entry point syntax in {filename}: " + f"{entrypoint!r}", + exc, + ) + except Exception as exc: + _print_error( + f"Error resolving entry point {entrypoint} " + f"from {filename}", + exc, + ) + else: + try: + callable_() + except Exception as exc: + _print_error( + f"Error in entry point {entrypoint} from {filename}", + exc, + ) def process_startup_files(): - """Flush all pending sys.path and entry points.""" - _extend_syspath() - _exec_imports() - _execute_start_entrypoints() - _pending_syspaths.clear() - _pending_importexecs.clear() - _pending_entrypoints.clear() + """Flush any pending startup-file state accumulated during a batch. + + Used by main() (and any external caller that drove addsitedir() with + defer_processing_start_files=True) to apply the accumulated paths + and run the deferred import lines / entry points. + + Reentrancy: the active batch state is detached from _startup_state + *before* state.process() runs. This way, if an exec'd import line + or .start entry point itself calls site.addsitedir(), that call + creates its own per-call _StartupState rather than mutating the dicts + being iterated here. See gh-149504. + """ + global _startup_state + if _startup_state is None: + return + state, _startup_state = _startup_state, None + state.process() def addpackage(sitedir, name, known_paths): @@ -370,16 +462,26 @@ def addpackage(sitedir, name, known_paths): reset = True else: reset = False - _read_pth_file(sitedir, name, known_paths) - process_startup_files() - if reset: - known_paths = None - return known_paths + + # If a batch is already in progress (for example, main() is still + # accumulating sitedirs), participate in the batch by writing into the + # shared _startup_state and letting the eventual process_startup_files() + # flush it. Otherwise this is a standalone call, so create a unique + # per-call state, populate it, and process it before returning. + if _startup_state is None: + state = _StartupState() + state.read_pth_file(sitedir, name, known_paths) + state.process() + else: + _startup_state.read_pth_file(sitedir, name, known_paths) + + return None if reset else known_paths def addsitedir(sitedir, known_paths=None, *, defer_processing_start_files=False): """Add 'sitedir' argument to sys.path if missing and handle startup files.""" + global _startup_state _trace(f"Adding directory: {sitedir!r}") if known_paths is None: known_paths = _init_pathinfo() @@ -387,44 +489,74 @@ def addsitedir(sitedir, known_paths=None, *, defer_processing_start_files=False) else: reset = False sitedir, sitedircase = makepath(sitedir) - if not sitedircase in known_paths: - sys.path.append(sitedir) # Add path component - known_paths.add(sitedircase) - try: - names = os.listdir(sitedir) - except OSError: - return - # The following phases are defined by PEP 829. - # Phases 1-3: Read .pth files, accumulating paths and import lines. - pth_names = sorted( - name for name in names - if name.endswith(".pth") and not name.startswith(".") - ) - for name in pth_names: - _read_pth_file(sitedir, name, known_paths) - - # Phases 6-7: Discover .start files and accumulate their entry points. - # Import lines from .pth files with a matching .start file are discarded - # at flush time by _exec_imports(). - start_names = sorted( - name for name in names - if name.endswith(".start") and not name.startswith(".") - ) - for name in start_names: - _read_start_file(sitedir, name) + # If the normcase'd new sitedir isn't already known, append it to + # sys.path, keep a record of it, and process all .pth and .start files + # found in that directory. If the new sitedir is known, be sure not + # to process all of those more than once! gh-75723 + if sitedircase not in known_paths: + sys.path.append(sitedir) + known_paths.add(sitedircase) - # Generally, when addsitedir() is called explicitly, we'll want to process - # all the startup file data immediately. However, when called through - # main(), we'll want to batch up all the startup file processing. main() - # will set this flag to True to defer processing. - if not defer_processing_start_files: - process_startup_files() + try: + names = os.listdir(sitedir) + except OSError: + return None if reset else known_paths + + # Pick the _StartupState we'll write into. There are three cases: + # + # 1. A batch is already active (_startup_state is set, e.g. because + # main() previously called us with + # defer_processing_start_files=True). Participate in this batch by + # sharing the same state. Don't flush the state since the batch's + # eventual process_startup_files() will do that. + # + # 2. There is no active batch but the caller passed + # defer_processing_start_files=True. Preserve a fresh + # _StartupState into the global _startup_state so that subsequent + # addsitedir() calls participate in this batch, and so that the + # caller's later process_startup_files() finds it. + # + # 3. This is a standalone call (there is no active batch and + # defer_processing_start_files=False). Create a unique per-call + # state, populate it, process it, and then clear it. Per-call + # state is what makes reentrant addsitedir() safe; a recursive call + # from inside process() lands here too and gets its own independent + # state. + + if _startup_state is not None: + state = _startup_state + flush_now = False + elif defer_processing_start_files: + state = _startup_state = _StartupState() + flush_now = False + else: + state = _StartupState() + flush_now = True + + # The following phases are defined by PEP 829. + # Phases 1-3: Read .pth files, accumulating paths and import lines. + pth_names = sorted( + name for name in names + if name.endswith(".pth") and not name.startswith(".") + ) + for name in pth_names: + state.read_pth_file(sitedir, name, known_paths) + + # Phases 6-7: Discover .start files and accumulate their entry points. + # Import lines from .pth files with a matching .start file are + # discarded at flush time by _StartupState._exec_imports(). + start_names = sorted( + name for name in names + if name.endswith(".start") and not name.startswith(".") + ) + for name in start_names: + state.read_start_file(sitedir, name) - if reset: - known_paths = None + if flush_now: + state.process() - return known_paths + return None if reset else known_paths def check_enableusersite(): diff --git a/Lib/test/test_site.py b/Lib/test/test_site.py index ac69e2cbdbbe54..0e6f352f49cd38 100644 --- a/Lib/test/test_site.py +++ b/Lib/test/test_site.py @@ -196,8 +196,9 @@ def test_addsitedir_explicit_flush(self): pth_file.cleanup(prep=True) with pth_file.create(): # Pass defer_processing_start_files=True to prevent flushing. - site.addsitedir(pth_file.base_dir, set(), - defer_processing_start_files=True) + site.addsitedir( + pth_file.base_dir, set(), + defer_processing_start_files=True) self.assertNotIn(pth_file.imported, sys.modules) site.process_startup_files() self.pth_file_tests(pth_file) @@ -423,15 +424,14 @@ def create(self): Used as a context manager: self.cleanup() is called on exit. """ - FILE = open(self.file_path, 'w') - try: - print("#import @bad module name", file=FILE) - print("\n", file=FILE) - print("import %s" % self.imported, file=FILE) - print(self.good_dirname, file=FILE) - print(self.bad_dirname, file=FILE) - finally: - FILE.close() + with open(self.file_path, 'w') as fp: + print(f"""\ +#import @bad module name +import {self.imported} +{self.good_dirname} +{self.bad_dirname} +""", file=fp) + os.mkdir(self.good_dir_path) try: yield self @@ -915,18 +915,16 @@ class StartFileTests(unittest.TestCase): def setUp(self): self.enterContext(import_helper.DirsOnSysPath()) self.tmpdir = self.sitedir = self.enterContext(os_helper.temp_dir()) - # Save and clear all pending dicts. - self.saved_entrypoints = site._pending_entrypoints.copy() - self.saved_syspaths = site._pending_syspaths.copy() - self.saved_importexecs = site._pending_importexecs.copy() - site._pending_entrypoints.clear() - site._pending_syspaths.clear() - site._pending_importexecs.clear() + # Each test gets its own _StartupState to drive the parser and + # processor methods directly. Defensively clear any _startup_state + # that a prior test may have left set via defer_processing_start_files + # without a corresponding process_startup_files() flush. + self.state = site._StartupState() + site._startup_state = None + self.addCleanup(self._reset_startup_state) - def tearDown(self): - site._pending_entrypoints = self.saved_entrypoints.copy() - site._pending_syspaths = self.saved_syspaths.copy() - site._pending_importexecs = self.saved_importexecs.copy() + def _reset_startup_state(self): + site._startup_state = None def _make_start(self, content, name='testpkg'): """Write a .start file and return its basename.""" @@ -944,10 +942,32 @@ def _make_pth(self, content, name='testpkg'): f.write(content) return basename + def _make_mod(self, contents, name='mod', *, package=False, on_path=False): + """Write an importable module (or package), returning its parent dir.""" + extdir = os.path.join(self.sitedir, 'extdir') + os.makedirs(extdir, exist_ok=True) + + # Put the code in a package's dunder-init or flat module. + if package: + pkgdir = os.path.join(extdir, name) + os.mkdir(pkgdir) + modpath = os.path.join(pkgdir, '__init__.py') + else: + modpath = os.path.join(extdir, f'{name}.py') + + with open(modpath, 'w') as fp: + fp.write(contents) + + self.addCleanup(sys.modules.pop, name, None) + if on_path: + # Don't worry, DirsOnSysPath() in setUp() will clean this up. + sys.path.insert(0, extdir) + return extdir + def _all_entrypoints(self): - """Flatten _pending_entrypoints dict into a list of (filename, entry) tuples.""" + """Flatten state._entrypoints into a list of (filename, entry) tuples.""" result = [] - for filename, entries in site._pending_entrypoints.items(): + for filename, entries in self.state._entrypoints.items(): for entry in entries: result.append((filename, entry)) return result @@ -955,28 +975,42 @@ def _all_entrypoints(self): def _just_entrypoints(self): return [entry for filename, entry in self._all_entrypoints()] - # --- _read_start_file tests --- + # There are two classes of tests here. Tests that start with `test_impl_` + # know details about the implementation and they access non-public methods + # and data structures to perform focused functional tests. + # + # Tests that start with `test_addsitedir_` are end-to-end tests that ensure + # integration semantics and functionality as a caller of the public + # surfaces would see. + + # --- _StartupState.read_start_file tests --- - def test_read_start_file_basic(self): + def test_impl_read_start_file_basic(self): self._make_start("os.path:join\n", name='foo') - site._read_start_file(self.sitedir, 'foo.start') + self.state.read_start_file(self.sitedir, 'foo.start') fullname = os.path.join(self.sitedir, 'foo.start') - self.assertEqual(site._pending_entrypoints[fullname], ['os.path:join']) + self.assertEqual( + self.state._entrypoints[fullname], ['os.path:join'] + ) - def test_read_start_file_multiple_entries(self): + def test_impl_read_start_file_multiple_entries(self): self._make_start("os.path:join\nos.path:exists\n", name='foo') - site._read_start_file(self.sitedir, 'foo.start') + self.state.read_start_file(self.sitedir, 'foo.start') fullname = os.path.join(self.sitedir, 'foo.start') - self.assertEqual(site._pending_entrypoints[fullname], - ['os.path:join', 'os.path:exists']) + self.assertEqual( + self.state._entrypoints[fullname], + ['os.path:join', 'os.path:exists'], + ) - def test_read_start_file_comments_and_blanks(self): + def test_impl_read_start_file_comments_and_blanks(self): self._make_start("# a comment\n\nos.path:join\n \n", name='foo') - site._read_start_file(self.sitedir, 'foo.start') + self.state.read_start_file(self.sitedir, 'foo.start') fullname = os.path.join(self.sitedir, 'foo.start') - self.assertEqual(site._pending_entrypoints[fullname], ['os.path:join']) + self.assertEqual( + self.state._entrypoints[fullname], ['os.path:join'] + ) - def test_read_start_file_accepts_all_non_blank_lines(self): + def test_impl_read_start_file_accepts_all_non_blank_lines(self): # Syntax validation is deferred to entry-point execution time # (where pkgutil.resolve_name(strict=True) enforces the strict # pkg.mod:callable form), so parsing accepts every non-blank, @@ -989,9 +1023,9 @@ def test_read_start_file_accepts_all_non_blank_lines(self): "os.path:join\n" # valid ) self._make_start(content, name='foo') - site._read_start_file(self.sitedir, 'foo.start') + self.state.read_start_file(self.sitedir, 'foo.start') fullname = os.path.join(self.sitedir, 'foo.start') - self.assertEqual(site._pending_entrypoints[fullname], [ + self.assertEqual(self.state._entrypoints[fullname], [ 'os.path', 'pkg.mod:', ':callable', @@ -999,155 +1033,169 @@ def test_read_start_file_accepts_all_non_blank_lines(self): 'os.path:join', ]) - def test_read_start_file_empty(self): + def test_impl_read_start_file_empty(self): # PEP 829: an empty .start file is still registered as present - # (with an empty entry-point list) so that it suppresses `import` + # (with an empty entry point list) so that it suppresses `import` # lines in any matching .pth file. self._make_start("", name='foo') - site._read_start_file(self.sitedir, 'foo.start') + self.state.read_start_file(self.sitedir, 'foo.start') fullname = os.path.join(self.sitedir, 'foo.start') - self.assertEqual(site._pending_entrypoints, {fullname: []}) + self.assertEqual(self.state._entrypoints, {fullname: []}) - def test_read_start_file_comments_only(self): + def test_impl_read_start_file_comments_only(self): # As with an empty file, a comments-only .start file is registered # as present so it can suppress matching .pth `import` lines. self._make_start("# just a comment\n# another\n", name='foo') - site._read_start_file(self.sitedir, 'foo.start') + self.state.read_start_file(self.sitedir, 'foo.start') fullname = os.path.join(self.sitedir, 'foo.start') - self.assertEqual(site._pending_entrypoints, {fullname: []}) + self.assertEqual(self.state._entrypoints, {fullname: []}) - def test_read_start_file_nonexistent(self): + def test_impl_read_start_file_nonexistent(self): with captured_stderr(): - site._read_start_file(self.tmpdir, 'nonexistent.start') - self.assertEqual(site._pending_entrypoints, {}) + self.state.read_start_file(self.tmpdir, 'nonexistent.start') + self.assertEqual(self.state._entrypoints, {}) @unittest.skipUnless(hasattr(os, 'chflags'), 'test needs os.chflags()') - def test_read_start_file_hidden_flags(self): + def test_impl_read_start_file_hidden_flags(self): self._make_start("os.path:join\n", name='foo') filepath = os.path.join(self.tmpdir, 'foo.start') st = os.stat(filepath) os.chflags(filepath, st.st_flags | stat.UF_HIDDEN) - site._read_start_file(self.sitedir, 'foo.start') - self.assertEqual(site._pending_entrypoints, {}) + self.state.read_start_file(self.sitedir, 'foo.start') + self.assertEqual(self.state._entrypoints, {}) - def test_read_start_file_duplicates_not_deduplicated(self): + def test_impl_one_start_file_with_duplicates_not_deduplicated(self): # PEP 829: duplicate entry points are NOT deduplicated. self._make_start("os.path:join\nos.path:join\n", name='foo') - site._read_start_file(self.sitedir, 'foo.start') + self.state.read_start_file(self.sitedir, 'foo.start') fullname = os.path.join(self.sitedir, 'foo.start') - self.assertEqual(site._pending_entrypoints[fullname], - ['os.path:join', 'os.path:join']) + self.assertEqual( + self.state._entrypoints[fullname], + ['os.path:join', 'os.path:join'], + ) + + def test_impl_two_start_files_with_duplicates_not_deduplicated(self): + self._make_start("os.path:join", name="foo") + self._make_start("os.path:join", name="bar") + self.state.read_start_file(self.sitedir, 'foo.start') + self.state.read_start_file(self.sitedir, 'bar.start') + self.assertEqual( + self._just_entrypoints(), + ['os.path:join', 'os.path:join'], + ) - def test_read_start_file_accepts_utf8_bom(self): + def test_impl_read_start_file_accepts_utf8_bom(self): # PEP 829: .start files MUST be utf-8-sig (UTF-8 with optional BOM). filepath = os.path.join(self.tmpdir, 'foo.start') with open(filepath, 'wb') as f: f.write(b'\xef\xbb\xbf' + b'os.path:join\n') - site._read_start_file(self.sitedir, 'foo.start') + self.state.read_start_file(self.sitedir, 'foo.start') fullname = os.path.join(self.sitedir, 'foo.start') self.assertEqual( - site._pending_entrypoints[fullname], ['os.path:join']) + self.state._entrypoints[fullname], ['os.path:join'] + ) - def test_read_start_file_invalid_utf8_silently_skipped(self): - # PEP 829: .start files MUST be utf-8-sig. Unlike .pth, there is - # no locale-encoding fallback -- a .start file that is not valid + def test_impl_read_start_file_invalid_utf8_silently_skipped(self): + # PEP 829: .start files MUST be utf-8-sig. Unlike .pth files, there + # is no locale-encoding fallback. A .start file that is not valid # UTF-8 is silently skipped, with no key registered in - # _pending_entrypoints and no output to stderr (parsing errors - # are reported only under -v). + # state._entrypoints and no output to stderr (parsing errors are + # reported only under -v). filepath = os.path.join(self.tmpdir, 'foo.start') with open(filepath, 'wb') as f: # Bare continuation byte -- invalid as a UTF-8 start byte. f.write(b'\x80\x80\x80\n') with captured_stderr() as err: - site._read_start_file(self.sitedir, 'foo.start') - self.assertEqual(site._pending_entrypoints, {}) + self.state.read_start_file(self.sitedir, 'foo.start') + self.assertEqual(self.state._entrypoints, {}) self.assertEqual(err.getvalue(), "") - def test_two_start_files_with_duplicates_not_deduplicated(self): - self._make_start("os.path:join", name="foo") - self._make_start("os.path:join", name="bar") - site._read_start_file(self.sitedir, 'foo.start') - site._read_start_file(self.sitedir, 'bar.start') - self.assertEqual(self._just_entrypoints(), - ['os.path:join', 'os.path:join']) + # --- _StartupState.read_pth_file tests --- - # --- _read_pth_file tests --- - - def test_read_pth_file_paths(self): + def test_impl_read_pth_file_paths(self): subdir = os.path.join(self.sitedir, 'mylib') os.mkdir(subdir) self._make_pth("mylib\n", name='foo') - site._read_pth_file(self.sitedir, 'foo.pth', set()) + self.state.read_pth_file(self.sitedir, 'foo.pth', set()) fullname = os.path.join(self.sitedir, 'foo.pth') - self.assertIn(subdir, site._pending_syspaths[fullname]) + self.assertIn(subdir, self.state._syspaths[fullname]) - def test_read_pth_file_imports_collected(self): + def test_impl_read_pth_file_imports_collected(self): self._make_pth("import sys\n", name='foo') - site._read_pth_file(self.sitedir, 'foo.pth', set()) + self.state.read_pth_file(self.sitedir, 'foo.pth', set()) fullname = os.path.join(self.sitedir, 'foo.pth') - self.assertEqual(site._pending_importexecs[fullname], ['import sys']) + self.assertEqual( + self.state._importexecs[fullname], ['import sys'] + ) - def test_read_pth_file_comments_and_blanks(self): + def test_impl_read_pth_file_comments_and_blanks(self): self._make_pth("# comment\n\n \n", name='foo') - site._read_pth_file(self.sitedir, 'foo.pth', set()) - self.assertEqual(site._pending_syspaths, {}) - self.assertEqual(site._pending_importexecs, {}) + self.state.read_pth_file(self.sitedir, 'foo.pth', set()) + self.assertEqual(self.state._syspaths, {}) + self.assertEqual(self.state._importexecs, {}) - def test_read_pth_file_deduplication(self): + def test_impl_read_pth_file_deduplication(self): subdir = os.path.join(self.sitedir, 'mylib') os.mkdir(subdir) + # An accumulator acts as a deduplication ledger. known_paths = set() self._make_pth("mylib\n", name='a') self._make_pth("mylib\n", name='b') - site._read_pth_file(self.sitedir, 'a.pth', known_paths) - site._read_pth_file(self.sitedir, 'b.pth', known_paths) - # Only one entry across both files. + self.state.read_pth_file(self.sitedir, 'a.pth', known_paths) + self.state.read_pth_file(self.sitedir, 'b.pth', known_paths) + # There is only one entry across both files. all_dirs = [] - for dirs in site._pending_syspaths.values(): + for dirs in self.state._syspaths.values(): all_dirs.extend(dirs) self.assertEqual(all_dirs, [subdir]) - def test_read_pth_file_bad_line_continues(self): - # PEP 829: errors on individual lines don't abort the file. + def test_impl_read_pth_file_bad_line_continues(self): + # PEP 829: errors on individual lines don't abort processing the file. subdir = os.path.join(self.sitedir, 'goodpath') os.mkdir(subdir) self._make_pth("abc\x00def\ngoodpath\n", name='foo') with captured_stderr(): - site._read_pth_file(self.sitedir, 'foo.pth', set()) + self.state.read_pth_file(self.sitedir, 'foo.pth', set()) fullname = os.path.join(self.sitedir, 'foo.pth') - self.assertIn(subdir, site._pending_syspaths.get(fullname, [])) + self.assertIn(subdir, self.state._syspaths.get(fullname, [])) def _flags_with_verbose(self, verbose): # Build a sys.flags clone with verbose overridden but every # other field preserved, so unrelated reads like # sys.flags.optimize during io.open_code() continue to work. - attrs = {name: getattr(sys.flags, name) - for name in sys.flags.__match_args__} + attrs = { + name: getattr(sys.flags, name) + for name in sys.flags.__match_args__ + } attrs['verbose'] = verbose return SimpleNamespace(**attrs) - def test_read_pth_file_parse_error_silent_by_default(self): + def test_impl_read_pth_file_parse_error_silent_by_default(self): # PEP 829: parse-time errors are silent unless -v is given. - # Force the error path by making makepath() raise. + # Force the error path by making makepath() raise an exception. self._make_pth("badline\n", name='foo') - with mock.patch('site.makepath', side_effect=ValueError("boom")), \ - mock.patch('sys.flags', self._flags_with_verbose(False)), \ - captured_stderr() as err: - site._read_pth_file(self.sitedir, 'foo.pth', set()) + with ( + mock.patch('site.makepath', side_effect=ValueError("boom")), + mock.patch('sys.flags', self._flags_with_verbose(False)), + captured_stderr() as err, + ): + self.state.read_pth_file(self.sitedir, 'foo.pth', set()) self.assertEqual(err.getvalue(), "") - def test_read_pth_file_parse_error_reported_under_verbose(self): + def test_impl_read_pth_file_parse_error_reported_under_verbose(self): # PEP 829: parse-time errors are reported when -v is given. self._make_pth("badline\n", name='foo') - with mock.patch('site.makepath', side_effect=ValueError("boom")), \ - mock.patch('sys.flags', self._flags_with_verbose(True)), \ - captured_stderr() as err: - site._read_pth_file(self.sitedir, 'foo.pth', set()) + with ( + mock.patch('site.makepath', side_effect=ValueError("boom")), + mock.patch('sys.flags', self._flags_with_verbose(True)), + captured_stderr() as err, + ): + self.state.read_pth_file(self.sitedir, 'foo.pth', set()) out = err.getvalue() self.assertIn('Error in', out) self.assertIn('foo.pth', out) - def test_read_pth_file_locale_fallback(self): + def test_impl_read_pth_file_locale_fallback(self): # PEP 829: .pth files that fail UTF-8 decoding fall back to the # locale encoding for backward compatibility (deprecated in # 3.15, to be removed in 3.20). Mock locale.getencoding() so @@ -1158,186 +1206,236 @@ def test_read_pth_file_locale_fallback(self): # \xe9 is invalid UTF-8 but valid in latin-1. with open(filepath, 'wb') as f: f.write(b'# caf\xe9 comment\nmylib\n') - with mock.patch('locale.getencoding', return_value='latin-1'), \ - captured_stderr(): - site._read_pth_file(self.sitedir, 'foo.pth', set()) + with ( + mock.patch('locale.getencoding', return_value='latin-1'), + captured_stderr(), + ): + self.state.read_pth_file(self.sitedir, 'foo.pth', set()) fullname = os.path.join(self.sitedir, 'foo.pth') - self.assertIn(subdir, site._pending_syspaths.get(fullname, [])) + self.assertIn(subdir, self.state._syspaths.get(fullname, [])) - # --- _execute_start_entrypoints tests --- + # --- _StartupState._execute_start_entrypoints tests --- - def test_execute_entrypoints_with_callable(self): - # Entrypoint with callable is invoked. - mod_dir = os.path.join(self.sitedir, 'epmod') - os.mkdir(mod_dir) - init_file = os.path.join(mod_dir, '__init__.py') - with open(init_file, 'w') as f: - f.write("""\ + def test_impl_execute_entrypoints_with_callable(self): + # An entry point with a callable. + self._make_mod("""\ called = False def startup(): global called called = True -""") - sys.path.insert(0, self.sitedir) - self.addCleanup(sys.modules.pop, 'epmod', None) +""", name='epmod', package=True, on_path=True) fullname = os.path.join(self.sitedir, 'epmod.start') - site._pending_entrypoints[fullname] = ['epmod:startup'] - site._execute_start_entrypoints() + self.state._entrypoints[fullname] = ['epmod:startup'] + self.state._execute_start_entrypoints() import epmod self.assertTrue(epmod.called) - def test_execute_entrypoints_import_error(self): - # Import error prints traceback but continues. + def test_impl_execute_entrypoints_import_error(self): + # Import errors print a traceback and continue. fullname = os.path.join(self.sitedir, 'bad.start') - site._pending_entrypoints[fullname] = [ - 'nosuchmodule_xyz:func', 'os.path:join'] + self.state._entrypoints[fullname] = [ + 'nosuchmodule_xyz:func', 'os.path:join', + ] with captured_stderr() as err: - site._execute_start_entrypoints() + self.state._execute_start_entrypoints() self.assertIn('nosuchmodule_xyz', err.getvalue()) # os.path:join should still have been called (no exception for it) - def test_execute_entrypoints_strict_syntax_rejection(self): - # PEP 829: only the strict pkg.mod:callable form is valid. - # At entry-point execution, pkgutil.resolve_name(strict=True) - # raises ValueError for invalid syntax; the invalid entry is - # reported and execution continues with the next one. + def test_impl_execute_entrypoints_strict_syntax_rejection(self): + # PEP 829: only the strict pkg.mod:callable form is valid. At entry + # point execution time, pkgutil.resolve_name(strict=True) raises a + # ValueError for the invalid syntax. The invalid entry is reported + # and execution continues with the next one. fullname = os.path.join(self.sitedir, 'bad.start') - site._pending_entrypoints[fullname] = [ + self.state._entrypoints[fullname] = [ 'os.path', # no colon 'pkg.mod:', # empty callable ':callable', # empty module 'pkg.mod:callable:extra', # multiple colons ] with captured_stderr() as err: - site._execute_start_entrypoints() + self.state._execute_start_entrypoints() out = err.getvalue() self.assertIn('Invalid entry point syntax', out) - for bad in ('os.path', 'pkg.mod:', ':callable', - 'pkg.mod:callable:extra'): + for bad in ( + 'os.path', + 'pkg.mod:', + ':callable', + 'pkg.mod:callable:extra', + ): self.assertIn(bad, out) - def test_execute_entrypoints_callable_error(self): - # Callable that raises prints traceback but continues. - mod_dir = os.path.join(self.sitedir, 'badmod') - os.mkdir(mod_dir) - init_file = os.path.join(mod_dir, '__init__.py') - with open(init_file, 'w') as f: - f.write("""\ + def test_impl_execute_entrypoints_callable_error(self): + # A callable that errors prints a traceback but continues. + self._make_mod("""\ def fail(): raise RuntimeError("boom") -""") - sys.path.insert(0, self.sitedir) - self.addCleanup(sys.modules.pop, 'badmod', None) +""", name='badmod', package=True, on_path=True) fullname = os.path.join(self.sitedir, 'badmod.start') - site._pending_entrypoints[fullname] = ['badmod:fail'] + self.state._entrypoints[fullname] = ['badmod:fail'] with captured_stderr() as err: - site._execute_start_entrypoints() + self.state._execute_start_entrypoints() self.assertIn('RuntimeError', err.getvalue()) self.assertIn('boom', err.getvalue()) - def test_execute_entrypoints_duplicates_called_twice(self): + def test_impl_execute_entrypoints_duplicates_called_twice(self): # PEP 829: duplicate entry points execute multiple times. - mod_dir = os.path.join(self.sitedir, 'countmod') - os.mkdir(mod_dir) - init_file = os.path.join(mod_dir, '__init__.py') - with open(init_file, 'w') as f: - f.write("""\ + self._make_mod("""\ call_count = 0 def bump(): global call_count call_count += 1 -""") - sys.path.insert(0, self.sitedir) - self.addCleanup(sys.modules.pop, 'countmod', None) +""", name='countmod', package=False, on_path=True) fullname = os.path.join(self.sitedir, 'countmod.start') - site._pending_entrypoints[fullname] = [ - 'countmod:bump', 'countmod:bump'] - site._execute_start_entrypoints() + self.state._entrypoints[fullname] = [ + 'countmod:bump', 'countmod:bump', + ] + self.state._execute_start_entrypoints() import countmod self.assertEqual(countmod.call_count, 2) - # --- _exec_imports tests --- + # --- _StartupState._exec_imports tests --- - def test_exec_imports_suppressed_by_matching_start(self): + def test_impl_exec_imports_suppressed_by_matching_start(self): # Import lines from foo.pth are suppressed when foo.start exists. + self._make_mod("""\ +call_count = 0 +def bump(): + global call_count + call_count += 1 +""", name='countmod', package=False, on_path=True) pth_fullname = os.path.join(self.sitedir, 'foo.pth') start_fullname = os.path.join(self.sitedir, 'foo.start') - site._pending_importexecs[pth_fullname] = ['import sys'] - site._pending_entrypoints[start_fullname] = ['os.path:join'] - # Should not exec the import line; no error expected. - site._exec_imports() + self.state._importexecs[pth_fullname] = ['import countmod; countmod.bump()'] + self.state._entrypoints[start_fullname] = ['os.path:join'] + self.state._exec_imports() + import countmod + self.assertEqual(countmod.call_count, 0) - def test_exec_imports_not_suppressed_by_different_start(self): + def test_impl_exec_imports_not_suppressed_by_different_start(self): # Import lines from foo.pth are NOT suppressed by bar.start. + self._make_mod("""\ +call_count = 0 +def bump(): + global call_count + call_count += 1 +""", name='countmod', package=False, on_path=True) pth_fullname = os.path.join(self.sitedir, 'foo.pth') start_fullname = os.path.join(self.sitedir, 'bar.start') - site._pending_importexecs[pth_fullname] = ['import sys'] - site._pending_entrypoints[start_fullname] = ['os.path:join'] - # Should execute the import line without error. - site._exec_imports() + self.state._importexecs[pth_fullname] = ['import countmod; countmod.bump()'] + self.state._entrypoints[start_fullname] = ['os.path:join'] + self.state._exec_imports() + import countmod + self.assertEqual(countmod.call_count, 1) - def test_exec_imports_suppressed_by_empty_matching_start(self): + def test_impl_exec_imports_suppressed_by_empty_matching_start(self): self._make_start("", name='foo') self._make_pth("import epmod; epmod.startup()", name='foo') - mod_dir = os.path.join(self.sitedir, 'epmod') - os.mkdir(mod_dir) - init_file = os.path.join(mod_dir, '__init__.py') - with open(init_file, 'w') as f: - f.write("""\ + self._make_mod("""\ called = False def startup(): global called called = True -""") - sys.path.insert(0, self.sitedir) - self.addCleanup(sys.modules.pop, 'epmod', None) - site._read_pth_file(self.sitedir, 'foo.pth', set()) - site._read_start_file(self.sitedir, 'foo.start') - site._exec_imports() +""", name='epmod', package=True, on_path=True) + self.state.read_pth_file(self.sitedir, 'foo.pth', set()) + self.state.read_start_file(self.sitedir, 'foo.start') + self.state._exec_imports() import epmod self.assertFalse(epmod.called) - # --- _extend_syspath tests --- + # --- _StartupState._extend_syspath tests --- - def test_extend_syspath_existing_dir(self): + def test_impl_extend_syspath_existing_dir(self): subdir = os.path.join(self.sitedir, 'extlib') os.mkdir(subdir) - site._pending_syspaths['test.pth'] = [subdir] - site._extend_syspath() + self.state._syspaths['test.pth'] = [subdir] + self.state._extend_syspath() self.assertIn(subdir, sys.path) - def test_extend_syspath_nonexistent_dir(self): - nosuch = os.path.join(self.sitedir, 'nosuchdir') - site._pending_syspaths['test.pth'] = [nosuch] + def test_impl_extend_syspath_nonexistent_dir(self): + nonesuch = os.path.join(self.sitedir, 'nosuchdir') + self.state._syspaths['test.pth'] = [nonesuch] with captured_stderr() as err: - site._extend_syspath() - self.assertNotIn(nosuch, sys.path) + self.state._extend_syspath() + self.assertNotIn(nonesuch, sys.path) self.assertIn('does not exist', err.getvalue()) # --- addsitedir integration tests --- + def test_addsitedir_pth_import_skipped_when_matching_start_exists(self): + # PEP 829: an empty .start file disables the matching .pth's import + # lines, even when the .start has no entry points of its own. + self._make_mod("flag = False\n", name='suppressed', on_path=True) + self._make_start("", name='foo') + self._make_pth( + "import suppressed; suppressed.flag = True\n", + name='foo') + site.addsitedir(self.sitedir, set()) + import suppressed + self.assertFalse( + suppressed.flag, + "import line in foo.pth should be suppressed by foo.start") + + def test_addsitedir_dotfile_start_entrypoint_not_executed(self): + # .start files starting with '.' are skipped, so their entry + # points must not run. + self._make_mod("""\ +called = False +def hook(): + global called + called = True +""", + name='dotted', on_path=True) + self._make_start("dotted:hook\n", name='.hidden') + site.addsitedir(self.sitedir, set()) + import dotted + self.assertFalse(dotted.called) + + def test_addsitedir_dedups_paths_across_pth_files(self): + # PEP 829: when multiple .pth files reference the same path within + # a single addsitedir() invocation, the path is appended to + # sys.path exactly once. + subdir = os.path.join(self.sitedir, 'shared') + os.mkdir(subdir) + self._make_pth("shared\n", name='a') + self._make_pth("shared\n", name='b') + before = sys.path.count(subdir) + site.addsitedir(self.sitedir, set()) + self.assertEqual(sys.path.count(subdir), before + 1) + def test_addsitedir_discovers_start_files(self): # addsitedir() should discover .start files and accumulate entries. + # With defer_processing_start_files=True the preserved state lives on + # site._startup_state and isn't flushed until the caller invokes + # process_startup_files(). self._make_start("os.path:join\n", name='foo') - site.addsitedir(self.sitedir, set(), - defer_processing_start_files=True) + site.addsitedir( + self.sitedir, set(), + defer_processing_start_files=True, + ) fullname = os.path.join(self.sitedir, 'foo.start') - self.assertIn('os.path:join', site._pending_entrypoints[fullname]) + self.assertIn( + 'os.path:join', site._startup_state._entrypoints[fullname] + ) - def test_addsitedir_start_suppresses_pth_imports(self): + def test_impl_exec_imports_skips_when_matching_start(self): # When foo.start exists, import lines in foo.pth are skipped - # at flush time by _exec_imports(). + # at flush time by _StartupState._exec_imports(). self._make_start("os.path:join\n", name='foo') self._make_pth("import sys\n", name='foo') - site.addsitedir(self.sitedir, set(), - defer_processing_start_files=True) + site.addsitedir( + self.sitedir, set(), + defer_processing_start_files=True, + ) pth_fullname = os.path.join(self.sitedir, 'foo.pth') start_fullname = os.path.join(self.sitedir, 'foo.start') # Import line was collected... - self.assertIn('import sys', - site._pending_importexecs.get(pth_fullname, [])) + self.assertIn( + 'import sys', + site._startup_state._importexecs.get(pth_fullname, []), + ) # ...but _exec_imports() will skip it because foo.start exists. - site._exec_imports() + site._startup_state._exec_imports() def test_addsitedir_pth_paths_still_work_with_start(self): # Path lines in .pth files still work even when a .start file exists. @@ -1345,17 +1443,26 @@ def test_addsitedir_pth_paths_still_work_with_start(self): os.mkdir(subdir) self._make_start("os.path:join\n", name='foo') self._make_pth("mylib\n", name='foo') - site.addsitedir(self.sitedir, set(), - defer_processing_start_files=True) + site.addsitedir( + self.sitedir, set(), + defer_processing_start_files=True, + ) fullname = os.path.join(self.sitedir, 'foo.pth') - self.assertIn(subdir, site._pending_syspaths.get(fullname, [])) + self.assertIn( + subdir, site._startup_state._syspaths.get(fullname, []) + ) def test_addsitedir_start_alphabetical_order(self): # Multiple .start files are discovered alphabetically. + # _all_entrypoints() reads from self.state, so swap in the + # preserved batch state for the duration of the assertion. self._make_start("os.path:join\n", name='zzz') self._make_start("os.path:exists\n", name='aaa') - site.addsitedir(self.sitedir, set(), - defer_processing_start_files=True) + site.addsitedir( + self.sitedir, set(), + defer_processing_start_files=True, + ) + self.state = site._startup_state all_entries = self._all_entrypoints() entries = [entry for _, entry in all_entries] idx_a = entries.index('os.path:exists') @@ -1370,49 +1477,65 @@ def test_addsitedir_pth_before_start(self): os.mkdir(subdir) self._make_pth("mylib\n", name='foo') self._make_start("os.path:join\n", name='foo') - site.addsitedir(self.sitedir, set(), - defer_processing_start_files=True) + site.addsitedir( + self.sitedir, set(), + defer_processing_start_files=True, + ) # Both should be collected. pth_fullname = os.path.join(self.sitedir, 'foo.pth') start_fullname = os.path.join(self.sitedir, 'foo.start') - self.assertIn(subdir, site._pending_syspaths.get(pth_fullname, [])) - self.assertIn('os.path:join', - site._pending_entrypoints.get(start_fullname, [])) + self.assertIn( + subdir, site._startup_state._syspaths.get(pth_fullname, []) + ) + self.assertIn( + 'os.path:join', + site._startup_state._entrypoints.get(start_fullname, []), + ) - def test_addsitedir_dotfile_start_ignored(self): + def test_impl_addsitedir_skips_dotfile_start(self): # .start files starting with '.' are skipped. Defer flushing so - # the assertion against _pending_entrypoints is meaningful; - # otherwise process_startup_files() would clear the dict - # regardless of whether the dotfile was picked up. + # the preserved batch state stays inspectable on + # site._startup_state; otherwise process_startup_files() would + # detach and consume it regardless of whether the dotfile was + # picked up. self._make_start("os.path:join\n", name='.hidden') - site.addsitedir(self.sitedir, set(), - defer_processing_start_files=True) - self.assertEqual(site._pending_entrypoints, {}) + site.addsitedir( + self.sitedir, set(), + defer_processing_start_files=True, + ) + self.assertEqual(site._startup_state._entrypoints, {}) def test_addsitedir_standalone_flushes(self): - # When called with known_paths=None (standalone), addsitedir - # flushes immediately so the caller sees the effect. + # When called with defer_processing_start_files=False (the + # default), addsitedir creates a per-call _StartupState and + # processes it before returning, so the caller sees the effect + # immediately. No batch state is left behind on + # site._startup_state. subdir = os.path.join(self.sitedir, 'flushlib') os.mkdir(subdir) self._make_pth("flushlib\n", name='foo') site.addsitedir(self.sitedir) # known_paths=None self.assertIn(subdir, sys.path) - # Pending dicts should be cleared after flush. - self.assertEqual(site._pending_syspaths, {}) + self.assertIsNone(site._startup_state) def test_addsitedir_defer_does_not_flush(self): # With defer_processing_start_files=True, addsitedir accumulates # pending state but does not flush; sys.path is updated only when - # process_startup_files() is called explicitly. + # process_startup_files() is called explicitly. The accumulated + # state lives on the lazily-promoted site._startup_state. subdir = os.path.join(self.sitedir, 'acclib') os.mkdir(subdir) self._make_pth("acclib\n", name='foo') - site.addsitedir(self.sitedir, set(), - defer_processing_start_files=True) + site.addsitedir( + self.sitedir, set(), + defer_processing_start_files=True, + ) # Path is pending, not yet on sys.path. self.assertNotIn(subdir, sys.path) fullname = os.path.join(self.sitedir, 'foo.pth') - self.assertIn(subdir, site._pending_syspaths.get(fullname, [])) + self.assertIn( + subdir, site._startup_state._syspaths.get(fullname, []) + ) def test_pth_path_is_available_to_start_entrypoint(self): # Core PEP 829 invariant: all .pth path extensions are applied to @@ -1420,18 +1543,12 @@ def test_pth_path_is_available_to_start_entrypoint(self): # point may live in a module reachable only via a .pth-extended # path. If the flush phases were inverted, resolving the entry # point would fail with ModuleNotFoundError. - extdir = os.path.join(self.sitedir, 'extdir') - os.mkdir(extdir) - modpath = os.path.join(extdir, 'mod.py') - with open(modpath, 'w') as f: - f.write("""\ + extdir = self._make_mod("""\ called = False def hook(): global called called = True """) - self.addCleanup(sys.modules.pop, 'mod', None) - # extdir is not on sys.path; only the .pth file makes it so. self.assertNotIn(extdir, sys.path) self._make_pth("extdir\n", name='extlib') @@ -1447,6 +1564,82 @@ def hook(): "entry point did not run; .pth path was likely not applied " "before .start entry-point execution") + # --- bugs --- + + # gh-75723 + def test_addsitdir_idempotent_pth(self): + # Adding the same sitedir twice with a known_paths, should not + # process .pth files twice. + extdir = self._make_mod("""\ +_pth_count = 0 +""") + self._make_pth(f"""\ +{extdir} +import mod; mod._pth_count += 1 +""") + dirs = set() + dirs = site.addsitedir(self.sitedir, dirs) + dirs = site.addsitedir(self.sitedir, dirs) + import mod + self.assertEqual(mod._pth_count, 1) + + def test_addsitdir_idempotent_start(self): + # Adding the same sitedir twice with a known_paths, should not + # process .pth files twice. + extdir = self._make_mod("""\ +_pth_count = 0 +def increment(): + global _pth_count + _pth_count += 1 +""") + self._make_pth(f"""\ +{extdir} +""") + self._make_start("""\ +mod:increment +""") + dirs = set() + dirs = site.addsitedir(self.sitedir, dirs) + dirs = site.addsitedir(self.sitedir, dirs) + import mod + self.assertEqual(mod._pth_count, 1) + + # gh-149504 + def test_reentrant_addsitedir_pth(self): + # An import line in a .pth file that calls site.addsitedir() + # must not crash or re-execute outer entries while the outer + # call is still processing its pending startup state. + overlay = self.enterContext(os_helper.temp_dir()) + overlay_pth = os.path.join(overlay, 'overlay.pth') + pkgdir = self.enterContext(os_helper.temp_dir()) + with open(overlay_pth, 'w', encoding='utf-8') as fp: + print(pkgdir, file=fp) + self._make_pth(f"import site; site.addsitedir({overlay!r})\n") + site.addsitedir(self.sitedir, set()) + self.assertIn(overlay, sys.path) + self.assertIn(pkgdir, sys.path) + + # gh-149504 + def test_reentrant_addsitedir_start(self): + # As above, but the re-entry happens from a .start entry point + # instead of a .pth import line. The entry point execution + # phase is vulnerable to the same class of bug. + overlay = self.enterContext(os_helper.temp_dir()) + overlay_pth = os.path.join(overlay, 'overlay.pth') + pkgdir = self.enterContext(os_helper.temp_dir()) + with open(overlay_pth, 'w', encoding='utf-8') as fp: + print(pkgdir, file=fp) + self._make_mod(f"""\ +import site +def bootstrap(): + site.addsitedir({overlay!r}) +""", + name='reenter_helper', on_path=True) + self._make_start("reenter_helper:bootstrap\n") + site.addsitedir(self.sitedir, set()) + self.assertIn(overlay, sys.path) + self.assertIn(pkgdir, sys.path) + if __name__ == "__main__": unittest.main() diff --git a/Misc/NEWS.d/next/Library/2026-05-10-23-51-23.gh-issue-149504.pDSCbn.rst b/Misc/NEWS.d/next/Library/2026-05-10-23-51-23.gh-issue-149504.pDSCbn.rst new file mode 100644 index 00000000000000..88bf268123bbec --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-05-10-23-51-23.gh-issue-149504.pDSCbn.rst @@ -0,0 +1,5 @@ +Fix :func:`site.addsitedir` to allow re-entrant calls from within startup +files. Previously, a ``.pth`` file containing an ``import`` line that +called :func:`site.addsitedir` (or a ``.start`` entry point doing the same) +could crash with ``RuntimeError: dictionary changed size during iteration`` +during site initialization, breaking tools such as ``uv run --with``. From dc7cad2f5db834aefb5ecabebc6f25bbb898381b Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 14 May 2026 01:24:29 +0200 Subject: [PATCH 052/818] [3.15] gh-149231: tomllib: Limit the number of parts in a key (GH-149233) (GH-149677) (cherry picked from commit bc7c102f3462a9f014f3ac2546acfb471b2a7eae) Co-authored-by: Petr Viktorin Co-authored-by: Stan Ulbrych --- .../next/Library/2026-05-01-16-45-31.gh-issue-149231.x2nBEE.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Library/2026-05-01-16-45-31.gh-issue-149231.x2nBEE.rst diff --git a/Misc/NEWS.d/next/Library/2026-05-01-16-45-31.gh-issue-149231.x2nBEE.rst b/Misc/NEWS.d/next/Library/2026-05-01-16-45-31.gh-issue-149231.x2nBEE.rst new file mode 100644 index 00000000000000..c265b54db8bed4 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-05-01-16-45-31.gh-issue-149231.x2nBEE.rst @@ -0,0 +1 @@ +In :mod:`tomllib`, the number of parts in TOML keys is now limited. From 894ec10b56d93743e082ac9569abf896e082a919 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 14 May 2026 01:34:59 +0200 Subject: [PATCH 053/818] [3.15] Fix incorrect sentence in stable.rst (GH-149684) (GH-149814) (cherry picked from commit 374f9d3f5e70d2204d88ab123f29825d71537de2) Co-authored-by: Manoj K M --- Doc/c-api/stable.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/c-api/stable.rst b/Doc/c-api/stable.rst index 0ff066680b8c73..13e5d5c96135c0 100644 --- a/Doc/c-api/stable.rst +++ b/Doc/c-api/stable.rst @@ -114,7 +114,7 @@ versions of Python. All functions in Stable ABI are present as functions in Python's shared library, not solely as macros. -This makes them usable are usable from languages that don't use the C +This makes them usable in languages that don't use the C preprocessor, including Python's :py:mod:`ctypes`. From b5d508d40b5c87baa23f9f1f8200db8e00280e5b Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 14 May 2026 10:52:51 +0200 Subject: [PATCH 054/818] [3.15] gh-149698: Update bundled expat to 2.8.1 (GH-149699) (#149812) (cherry picked from commit f1a47e79fb7081d3cde6364530bfa98240ebbe4c) Co-authored-by: Stan Ulbrych --- ...-05-11-21-15-07.gh-issue-149698.OudOcW.rst | 2 ++ Misc/sbom.spdx.json | 16 ++++----- Modules/expat/expat.h | 2 +- Modules/expat/refresh.sh | 6 ++-- Modules/expat/xmlparse.c | 36 +++++++++++++++---- 5 files changed, 44 insertions(+), 18 deletions(-) create mode 100644 Misc/NEWS.d/next/Security/2026-05-11-21-15-07.gh-issue-149698.OudOcW.rst diff --git a/Misc/NEWS.d/next/Security/2026-05-11-21-15-07.gh-issue-149698.OudOcW.rst b/Misc/NEWS.d/next/Security/2026-05-11-21-15-07.gh-issue-149698.OudOcW.rst new file mode 100644 index 00000000000000..3c8671b9a5adc4 --- /dev/null +++ b/Misc/NEWS.d/next/Security/2026-05-11-21-15-07.gh-issue-149698.OudOcW.rst @@ -0,0 +1,2 @@ +Update bundled `libexpat `_ to version 2.8.1 +for the fix for :cve:`2026-45186`. diff --git a/Misc/sbom.spdx.json b/Misc/sbom.spdx.json index aaeffd58e799ed..1eca892fb12ace 100644 --- a/Misc/sbom.spdx.json +++ b/Misc/sbom.spdx.json @@ -48,11 +48,11 @@ "checksums": [ { "algorithm": "SHA1", - "checksumValue": "5343adc95840915b022b1d4524d0acb66b369ba2" + "checksumValue": "58101ef0951568acadd3117033bef084fea24cc1" }, { "algorithm": "SHA256", - "checksumValue": "1ec3bad08b6864c2c479e1fd941038c2dcd24c6d9a16400f4da54912d95aa321" + "checksumValue": "52d756026bf09befdb211c453e2009a646d6c6b519e6885e971b2550396619fb" } ], "fileName": "Modules/expat/expat.h" @@ -174,11 +174,11 @@ "checksums": [ { "algorithm": "SHA1", - "checksumValue": "cb0af01558ec7b6474d2bd0c9386380c82618e8f" + "checksumValue": "1dad2ab196cdbe37572674c465bd9187fdbe4495" }, { "algorithm": "SHA256", - "checksumValue": "6745a6b8cdd7344d4bd8f27f605363ed746e57ff02d4ebce3eb1806579cd030f" + "checksumValue": "740137e670d2f3b7269364ffb6f60064e6560091850c5d6f2c3bb1b8ca6e3dd1" } ], "fileName": "Modules/expat/xmlparse.c" @@ -1730,14 +1730,14 @@ "checksums": [ { "algorithm": "SHA256", - "checksumValue": "c7cec5f60ea3a42e7780781c6745255c19aa3dbfeeae58646b7132f88dc24780" + "checksumValue": "a52eb72108be160e190b5cafa5bba8663f1313f2013e26060d1c18e26e31067b" } ], - "downloadLocation": "https://github.com/libexpat/libexpat/releases/download/R_2_8_0/expat-2.8.0.tar.gz", + "downloadLocation": "https://github.com/libexpat/libexpat/releases/download/R_2_8_1/expat-2.8.1.tar.gz", "externalRefs": [ { "referenceCategory": "SECURITY", - "referenceLocator": "cpe:2.3:a:libexpat_project:libexpat:2.8.0:*:*:*:*:*:*:*", + "referenceLocator": "cpe:2.3:a:libexpat_project:libexpat:2.8.1:*:*:*:*:*:*:*", "referenceType": "cpe23Type" } ], @@ -1745,7 +1745,7 @@ "name": "expat", "originator": "Organization: Expat development team", "primaryPackagePurpose": "SOURCE", - "versionInfo": "2.8.0" + "versionInfo": "2.8.1" }, { "SPDXID": "SPDXRef-PACKAGE-hacl-star", diff --git a/Modules/expat/expat.h b/Modules/expat/expat.h index 79c609f19aa4cf..ec3f58544cb00d 100644 --- a/Modules/expat/expat.h +++ b/Modules/expat/expat.h @@ -1094,7 +1094,7 @@ XML_SetReparseDeferralEnabled(XML_Parser parser, XML_Bool enabled); */ # define XML_MAJOR_VERSION 2 # define XML_MINOR_VERSION 8 -# define XML_MICRO_VERSION 0 +# define XML_MICRO_VERSION 1 # ifdef __cplusplus } diff --git a/Modules/expat/refresh.sh b/Modules/expat/refresh.sh index 774e0b89d94c0e..fa3692f9379510 100755 --- a/Modules/expat/refresh.sh +++ b/Modules/expat/refresh.sh @@ -12,9 +12,9 @@ fi # Update this when updating to a new version after verifying that the changes # the update brings in are good. These values are used for verifying the SBOM, too. -expected_libexpat_tag="R_2_8_0" -expected_libexpat_version="2.8.0" -expected_libexpat_sha256="c7cec5f60ea3a42e7780781c6745255c19aa3dbfeeae58646b7132f88dc24780" +expected_libexpat_tag="R_2_8_1" +expected_libexpat_version="2.8.1" +expected_libexpat_sha256="a52eb72108be160e190b5cafa5bba8663f1313f2013e26060d1c18e26e31067b" expat_dir="$(realpath "$(dirname -- "${BASH_SOURCE[0]}")")" cd ${expat_dir} diff --git a/Modules/expat/xmlparse.c b/Modules/expat/xmlparse.c index e6842f3f0bf750..95d346758563ab 100644 --- a/Modules/expat/xmlparse.c +++ b/Modules/expat/xmlparse.c @@ -1,4 +1,4 @@ -/* a5d18f6a50f536615ac1c70304f87d94f99cc85a86b502188952440610ccf0f8 (2.8.0+) +/* 75ef4224f81c052e9e5aeea2ac7de75357d2169ff9908e39edc08b9dc3052513 (2.8.1+) __ __ _ ___\ \/ /_ __ __ _| |_ / _ \\ /| '_ \ / _` | __| @@ -387,6 +387,7 @@ typedef struct { int nDefaultAtts; int allocDefaultAtts; DEFAULT_ATTRIBUTE *defaultAtts; + HASH_TABLE defaultAttsNames; } ELEMENT_TYPE; typedef struct { @@ -3769,6 +3770,8 @@ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr, sizeof(ELEMENT_TYPE)); if (! elementType) return XML_ERROR_NO_MEMORY; + if (! elementType->defaultAttsNames.parser) + hashTableInit(&(elementType->defaultAttsNames), parser); if (parser->m_ns && ! setElementTypePrefix(parser, elementType)) return XML_ERROR_NO_MEMORY; } @@ -7102,10 +7105,10 @@ defineAttribute(ELEMENT_TYPE *type, ATTRIBUTE_ID *attId, XML_Bool isCdata, if (value || isId) { /* The handling of default attributes gets messed up if we have a default which duplicates a non-default. */ - int i; - for (i = 0; i < type->nDefaultAtts; i++) - if (attId == type->defaultAtts[i].id) - return 1; + NAMED *const nameFound + = (NAMED *)lookup(parser, &(type->defaultAttsNames), attId->name, 0); + if (nameFound) + return 1; if (isId && ! type->idAtt && ! attId->xmlns) type->idAtt = attId; } @@ -7152,6 +7155,12 @@ defineAttribute(ELEMENT_TYPE *type, ATTRIBUTE_ID *attId, XML_Bool isCdata, att->isCdata = isCdata; if (! isCdata) attId->maybeTokenized = XML_TRUE; + + NAMED *const nameAddedOrFound = (NAMED *)lookup( + parser, &(type->defaultAttsNames), attId->name, sizeof(NAMED)); + if (! nameAddedOrFound) + return 0; + type->nDefaultAtts += 1; return 1; } @@ -7477,6 +7486,7 @@ dtdReset(DTD *p, XML_Parser parser) { ELEMENT_TYPE *e = (ELEMENT_TYPE *)hashTableIterNext(&iter); if (! e) break; + hashTableDestroy(&(e->defaultAttsNames)); if (e->allocDefaultAtts != 0) FREE(parser, e->defaultAtts); } @@ -7518,6 +7528,7 @@ dtdDestroy(DTD *p, XML_Bool isDocEntity, XML_Parser parser) { ELEMENT_TYPE *e = (ELEMENT_TYPE *)hashTableIterNext(&iter); if (! e) break; + hashTableDestroy(&(e->defaultAttsNames)); if (e->allocDefaultAtts != 0) FREE(parser, e->defaultAtts); } @@ -7611,6 +7622,10 @@ dtdCopy(XML_Parser oldParser, DTD *newDtd, const DTD *oldDtd, sizeof(ELEMENT_TYPE)); if (! newE) return 0; + + if (! newE->defaultAttsNames.parser) + hashTableInit(&(newE->defaultAttsNames), parser); + if (oldE->nDefaultAtts) { /* Detect and prevent integer overflow. * The preprocessor guard addresses the "always false" warning @@ -7635,8 +7650,9 @@ dtdCopy(XML_Parser oldParser, DTD *newDtd, const DTD *oldDtd, newE->prefix = (PREFIX *)lookup(oldParser, &(newDtd->prefixes), oldE->prefix->name, 0); for (i = 0; i < newE->nDefaultAtts; i++) { + const XML_Char *const attributeName = oldE->defaultAtts[i].id->name; newE->defaultAtts[i].id = (ATTRIBUTE_ID *)lookup( - oldParser, &(newDtd->attributeIds), oldE->defaultAtts[i].id->name, 0); + oldParser, &(newDtd->attributeIds), attributeName, 0); newE->defaultAtts[i].isCdata = oldE->defaultAtts[i].isCdata; if (oldE->defaultAtts[i].value) { newE->defaultAtts[i].value @@ -7645,6 +7661,12 @@ dtdCopy(XML_Parser oldParser, DTD *newDtd, const DTD *oldDtd, return 0; } else newE->defaultAtts[i].value = NULL; + + NAMED *const nameAddedOrFound = (NAMED *)lookup( + parser, &(newE->defaultAttsNames), attributeName, sizeof(NAMED)); + if (! nameAddedOrFound) { + return 0; + } } } @@ -8391,6 +8413,8 @@ getElementType(XML_Parser parser, const ENCODING *enc, const char *ptr, sizeof(ELEMENT_TYPE)); if (! ret) return NULL; + if (! ret->defaultAttsNames.parser) + hashTableInit(&(ret->defaultAttsNames), getRootParserOf(parser, NULL)); if (ret->name != name) poolDiscard(&dtd->pool); else { From 6302a8f17a6113a3ef0cbb3afad35632a7be9e02 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 14 May 2026 12:37:11 +0200 Subject: [PATCH 055/818] [3.15] gh-148821: Add more tests for invalid XML encodings (GH-149820) (GH-149821) (cherry picked from commit c6f7368157ecf9f2cdd537d8b6fad6e011bce344) Co-authored-by: Serhiy Storchaka --- Lib/test/test_pyexpat.py | 48 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 44 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_pyexpat.py b/Lib/test/test_pyexpat.py index 4fe2e02326f04f..10dca684accee3 100644 --- a/Lib/test/test_pyexpat.py +++ b/Lib/test/test_pyexpat.py @@ -289,7 +289,7 @@ def test_parse_again(self): 'mac-roman', 'mac-turkish', 'koi8-r', 'koi8-t', 'koi8-u', 'kz1048', 'ptcp154', ]) - def test_supported_ecodings(self, encoding): + def test_supported_encodings(self, encoding): out = self.Outputter() parser = expat.ParserCreate() self._hookup_callbacks(parser, out) @@ -308,7 +308,7 @@ def test_supported_ecodings(self, encoding): 'UTF-8', 'utf-8', 'utf-16', 'utf-16le', 'utf-16be', 'koi8-u', 'cp1125', 'cp1251', 'iso8859-5', 'mac-cyrillic', ]) - def test_supported_ecodings2(self, encoding): + def test_supported_encodings2(self, encoding): out = self.Outputter() parser = expat.ParserCreate() self._hookup_callbacks(parser, out) @@ -334,14 +334,54 @@ def test_supported_ecodings2(self, encoding): "johab", "Shift_JIS", "Shift_JIS-2004", "Shift_JISX0213", ]) - def test_unsupportes_ecodings(self, encoding): + def test_unsupported_encodings(self, encoding): parser = expat.ParserCreate() data = (f'\n' '').encode(encoding) with self.assertRaises(ValueError): parser.Parse(data, True) - def test_unknown_ecoding(self): + parser = expat.ParserCreate() + data = (f'\n' + '').encode() + with self.assertRaises(ValueError): + parser.Parse(data, True) + + @support.subTests('encoding', [ + 'cp037', 'cp273', 'cp424', 'cp500', 'cp864', 'cp875', + 'cp1026', 'cp1140', + 'mac_arabic', 'mac_farsi', + ]) + def test_incompatible_encodings(self, encoding): + parser = expat.ParserCreate() + data = (f'\n' + '').encode(encoding) + with self.assertRaises(expat.ExpatError): + parser.Parse(data, True) + + parser = expat.ParserCreate() + data = (f'\n' + '').encode() + with self.assertRaisesRegex(expat.ExpatError, 'unknown encoding'): + parser.Parse(data, True) + + @support.subTests('encoding', [ + 'hex_codec', 'rot_13', + ]) + def test_non_text_encodings(self, encoding): + parser = expat.ParserCreate() + data = (f'\n' + '').encode() + with self.assertRaises(LookupError): + parser.Parse(data, True) + + def test_undefined_encoding(self): + parser = expat.ParserCreate() + data = b'\n' + with self.assertRaises(UnicodeError): + parser.Parse(data, True) + + def test_unknown_encoding(self): parser = expat.ParserCreate() data = b'\n' with self.assertRaises(LookupError): From 451f06b02ef86c0c218249694f763758ae09d414 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 14 May 2026 19:09:05 +0200 Subject: [PATCH 056/818] [3.15] Link to existing rules in compound_stmts.rst (GH-149811) (GH-149836) Link to existing rules in compound_stmts.rst (GH-149811) In gh-138418, `!` was added to links to rules that don't exist in the docs, in order to silence broken link warnings. However, productionlist doesn't parse the `!`, which ends up in the rendered documentation. (It's possible that gh-127835 broke the `!` support.) Replace the names with ones that appear in docs: - `star_named_expression` in the grammar corresponds to `flexible_expression` in the docs - `star_named_expressions` in the grammar corresponds to `flexible_expression_list` in the docs - `named_expression` in the grammar corresponds to `assignment_expression` in the docs Having two sets of names isn't great of course. Consolidating them is tracked in (subissues of) gh-127833. (cherry picked from commit c37529293d1e05081cb4e8668162c76583b88007) Co-authored-by: Petr Viktorin --- Doc/reference/compound_stmts.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/reference/compound_stmts.rst b/Doc/reference/compound_stmts.rst index 72e1cad3bbd892..a819c41d834aa7 100644 --- a/Doc/reference/compound_stmts.rst +++ b/Doc/reference/compound_stmts.rst @@ -618,8 +618,8 @@ The match statement is used for pattern matching. Syntax: .. productionlist:: python-grammar match_stmt: 'match' `subject_expr` ":" NEWLINE INDENT `case_block`+ DEDENT - subject_expr: `!star_named_expression` "," `!star_named_expressions`? - : | `!named_expression` + subject_expr: `flexible_expression` "," [`flexible_expression_list` [',']] + : | `assignment_expression` case_block: 'case' `patterns` [`guard`] ":" `!block` .. note:: @@ -709,7 +709,7 @@ Guards .. index:: ! guard .. productionlist:: python-grammar - guard: "if" `!named_expression` + guard: "if" `assignment_expression` A ``guard`` (which is part of the ``case``) must succeed for code inside the ``case`` block to execute. It takes the form: :keyword:`if` followed by an From ff6f921ffadba51ed350588457347a6d9fc2c986 Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Thu, 14 May 2026 19:16:23 +0200 Subject: [PATCH 057/818] [3.15] gh-149231: Revert extra NEWS entry (GH-149840) gh-149231: Revert extra NEWS entry This reverts commit dc7cad2f5db834aefb5ecabebc6f25bbb898381b. --- .../next/Library/2026-05-01-16-45-31.gh-issue-149231.x2nBEE.rst | 1 - 1 file changed, 1 deletion(-) delete mode 100644 Misc/NEWS.d/next/Library/2026-05-01-16-45-31.gh-issue-149231.x2nBEE.rst diff --git a/Misc/NEWS.d/next/Library/2026-05-01-16-45-31.gh-issue-149231.x2nBEE.rst b/Misc/NEWS.d/next/Library/2026-05-01-16-45-31.gh-issue-149231.x2nBEE.rst deleted file mode 100644 index c265b54db8bed4..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-05-01-16-45-31.gh-issue-149231.x2nBEE.rst +++ /dev/null @@ -1 +0,0 @@ -In :mod:`tomllib`, the number of parts in TOML keys is now limited. From 21909e898e6cc444c2c860edf6bc6b9c3a86abb2 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 14 May 2026 20:49:29 +0200 Subject: [PATCH 058/818] [3.15] gh-124111: Update Windows build to use Tcl/Tk 9.0.3 (GH-149842) (cherry picked from commit c62c3710dc795a60c3c3dc8e2aeeeb16c06da197) Co-authored-by: Zachary Ware --- Lib/test/test_tcl.py | 12 +++++++++-- ...-05-06-21-36-53.gh-issue-124111.m4OBX8.rst | 1 + Misc/externals.spdx.json | 20 +++++++++---------- PCbuild/get_externals.bat | 6 +++--- PCbuild/readme.txt | 2 +- PCbuild/tcltk.props | 6 ++++-- Tools/msi/tcltk/tcltk_files.wxs | 11 ++++++---- Tools/msi/testrelease.bat | 2 -- 8 files changed, 36 insertions(+), 24 deletions(-) create mode 100644 Misc/NEWS.d/next/Windows/2026-05-06-21-36-53.gh-issue-124111.m4OBX8.rst diff --git a/Lib/test/test_tcl.py b/Lib/test/test_tcl.py index 47450d3fd5976f..81a5477b496b5c 100644 --- a/Lib/test/test_tcl.py +++ b/Lib/test/test_tcl.py @@ -54,7 +54,11 @@ def test_eval_null_in_result(self): def test_eval_surrogates_in_result(self): tcl = self.interp - self.assertEqual(tcl.eval(r'set a "<\ud83d\udcbb>"'), '<\U0001f4bb>') + result = tcl.eval(r'set a "<\ud83d\udcbb>"') + if sys.platform == 'win32': + self.assertEqual('<\ud83d\udcbb>', result) + else: + self.assertEqual('<\U0001f4bb>', result) def testEvalException(self): tcl = self.interp @@ -289,7 +293,11 @@ def test_evalfile_surrogates_in_result(self): set b "<\\ud83d\\udcbb>" """) tcl.evalfile(filename) - self.assertEqual(tcl.eval('set b'), '<\U0001f4bb>') + result = tcl.eval('set b') + if sys.platform == 'win32': + self.assertEqual('<\ud83d\udcbb>', result) + else: + self.assertEqual('<\U0001f4bb>', result) def testEvalFileException(self): tcl = self.interp diff --git a/Misc/NEWS.d/next/Windows/2026-05-06-21-36-53.gh-issue-124111.m4OBX8.rst b/Misc/NEWS.d/next/Windows/2026-05-06-21-36-53.gh-issue-124111.m4OBX8.rst new file mode 100644 index 00000000000000..9a57536f1dc96b --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2026-05-06-21-36-53.gh-issue-124111.m4OBX8.rst @@ -0,0 +1 @@ +Updated Windows builds to use Tcl/Tk 9.0.3. diff --git a/Misc/externals.spdx.json b/Misc/externals.spdx.json index 593fa01bf25ed1..9a571fba732ab4 100644 --- a/Misc/externals.spdx.json +++ b/Misc/externals.spdx.json @@ -108,46 +108,46 @@ "versionInfo": "3.50.4.0" }, { - "SPDXID": "SPDXRef-PACKAGE-tcl-core", + "SPDXID": "SPDXRef-PACKAGE-tcl", "checksums": [ { "algorithm": "SHA256", - "checksumValue": "4c23f0dd3efcbe6f3a22c503a68d147617bb30c4f5290f1eb3eaacf0b460440b" + "checksumValue": "7a1d1f3a2b8f4484a9c2a027a157963c18f85a81785e85fcb5d1e3df6b6a4fd4" } ], - "downloadLocation": "https://github.com/python/cpython-source-deps/archive/refs/tags/tcl-core-8.6.15.0.tar.gz", + "downloadLocation": "https://github.com/python/cpython-source-deps/archive/refs/tags/tcl-9.0.3.0.tar.gz", "externalRefs": [ { "referenceCategory": "SECURITY", - "referenceLocator": "cpe:2.3:a:tcl_tk:tcl_tk:8.6.15.0:*:*:*:*:*:*:*", + "referenceLocator": "cpe:2.3:a:tcl_tk:tcl_tk:9.0.3.0:*:*:*:*:*:*:*", "referenceType": "cpe23Type" } ], "licenseConcluded": "NOASSERTION", - "name": "tcl-core", + "name": "tcl", "primaryPackagePurpose": "SOURCE", - "versionInfo": "8.6.15.0" + "versionInfo": "9.0.3.0" }, { "SPDXID": "SPDXRef-PACKAGE-tk", "checksums": [ { "algorithm": "SHA256", - "checksumValue": "0ae56d39bca92865f338529557a1e56d110594184b6dc5a91339c5675751e264" + "checksumValue": "54fb59df12c489c6264f5b7d3d7444b150d1e3d6561fd59cdb11483440cec000" } ], - "downloadLocation": "https://github.com/python/cpython-source-deps/archive/refs/tags/tk-8.6.15.0.tar.gz", + "downloadLocation": "https://github.com/python/cpython-source-deps/archive/refs/tags/tk-9.0.3.1.tar.gz", "externalRefs": [ { "referenceCategory": "SECURITY", - "referenceLocator": "cpe:2.3:a:tcl_tk:tcl_tk:8.6.15.0:*:*:*:*:*:*:*", + "referenceLocator": "cpe:2.3:a:tcl_tk:tcl_tk:9.0.3.1:*:*:*:*:*:*:*", "referenceType": "cpe23Type" } ], "licenseConcluded": "NOASSERTION", "name": "tk", "primaryPackagePurpose": "SOURCE", - "versionInfo": "8.6.15.0" + "versionInfo": "9.0.3.1" }, { "SPDXID": "SPDXRef-PACKAGE-xz", diff --git a/PCbuild/get_externals.bat b/PCbuild/get_externals.bat index 405285b65dd270..368bc489bfa968 100644 --- a/PCbuild/get_externals.bat +++ b/PCbuild/get_externals.bat @@ -57,8 +57,8 @@ if NOT "%IncludeLibffiSrc%"=="false" set libraries=%libraries% libffi-3.4.4 if NOT "%IncludeSSLSrc%"=="false" set libraries=%libraries% openssl-3.5.6 set libraries=%libraries% mpdecimal-4.0.0 set libraries=%libraries% sqlite-3.50.4.0 -if NOT "%IncludeTkinterSrc%"=="false" set libraries=%libraries% tcl-core-8.6.15.0 -if NOT "%IncludeTkinterSrc%"=="false" set libraries=%libraries% tk-8.6.15.0 +if NOT "%IncludeTkinterSrc%"=="false" set libraries=%libraries% tcl-9.0.3.0 +if NOT "%IncludeTkinterSrc%"=="false" set libraries=%libraries% tk-9.0.3.1 set libraries=%libraries% xz-5.8.1.1 set libraries=%libraries% zlib-ng-2.2.4 set libraries=%libraries% zstd-1.5.7 @@ -80,7 +80,7 @@ echo.Fetching external binaries... set binaries= if NOT "%IncludeLibffi%"=="false" set binaries=%binaries% libffi-3.4.4 if NOT "%IncludeSSL%"=="false" set binaries=%binaries% openssl-bin-3.5.6 -if NOT "%IncludeTkinter%"=="false" set binaries=%binaries% tcltk-8.6.15.0 +if NOT "%IncludeTkinter%"=="false" set binaries=%binaries% tcltk-9.0.3.0 if NOT "%IncludeSSLSrc%"=="false" set binaries=%binaries% nasm-2.11.06 if NOT "%IncludeLLVM%"=="false" set binaries=%binaries% llvm-21.1.4.0 diff --git a/PCbuild/readme.txt b/PCbuild/readme.txt index 14aac0b0dc84b6..6aecbfff182dcb 100644 --- a/PCbuild/readme.txt +++ b/PCbuild/readme.txt @@ -247,7 +247,7 @@ _sqlite3 https://www.sqlite.org/ _tkinter - Wraps version 8.6.15 of the Tk windowing system, which is downloaded + Wraps version 9.0.3 of the Tk windowing system, which is downloaded from our binaries repository at https://github.com/python/cpython-bin-deps. diff --git a/PCbuild/tcltk.props b/PCbuild/tcltk.props index a1da1155b881fd..28e8c0db4d1eaf 100644 --- a/PCbuild/tcltk.props +++ b/PCbuild/tcltk.props @@ -2,7 +2,7 @@ - 8.6.15.0 + 9.0.3.0 $(TclVersion) $([System.Version]::Parse($(TclVersion)).Major) $([System.Version]::Parse($(TclVersion)).Minor) @@ -12,7 +12,9 @@ $([System.Version]::Parse($(TkVersion)).Minor) $([System.Version]::Parse($(TkVersion)).Build) $([System.Version]::Parse($(TkVersion)).Revision) - $(ExternalsDir)tcl-core-$(TclVersion)\ + + $(ExternalsDir)tcl-core-$(TclVersion)\ + $(ExternalsDir)tcl-$(TclVersion)\ $(ExternalsDir)tk-$(TkVersion)\ $(ExternalsDir)tcltk-$(TclVersion)\$(ArchName)\ t diff --git a/Tools/msi/tcltk/tcltk_files.wxs b/Tools/msi/tcltk/tcltk_files.wxs index 5dad7c98d4f048..7c7784741d9178 100644 --- a/Tools/msi/tcltk/tcltk_files.wxs +++ b/Tools/msi/tcltk/tcltk_files.wxs @@ -10,11 +10,14 @@ - - + + - - + + + + + diff --git a/Tools/msi/testrelease.bat b/Tools/msi/testrelease.bat index 02bcca943cf79b..db98f690151196 100644 --- a/Tools/msi/testrelease.bat +++ b/Tools/msi/testrelease.bat @@ -88,9 +88,7 @@ exit /B 0 ) @if not errorlevel 1 ( @echo Testing Tcl/tk - @set TCL_LIBRARY=%~2\Python\tcl\tcl8.6 "%~2\Python\python.exe" -m test -uall -v test_ttk_guionly test_tk test_idle > "%~2\tcltk.txt" 2>&1 - @set TCL_LIBRARY= ) @set EXITCODE=%ERRORLEVEL% From ed27363ddf340577afd5b7b67e604489f5ee7aa3 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 15 May 2026 00:38:11 +0200 Subject: [PATCH 059/818] [3.15] gh-149144: Use decodeURIComponent() for UTF-8 support in js_output() (GH-149157) (GH-149846) gh-149144: Use decodeURIComponent() for UTF-8 support in js_output() (GH-149157) (cherry picked from commit 461b1d96313de02992d284c1782be9aff24586c9) Co-authored-by: Seth Larson --- Lib/http/cookies.py | 7 +++---- Lib/test/test_http_cookies.py | 27 ++++++++++++++------------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/Lib/http/cookies.py b/Lib/http/cookies.py index 800a2c18e3fa41..9a6f01dfb5e69a 100644 --- a/Lib/http/cookies.py +++ b/Lib/http/cookies.py @@ -391,21 +391,20 @@ def output(self, attrs=None, header="Set-Cookie:"): def __repr__(self): return '<%s: %s>' % (self.__class__.__name__, self.OutputString()) - def _js_output(self, attrs=None): """Internal implementation without deprecation warning.""" - import base64 + import urllib.parse # Print javascript output_string = self.OutputString(attrs) if _has_control_character(output_string): raise CookieError("Control characters are not allowed in cookies") # Base64-encode value to avoid template # injection in cookie values. - output_encoded = base64.b64encode(output_string.encode('utf-8')).decode("ascii") + output_encoded = urllib.parse.quote(output_string, safe='', encoding='utf-8') return """ """ % (output_encoded,) diff --git a/Lib/test/test_http_cookies.py b/Lib/test/test_http_cookies.py index cde268e3241850..d1df2ec42f0d14 100644 --- a/Lib/test/test_http_cookies.py +++ b/Lib/test/test_http_cookies.py @@ -1,11 +1,11 @@ # Simple test suite for http/cookies.py -import base64 import copy import unittest import doctest from http import cookies import pickle from test import support +import urllib.parse class CookieTests(unittest.TestCase): @@ -152,21 +152,21 @@ def test_load(self): self.assertEqual(C.output(['path']), 'Set-Cookie: Customer="WILE_E_COYOTE"; Path=/acme') - cookie_encoded = base64.b64encode(b'Customer="WILE_E_COYOTE"; Path=/acme; Version=1').decode('ascii') + cookie_encoded = urllib.parse.quote('Customer="WILE_E_COYOTE"; Path=/acme; Version=1', safe='', encoding='utf-8') with self.assertWarnsRegex(DeprecationWarning, r"BaseCookie\.js_output"): self.assertEqual(C.js_output(), fr""" """) - cookie_encoded = base64.b64encode(b'Customer="WILE_E_COYOTE"; Path=/acme').decode('ascii') + cookie_encoded = urllib.parse.quote('Customer="WILE_E_COYOTE"; Path=/acme', safe='', encoding='utf-8') with self.assertWarnsRegex(DeprecationWarning, r"BaseCookie\.js_output"): self.assertEqual(C.js_output(['path']), fr""" """) @@ -271,21 +271,21 @@ def test_quoted_meta(self): self.assertEqual(C.output(['path']), 'Set-Cookie: Customer="WILE_E_COYOTE"; Path=/acme') - expected_encoded_cookie = base64.b64encode(b'Customer=\"WILE_E_COYOTE\"; Path=/acme; Version=1').decode('ascii') + expected_encoded_cookie = urllib.parse.quote('Customer=\"WILE_E_COYOTE\"; Path=/acme; Version=1', safe='', encoding='utf-8') with self.assertWarnsRegex(DeprecationWarning, r"BaseCookie\.js_output"): self.assertEqual(C.js_output(), fr""" """) - expected_encoded_cookie = base64.b64encode(b'Customer=\"WILE_E_COYOTE\"; Path=/acme').decode('ascii') + expected_encoded_cookie = urllib.parse.quote('Customer=\"WILE_E_COYOTE\"; Path=/acme', safe='', encoding='utf-8') with self.assertWarnsRegex(DeprecationWarning, r"BaseCookie\.js_output"): self.assertEqual(C.js_output(['path']), fr""" """) @@ -376,13 +376,14 @@ def test_setter(self): self.assertEqual( M.output(), "Set-Cookie: %s=%s; Path=/foo" % (i, "%s_coded_val" % i)) - expected_encoded_cookie = base64.b64encode( - ("%s=%s; Path=/foo" % (i, "%s_coded_val" % i)).encode("ascii") - ).decode('ascii') + expected_encoded_cookie = urllib.parse.quote( + "%s=%s; Path=/foo" % (i, "%s_coded_val" % i), + safe='', encoding='utf-8', + ) expected_js_output = """ """ % (expected_encoded_cookie,) From 168a3c85be3f34dcd4175311a0bac558dcaa5ef7 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 15 May 2026 09:24:43 +0200 Subject: [PATCH 060/818] [3.15] gh-149763: Improve availablity docs in `select.rst` (GH-149764) (#149854) gh-149763: Improve availablity docs in `select.rst` (GH-149764) (cherry picked from commit 7e98debdf4bfcf1c3f592c9424bc654117c2723e) Co-authored-by: sobolevn --- Doc/library/select.rst | 260 +++++++++++++++++++++-------------------- 1 file changed, 135 insertions(+), 125 deletions(-) diff --git a/Doc/library/select.rst b/Doc/library/select.rst index 09563af14d018a..6400005871746a 100644 --- a/Doc/library/select.rst +++ b/Doc/library/select.rst @@ -37,7 +37,7 @@ The module defines the following: .. function:: devpoll() - (Only supported on Solaris and derivatives.) Returns a ``/dev/poll`` + Returns a ``/dev/poll`` polling object; see section :ref:`devpoll-objects` below for the methods supported by devpoll objects. @@ -54,9 +54,11 @@ The module defines the following: .. versionchanged:: 3.4 The new file descriptor is now non-inheritable. + .. availability:: Solaris. + .. function:: epoll(sizehint=-1, flags=0) - (Only supported on Linux 2.5.44 and newer.) Return an edge polling object, + Return an edge polling object, which can be used as Edge or Level Triggered interface for I/O events. @@ -94,18 +96,22 @@ The module defines the following: When CPython is built, this function may be disabled using :option:`--disable-epoll`. + .. availability:: Linux >= 2.5.44. + .. function:: poll() - (Not supported by all operating systems.) Returns a polling object, which + Returns a polling object, which supports registering and unregistering file descriptors, and then polling them for I/O events; see section :ref:`poll-objects` below for the methods supported by polling objects. + .. availability:: Unix. + .. function:: kqueue() - (Only supported on BSD.) Returns a kernel queue object; see section + Returns a kernel queue object; see section :ref:`kqueue-objects` below for the methods supported by kqueue objects. The new file descriptor is :ref:`non-inheritable `. @@ -113,12 +119,16 @@ The module defines the following: .. versionchanged:: 3.4 The new file descriptor is now non-inheritable. + .. availability:: BSD, macOS. + .. function:: kevent(ident, filter=KQ_FILTER_READ, flags=KQ_EV_ADD, fflags=0, data=0, udata=0) - (Only supported on BSD.) Returns a kernel event object; see section + Returns a kernel event object; see section :ref:`kevent-objects` below for the methods supported by kevent objects. + .. availability:: BSD, macOS. + .. function:: select(rlist, wlist, xlist, timeout=None) @@ -190,7 +200,7 @@ The module defines the following: .. _devpoll-objects: -``/dev/poll`` Polling Objects +``/dev/poll`` polling objects ----------------------------- Solaris and derivatives have ``/dev/poll``. While :c:func:`!select` is @@ -285,52 +295,52 @@ object. .. _epoll-objects: -Edge and Level Trigger Polling (epoll) Objects +Edge and level trigger polling (epoll) objects ---------------------------------------------- https://linux.die.net/man/4/epoll - *eventmask* - - +-------------------------+-----------------------------------------------+ - | Constant | Meaning | - +=========================+===============================================+ - | :const:`EPOLLIN` | Available for read | - +-------------------------+-----------------------------------------------+ - | :const:`EPOLLOUT` | Available for write | - +-------------------------+-----------------------------------------------+ - | :const:`EPOLLPRI` | Urgent data for read | - +-------------------------+-----------------------------------------------+ - | :const:`EPOLLERR` | Error condition happened on the assoc. fd | - +-------------------------+-----------------------------------------------+ - | :const:`EPOLLHUP` | Hang up happened on the assoc. fd | - +-------------------------+-----------------------------------------------+ - | :const:`EPOLLET` | Set Edge Trigger behavior, the default is | - | | Level Trigger behavior | - +-------------------------+-----------------------------------------------+ - | :const:`EPOLLONESHOT` | Set one-shot behavior. After one event is | - | | pulled out, the fd is internally disabled | - +-------------------------+-----------------------------------------------+ - | :const:`EPOLLEXCLUSIVE` | Wake only one epoll object when the | - | | associated fd has an event. The default (if | - | | this flag is not set) is to wake all epoll | - | | objects polling on a fd. | - +-------------------------+-----------------------------------------------+ - | :const:`EPOLLRDHUP` | Stream socket peer closed connection or shut | - | | down writing half of connection. | - +-------------------------+-----------------------------------------------+ - | :const:`EPOLLRDNORM` | Equivalent to :const:`EPOLLIN` | - +-------------------------+-----------------------------------------------+ - | :const:`EPOLLRDBAND` | Priority data band can be read. | - +-------------------------+-----------------------------------------------+ - | :const:`EPOLLWRNORM` | Equivalent to :const:`EPOLLOUT` | - +-------------------------+-----------------------------------------------+ - | :const:`EPOLLWRBAND` | Priority data may be written. | - +-------------------------+-----------------------------------------------+ - | :const:`EPOLLMSG` | Ignored. | - +-------------------------+-----------------------------------------------+ - | :const:`EPOLLWAKEUP` | Prevents sleep during event waiting. | - +-------------------------+-----------------------------------------------+ + The *eventmask* is a bit mask using the following constants: + + +-------------------------+------------------------------------------------+ + | Constant | Meaning | + +=========================+================================================+ + | :const:`EPOLLIN` | Available for read. | + +-------------------------+------------------------------------------------+ + | :const:`EPOLLOUT` | Available for write. | + +-------------------------+------------------------------------------------+ + | :const:`EPOLLPRI` | Urgent data for read. | + +-------------------------+------------------------------------------------+ + | :const:`EPOLLERR` | Error condition happened on the associated fd. | + +-------------------------+------------------------------------------------+ + | :const:`EPOLLHUP` | Hang up happened on the associated fd. | + +-------------------------+------------------------------------------------+ + | :const:`EPOLLET` | Set Edge Trigger behavior, the default is | + | | Level Trigger behavior. | + +-------------------------+------------------------------------------------+ + | :const:`EPOLLONESHOT` | Set one-shot behavior. After one event is | + | | pulled out, the fd is internally disabled. | + +-------------------------+------------------------------------------------+ + | :const:`EPOLLEXCLUSIVE` | Wake only one epoll object when the | + | | associated fd has an event. The default (if | + | | this flag is not set) is to wake all epoll | + | | objects polling on an fd. | + +-------------------------+------------------------------------------------+ + | :const:`EPOLLRDHUP` | Stream socket peer closed connection or shut | + | | down writing half of connection. | + +-------------------------+------------------------------------------------+ + | :const:`EPOLLRDNORM` | Equivalent to :const:`EPOLLIN` | + +-------------------------+------------------------------------------------+ + | :const:`EPOLLRDBAND` | Priority data band can be read. | + +-------------------------+------------------------------------------------+ + | :const:`EPOLLWRNORM` | Equivalent to :const:`EPOLLOUT`. | + +-------------------------+------------------------------------------------+ + | :const:`EPOLLWRBAND` | Priority data may be written. | + +-------------------------+------------------------------------------------+ + | :const:`EPOLLMSG` | Ignored. | + +-------------------------+------------------------------------------------+ + | :const:`EPOLLWAKEUP` | Prevents sleep during event waiting. | + +-------------------------+------------------------------------------------+ .. versionadded:: 3.6 :const:`EPOLLEXCLUSIVE` was added. It's only supported by Linux Kernel 4.5 @@ -362,12 +372,12 @@ Edge and Level Trigger Polling (epoll) Objects .. method:: epoll.register(fd[, eventmask]) - Register a fd descriptor with the epoll object. + Register a file descriptor *fd* with the epoll object. .. method:: epoll.modify(fd, eventmask) - Modify a registered file descriptor. + Modify a registered file descriptor *fd*. .. method:: epoll.unregister(fd) @@ -396,7 +406,7 @@ Edge and Level Trigger Polling (epoll) Objects .. _poll-objects: -Polling Objects +Polling objects --------------- The :c:func:`!poll` system call, supported on most Unix systems, provides better @@ -421,24 +431,24 @@ linearly scanned again. :c:func:`!select` is *O*\ (*highest file descriptor*), w :const:`POLLPRI`, and :const:`POLLOUT`, described in the table below. If not specified, the default value used will check for all 3 types of events. - +-------------------+------------------------------------------+ - | Constant | Meaning | - +===================+==========================================+ - | :const:`POLLIN` | There is data to read | - +-------------------+------------------------------------------+ - | :const:`POLLPRI` | There is urgent data to read | - +-------------------+------------------------------------------+ - | :const:`POLLOUT` | Ready for output: writing will not block | - +-------------------+------------------------------------------+ - | :const:`POLLERR` | Error condition of some sort | - +-------------------+------------------------------------------+ - | :const:`POLLHUP` | Hung up | - +-------------------+------------------------------------------+ - | :const:`POLLRDHUP`| Stream socket peer closed connection, or | - | | shut down writing half of connection | - +-------------------+------------------------------------------+ - | :const:`POLLNVAL` | Invalid request: descriptor not open | - +-------------------+------------------------------------------+ + +-------------------+-------------------------------------------+ + | Constant | Meaning | + +===================+===========================================+ + | :const:`POLLIN` | There is data to read. | + +-------------------+-------------------------------------------+ + | :const:`POLLPRI` | There is urgent data to read. | + +-------------------+-------------------------------------------+ + | :const:`POLLOUT` | Ready for output: writing will not block. | + +-------------------+-------------------------------------------+ + | :const:`POLLERR` | Error condition of some sort. | + +-------------------+-------------------------------------------+ + | :const:`POLLHUP` | Hung up. | + +-------------------+-------------------------------------------+ + | :const:`POLLRDHUP`| Stream socket peer closed connection, or | + | | shut down writing half of connection. | + +-------------------+-------------------------------------------+ + | :const:`POLLNVAL` | Invalid request: descriptor not open. | + +-------------------+-------------------------------------------+ Registering a file descriptor that's already registered is not an error, and has the same effect as registering the descriptor exactly once. @@ -489,7 +499,7 @@ linearly scanned again. :c:func:`!select` is *O*\ (*highest file descriptor*), w .. _kqueue-objects: -Kqueue Objects +Kqueue objects -------------- .. method:: kqueue.close() @@ -533,7 +543,7 @@ Kqueue Objects .. _kevent-objects: -Kevent Objects +Kevent objects -------------- https://man.freebsd.org/cgi/man.cgi?query=kqueue&sektion=2 @@ -553,66 +563,66 @@ https://man.freebsd.org/cgi/man.cgi?query=kqueue&sektion=2 | Constant | Meaning | +===========================+=============================================+ | :const:`KQ_FILTER_READ` | Takes a descriptor and returns whenever | - | | there is data available to read | + | | there is data available to read. | +---------------------------+---------------------------------------------+ | :const:`KQ_FILTER_WRITE` | Takes a descriptor and returns whenever | - | | there is data available to write | + | | there is data available to write. | +---------------------------+---------------------------------------------+ - | :const:`KQ_FILTER_AIO` | AIO requests | + | :const:`KQ_FILTER_AIO` | AIO requests. | +---------------------------+---------------------------------------------+ | :const:`KQ_FILTER_VNODE` | Returns when one or more of the requested | - | | events watched in *fflag* occurs | + | | events watched in *fflag* occurs. | +---------------------------+---------------------------------------------+ - | :const:`KQ_FILTER_PROC` | Watch for events on a process id | + | :const:`KQ_FILTER_PROC` | Watch for events on a process ID. | +---------------------------+---------------------------------------------+ | :const:`KQ_FILTER_NETDEV` | Watch for events on a network device | - | | [not available on macOS] | + | | (not available on macOS). | +---------------------------+---------------------------------------------+ | :const:`KQ_FILTER_SIGNAL` | Returns whenever the watched signal is | - | | delivered to the process | + | | delivered to the process. | +---------------------------+---------------------------------------------+ - | :const:`KQ_FILTER_TIMER` | Establishes an arbitrary timer | + | :const:`KQ_FILTER_TIMER` | Establishes an arbitrary timer. | +---------------------------+---------------------------------------------+ .. attribute:: kevent.flags Filter action. - +---------------------------+---------------------------------------------+ - | Constant | Meaning | - +===========================+=============================================+ - | :const:`KQ_EV_ADD` | Adds or modifies an event | - +---------------------------+---------------------------------------------+ - | :const:`KQ_EV_DELETE` | Removes an event from the queue | - +---------------------------+---------------------------------------------+ - | :const:`KQ_EV_ENABLE` | Permits control() to return the event | - +---------------------------+---------------------------------------------+ - | :const:`KQ_EV_DISABLE` | Disables event | - +---------------------------+---------------------------------------------+ - | :const:`KQ_EV_ONESHOT` | Removes event after first occurrence | - +---------------------------+---------------------------------------------+ - | :const:`KQ_EV_CLEAR` | Reset the state after an event is retrieved | - +---------------------------+---------------------------------------------+ - | :const:`KQ_EV_SYSFLAGS` | internal event | - +---------------------------+---------------------------------------------+ - | :const:`KQ_EV_FLAG1` | internal event | - +---------------------------+---------------------------------------------+ - | :const:`KQ_EV_EOF` | Filter specific EOF condition | - +---------------------------+---------------------------------------------+ - | :const:`KQ_EV_ERROR` | See return values | - +---------------------------+---------------------------------------------+ + +---------------------------+----------------------------------------------+ + | Constant | Meaning | + +===========================+==============================================+ + | :const:`KQ_EV_ADD` | Adds or modifies an event. | + +---------------------------+----------------------------------------------+ + | :const:`KQ_EV_DELETE` | Removes an event from the queue. | + +---------------------------+----------------------------------------------+ + | :const:`KQ_EV_ENABLE` | Permits control() to return the event. | + +---------------------------+----------------------------------------------+ + | :const:`KQ_EV_DISABLE` | Disables event. | + +---------------------------+----------------------------------------------+ + | :const:`KQ_EV_ONESHOT` | Removes event after first occurrence. | + +---------------------------+----------------------------------------------+ + | :const:`KQ_EV_CLEAR` | Reset the state after an event is retrieved. | + +---------------------------+----------------------------------------------+ + | :const:`KQ_EV_SYSFLAGS` | Internal event. | + +---------------------------+----------------------------------------------+ + | :const:`KQ_EV_FLAG1` | Internal event. | + +---------------------------+----------------------------------------------+ + | :const:`KQ_EV_EOF` | Filter-specific EOF condition. | + +---------------------------+----------------------------------------------+ + | :const:`KQ_EV_ERROR` | See return values. | + +---------------------------+----------------------------------------------+ .. attribute:: kevent.fflags - Filter specific flags. + Filter-specific flags. :const:`KQ_FILTER_READ` and :const:`KQ_FILTER_WRITE` filter flags: +----------------------------+--------------------------------------------+ | Constant | Meaning | +============================+============================================+ - | :const:`KQ_NOTE_LOWAT` | low water mark of a socket buffer | + | :const:`KQ_NOTE_LOWAT` | Low water mark of a socket buffer. | +----------------------------+--------------------------------------------+ :const:`KQ_FILTER_VNODE` filter flags: @@ -620,19 +630,19 @@ https://man.freebsd.org/cgi/man.cgi?query=kqueue&sektion=2 +----------------------------+--------------------------------------------+ | Constant | Meaning | +============================+============================================+ - | :const:`KQ_NOTE_DELETE` | *unlink()* was called | + | :const:`KQ_NOTE_DELETE` | *unlink()* was called. | +----------------------------+--------------------------------------------+ - | :const:`KQ_NOTE_WRITE` | a write occurred | + | :const:`KQ_NOTE_WRITE` | A write occurred. | +----------------------------+--------------------------------------------+ - | :const:`KQ_NOTE_EXTEND` | the file was extended | + | :const:`KQ_NOTE_EXTEND` | The file was extended. | +----------------------------+--------------------------------------------+ - | :const:`KQ_NOTE_ATTRIB` | an attribute was changed | + | :const:`KQ_NOTE_ATTRIB` | An attribute was changed. | +----------------------------+--------------------------------------------+ - | :const:`KQ_NOTE_LINK` | the link count has changed | + | :const:`KQ_NOTE_LINK` | The link count has changed. | +----------------------------+--------------------------------------------+ - | :const:`KQ_NOTE_RENAME` | the file was renamed | + | :const:`KQ_NOTE_RENAME` | The file was renamed. | +----------------------------+--------------------------------------------+ - | :const:`KQ_NOTE_REVOKE` | access to the file was revoked | + | :const:`KQ_NOTE_REVOKE` | Access to the file was revoked. | +----------------------------+--------------------------------------------+ :const:`KQ_FILTER_PROC` filter flags: @@ -640,22 +650,22 @@ https://man.freebsd.org/cgi/man.cgi?query=kqueue&sektion=2 +----------------------------+--------------------------------------------+ | Constant | Meaning | +============================+============================================+ - | :const:`KQ_NOTE_EXIT` | the process has exited | + | :const:`KQ_NOTE_EXIT` | The process has exited. | +----------------------------+--------------------------------------------+ - | :const:`KQ_NOTE_FORK` | the process has called *fork()* | + | :const:`KQ_NOTE_FORK` | The process has called *fork()*. | +----------------------------+--------------------------------------------+ - | :const:`KQ_NOTE_EXEC` | the process has executed a new process | + | :const:`KQ_NOTE_EXEC` | The process has executed a new process. | +----------------------------+--------------------------------------------+ - | :const:`KQ_NOTE_PCTRLMASK` | internal filter flag | + | :const:`KQ_NOTE_PCTRLMASK` | Internal filter flag. | +----------------------------+--------------------------------------------+ - | :const:`KQ_NOTE_PDATAMASK` | internal filter flag | + | :const:`KQ_NOTE_PDATAMASK` | Internal filter flag. | +----------------------------+--------------------------------------------+ - | :const:`KQ_NOTE_TRACK` | follow a process across *fork()* | + | :const:`KQ_NOTE_TRACK` | Follow a process across *fork()*. | +----------------------------+--------------------------------------------+ - | :const:`KQ_NOTE_CHILD` | returned on the child process for | - | | *NOTE_TRACK* | + | :const:`KQ_NOTE_CHILD` | Returned on the child process for | + | | *NOTE_TRACK*. | +----------------------------+--------------------------------------------+ - | :const:`KQ_NOTE_TRACKERR` | unable to attach to a child | + | :const:`KQ_NOTE_TRACKERR` | Unable to attach to a child. | +----------------------------+--------------------------------------------+ :const:`KQ_FILTER_NETDEV` filter flags (not available on macOS): @@ -663,19 +673,19 @@ https://man.freebsd.org/cgi/man.cgi?query=kqueue&sektion=2 +----------------------------+--------------------------------------------+ | Constant | Meaning | +============================+============================================+ - | :const:`KQ_NOTE_LINKUP` | link is up | + | :const:`KQ_NOTE_LINKUP` | Link is up. | +----------------------------+--------------------------------------------+ - | :const:`KQ_NOTE_LINKDOWN` | link is down | + | :const:`KQ_NOTE_LINKDOWN` | Link is down. | +----------------------------+--------------------------------------------+ - | :const:`KQ_NOTE_LINKINV` | link state is invalid | + | :const:`KQ_NOTE_LINKINV` | Link state is invalid. | +----------------------------+--------------------------------------------+ .. attribute:: kevent.data - Filter specific data. + Filter-specific data. .. attribute:: kevent.udata - User defined value. + User-defined value. From 5dadc64673ce875ebfb24163907777dae0f6ca06 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 15 May 2026 12:50:45 +0200 Subject: [PATCH 061/818] [3.15] gh-87451: Apply CVE-2021-4189 PASV fix to ftplib.ftpcp() (GH-149648) (#149792) gh-87451: Apply CVE-2021-4189 PASV fix to ftplib.ftpcp() (GH-149648) ftpcp() called parse227() directly and passed the source server's self-reported PASV IPv4 address to the target server's PORT command, bypassing the CVE-2021-4189 fix that was applied only to FTP.makepasv(). A malicious source FTP server could use this to redirect the target server's data connection to an arbitrary host:port (SSRF). ftpcp() now uses the source server's actual peer address, honoring the existing trust_server_pasv_ipv4_address opt-out, the same as makepasv(). Thanks to Qi Ding at Aurascape AI for the report. (GHSA-w8c5-q2xf-gf7c) (cherry picked from commit eac4fe3b2c77693790a5ef7dfab127c1fee81bf9) Co-authored-by: Gregory P. Smith <68491+gpshead@users.noreply.github.com> --- Lib/ftplib.py | 11 +++++- Lib/test/test_ftplib.py | 36 ++++++++++++++++++- ...6-05-10-18-05-32.gh-issue-87451.XkKB6M.rst | 6 ++++ 3 files changed, 51 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Security/2026-05-10-18-05-32.gh-issue-87451.XkKB6M.rst diff --git a/Lib/ftplib.py b/Lib/ftplib.py index 640acc64f620cc..2f092d50f31782 100644 --- a/Lib/ftplib.py +++ b/Lib/ftplib.py @@ -883,7 +883,16 @@ def ftpcp(source, sourcename, target, targetname = '', type = 'I'): type = 'TYPE ' + type source.voidcmd(type) target.voidcmd(type) - sourcehost, sourceport = parse227(source.sendcmd('PASV')) + # Don't trust the IPv4 address the source server advertises in its PASV + # reply: a malicious source could otherwise point the target's data + # connection at an arbitrary host (SSRF). A caller that needs the old + # behavior can set trust_server_pasv_ipv4_address on the source FTP + # object. See FTP.makepasv(), which applies the same rule. + untrusted_host, sourceport = parse227(source.sendcmd('PASV')) + if source.trust_server_pasv_ipv4_address: + sourcehost = untrusted_host + else: + sourcehost = source.sock.getpeername()[0] target.sendport(sourcehost, sourceport) # RFC 959: the user must "listen" [...] BEFORE sending the # transfer request. diff --git a/Lib/test/test_ftplib.py b/Lib/test/test_ftplib.py index c864d401f9ed67..f1eff9430f7351 100644 --- a/Lib/test/test_ftplib.py +++ b/Lib/test/test_ftplib.py @@ -16,7 +16,7 @@ except ImportError: ssl = None -from unittest import TestCase, skipUnless +from unittest import mock, TestCase, skipUnless from test import support from test.support import requires_subprocess from test.support import threading_helper @@ -1145,6 +1145,40 @@ def testTimeoutDirectAccess(self): ftp.close() +class TestFtpcpSecurity(TestCase): + """ftpcp() must not trust the host a source server advertises in PASV. + + A malicious source server can otherwise redirect the target server's + data connection to an arbitrary host:port (SSRF), so ftpcp() uses the + source server's actual peer address instead, the same as FTP.makepasv(). + """ + + def _make_pair(self, *, advertised_host, real_host, trust=False): + source = mock.Mock(spec=ftplib.FTP) + source.trust_server_pasv_ipv4_address = trust + source.sock.getpeername.return_value = (real_host, 21) + # PASV replies give the host as comma-separated octets, not dotted. + advertised = advertised_host.replace('.', ',') + source.sendcmd.side_effect = lambda cmd: ( + f'227 Entering Passive Mode ({advertised},1,2).' + if cmd == 'PASV' else '150 ok') + target = mock.Mock(spec=ftplib.FTP) + target.sendcmd.return_value = '150 ok' + return source, target + + def test_ftpcp_ignores_untrusted_pasv_host(self): + source, target = self._make_pair(advertised_host='10.0.0.5', + real_host='198.51.100.7') + ftplib.ftpcp(source, 'a', target, 'b') + target.sendport.assert_called_once_with('198.51.100.7', 258) + + def test_ftpcp_trust_server_pasv_ipv4_address(self): + source, target = self._make_pair(advertised_host='10.0.0.5', + real_host='198.51.100.7', trust=True) + ftplib.ftpcp(source, 'a', target, 'b') + target.sendport.assert_called_once_with('10.0.0.5', 258) + + class MiscTestCase(TestCase): def test__all__(self): not_exported = { diff --git a/Misc/NEWS.d/next/Security/2026-05-10-18-05-32.gh-issue-87451.XkKB6M.rst b/Misc/NEWS.d/next/Security/2026-05-10-18-05-32.gh-issue-87451.XkKB6M.rst new file mode 100644 index 00000000000000..21a79c3e0e7db7 --- /dev/null +++ b/Misc/NEWS.d/next/Security/2026-05-10-18-05-32.gh-issue-87451.XkKB6M.rst @@ -0,0 +1,6 @@ +The :mod:`ftplib` module's undocumented ``ftpcp`` function no longer trusts +the IPv4 address value returned from the source server in response to the +``PASV`` command by default, completing the fix for CVE-2021-4189. As with +:class:`ftplib.FTP`, the former behavior can be re-enabled by setting the +``trust_server_pasv_ipv4_address`` attribute on the source :class:`ftplib.FTP` +instance to ``True``. Thanks to Qi Deng at Aurascape AI for the report. From 8d32ae75d45ff0c9fd848b78a95bbec882d7ca3a Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 15 May 2026 13:36:21 +0200 Subject: [PATCH 062/818] [3.15] gh-149707: Fix compiler warning in _ctypes_test on strchr() (#149791) (#149865) gh-149707: Fix compiler warning in _ctypes_test on strchr() (#149791) Change my_strchr() return type to "const char*" (add "const"). Fix the compiler warning: Modules/_ctypes/_ctypes_test.c: In function 'my_strchr': Modules/_ctypes/_ctypes_test.c:451:12: warning: return discards 'const' qualifier from pointer target type [-Wdiscarded-qualifiers] 451 | return strchr(s, c); | ^~~~~~ When using C23, strchr(text, ch) return type is "const char*" if text type is "const char*". (cherry picked from commit 5465b69255890650df99debb8256e0a7bc68138b) --- Modules/_ctypes/_ctypes_test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/_ctypes/_ctypes_test.c b/Modules/_ctypes/_ctypes_test.c index a0c9d8b70fee46..991ff0d675c2f1 100644 --- a/Modules/_ctypes/_ctypes_test.c +++ b/Modules/_ctypes/_ctypes_test.c @@ -446,7 +446,7 @@ EXPORT(char *)my_strtok(char *token, const char *delim) return strtok(token, delim); } -EXPORT(char *)my_strchr(const char *s, int c) +EXPORT(const char *) my_strchr(const char *s, int c) { return strchr(s, c); } From cc624f74ba6d4a2b9fc39330c851269b02f8d9c9 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 15 May 2026 13:52:55 +0200 Subject: [PATCH 063/818] [3.15] gh-148675: Use a string for ctypes cparam tag (GH-149778) (#149869) gh-148675: Use a string for ctypes cparam tag (GH-149778) (cherry picked from commit 3ecca22567249ae44bf4369fbdb4d6d056701405) Co-authored-by: Victor Stinner --- Lib/test/test_ctypes/test_parameters.py | 8 +++++ Modules/_ctypes/_ctypes.c | 32 +++++++++--------- Modules/_ctypes/callproc.c | 45 +++++++++++++------------ Modules/_ctypes/ctypes.h | 4 +-- 4 files changed, 50 insertions(+), 39 deletions(-) diff --git a/Lib/test/test_ctypes/test_parameters.py b/Lib/test/test_ctypes/test_parameters.py index 46f8ff93efa915..6dadb7b410d703 100644 --- a/Lib/test/test_ctypes/test_parameters.py +++ b/Lib/test/test_ctypes/test_parameters.py @@ -1,6 +1,7 @@ import sys import unittest import test.support +import ctypes from ctypes import (CDLL, PyDLL, ArgumentError, Structure, Array, Union, _Pointer, _SimpleCData, _CFuncPtr, @@ -247,6 +248,13 @@ def test_parameter_repr(self): self.assertRegex(repr(c_char_p.from_param(b'hihi')), r"^$") self.assertRegex(repr(c_wchar_p.from_param('hihi')), r"^$") self.assertRegex(repr(c_void_p.from_param(0x12)), r"^$") + if hasattr(ctypes, 'c_double_complex'): + self.assertRegex(repr(ctypes.c_double_complex.from_param(0)), + r"^$") + self.assertRegex(repr(ctypes.c_float_complex.from_param(0)), + r"^$") + self.assertRegex(repr(ctypes.c_longdouble_complex.from_param(0)), + r"^$") @test.support.cpython_only def test_from_param_result_refcount(self): diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c index 98ac821c525a64..09eae97dd21a36 100644 --- a/Modules/_ctypes/_ctypes.c +++ b/Modules/_ctypes/_ctypes.c @@ -708,7 +708,7 @@ StructUnionType_paramfunc(ctypes_state *st, CDataObject *self) } assert(stginfo); /* Cannot be NULL for structure/union instances */ - parg->tag = 'V'; + parg->tag = "V"; parg->pffi_type = &stginfo->ffi_type_pointer; parg->value.p = ptr; parg->size = self->b_size; @@ -1282,7 +1282,7 @@ PyCPointerType_paramfunc(ctypes_state *st, CDataObject *self) if (parg == NULL) return NULL; - parg->tag = 'P'; + parg->tag = "P"; parg->pffi_type = &ffi_type_pointer; parg->obj = Py_NewRef(self); parg->value.p = *(void **)self->b_ptr; @@ -1703,7 +1703,7 @@ PyCArrayType_paramfunc(ctypes_state *st, CDataObject *self) PyCArgObject *p = PyCArgObject_new(st); if (p == NULL) return NULL; - p->tag = 'P'; + p->tag = "P"; p->pffi_type = &ffi_type_pointer; p->value.p = (char *)self->b_ptr; p->obj = Py_NewRef(self); @@ -1909,7 +1909,7 @@ c_wchar_p_from_param_impl(PyObject *type, PyTypeObject *cls, PyObject *value) if (parg == NULL) return NULL; parg->pffi_type = &ffi_type_pointer; - parg->tag = 'Z'; + parg->tag = "Z"; parg->obj = fd->setfunc(&parg->value, value, 0); if (parg->obj == NULL) { Py_DECREF(parg); @@ -1998,7 +1998,7 @@ c_char_p_from_param_impl(PyObject *type, PyTypeObject *cls, PyObject *value) if (parg == NULL) return NULL; parg->pffi_type = &ffi_type_pointer; - parg->tag = 'z'; + parg->tag = "z"; parg->obj = fd->setfunc(&parg->value, value, 0); if (parg->obj == NULL) { Py_DECREF(parg); @@ -2092,7 +2092,7 @@ c_void_p_from_param_impl(PyObject *type, PyTypeObject *cls, PyObject *value) if (parg == NULL) return NULL; parg->pffi_type = &ffi_type_pointer; - parg->tag = 'P'; + parg->tag = "P"; parg->obj = fd->setfunc(&parg->value, value, sizeof(void*)); if (parg->obj == NULL) { Py_DECREF(parg); @@ -2110,7 +2110,7 @@ c_void_p_from_param_impl(PyObject *type, PyTypeObject *cls, PyObject *value) if (parg == NULL) return NULL; parg->pffi_type = &ffi_type_pointer; - parg->tag = 'z'; + parg->tag = "z"; parg->obj = fd->setfunc(&parg->value, value, 0); if (parg->obj == NULL) { Py_DECREF(parg); @@ -2127,7 +2127,7 @@ c_void_p_from_param_impl(PyObject *type, PyTypeObject *cls, PyObject *value) if (parg == NULL) return NULL; parg->pffi_type = &ffi_type_pointer; - parg->tag = 'Z'; + parg->tag = "Z"; parg->obj = fd->setfunc(&parg->value, value, 0); if (parg->obj == NULL) { Py_DECREF(parg); @@ -2152,7 +2152,7 @@ c_void_p_from_param_impl(PyObject *type, PyTypeObject *cls, PyObject *value) if (PyCArg_CheckExact(st, value)) { /* byref(c_xxx()) */ PyCArgObject *a = (PyCArgObject *)value; - if (a->tag == 'P') { + if (strcmp(a->tag, "P") == 0) { return Py_NewRef(value); } } @@ -2165,7 +2165,7 @@ c_void_p_from_param_impl(PyObject *type, PyTypeObject *cls, PyObject *value) if (parg == NULL) return NULL; parg->pffi_type = &ffi_type_pointer; - parg->tag = 'P'; + parg->tag = "P"; Py_INCREF(value); // Function pointers don't change their contents, no need to lock parg->value.p = *(void **)func->b_ptr; @@ -2191,7 +2191,7 @@ c_void_p_from_param_impl(PyObject *type, PyTypeObject *cls, PyObject *value) if (parg == NULL) return NULL; parg->pffi_type = &ffi_type_pointer; - parg->tag = 'Z'; + parg->tag = "Z"; parg->obj = Py_NewRef(value); /* Remember: b_ptr points to where the pointer is stored! */ Py_BEGIN_CRITICAL_SECTION(value); @@ -2332,7 +2332,8 @@ PyCSimpleType_paramfunc(ctypes_state *st, CDataObject *self) if (parg == NULL) return NULL; - parg->tag = fmt[0]; + assert(strcmp(fd->code, fmt) == 0); + parg->tag = fd->code; parg->pffi_type = fd->pffi_type; parg->obj = Py_NewRef(self); memcpy(&parg->value, self->b_ptr, self->b_size); @@ -2578,7 +2579,8 @@ PyCSimpleType_from_param_impl(PyObject *type, PyTypeObject *cls, if (parg == NULL) return NULL; - parg->tag = fmt[0]; + assert(strcmp(fd->code, fmt) == 0); + parg->tag = fd->code; parg->pffi_type = fd->pffi_type; parg->obj = fd->setfunc(&parg->value, value, info->size); if (parg->obj) @@ -2832,7 +2834,7 @@ PyCFuncPtrType_paramfunc(ctypes_state *st, CDataObject *self) if (parg == NULL) return NULL; - parg->tag = 'P'; + parg->tag = "P"; parg->pffi_type = &ffi_type_pointer; parg->obj = Py_NewRef(self); parg->value.p = *(void **)self->b_ptr; @@ -4303,7 +4305,7 @@ _byref(ctypes_state *st, PyObject *obj) return NULL; } - parg->tag = 'P'; + parg->tag = "P"; parg->pffi_type = &ffi_type_pointer; parg->obj = obj; parg->value.p = ((CDataObject *)obj)->b_ptr; diff --git a/Modules/_ctypes/callproc.c b/Modules/_ctypes/callproc.c index e208e27c5dbed4..e453cfeec9cc8c 100644 --- a/Modules/_ctypes/callproc.c +++ b/Modules/_ctypes/callproc.c @@ -468,7 +468,7 @@ PyCArgObject_new(ctypes_state *st) if (p == NULL) return NULL; p->pffi_type = NULL; - p->tag = '\0'; + p->tag = ""; p->obj = NULL; memset(&p->value, 0, sizeof(p->value)); PyObject_GC_Track(p); @@ -512,45 +512,50 @@ static PyObject * PyCArg_repr(PyObject *op) { PyCArgObject *self = _PyCArgObject_CAST(op); - switch(self->tag) { + + if (strlen(self->tag) != 1) { + goto generic; + } + + switch(self->tag[0]) { case 'b': case 'B': - return PyUnicode_FromFormat("", + return PyUnicode_FromFormat("", self->tag, self->value.b); case 'h': case 'H': - return PyUnicode_FromFormat("", + return PyUnicode_FromFormat("", self->tag, self->value.h); case 'i': case 'I': - return PyUnicode_FromFormat("", + return PyUnicode_FromFormat("", self->tag, self->value.i); case 'l': case 'L': - return PyUnicode_FromFormat("", + return PyUnicode_FromFormat("", self->tag, self->value.l); case 'q': case 'Q': - return PyUnicode_FromFormat("", + return PyUnicode_FromFormat("", self->tag, self->value.q); case 'd': case 'f': { - PyObject *f = PyFloat_FromDouble((self->tag == 'f') ? self->value.f : self->value.d); + PyObject *f = PyFloat_FromDouble((strcmp(self->tag, "f") == 0) ? self->value.f : self->value.d); if (f == NULL) { return NULL; } - PyObject *result = PyUnicode_FromFormat("", self->tag, f); + PyObject *result = PyUnicode_FromFormat("", self->tag, f); Py_DECREF(f); return result; } case 'c': if (is_literal_char((unsigned char)self->value.c)) { - return PyUnicode_FromFormat("", + return PyUnicode_FromFormat("", self->tag, self->value.c); } else { - return PyUnicode_FromFormat("", + return PyUnicode_FromFormat("", self->tag, (unsigned char)self->value.c); } @@ -561,20 +566,16 @@ PyCArg_repr(PyObject *op) case 'z': case 'Z': case 'P': - return PyUnicode_FromFormat("", + return PyUnicode_FromFormat("", self->tag, self->value.p); - break; default: - if (is_literal_char((unsigned char)self->tag)) { - return PyUnicode_FromFormat("", - (unsigned char)self->tag, (void *)self); - } - else { - return PyUnicode_FromFormat("", - (unsigned char)self->tag, (void *)self); - } + break; } + +generic: + return PyUnicode_FromFormat("", + self->tag, (void *)self); } static PyMemberDef PyCArgType_members[] = { @@ -1807,7 +1808,7 @@ _ctypes_byref_impl(PyObject *module, PyObject *obj, Py_ssize_t offset) if (parg == NULL) return NULL; - parg->tag = 'P'; + parg->tag = "P"; parg->pffi_type = &ffi_type_pointer; parg->obj = Py_NewRef(obj); parg->value.p = (char *)((CDataObject *)obj)->b_ptr + offset; diff --git a/Modules/_ctypes/ctypes.h b/Modules/_ctypes/ctypes.h index 7b6b7f08582251..248559aa364a19 100644 --- a/Modules/_ctypes/ctypes.h +++ b/Modules/_ctypes/ctypes.h @@ -494,7 +494,7 @@ PyObject *_ctypes_callproc(ctypes_state *st, struct tagPyCArgObject { PyObject_HEAD ffi_type *pffi_type; - char tag; + const char *tag; union { char c; char b; @@ -511,7 +511,7 @@ struct tagPyCArgObject { long double G[2]; } value; PyObject *obj; - Py_ssize_t size; /* for the 'V' tag */ + Py_ssize_t size; /* for the "V" tag */ }; #define _PyCArgObject_CAST(op) ((PyCArgObject *)(op)) From 176d0f51cf23e2059e89e15b0004a37121b97e1b Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 15 May 2026 14:08:15 +0200 Subject: [PATCH 064/818] [3.15] gh-149801: Add IANA registered names and aliases with leading zeros (GH-149804) (GH-149870) Like IBM00858, CP00858, IBM01140, CP01140. (cherry picked from commit 20438866aefc2e63949d8bb85d8f8e55633fd977) Co-authored-by: Serhiy Storchaka --- Doc/library/codecs.rst | 4 ++-- Lib/encodings/aliases.py | 8 ++++++++ .../2026-05-13-23-18-39.gh-issue-149801.S_FfGr.rst | 2 ++ 3 files changed, 12 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-05-13-23-18-39.gh-issue-149801.S_FfGr.rst diff --git a/Doc/library/codecs.rst b/Doc/library/codecs.rst index 9259ab10d5850b..059ed2c03acfa3 100644 --- a/Doc/library/codecs.rst +++ b/Doc/library/codecs.rst @@ -1155,7 +1155,7 @@ particular, the following variants typically exist: +-----------------+--------------------------------+--------------------------------+ | cp857 | 857, IBM857 | Turkish | +-----------------+--------------------------------+--------------------------------+ -| cp858 | 858, IBM858 | Western Europe | +| cp858 | 858, IBM00858 | Western Europe | +-----------------+--------------------------------+--------------------------------+ | cp860 | 860, IBM860 | Portuguese | +-----------------+--------------------------------+--------------------------------+ @@ -1192,7 +1192,7 @@ particular, the following variants typically exist: | | | | | | | .. versionadded:: 3.4 | +-----------------+--------------------------------+--------------------------------+ -| cp1140 | ibm1140 | Western Europe | +| cp1140 | IBM01140 | Western Europe | +-----------------+--------------------------------+--------------------------------+ | cp1250 | windows-1250 | Central and Eastern Europe | +-----------------+--------------------------------+--------------------------------+ diff --git a/Lib/encodings/aliases.py b/Lib/encodings/aliases.py index f4b1b8dd43f920..e5e50630f33d14 100644 --- a/Lib/encodings/aliases.py +++ b/Lib/encodings/aliases.py @@ -71,6 +71,10 @@ # cp1140 codec '1140' : 'cp1140', + 'cp01140' : 'cp1140', + 'csibm01140' : 'cp1140', + 'ebcdic_us_37_euro' : 'cp1140', + 'ibm01140' : 'cp1140', 'ibm1140' : 'cp1140', # cp1250 codec @@ -159,8 +163,12 @@ # cp858 codec '858' : 'cp858', + 'cp00858' : 'cp858', + 'csibm00858' : 'cp858', 'csibm858' : 'cp858', + 'ibm00858' : 'cp858', 'ibm858' : 'cp858', + 'pc_multilingual_850_euro' : 'cp858', # cp860 codec '860' : 'cp860', diff --git a/Misc/NEWS.d/next/Library/2026-05-13-23-18-39.gh-issue-149801.S_FfGr.rst b/Misc/NEWS.d/next/Library/2026-05-13-23-18-39.gh-issue-149801.S_FfGr.rst new file mode 100644 index 00000000000000..f9e8538527d204 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-05-13-23-18-39.gh-issue-149801.S_FfGr.rst @@ -0,0 +1,2 @@ +Add IANA registered names and aliases with leading zeros before number (like +IBM00858, CP00858, IBM01140, CP01140) for corresponding codecs. From b3819aeff3dde744bab025b5b451182e3fc5a3a6 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 15 May 2026 15:07:18 +0200 Subject: [PATCH 065/818] [3.15] gh-149816: Fix race condition in `memoryview` with free-threading (GH-149858) (#149875) gh-149816: Fix race condition in `memoryview` with free-threading (GH-149858) (cherry picked from commit 1fdf0337742762cc47837042747cc607f024a202) Co-authored-by: sobolevn --- ...-05-15-11-31-57.gh-issue-149816.ugN2rx.rst | 1 + Objects/memoryobject.c | 20 ++++++------------- 2 files changed, 7 insertions(+), 14 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-05-15-11-31-57.gh-issue-149816.ugN2rx.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-15-11-31-57.gh-issue-149816.ugN2rx.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-15-11-31-57.gh-issue-149816.ugN2rx.rst new file mode 100644 index 00000000000000..016c17dd66b19e --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-15-11-31-57.gh-issue-149816.ugN2rx.rst @@ -0,0 +1 @@ +Fix a race condition in :class:`memoryview` with free-threading. diff --git a/Objects/memoryobject.c b/Objects/memoryobject.c index 900db864621a84..9d1ca633780f92 100644 --- a/Objects/memoryobject.c +++ b/Objects/memoryobject.c @@ -1629,11 +1629,7 @@ memory_getbuf(PyObject *_self, Py_buffer *view, int flags) view->obj = Py_NewRef(self); -#ifdef Py_GIL_DISABLED - _Py_atomic_add_ssize(&self->exports, 1); -#else - self->exports++; -#endif + FT_ATOMIC_ADD_SSIZE(self->exports, 1); return 0; } @@ -1642,11 +1638,7 @@ static void memory_releasebuf(PyObject *_self, Py_buffer *view) { PyMemoryViewObject *self = (PyMemoryViewObject *)_self; -#ifdef Py_GIL_DISABLED - _Py_atomic_add_ssize(&self->exports, -1); -#else - self->exports--; -#endif + FT_ATOMIC_ADD_SSIZE(self->exports, -1); return; /* PyBuffer_Release() decrements view->obj after this function returns. */ } @@ -2434,9 +2426,9 @@ memoryview_hex_impl(PyMemoryViewObject *self, PyObject *sep, // Prevent 'self' from being freed if computing len(sep) mutates 'self' // in _Py_strhex_with_sep(). // See: https://github.com/python/cpython/issues/143195. - self->exports++; + FT_ATOMIC_ADD_SSIZE(self->exports, 1); PyObject *ret = _Py_strhex_with_sep(src->buf, src->len, sep, bytes_per_sep); - self->exports--; + FT_ATOMIC_ADD_SSIZE(self->exports, -1); return ret; } @@ -3363,9 +3355,9 @@ memory_hash(PyObject *_self) if (view->obj != NULL) { // Prevent 'self' from being freed when computing the item's hash. // See https://github.com/python/cpython/issues/142664. - self->exports++; + FT_ATOMIC_ADD_SSIZE(self->exports, 1); Py_hash_t h = PyObject_Hash(view->obj); - self->exports--; + FT_ATOMIC_ADD_SSIZE(self->exports, -1); if (h == -1) { /* Keep the original error message */ return -1; From a57855561e6c80be88e828183eb7a6ebc68395c2 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 15 May 2026 15:19:39 +0200 Subject: [PATCH 066/818] [3.15] gh-138489: Add build-details.json generation to PC/layout (GH-149153) (cherry picked from commit 4aa296f9c4a85a7badc09bf7ca6ede36cd8cd14c) Co-authored-by: Steve Dower --- ...-04-29-14-44-51.gh-issue-138489.234aj6.rst | 4 + PC/layout/main.py | 4 + PC/layout/support/builddetails.py | 119 ++++++++++++++++++ PC/layout/support/constants.py | 9 ++ PC/layout/support/options.py | 6 + 5 files changed, 142 insertions(+) create mode 100644 Misc/NEWS.d/next/Windows/2026-04-29-14-44-51.gh-issue-138489.234aj6.rst create mode 100644 PC/layout/support/builddetails.py diff --git a/Misc/NEWS.d/next/Windows/2026-04-29-14-44-51.gh-issue-138489.234aj6.rst b/Misc/NEWS.d/next/Windows/2026-04-29-14-44-51.gh-issue-138489.234aj6.rst new file mode 100644 index 00000000000000..4afb8f737b692e --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2026-04-29-14-44-51.gh-issue-138489.234aj6.rst @@ -0,0 +1,4 @@ +Windows distributions now include a :file:`build-details.json` file (see +:pep:`739`). The legacy installer does not install it, but all other +distributions from python.org and all preset configurations in the +``PC\layout`` script will include one. diff --git a/PC/layout/main.py b/PC/layout/main.py index 3a62ea91420c9e..f70a26b2b29659 100644 --- a/PC/layout/main.py +++ b/PC/layout/main.py @@ -22,6 +22,7 @@ __path__ = [str(Path(__file__).resolve().parent)] from .support.appxmanifest import * +from .support.builddetails import * from .support.catalog import * from .support.constants import * from .support.filesets import * @@ -317,6 +318,9 @@ def _c(d): for dest, src in get_appx_layout(ns): yield dest, src + for dest, src in get_builddetails(ns): + yield dest, src + if ns.include_cat: if ns.flat_dlls: yield ns.include_cat.name, ns.include_cat diff --git a/PC/layout/support/builddetails.py b/PC/layout/support/builddetails.py new file mode 100644 index 00000000000000..6ef860eeb04354 --- /dev/null +++ b/PC/layout/support/builddetails.py @@ -0,0 +1,119 @@ +import io +import json +from . import constants + +_LEVELS = { + 0xA0: "alpha", + 0xB0: "beta", + 0xC0: "candidate", + 0xF0: "final", +} + + +_TEMPLATE = { + "schema_version": "1.0", + "base_prefix": ".", + "base_interpreter": "python.exe", + "platform": None, # Set later + "language": { + "version": f"{constants.VER_MAJOR}.{constants.VER_MINOR}", + "version_info": { + "major": constants.VER_MAJOR, + "minor": constants.VER_MINOR, + "micro": constants.VER_MICRO, + "releaselevel": _LEVELS.get(constants.VER_FIELD4 & 0xF0, "final"), + "serial": constants.VER_FIELD4 & 0x0F, + }, + }, + "implementation": { + "name": "cpython", + "cache_tag": f"cpython-{constants.VER_MAJOR}{constants.VER_MINOR}", + "version": { + "major": constants.VER_MAJOR, + "minor": constants.VER_MINOR, + "micro": constants.VER_MICRO, + "releaselevel": _LEVELS.get(constants.VER_FIELD4 & 0xF0, "final"), + "serial": constants.VER_FIELD4 & 0x0F, + }, + "hexversion": constants.VER_HEXVERSION, + }, + "abi": { + "flags": [], + "extension_suffix": ".pyd", + "stable_abi_suffix": ".pyd", + }, + "suffixes": { + "source": [".py", ".pyw"], + "bytecode": [".pyc"], + "extensions": [".pyd"], + }, + "libpython": { + "dynamic": constants.PYTHON_DLL_NAME, + "dynamic_stableabi": constants.PYTHON_STABLE_DLL_NAME, + "link_extensions": True, + }, + "c_api": { + }, +} + + +def _with_d(path): + pre, sep, post = path.partition(".") + return pre + "_d" + sep + post + + +def _add_d(data, *args): + for a in args[:-1]: + data = data[a] + a = args[-1] + v = data[a] + if isinstance(v, list): + data[a] = [_with_d(i) for i in data[a]] + else: + data[a] = _with_d(data[a]) + + +def get_builddetails(ns): + if not ns.include_builddetails_json: + return + + details = dict(_TEMPLATE) + + plat = { + "win32": "win32", + "amd64": "win-amd64", + "arm64": "win-arm64", + }.get(ns.arch, ns.arch) + + pyd_abi_flags = "" + if ns.include_freethreaded: + details["abi"]["flags"].append("t") + pyd_abi_flags += "t" + if ns.debug: + details["abi"]["flags"].append("d") + + norm_plat = plat.replace("-", "_") + ext_suffix = f".cp{constants.VER_MAJOR}{constants.VER_MINOR}{pyd_abi_flags}-{norm_plat}.pyd" + details["abi"]["extension_suffix"] = ext_suffix + details["suffixes"]["extensions"].insert(0, ext_suffix) + + details["platform"] = plat + + if ns.include_dev: + details["c_api"]["headers"] = "Include" + + if ns.include_freethreaded: + details["libpython"]["dynamic"] = constants.FREETHREADED_PYTHON_DLL_NAME + details["libpython"]["dynamic_stableabi"] = constants.FREETHREADED_PYTHON_STABLE_DLL_NAME + + if ns.debug: + _add_d(details, "base_interpreter") + _add_d(details, "abi", "stable_abi_suffix") + _add_d(details, "abi", "extension_suffix") + _add_d(details, "suffixes", "extensions") + _add_d(details, "libpython", "dynamic") + _add_d(details, "libpython", "dynamic_stableabi") + + buffer = io.StringIO() + json.dump(details, buffer, indent=2) + yield "build-details.json", ("build-details.json", buffer.getvalue().encode()) diff --git a/PC/layout/support/constants.py b/PC/layout/support/constants.py index 6b8c915e519743..cb16f534685c8f 100644 --- a/PC/layout/support/constants.py +++ b/PC/layout/support/constants.py @@ -23,6 +23,14 @@ def _unpack_hexversion(): return _read_patchlevel_version(pathlib.Path(os.getenv("PYTHONINCLUDE"))) except OSError: pass + # Manual search for a '-s ` arument + try: + src = sys.argv[sys.argv.index("-s") + 1] + return _read_patchlevel_version(pathlib.Path(src) / "Include") + except (IndexError, ValueError): + pass + except OSError: + pass return struct.pack(">i", sys.hexversion) @@ -68,6 +76,7 @@ def check_patchlevel_version(sources): VER_MAJOR, VER_MINOR, VER_MICRO, VER_FIELD4 = _unpack_hexversion() +VER_HEXVERSION = (VER_MAJOR << 24) | (VER_MINOR << 16) | (VER_MICRO << 8) | (VER_FIELD4) VER_SUFFIX = _get_suffix(VER_FIELD4) VER_FIELD3 = VER_MICRO << 8 | VER_FIELD4 VER_DOT = "{}.{}".format(VER_MAJOR, VER_MINOR) diff --git a/PC/layout/support/options.py b/PC/layout/support/options.py index e8c393385425e7..3a6e00f720f01f 100644 --- a/PC/layout/support/options.py +++ b/PC/layout/support/options.py @@ -39,6 +39,7 @@ def public(f): "install-json": {"help": "a PyManager __install__.json file"}, "install-embed-json": {"help": "a PyManager __install__.json file for embeddable distro"}, "install-test-json": {"help": "a PyManager __install__.json for the test distro"}, + "builddetails-json": {"help": "a PEP 739 build-details.json"}, } @@ -69,6 +70,7 @@ def public(f): "props", "nuspec", "alias", + "builddetails-json", ], }, "iot": {"help": "Windows IoT Core", "options": ["alias", "stable", "pip"]}, @@ -85,6 +87,7 @@ def public(f): "symbols", "html-doc", "alias", + "builddetails-json", ], }, "embed": { @@ -96,6 +99,7 @@ def public(f): "flat-dlls", "underpth", "precompile", + "builddetails-json", ], }, "pymanager": { @@ -109,6 +113,7 @@ def public(f): "dev", "html-doc", "install-json", + "builddetails-json", ], }, "pymanager-test": { @@ -124,6 +129,7 @@ def public(f): "symbols", "tests", "install-test-json", + "builddetails-json", ], }, } From 0e2184aca0dabfe7009f1316c75d443085e2b3d6 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 15 May 2026 16:12:05 +0200 Subject: [PATCH 067/818] [3.15] gh-149786: Fixes venvlauncher builds on Windows free-threaded (GH-149847) (cherry picked from commit 1c5fe21eb2a65190c04bb3f4c0931d76f5ccf415) Co-authored-by: Steve Dower --- Lib/test/test_venv.py | 12 ++++++------ .../2026-05-14-22-09-46.gh-issue-149786.UI-HZM.rst | 1 + PC/layout/support/options.py | 2 ++ PC/layout/support/pymanager.py | 5 +++-- PCbuild/python.vcxproj | 8 ++++++++ PCbuild/pythonw.vcxproj | 8 ++++++++ PCbuild/venvlauncher.vcxproj | 7 +++++-- PCbuild/venvwlauncher.vcxproj | 7 +++++-- 8 files changed, 38 insertions(+), 12 deletions(-) create mode 100644 Misc/NEWS.d/next/Windows/2026-05-14-22-09-46.gh-issue-149786.UI-HZM.rst diff --git a/Lib/test/test_venv.py b/Lib/test/test_venv.py index a42787f261bfe8..9d2960664abfad 100644 --- a/Lib/test/test_venv.py +++ b/Lib/test/test_venv.py @@ -301,9 +301,9 @@ def test_sysconfig(self): self.assertEqual(out.strip(), expected, err) for attr, expected in ( ('executable', self.envpy()), - # Usually compare to sys.executable, but if we're running in our own - # venv then we really need to compare to our base executable - ('_base_executable', sys._base_executable), + # Usually compare to sys.prefix, but if we're running in our own + # venv then we really need to compare to our base prefix + ('base_prefix', sys.base_prefix), ): with self.subTest(attr): cmd[2] = f'import sys; print(sys.{attr})' @@ -916,10 +916,10 @@ def test_venvwlauncher(self): exename = exename.replace("python", "pythonw") envpyw = os.path.join(self.env_dir, self.bindir, exename) try: - subprocess.check_call([envpyw, "-c", "import sys; " - "assert sys._base_executable.endswith('%s')" % exename]) + subprocess.check_call([envpyw, "-c", "import fnmatch, sys; " + "assert fnmatch.fnmatch(sys._base_executable, '**/pythonw*.exe')"]) except subprocess.CalledProcessError: - self.fail("venvwlauncher.exe did not run %s" % exename) + self.fail("venvwlauncher.exe did not run pythonw.exe") @requireVenvCreate diff --git a/Misc/NEWS.d/next/Windows/2026-05-14-22-09-46.gh-issue-149786.UI-HZM.rst b/Misc/NEWS.d/next/Windows/2026-05-14-22-09-46.gh-issue-149786.UI-HZM.rst new file mode 100644 index 00000000000000..64ca91a01f41af --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2026-05-14-22-09-46.gh-issue-149786.UI-HZM.rst @@ -0,0 +1 @@ +Fixes virtual environment launchers on Windows free-threaded builds. diff --git a/PC/layout/support/options.py b/PC/layout/support/options.py index 3a6e00f720f01f..f67d8ba04d9070 100644 --- a/PC/layout/support/options.py +++ b/PC/layout/support/options.py @@ -112,6 +112,7 @@ def public(f): "venv", "dev", "html-doc", + "alias", "install-json", "builddetails-json", ], @@ -128,6 +129,7 @@ def public(f): "html-doc", "symbols", "tests", + "alias", "install-test-json", "builddetails-json", ], diff --git a/PC/layout/support/pymanager.py b/PC/layout/support/pymanager.py index 831d49ea3f9b46..f6316e0295c74a 100644 --- a/PC/layout/support/pymanager.py +++ b/PC/layout/support/pymanager.py @@ -66,8 +66,9 @@ def calculate_install_json(ns, *, for_embed=False, for_test=False): if ns.include_freethreaded: # Free-threaded distro comes with a tag suffix TAG_SUFFIX = "t" - TARGET = f"python{VER_MAJOR}.{VER_MINOR}t.exe" - TARGETW = f"pythonw{VER_MAJOR}.{VER_MINOR}t.exe" + if not ns.include_alias: + TARGET = f"python{VER_MAJOR}.{VER_MINOR}t.exe" + TARGETW = f"pythonw{VER_MAJOR}.{VER_MINOR}t.exe" DISPLAY_TAGS.append("free-threaded") FILE_SUFFIX = f"t-{ns.arch}" diff --git a/PCbuild/python.vcxproj b/PCbuild/python.vcxproj index 70dabaa3c8bc02..417ede34c54af3 100644 --- a/PCbuild/python.vcxproj +++ b/PCbuild/python.vcxproj @@ -135,6 +135,14 @@ set PYTHONPATH=$(PySourcePath)Lib "$(OutDir)$(PyExeName)$(PyDebugExt).exe" "$(PySourcePath)PC\validate_ucrtbase.py" $(UcrtName)' ContinueOnError="true" /> + + + + <_Content>@rem This script invokes the most recently built Python with all arguments diff --git a/PCbuild/pythonw.vcxproj b/PCbuild/pythonw.vcxproj index c6a5b8ce90a0d9..244cdf622ad915 100644 --- a/PCbuild/pythonw.vcxproj +++ b/PCbuild/pythonw.vcxproj @@ -115,4 +115,12 @@ + + + + \ No newline at end of file diff --git a/PCbuild/venvlauncher.vcxproj b/PCbuild/venvlauncher.vcxproj index abaf3a979af268..a2e8ffa82b10eb 100644 --- a/PCbuild/venvlauncher.vcxproj +++ b/PCbuild/venvlauncher.vcxproj @@ -89,10 +89,13 @@ - + + $(PyExeName)$(PyDebugExt).exe + $(PyExeName)$(MajorVersionNumber).$(MinorVersionNumber)t$(PyDebugExt).exe + - EXENAME=L"$(PyExeName)$(PyDebugExt).exe";_CONSOLE;%(PreprocessorDefinitions) + EXENAME=L"$(ExeName)";_CONSOLE;%(PreprocessorDefinitions) MultiThreaded diff --git a/PCbuild/venvwlauncher.vcxproj b/PCbuild/venvwlauncher.vcxproj index c58280deb8abeb..f2aaf83fe2b378 100644 --- a/PCbuild/venvwlauncher.vcxproj +++ b/PCbuild/venvwlauncher.vcxproj @@ -89,10 +89,13 @@ - + + $(PyWExeName)$(PyDebugExt).exe + $(PyWExeName)$(MajorVersionNumber).$(MinorVersionNumber)t$(PyDebugExt).exe + - EXENAME=L"$(PyWExeName)$(PyDebugExt).exe";_WINDOWS;%(PreprocessorDefinitions) + EXENAME=L"$(ExeName)";_WINDOWS;%(PreprocessorDefinitions) MultiThreaded From 6136ad68010756edfc4474ad24793e62e1b9907e Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 15 May 2026 18:57:59 +0200 Subject: [PATCH 068/818] [3.15] gh-142349: Add `help("lazy")` support (GH-149886) (#149889) gh-142349: Add `help("lazy")` support (GH-149886) (cherry picked from commit 8be3fb1b50ce6b01bf0924f0a0362a5e04af83b4) Co-authored-by: sobolevn --- Doc/tools/extensions/pydoc_topics.py | 1 + Lib/pydoc.py | 1 + Lib/test/test_pydoc/test_pydoc.py | 2 +- .../next/Library/2026-05-15-18-44-20.gh-issue-142349.fHK3v1.rst | 1 + 4 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2026-05-15-18-44-20.gh-issue-142349.fHK3v1.rst diff --git a/Doc/tools/extensions/pydoc_topics.py b/Doc/tools/extensions/pydoc_topics.py index a65d77433b255b..35878e2d1e43e9 100644 --- a/Doc/tools/extensions/pydoc_topics.py +++ b/Doc/tools/extensions/pydoc_topics.py @@ -68,6 +68,7 @@ "in", "integers", "lambda", + "lazy", "lists", "naming", "nonlocal", diff --git a/Lib/pydoc.py b/Lib/pydoc.py index a1a6aad434ddf4..497cc7d90a4245 100644 --- a/Lib/pydoc.py +++ b/Lib/pydoc.py @@ -1845,6 +1845,7 @@ class Helper: 'in': ('in', 'SEQUENCEMETHODS'), 'is': 'COMPARISON', 'lambda': ('lambda', 'FUNCTIONS'), + 'lazy': ('lazy', 'MODULES'), 'nonlocal': ('nonlocal', 'global NAMESPACES'), 'not': 'BOOLEAN', 'or': 'BOOLEAN', diff --git a/Lib/test/test_pydoc/test_pydoc.py b/Lib/test/test_pydoc/test_pydoc.py index 2e190d1b81be8e..5cd26923f75c31 100644 --- a/Lib/test/test_pydoc/test_pydoc.py +++ b/Lib/test/test_pydoc/test_pydoc.py @@ -2172,7 +2172,7 @@ def mock_getline(prompt): def test_keywords(self): self.assertEqual(sorted(pydoc.Helper.keywords), - sorted(keyword.kwlist)) + sorted(keyword.kwlist + ['lazy'])) def test_interact_empty_line_continues(self): # gh-138568: test pressing Enter without input should continue in help session diff --git a/Misc/NEWS.d/next/Library/2026-05-15-18-44-20.gh-issue-142349.fHK3v1.rst b/Misc/NEWS.d/next/Library/2026-05-15-18-44-20.gh-issue-142349.fHK3v1.rst new file mode 100644 index 00000000000000..fa667c4110941e --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-05-15-18-44-20.gh-issue-142349.fHK3v1.rst @@ -0,0 +1 @@ +Add :keyword:`lazy` to the list of support topic by :func:`help`. From ec3aa6ab4847ebd6f8f3e9b2b7023c5ab3a6e39a Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 16 May 2026 11:06:14 +0200 Subject: [PATCH 069/818] [3.15] gh-149816: Fix a race condition in `_PyBytes_FromList` with free-threading (GH-149909) (#149911) gh-149816: Fix a race condition in `_PyBytes_FromList` with free-threading (GH-149909) (cherry picked from commit 46afba7b9324bc9492c3527d0fe47dd74f1f598c) Co-authored-by: sobolevn --- .../2026-05-16-11-03-54.gh-issue-149816.X_gqMT.rst | 1 + Objects/bytesobject.c | 7 +++++-- 2 files changed, 6 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-05-16-11-03-54.gh-issue-149816.X_gqMT.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-16-11-03-54.gh-issue-149816.X_gqMT.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-16-11-03-54.gh-issue-149816.X_gqMT.rst new file mode 100644 index 00000000000000..d35f0857a1aefe --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-16-11-03-54.gh-issue-149816.X_gqMT.rst @@ -0,0 +1 @@ +Fix a race condition in ``_PyBytes_FromList`` in free-threading mode. diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c index 8a9d1b133affb3..2d694922557429 100644 --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -11,6 +11,7 @@ #include "pycore_global_objects.h"// _Py_GET_GLOBAL_OBJECT() #include "pycore_initconfig.h" // _PyStatus_OK() #include "pycore_long.h" // _PyLong_DigitValue +#include "pycore_list.h" // _PyList_GetItemRef #include "pycore_object.h" // _PyObject_GC_TRACK #include "pycore_pymem.h" // PYMEM_CLEANBYTE #include "pycore_strhex.h" // _Py_strhex_with_sep() @@ -2991,8 +2992,10 @@ _PyBytes_FromList(PyObject *x) size = _PyBytesWriter_GetAllocated(writer); for (Py_ssize_t i = 0; i < PyList_GET_SIZE(x); i++) { - PyObject *item = PyList_GET_ITEM(x, i); - Py_INCREF(item); + PyObject *item = _PyList_GetItemRef((PyListObject *)x, i); + if (item == NULL) { + goto error; + } Py_ssize_t value = PyNumber_AsSsize_t(item, NULL); Py_DECREF(item); if (value == -1 && PyErr_Occurred()) From bdc44c55a277b7c26efdb63885dec606e2abf1b7 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 17 May 2026 10:33:11 +0200 Subject: [PATCH 070/818] [3.15] gh-149916: Restore the commented out part of test_body_encode in test_email (GH-149917) (GH-149937) (cherry picked from commit 1cbe035723698f15aa1b1af5deef615b28aae2e5) Co-authored-by: Serhiy Storchaka --- Lib/test/test_email/test_email.py | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/Lib/test/test_email/test_email.py b/Lib/test/test_email/test_email.py index 7778566492d8f4..d2c2261edbe04e 100644 --- a/Lib/test/test_email/test_email.py +++ b/Lib/test/test_email/test_email.py @@ -4995,15 +4995,8 @@ def test_body_encode(self): # Try the convert argument, where input codec != output codec c = Charset('euc-jp') # With apologies to Tokio Kikuchi ;) - # XXX FIXME -## try: -## eq('\x1b$B5FCO;~IW\x1b(B', -## c.body_encode('\xb5\xc6\xc3\xcf\xbb\xfe\xc9\xd7')) -## eq('\xb5\xc6\xc3\xcf\xbb\xfe\xc9\xd7', -## c.body_encode('\xb5\xc6\xc3\xcf\xbb\xfe\xc9\xd7', False)) -## except LookupError: -## # We probably don't have the Japanese codecs installed -## pass + eq('\x1b$B5FCO;~IW\x1b(B', + c.body_encode('\u83ca\u5730\u6642\u592b')) # Testing SF bug #625509, which we have to fake, since there are no # built-in encodings where the header encoding is QP but the body # encoding is not. From 42ff9b4959667cf31bde13a53fca01b1ec381168 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 17 May 2026 13:01:15 +0200 Subject: [PATCH 071/818] [3.15] gh-149921: Fix reference leaks in _interpchannels and _interpqueues modules (GH-149922) (#149943) gh-149921: Fix reference leaks in _interpchannels and _interpqueues modules (GH-149922) (cherry picked from commit acefff95eab3db6b7cf837f3ce2707bbf9199376) Co-authored-by: AN Long --- .../Library/2026-05-16-21-08-33.gh-issue-149921.I1yNML.rst | 2 ++ Modules/_interpchannelsmodule.c | 4 ++-- Modules/_interpqueuesmodule.c | 1 + 3 files changed, 5 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-05-16-21-08-33.gh-issue-149921.I1yNML.rst diff --git a/Misc/NEWS.d/next/Library/2026-05-16-21-08-33.gh-issue-149921.I1yNML.rst b/Misc/NEWS.d/next/Library/2026-05-16-21-08-33.gh-issue-149921.I1yNML.rst new file mode 100644 index 00000000000000..113bd1a802f799 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-05-16-21-08-33.gh-issue-149921.I1yNML.rst @@ -0,0 +1,2 @@ +Fix reference leaks in error paths of the :mod:`!_interpchannels` and +:mod:`!_interpqueues` extension modules. diff --git a/Modules/_interpchannelsmodule.c b/Modules/_interpchannelsmodule.c index 3c356cb40d2bca..c6d107d243dda0 100644 --- a/Modules/_interpchannelsmodule.c +++ b/Modules/_interpchannelsmodule.c @@ -2586,6 +2586,7 @@ static PyObject * _channelid_from_xid(_PyXIData_t *data) { struct _channelid_xid *xid = (struct _channelid_xid *)_PyXIData_DATA(data); + PyObject *cidobj = NULL; // It might not be imported yet, so we can't use _get_current_module(). PyObject *mod = PyImport_ImportModule(MODULE_NAME_STR); @@ -2595,11 +2596,10 @@ _channelid_from_xid(_PyXIData_t *data) assert(mod != Py_None); module_state *state = get_module_state(mod); if (state == NULL) { - return NULL; + goto done; } // Note that we do not preserve the "resolve" flag. - PyObject *cidobj = NULL; int err = newchannelid(state->ChannelIDType, xid->cid, xid->end, _global_channels(), 0, 0, (channelid **)&cidobj); diff --git a/Modules/_interpqueuesmodule.c b/Modules/_interpqueuesmodule.c index 777b6854749884..b23aa5f39489d9 100644 --- a/Modules/_interpqueuesmodule.c +++ b/Modules/_interpqueuesmodule.c @@ -1363,6 +1363,7 @@ _queueobj_from_xid(_PyXIData_t *data) if (mod == NULL) { mod = PyImport_ImportModule(MODULE_NAME_STR); if (mod == NULL) { + Py_DECREF(qidobj); return NULL; } } From 6e83c55e643ac1c189535604e70b0328c0ebec44 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 18 May 2026 11:00:19 +0200 Subject: [PATCH 072/818] [3.15] gh-149953: Fix null pointer dereference order in `code_objects.c` (GH-149956) (#149976) gh-149953: Fix null pointer dereference order in `code_objects.c` (GH-149956) Move check before (cherry picked from commit 0ed497a350d76dd20de1a1689c84426c7c1d6e22) Co-authored-by: Nezuko Agent --- Modules/_remote_debugging/code_objects.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/_remote_debugging/code_objects.c b/Modules/_remote_debugging/code_objects.c index 7b95c0f2d4fa8d..97c6ba772e88f1 100644 --- a/Modules/_remote_debugging/code_objects.c +++ b/Modules/_remote_debugging/code_objects.c @@ -432,7 +432,7 @@ parse_code_object(RemoteUnwinderObject *unwinder, #ifdef Py_GIL_DISABLED // Handle thread-local bytecode (TLBC) in free threading builds - if (ctx->tlbc_index == 0 || unwinder->debug_offsets.code_object.co_tlbc == 0 || unwinder == NULL) { + if (ctx->tlbc_index == 0 || unwinder == NULL || unwinder->debug_offsets.code_object.co_tlbc == 0) { // No TLBC or no unwinder - use main bytecode directly addrq = (uint16_t *)ip - (uint16_t *)meta->addr_code_adaptive; goto done_tlbc; From 34e4005c35f92ef3257e4ec2d1d4dc0eeebb321e Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 18 May 2026 15:52:17 +0200 Subject: [PATCH 073/818] [3.15] gh-149887: Install python3t.lib for GIL-enabled Windows install (GH-149900) gh-149887: Install python3t.lib for GIL-enabled Windows install (GH-149900) (cherry picked from commit bd6bf91fcba8a8fba8b9aea6cc971333c9be3ad9) Co-authored-by: Nathan Goldbaum --- Tools/msi/dev/dev_files.wxs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Tools/msi/dev/dev_files.wxs b/Tools/msi/dev/dev_files.wxs index 21f9c848cc6be5..a9039d03f5f6fa 100644 --- a/Tools/msi/dev/dev_files.wxs +++ b/Tools/msi/dev/dev_files.wxs @@ -13,6 +13,9 @@ + + + @@ -24,6 +27,9 @@ + + + From 01b07df858a9594f4421dacfd10a1c1b26102e29 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 18 May 2026 18:16:55 +0200 Subject: [PATCH 074/818] [3.15] gh-149816: Fix a RC in `_random.Random.__init__` method (GH-149824) (#149997) gh-149816: Fix a RC in `_random.Random.__init__` method (GH-149824) (cherry picked from commit 14af19e6c0d9dd05b525596fdd53373f726253d8) Co-authored-by: sobolevn --- ...-05-14-15-55-28.gh-issue-149816.ZaXQ0q.rst | 2 ++ Modules/_randommodule.c | 35 ++++++++----------- Modules/clinic/_randommodule.c.h | 33 ++++++++++++++++- 3 files changed, 48 insertions(+), 22 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-05-14-15-55-28.gh-issue-149816.ZaXQ0q.rst diff --git a/Misc/NEWS.d/next/Library/2026-05-14-15-55-28.gh-issue-149816.ZaXQ0q.rst b/Misc/NEWS.d/next/Library/2026-05-14-15-55-28.gh-issue-149816.ZaXQ0q.rst new file mode 100644 index 00000000000000..3ea70071ec3c75 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-05-14-15-55-28.gh-issue-149816.ZaXQ0q.rst @@ -0,0 +1,2 @@ +Fix a race condition in ``_random.Random.__init__`` method in free-threading +mode. diff --git a/Modules/_randommodule.c b/Modules/_randommodule.c index 0fb73481651748..a06966be23be1e 100644 --- a/Modules/_randommodule.c +++ b/Modules/_randommodule.c @@ -123,9 +123,9 @@ typedef struct { /*[clinic input] module _random -class _random.Random "RandomObject *" "_randomstate_type(type)->Random_Type" +class _random.Random "RandomObject *" "(PyTypeObject *)_randomstate_type(Py_TYPE(self))->Random_Type" [clinic start generated code]*/ -/*[clinic end generated code: output=da39a3ee5e6b4b0d input=70a2c99619474983]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=f04bcbfba61a322e]*/ /* Random methods */ @@ -549,27 +549,20 @@ _random_Random_getrandbits_impl(RandomObject *self, uint64_t k) return result; } -static int -random_init(PyObject *self, PyObject *args, PyObject *kwds) -{ - PyObject *arg = NULL; - _randomstate *state = _randomstate_type(Py_TYPE(self)); - - if ((Py_IS_TYPE(self, (PyTypeObject *)state->Random_Type) || - Py_TYPE(self)->tp_init == ((PyTypeObject*)state->Random_Type)->tp_init) && - !_PyArg_NoKeywords("Random", kwds)) { - return -1; - } - - if (PyTuple_GET_SIZE(args) > 1) { - PyErr_SetString(PyExc_TypeError, "Random() requires 0 or 1 argument"); - return -1; - } +/*[clinic input] +@critical_section +@text_signature "($self, [seed])" +_random.Random.__init__ as random_init - if (PyTuple_GET_SIZE(args) == 1) - arg = PyTuple_GET_ITEM(args, 0); + seed: object = NULL + / +[clinic start generated code]*/ - return random_seed(RandomObject_CAST(self), arg); +static int +random_init_impl(RandomObject *self, PyObject *seed) +/*[clinic end generated code: output=260734a3739c394f input=e516bf32e8a05e28]*/ +{ + return random_seed(self, seed); } diff --git a/Modules/clinic/_randommodule.c.h b/Modules/clinic/_randommodule.c.h index 2563a16aea0b6f..ca9cad7a572dad 100644 --- a/Modules/clinic/_randommodule.c.h +++ b/Modules/clinic/_randommodule.c.h @@ -143,4 +143,35 @@ _random_Random_getrandbits(PyObject *self, PyObject *arg) exit: return return_value; } -/*[clinic end generated code: output=7ce97b2194eecaf7 input=a9049054013a1b77]*/ + +static int +random_init_impl(RandomObject *self, PyObject *seed); + +static int +random_init(PyObject *self, PyObject *args, PyObject *kwargs) +{ + int return_value = -1; + PyTypeObject *base_tp = (PyTypeObject *)_randomstate_type(Py_TYPE(self))->Random_Type; + PyObject *seed = NULL; + + if ((Py_IS_TYPE(self, base_tp) || + Py_TYPE(self)->tp_new == base_tp->tp_new) && + !_PyArg_NoKeywords("Random", kwargs)) { + goto exit; + } + if (!_PyArg_CheckPositional("Random", PyTuple_GET_SIZE(args), 0, 1)) { + goto exit; + } + if (PyTuple_GET_SIZE(args) < 1) { + goto skip_optional; + } + seed = PyTuple_GET_ITEM(args, 0); +skip_optional: + Py_BEGIN_CRITICAL_SECTION(self); + return_value = random_init_impl((RandomObject *)self, seed); + Py_END_CRITICAL_SECTION(); + +exit: + return return_value; +} +/*[clinic end generated code: output=ec95f7df0c3f3c19 input=a9049054013a1b77]*/ From 84ea87cde0132ca59f0390031d17b1f867dba8e0 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 18 May 2026 21:24:06 +0200 Subject: [PATCH 075/818] [3.15] gh-149977: Fix extra output of `-m test test_lazy_import` (GH-149978) (#150016) gh-149977: Fix extra output of `-m test test_lazy_import` (GH-149978) (cherry picked from commit 6d5be4b1d6ca91a18e76ae8dad2c5e94837d6309) Co-authored-by: sobolevn --- Lib/test/test_lazy_import/__init__.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_lazy_import/__init__.py b/Lib/test/test_lazy_import/__init__.py index 5d770eeae07a15..bcbf1a23233ba8 100644 --- a/Lib/test/test_lazy_import/__init__.py +++ b/Lib/test/test_lazy_import/__init__.py @@ -10,6 +10,7 @@ import unittest import tempfile import os +import contextlib from test import support from test.support.script_helper import assert_python_ok @@ -441,10 +442,14 @@ def tearDown(self): def test_lazy_import_pkg(self): """lazy import of package submodule should load the package.""" - import test.test_lazy_import.data.lazy_import_pkg + out = io.StringIO() + + with contextlib.redirect_stdout(out): + import test.test_lazy_import.data.lazy_import_pkg self.assertIn("test.test_lazy_import.data.pkg", sys.modules) self.assertIn("test.test_lazy_import.data.pkg.bar", sys.modules) + self.assertIn("BAR_MODULE_LOADED", out.getvalue()) def test_lazy_import_pkg_cross_import(self): """Cross-imports within package should preserve lazy imports.""" From 16f8ed5a82961cbfd3f74a529f940527957627f7 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 18 May 2026 23:47:19 +0200 Subject: [PATCH 076/818] [3.15] gh-95816: Fix TLS version range example in docs (GH-148574) (#150008) gh-95816: Fix TLS version range example in docs (GH-148574) docs(ssl): Fix TLS version range example (cherry picked from commit dbd8985e8262055ed091de9a72660b7c112a4ce7) Co-authored-by: Jan Brasna <1784648+janbrasna@users.noreply.github.com> --- Doc/library/ssl.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/library/ssl.rst b/Doc/library/ssl.rst index d9c736d27dcaec..b180673f22973e 100644 --- a/Doc/library/ssl.rst +++ b/Doc/library/ssl.rst @@ -2076,7 +2076,7 @@ to speed up repeated connections from the same clients. :attr:`~SSLContext.minimum_version` and :attr:`SSLContext.options` all affect the supported SSL and TLS versions of the context. The implementation does not prevent - invalid combination. For example a context with + invalid combinations. For example a context with :attr:`OP_NO_TLSv1_2` in :attr:`~SSLContext.options` and :attr:`~SSLContext.maximum_version` set to :attr:`TLSVersion.TLSv1_2` will not be able to establish a TLS 1.2 connection. @@ -2891,11 +2891,11 @@ disabled by default. :: >>> client_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) - >>> client_context.minimum_version = ssl.TLSVersion.TLSv1_3 + >>> client_context.minimum_version = ssl.TLSVersion.TLSv1_2 >>> client_context.maximum_version = ssl.TLSVersion.TLSv1_3 -The SSL context created above will only allow TLSv1.3 and later (if +The SSL client context created above will only allow TLSv1.2 and TLSv1.3 (if supported by your system) connections to a server. :const:`PROTOCOL_TLS_CLIENT` implies certificate validation and hostname checks by default. You have to load certificates into the context. From c417fcabfdd56ed3b7e835ea66117a304d128200 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 19 May 2026 01:28:04 +0200 Subject: [PATCH 077/818] [3.15] gh-149590: Remove faulthandler_traverse (GH-150023) (#150037) gh-149590: Remove faulthandler_traverse (GH-150023) `faulthandler_traverse` visits Python objects owned by `_PyRuntime`, not by the module instance. With multi-phase init allowing multiple module instances, each instance's GC traversal decrements `gc_refs` on the same runtime-owned objects, driving it negative when two instances are collected simultaneously. (cherry picked from commit 56737483c2ffdaadfec648fd38d409c6b10941c0) Co-authored-by: Armaan Vakharia <43391096+armaan-v924@users.noreply.github.com> --- ...026-05-18-13-47-17.gh-issue-149590.IPBeQx.rst | 1 + Modules/faulthandler.c | 16 ---------------- 2 files changed, 1 insertion(+), 16 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-05-18-13-47-17.gh-issue-149590.IPBeQx.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-18-13-47-17.gh-issue-149590.IPBeQx.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-18-13-47-17.gh-issue-149590.IPBeQx.rst new file mode 100644 index 00000000000000..8d3b29d69cc857 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-18-13-47-17.gh-issue-149590.IPBeQx.rst @@ -0,0 +1 @@ +Fix crash when faulthandler is imported more than once. diff --git a/Modules/faulthandler.c b/Modules/faulthandler.c index 1b4f0c2302daae..fa7fb7085d7e8b 100644 --- a/Modules/faulthandler.c +++ b/Modules/faulthandler.c @@ -1349,21 +1349,6 @@ faulthandler__stack_overflow_impl(PyObject *module) #endif /* defined(FAULTHANDLER_USE_ALT_STACK) && defined(HAVE_SIGACTION) */ -static int -faulthandler_traverse(PyObject *module, visitproc visit, void *arg) -{ - Py_VISIT(thread.file); -#ifdef FAULTHANDLER_USER - if (user_signals != NULL) { - for (size_t signum=0; signum < Py_NSIG; signum++) - Py_VISIT(user_signals[signum].file); - } -#endif - Py_VISIT(fatal_error.file); - return 0; -} - - #ifdef MS_WINDOWS /*[clinic input] faulthandler._raise_exception @@ -1459,7 +1444,6 @@ static struct PyModuleDef module_def = { .m_name = "faulthandler", .m_doc = module_doc, .m_methods = module_methods, - .m_traverse = faulthandler_traverse, .m_slots = faulthandler_slots }; From 66ade2861fec1d6c18998710938a1c71fde5f76b Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 19 May 2026 01:53:57 +0200 Subject: [PATCH 078/818] [3.15] gh-146452: Improve locking granularity in pickle's batch_dict_exact and fix race condition (GH-150025) (#150039) gh-146452: Improve locking granularity in pickle's batch_dict_exact and fix race condition (GH-150025) Remove assertion that could fail in rare race condition. Replace the coarse critical section wrapping the entire function with fine-grained sections covering only PyDict_Next + Py_INCREF. Also handle PyDict_Next returning 0 in the single-item fast path. (cherry picked from commit 57a0e570d36f41b953a91bbaf4262a5d05d0391b) Co-authored-by: Saul Cooperman <58375603+scopreon@users.noreply.github.com> --- ...-05-18-15-30-34.gh-issue-146452.RM0EVJ.rst | 2 ++ Modules/_pickle.c | 35 +++++++++++++++---- 2 files changed, 30 insertions(+), 7 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-05-18-15-30-34.gh-issue-146452.RM0EVJ.rst diff --git a/Misc/NEWS.d/next/Library/2026-05-18-15-30-34.gh-issue-146452.RM0EVJ.rst b/Misc/NEWS.d/next/Library/2026-05-18-15-30-34.gh-issue-146452.RM0EVJ.rst new file mode 100644 index 00000000000000..66f9acf6c710a7 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-05-18-15-30-34.gh-issue-146452.RM0EVJ.rst @@ -0,0 +1,2 @@ +Fix race condition when pickling dictionaries in free threaded builds. Also +reduce critical section cover. diff --git a/Modules/_pickle.c b/Modules/_pickle.c index 9874f9475ac029..15d95c658d6f90 100644 --- a/Modules/_pickle.c +++ b/Modules/_pickle.c @@ -3450,6 +3450,9 @@ batch_dict(PickleState *state, PicklerObject *self, PyObject *iter, PyObject *or * Returns 0 on success, -1 on error. * * Note that this currently doesn't work for protocol 0. + + * gh-146452: Wrap the dict iteration in a critical sections to prevent + * concurrent mutation from invalidating PyDict_Next() iteration state. */ static int batch_dict_exact(PickleState *state, PicklerObject *self, PyObject *obj) @@ -3466,15 +3469,24 @@ batch_dict_exact(PickleState *state, PicklerObject *self, PyObject *obj) assert(self->proto > 0); dict_size = PyDict_GET_SIZE(obj); - assert(dict_size); /* Write in batches of BATCHSIZE. */ Py_ssize_t total = 0; do { if (dict_size - total == 1) { - PyDict_Next(obj, &ppos, &key, &value); - Py_INCREF(key); - Py_INCREF(value); + int next; + Py_BEGIN_CRITICAL_SECTION(obj); + next = PyDict_Next(obj, &ppos, &key, &value); + if (next) { + Py_INCREF(key); + Py_INCREF(value); + } + Py_END_CRITICAL_SECTION(); + if (!next) { + PyErr_SetString(PyExc_RuntimeError, + "dictionary changed size during iteration"); + goto error; + } if (save(state, self, key, 0) < 0) { goto error; } @@ -3492,9 +3504,18 @@ batch_dict_exact(PickleState *state, PicklerObject *self, PyObject *obj) i = 0; if (_Pickler_Write(self, &mark_op, 1) < 0) return -1; - while (PyDict_Next(obj, &ppos, &key, &value)) { - Py_INCREF(key); - Py_INCREF(value); + int next; + while (1) { + Py_BEGIN_CRITICAL_SECTION(obj); + next = PyDict_Next(obj, &ppos, &key, &value); + if (next) { + Py_INCREF(key); + Py_INCREF(value); + } + Py_END_CRITICAL_SECTION(); + if (!next) { + break; + } if (save(state, self, key, 0) < 0) { goto error; } From 94c8bac2cd50bd05aa1811d35f4b00f1080a40a9 Mon Sep 17 00:00:00 2001 From: Dino Viehland Date: Mon, 18 May 2026 17:53:54 -0700 Subject: [PATCH 079/818] =?UTF-8?q?[3.15]=20gh-148587:=20Make=20sys.lazy?= =?UTF-8?q?=5Fmodules=20match=20PEP=20and=20keep=20internal=20lazy=20submo?= =?UTF-8?q?dules=20tra=E2=80=A6=20(#150014)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make sys.lazy_modules match PEP and keep internal lazy submodules tracking internal --- Include/internal/pycore_interp_structs.h | 8 +++ Lib/test/test_lazy_import/__init__.py | 27 ++++------ Lib/test/test_lazy_import/__main__.py | 3 ++ ...-05-18-18-36-28.gh-issue-148587.-RD3z5.rst | 1 + Python/import.c | 54 ++++++++++++++----- 5 files changed, 62 insertions(+), 31 deletions(-) create mode 100644 Lib/test/test_lazy_import/__main__.py create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-05-18-18-36-28.gh-issue-148587.-RD3z5.rst diff --git a/Include/internal/pycore_interp_structs.h b/Include/internal/pycore_interp_structs.h index f13bc2178b1e7e..d8e83cf2ff5c9a 100644 --- a/Include/internal/pycore_interp_structs.h +++ b/Include/internal/pycore_interp_structs.h @@ -349,7 +349,15 @@ struct _import_state { int lazy_imports_mode; PyObject *lazy_imports_filter; PyObject *lazy_importing_modules; + // The set stored in sys.lazy_modules if values that have been + // lazily imported. This value is only for debugging/introspection + // purposes and is not used by the runtime. PyObject *lazy_modules; + // A dict mapping package names to a set of submodule names that + // have been imported lazily from packages which have been imported + // lazily. When the package is reified we need to add a + // LazyImportObject which refers to the submodule on the module. + PyObject *lazy_pending_submodules; #ifdef Py_GIL_DISABLED PyMutex lazy_mutex; #endif diff --git a/Lib/test/test_lazy_import/__init__.py b/Lib/test/test_lazy_import/__init__.py index bcbf1a23233ba8..366cb203f8f256 100644 --- a/Lib/test/test_lazy_import/__init__.py +++ b/Lib/test/test_lazy_import/__init__.py @@ -38,8 +38,7 @@ def test_basic_unused(self): """Lazy imported module should not be loaded if never accessed.""" import test.test_lazy_import.data.basic_unused self.assertNotIn("test.test_lazy_import.data.basic2", sys.modules) - self.assertIn("test.test_lazy_import.data", sys.lazy_modules) - self.assertEqual(sys.lazy_modules["test.test_lazy_import.data"], {"basic2"}) + self.assertIn("test.test_lazy_import.data.basic2", sys.lazy_modules) def test_sys_lazy_modules(self): try: @@ -49,7 +48,7 @@ def test_sys_lazy_modules(self): self.assertFalse("test.test_lazy_import.data.basic2" in sys.modules) self.assertIn("test.test_lazy_import.data", sys.lazy_modules) - self.assertEqual(sys.lazy_modules["test.test_lazy_import.data"], {"basic2"}) + self.assertIn("test.test_lazy_import.data.basic2", sys.lazy_modules) test.test_lazy_import.data.basic_from_unused.basic2 self.assertNotIn("test.test_import.data", sys.lazy_modules) @@ -574,8 +573,8 @@ def my_filter(name): self.assertIs(sys.get_lazy_imports_filter(), my_filter) def test_lazy_modules_attribute_is_dict(self): - """sys.lazy_modules should be a dict per PEP 810.""" - self.assertIsInstance(sys.lazy_modules, dict) + """sys.lazy_modules should be a set per PEP 810.""" + self.assertIsInstance(sys.lazy_modules, set) @support.requires_subprocess() def test_lazy_modules_tracks_lazy_imports(self): @@ -584,8 +583,7 @@ def test_lazy_modules_tracks_lazy_imports(self): import sys initial_count = len(sys.lazy_modules) import test.test_lazy_import.data.basic_unused - assert "test.test_lazy_import.data" in sys.lazy_modules - assert sys.lazy_modules["test.test_lazy_import.data"] == {"basic2"} + assert "test.test_lazy_import.data.basic2" in sys.lazy_modules assert len(sys.lazy_modules) > initial_count print("OK") """) @@ -1034,15 +1032,14 @@ def test_module_added_to_lazy_modules_on_lazy_import(self): lazy import test.test_lazy_import.data.basic2 # Should be in lazy_modules after lazy import - assert "test.test_lazy_import.data" in sys.lazy_modules - assert sys.lazy_modules["test.test_lazy_import.data"] == {"basic2"} + assert "test.test_lazy_import.data.basic2" in sys.lazy_modules assert len(sys.lazy_modules) > initial_count # Trigger reification _ = test.test_lazy_import.data.basic2.x # Module should still be tracked (for diagnostics per PEP 810) - assert "test.test_lazy_import.data" not in sys.lazy_modules + assert "test.test_lazy_import.data.basic2" not in sys.lazy_modules print("OK") """) result = subprocess.run( @@ -1055,8 +1052,8 @@ def test_module_added_to_lazy_modules_on_lazy_import(self): def test_lazy_modules_is_per_interpreter(self): """Each interpreter should have independent sys.lazy_modules.""" - # Basic test that sys.lazy_modules exists and is a dict - self.assertIsInstance(sys.lazy_modules, dict) + # Basic test that sys.lazy_modules exists and is a set + self.assertIsInstance(sys.lazy_modules, set) def test_lazy_module_without_children_is_tracked(self): code = textwrap.dedent(""" @@ -1065,10 +1062,6 @@ def test_lazy_module_without_children_is_tracked(self): assert "json" in sys.lazy_modules, ( f"expected 'json' in sys.lazy_modules, got {set(sys.lazy_modules)}" ) - assert sys.lazy_modules["json"] == set(), ( - f"expected empty set for sys.lazy_modules['json'], " - f"got {sys.lazy_modules['json']!r}" - ) print("OK") """) assert_python_ok("-c", code) @@ -1937,7 +1930,7 @@ def create_lazy_imports(idx): t.join() assert not errors, f"Errors: {errors}" - assert isinstance(sys.lazy_modules, dict), "sys.lazy_modules is not a dict" + assert isinstance(sys.lazy_modules, set), "sys.lazy_modules is not a dict" print("OK") """) diff --git a/Lib/test/test_lazy_import/__main__.py b/Lib/test/test_lazy_import/__main__.py new file mode 100644 index 00000000000000..d6c94efaf30833 --- /dev/null +++ b/Lib/test/test_lazy_import/__main__.py @@ -0,0 +1,3 @@ +import unittest + +unittest.main('test.test_lazy_import') diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-18-18-36-28.gh-issue-148587.-RD3z5.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-18-18-36-28.gh-issue-148587.-RD3z5.rst new file mode 100644 index 00000000000000..61bfdcdd37362c --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-18-18-36-28.gh-issue-148587.-RD3z5.rst @@ -0,0 +1 @@ +``sys.lazy_modules`` is now a set instead of a dict as initially spelled out in PEP 810. diff --git a/Python/import.c b/Python/import.c index 60a5ee6e770f59..c5cc7b52922d5b 100644 --- a/Python/import.c +++ b/Python/import.c @@ -94,6 +94,8 @@ static struct _inittab *inittab_copy = NULL; (interp)->imports.modules_by_index #define LAZY_MODULES(interp) \ (interp)->imports.lazy_modules +#define LAZY_PENDING_SUBMODULES(interp) \ + (interp)->imports.lazy_pending_submodules #define IMPORTLIB(interp) \ (interp)->imports.importlib #define OVERRIDE_MULTI_INTERP_EXTENSIONS_CHECK(interp) \ @@ -271,8 +273,11 @@ import_get_module(PyThreadState *tstate, PyObject *name) PyObject * _PyImport_InitLazyModules(PyInterpreterState *interp) { - assert(LAZY_MODULES(interp) == NULL); - LAZY_MODULES(interp) = PyDict_New(); + assert(LAZY_MODULES(interp) == NULL && + LAZY_PENDING_SUBMODULES(interp) == NULL); + + LAZY_PENDING_SUBMODULES(interp) = PyDict_New(); + LAZY_MODULES(interp) = PySet_New(0); return LAZY_MODULES(interp); } @@ -280,6 +285,7 @@ void _PyImport_ClearLazyModules(PyInterpreterState *interp) { Py_CLEAR(LAZY_MODULES(interp)); + Py_CLEAR(LAZY_PENDING_SUBMODULES(interp)); } static int @@ -4339,7 +4345,7 @@ get_mod_dict(PyObject *module) // ensure we have the set for the parent module name in sys.lazy_modules. // Returns a new reference. static PyObject * -ensure_lazy_submodules(PyDictObject *lazy_modules, PyObject *parent) +ensure_lazy_pending_submodules(PyDictObject *lazy_modules, PyObject *parent) { PyObject *lazy_submodules; Py_BEGIN_CRITICAL_SECTION(lazy_modules); @@ -4358,6 +4364,9 @@ ensure_lazy_submodules(PyDictObject *lazy_modules, PyObject *parent) return lazy_submodules; } +// Ensures that we have a LazyImportObject on the parent module for +// all children modules which have been lazily imported. If the parent +// module overrides the child attribute then the value is not replaced. static int register_lazy_on_parent(PyThreadState *tstate, PyObject *name, PyObject *builtins) @@ -4369,16 +4378,16 @@ register_lazy_on_parent(PyThreadState *tstate, PyObject *name, PyObject *parent_dict = NULL; PyInterpreterState *interp = tstate->interp; - PyObject *lazy_modules = LAZY_MODULES(interp); - assert(lazy_modules != NULL); + PyObject *lazy_pending_submodules = LAZY_PENDING_SUBMODULES(interp); + assert(lazy_pending_submodules != NULL); Py_INCREF(name); while (true) { Py_ssize_t dot = PyUnicode_FindChar(name, '.', 0, PyUnicode_GET_LENGTH(name), -1); if (dot < 0) { - PyObject *lazy_submodules = ensure_lazy_submodules( - (PyDictObject *)lazy_modules, name); + PyObject *lazy_submodules = ensure_lazy_pending_submodules( + (PyDictObject *)lazy_pending_submodules, name); if (lazy_submodules == NULL) { goto done; } @@ -4400,8 +4409,8 @@ register_lazy_on_parent(PyThreadState *tstate, PyObject *name, } // Record the child as being lazily imported from the parent. - PyObject *lazy_submodules = ensure_lazy_submodules( - (PyDictObject *)lazy_modules, parent); + PyObject *lazy_submodules = ensure_lazy_pending_submodules( + (PyDictObject *)lazy_pending_submodules, parent); if (lazy_submodules == NULL) { goto done; } @@ -4464,6 +4473,14 @@ register_from_lazy_on_parent(PyThreadState *tstate, PyObject *abs_name, if (fromname == NULL) { return -1; } + + // Add the module name to sys.lazy_modules set (PEP 810). + PyObject *lazy_modules = LAZY_MODULES(tstate->interp); + if (PySet_Add(lazy_modules, fromname) < 0) { + Py_DECREF(fromname); + return -1; + } + int res = register_lazy_on_parent(tstate, fromname, builtins); Py_DECREF(fromname); return res; @@ -4555,6 +4572,13 @@ _PyImport_LazyImportModuleLevelObject(PyThreadState *tstate, Py_DECREF(abs_name); return NULL; } + + // Add the module name to sys.lazy_modules set (PEP 810). + PyObject *lazy_modules = LAZY_MODULES(tstate->interp); + if (PySet_Add(lazy_modules, abs_name) < 0) { + goto error; + } + if (fromlist && PyUnicode_Check(fromlist)) { if (register_from_lazy_on_parent(tstate, abs_name, fromlist, builtins) < 0) { @@ -4791,6 +4815,7 @@ _PyImport_ClearCore(PyInterpreterState *interp) Py_CLEAR(IMPORTLIB(interp)); Py_CLEAR(IMPORT_FUNC(interp)); Py_CLEAR(LAZY_IMPORT_FUNC(interp)); + Py_CLEAR(interp->imports.lazy_pending_submodules); Py_CLEAR(interp->imports.lazy_modules); Py_CLEAR(interp->imports.lazy_importing_modules); Py_CLEAR(interp->imports.lazy_imports_filter); @@ -5636,11 +5661,13 @@ _imp__set_lazy_attributes_impl(PyObject *module, PyObject *modobj, PyThreadState *tstate = _PyThreadState_GET(); PyObject *module_dict = NULL; PyObject *ret = NULL; - PyObject *lazy_modules = LAZY_MODULES(tstate->interp); - assert(lazy_modules != NULL); + PyObject *lazy_pending_modules = LAZY_PENDING_SUBMODULES(tstate->interp); + assert(lazy_pending_modules != NULL); PyObject *lazy_submodules; - if (PyDict_GetItemRef(lazy_modules, name, &lazy_submodules) < 0) { + if (PySet_Discard(LAZY_MODULES(tstate->interp), name) < 0) { + return NULL; + } else if (PyDict_GetItemRef(lazy_pending_modules, name, &lazy_submodules) < 0) { return NULL; } else if (lazy_submodules == NULL) { @@ -5659,8 +5686,7 @@ _imp__set_lazy_attributes_impl(PyObject *module, PyObject *modobj, Py_END_CRITICAL_SECTION(); Py_DECREF(lazy_submodules); - // once a module is imported it is removed from sys.lazy_modules - if (PyDict_DelItem(lazy_modules, name) < 0) { + if (PyDict_DelItem(lazy_pending_modules, name) < 0) { goto error; } From 0b92f01c59c82a111bb6b9929fbfc0f9cb1241db Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 19 May 2026 06:41:43 +0200 Subject: [PATCH 080/818] [3.15] gh-149816: fix thread safety of deletion of list slice (GH-149936) (#150003) gh-149816: fix thread safety of deletion of list slice (GH-149936) (cherry picked from commit 00ea77613b942a9e08df6e3eb74b2ccd37641ba6) Co-authored-by: Kumar Aditya --- Objects/listobject.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/Objects/listobject.c b/Objects/listobject.c index 10e25bbdcdcb6c..c76721c5d2ac9e 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -3793,16 +3793,13 @@ list_ass_subscript_lock_held(PyObject *_self, PyObject *item, PyObject *value) lim = Py_SIZE(self) - cur - 1; } - memmove(self->ob_item + cur - i, - self->ob_item + cur + 1, - lim * sizeof(PyObject *)); + ptr_wise_atomic_memmove(self, self->ob_item + cur - i, + self->ob_item + cur + 1, lim); } cur = start + (size_t)slicelength * step; if (cur < (size_t)Py_SIZE(self)) { - memmove(self->ob_item + cur - slicelength, - self->ob_item + cur, - (Py_SIZE(self) - cur) * - sizeof(PyObject *)); + ptr_wise_atomic_memmove(self, self->ob_item + cur - slicelength, + self->ob_item + cur, Py_SIZE(self) - cur); } Py_SET_SIZE(self, Py_SIZE(self) - slicelength); From d36e08099d56a54028174429a946c9816f284374 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 19 May 2026 06:42:25 +0200 Subject: [PATCH 081/818] [3.15] gh-149816: fix `dict.clear()` race on split-table dict with non-embedded values (GH-149914) (#150000) gh-149816: fix `dict.clear()` race on split-table dict with non-embedded values (GH-149914) (cherry picked from commit 169285470630b697c5e6e0e4c8091c31f25ffb04) Co-authored-by: Kumar Aditya --- Lib/test/test_free_threading/test_dict.py | 28 +++++++++++++++++++++++ Objects/dictobject.c | 6 +++-- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_free_threading/test_dict.py b/Lib/test/test_free_threading/test_dict.py index 55272a00c3ad50..dfe0634211d4b0 100644 --- a/Lib/test/test_free_threading/test_dict.py +++ b/Lib/test/test_free_threading/test_dict.py @@ -268,6 +268,34 @@ def watcher(): finally: _testcapi.clear_dict_watcher(wid) + def test_racing_split_dict_clear_and_lookup(self): + class C: + pass + + keys = [f"a{i}" for i in range(16)] + + def make_split_nonembedded(): + inst = C() + for key in keys: + setattr(inst, key, keys.index(key)) + # dict.copy() of a split instance dict yields a split table + # with non-embedded values + return inst.__dict__.copy() + + d = make_split_nonembedded() + + def clearer(): + for _ in range(1000): + d.clear() + d.update(make_split_nonembedded()) + + def reader(): + for _ in range(1000): + for k in keys: + d.get(k) + + threading_helper.run_concurrently([clearer, reader, reader]) + def test_racing_dict_update_and_method_lookup(self): # gh-144295: test race between dict modifications and method lookups. # Uses BytesIO because the race requires a type without Py_TPFLAGS_INLINE_VALUES diff --git a/Objects/dictobject.c b/Objects/dictobject.c index b33a273dac3b95..a7d67812bec925 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -3083,10 +3083,12 @@ clear_lock_held(PyObject *op) set_keys(mp, Py_EMPTY_KEYS); n = oldkeys->dk_nentries; for (i = 0; i < n; i++) { - Py_CLEAR(oldvalues->values[i]); + PyObject *tmp = oldvalues->values[i]; + FT_ATOMIC_STORE_PTR_RELEASE(oldvalues->values[i], NULL); + Py_XDECREF(tmp); } free_values(oldvalues, IS_DICT_SHARED(mp)); - dictkeys_decref(oldkeys, false); + dictkeys_decref(oldkeys, IS_DICT_SHARED(mp)); } ASSERT_CONSISTENT(mp); } From 28f275f713124a1425effe3c998394e829b20db7 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 19 May 2026 07:10:01 +0200 Subject: [PATCH 082/818] [3.15] gh-86533: Restore os.makedirs() ability to apply *mode* recursively (GH-150011) (#150036) bpo-42367: Restore os.makedirs() and pathlib.mkdir() ability to apply *mode* recursively via a new parent_mode= keyword argument. (cherry picked from commit 9770e32ce07110f0c8c7a381604ec9a490028eed) + Make Path.mkdir parent_mode tests umask-independent test_mkdir_with_parent_mode, test_mkdir_parent_mode_deep_hierarchy and test_mkdir_parent_mode_same_as_mode assert exact directory mode bits but did not pin the process umask. On buildbots running with a restrictive umask (e.g. 0o077) the 0o755 leaf was masked down to 0o700, failing the assertions. Wrap them in os_helper.temp_umask(0o022), matching the other umask-aware mkdir tests in this file. --------- Co-authored-by: nessita <124304+nessita@users.noreply.github.com> Co-authored-by: Zackery Spytz Co-authored-by: Erlend E. Aasland Co-authored-by: Gregory P. Smith --- Doc/library/os.rst | 14 ++- Doc/library/pathlib.rst | 12 +- Doc/whatsnew/3.15.rst | 8 ++ Lib/os.py | 15 ++- Lib/pathlib/__init__.py | 8 +- Lib/test/test_os/test_os.py | 100 ++++++++++++++-- Lib/test/test_pathlib/test_pathlib.py | 110 ++++++++++++++++++ ...-08-30-07-44-30.gh-issue-86533.pathlib.rst | 4 + 8 files changed, 254 insertions(+), 17 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2025-08-30-07-44-30.gh-issue-86533.pathlib.rst diff --git a/Doc/library/os.rst b/Doc/library/os.rst index d2534b3e974f36..27a032a8a97c63 100644 --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -2549,7 +2549,8 @@ features: Windows now handles a *mode* of ``0o700``. -.. function:: makedirs(name, mode=0o777, exist_ok=False) +.. function:: makedirs(name, mode=0o777, exist_ok=False, *, \ + parent_mode=None) .. index:: single: directory; creating @@ -2567,6 +2568,12 @@ features: If *exist_ok* is ``False`` (the default), a :exc:`FileExistsError` is raised if the target directory already exists. + If *parent_mode* is not ``None``, it is used as the mode for any + newly-created, intermediate-level directories. Like *mode*, it is + combined with the process's umask value; see :ref:`the mkdir() + description `. Otherwise, intermediate directories are + created with the default mode, which is also subject to the umask. + .. note:: :func:`makedirs` will become confused if the path elements to create @@ -2593,6 +2600,11 @@ features: The *mode* argument no longer affects the file permission bits of newly created intermediate-level directories. + .. versionadded:: 3.15 + The *parent_mode* parameter. To match the behavior from Python 3.6 and + earlier (where *mode* was applied to all created directories), pass + ``parent_mode=mode``. + .. function:: mkfifo(path, mode=0o666, *, dir_fd=None) diff --git a/Doc/library/pathlib.rst b/Doc/library/pathlib.rst index 2867015042ee16..45b5797058f623 100644 --- a/Doc/library/pathlib.rst +++ b/Doc/library/pathlib.rst @@ -1514,7 +1514,8 @@ Creating files and directories :meth:`~Path.write_bytes` methods are often used to create files. -.. method:: Path.mkdir(mode=0o777, parents=False, exist_ok=False) +.. method:: Path.mkdir(mode=0o777, parents=False, exist_ok=False, *, \ + parent_mode=None) Create a new directory at this given path. If *mode* is given, it is combined with the process's ``umask`` value to determine the file mode @@ -1525,6 +1526,12 @@ Creating files and directories as needed; they are created with the default permissions without taking *mode* into account (mimicking the POSIX ``mkdir -p`` command). + If *parent_mode* is not ``None``, it is used as the mode for any + newly-created, intermediate-level directories when *parents* is true. + Like *mode*, it is combined with the process's ``umask`` value. + Otherwise, intermediate directories are created with the default + permissions (also subject to the umask). + If *parents* is false (the default), a missing parent raises :exc:`FileNotFoundError`. @@ -1538,6 +1545,9 @@ Creating files and directories .. versionchanged:: 3.5 The *exist_ok* parameter was added. + .. versionadded:: 3.15 + The *parent_mode* parameter. + .. method:: Path.symlink_to(target, target_is_directory=False) diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst index fb0755e8ffec5b..9bef7aa61d23cd 100644 --- a/Doc/whatsnew/3.15.rst +++ b/Doc/whatsnew/3.15.rst @@ -1285,6 +1285,10 @@ os glibc versions 2.28 and later. (Contributed by Jeffrey Bosboom and Victor Stinner in :gh:`83714`.) +* :func:`os.makedirs` function now has a *parent_mode* parameter that allows + specifying the mode for intermediate directories. This can be used to match + the behavior from Python 3.6 and earlier by passing ``parent_mode=mode``. + (Contributed by Zackery Spytz and Gregory P. Smith in :gh:`86533`.) os.path ------- @@ -2057,6 +2061,10 @@ importlib.resources pathlib ------- +* :meth:`pathlib.Path.mkdir` now has a *parent_mode* parameter that allows + specifying the mode for intermediate directories when ``parents=True``. + (Contributed by Gregory P. Smith in :gh:`86533`.) + * Removed deprecated :meth:`!pathlib.PurePath.is_reserved`. Use :func:`os.path.isreserved` to detect reserved paths on Windows. (Contributed by Nikita Sobolev in :gh:`133875`.) diff --git a/Lib/os.py b/Lib/os.py index 52cbc5bc85864e..1ca4648cc95c3e 100644 --- a/Lib/os.py +++ b/Lib/os.py @@ -219,14 +219,17 @@ def _add(str, fn): # Super directory utilities. # (Inspired by Eric Raymond; the doc strings are mostly his) -def makedirs(name, mode=0o777, exist_ok=False): - """makedirs(name [, mode=0o777][, exist_ok=False]) +def makedirs(name, mode=0o777, exist_ok=False, *, parent_mode=None): + """makedirs(name [, mode=0o777][, exist_ok=False][, parent_mode=None]) Super-mkdir; create a leaf directory and all intermediate ones. Works like mkdir, except that any intermediate path segment (not just the rightmost) will be created if it does not exist. If the target directory already exists, raise an OSError if exist_ok is False. Otherwise no exception is - raised. This is recursive. + raised. If parent_mode is not None, it will be used as the mode for any + newly-created, intermediate-level directories. Otherwise, intermediate + directories are created with the default permissions (respecting umask). + This is recursive. """ head, tail = path.split(name) @@ -234,7 +237,11 @@ def makedirs(name, mode=0o777, exist_ok=False): head, tail = path.split(head) if head and tail and not path.exists(head): try: - makedirs(head, exist_ok=exist_ok) + if parent_mode is not None: + makedirs(head, mode=parent_mode, exist_ok=exist_ok, + parent_mode=parent_mode) + else: + makedirs(head, exist_ok=exist_ok) except FileExistsError: # Defeats race condition when another thread created the path pass diff --git a/Lib/pathlib/__init__.py b/Lib/pathlib/__init__.py index a32e4b5320ff6d..8dd16c6225b927 100644 --- a/Lib/pathlib/__init__.py +++ b/Lib/pathlib/__init__.py @@ -1202,7 +1202,7 @@ def touch(self, mode=0o666, exist_ok=True): fd = os.open(self, flags, mode) os.close(fd) - def mkdir(self, mode=0o777, parents=False, exist_ok=False): + def mkdir(self, mode=0o777, parents=False, exist_ok=False, *, parent_mode=None): """ Create a new directory at this given path. """ @@ -1211,7 +1211,11 @@ def mkdir(self, mode=0o777, parents=False, exist_ok=False): except FileNotFoundError: if not parents or self.parent == self: raise - self.parent.mkdir(parents=True, exist_ok=True) + if parent_mode is not None: + self.parent.mkdir(mode=parent_mode, parents=True, exist_ok=True, + parent_mode=parent_mode) + else: + self.parent.mkdir(parents=True, exist_ok=True) self.mkdir(mode, parents=False, exist_ok=exist_ok) except OSError: # Cannot rely on checking for EEXIST, since the operating system diff --git a/Lib/test/test_os/test_os.py b/Lib/test/test_os/test_os.py index 7e670e5a139d99..6fcf94fc825385 100644 --- a/Lib/test/test_os/test_os.py +++ b/Lib/test/test_os/test_os.py @@ -2137,6 +2137,94 @@ def test_mode(self): self.assertEqual(os.stat(path).st_mode & 0o777, 0o555) self.assertEqual(os.stat(parent).st_mode & 0o777, 0o775) + @unittest.skipIf( + support.is_emscripten or support.is_wasi, + "umask is not implemented on Emscripten/WASI." + ) + @unittest.skipIf( + sys.platform == "android", + "Android filesystem may not honor requested permissions." + ) + def test_mode_with_parent_mode(self): + # Test the parent_mode parameter + parent = os.path.join(os_helper.TESTFN, 'dir1') + path = os.path.join(parent, 'dir2') + with os_helper.temp_umask(0o002): + # Specify mode for both leaf and parent directories + os.makedirs(path, 0o770, parent_mode=0o750) + self.assertTrue(os.path.exists(path)) + self.assertTrue(os.path.isdir(path)) + if os.name != 'nt': + # Leaf directory gets the mode parameter + self.assertEqual(os.stat(path).st_mode & 0o777, 0o770) + # Parent directory gets the parent_mode parameter + self.assertEqual(os.stat(parent).st_mode & 0o777, 0o750) + + @unittest.skipIf( + support.is_emscripten or support.is_wasi, + "umask is not implemented on Emscripten/WASI." + ) + @unittest.skipIf( + sys.platform == "android", + "Android filesystem may not honor requested permissions." + ) + def test_parent_mode_deep_hierarchy(self): + # Test parent_mode with deep directory hierarchy + base = os.path.join(os_helper.TESTFN, 'dir1', 'dir2', 'dir3') + with os_helper.temp_umask(0o002): + os.makedirs(base, 0o755, parent_mode=0o700) + self.assertTrue(os.path.exists(base)) + if os.name != 'nt': + # Check that all parent directories have parent_mode + level1 = os.path.join(os_helper.TESTFN, 'dir1') + level2 = os.path.join(level1, 'dir2') + self.assertEqual(os.stat(level1).st_mode & 0o777, 0o700) + self.assertEqual(os.stat(level2).st_mode & 0o777, 0o700) + # Leaf directory has the regular mode + self.assertEqual(os.stat(base).st_mode & 0o777, 0o755) + + @unittest.skipIf( + support.is_emscripten or support.is_wasi, + "umask is not implemented on Emscripten/WASI." + ) + @unittest.skipIf( + sys.platform == "android", + "Android filesystem may not honor requested permissions." + ) + def test_parent_mode_same_as_mode(self): + # Test emulating Python 3.6 behavior by setting parent_mode=mode + parent = os.path.join(os_helper.TESTFN, 'dir1') + path = os.path.join(parent, 'dir2') + with os_helper.temp_umask(0o002): + os.makedirs(path, 0o705, parent_mode=0o705) + self.assertTrue(os.path.exists(path)) + if os.name != 'nt': + # Both directories should have the same mode + self.assertEqual(os.stat(path).st_mode & 0o777, 0o705) + self.assertEqual(os.stat(parent).st_mode & 0o777, 0o705) + + @unittest.skipIf( + support.is_emscripten or support.is_wasi, + "umask is not implemented on Emscripten/WASI." + ) + @unittest.skipIf( + sys.platform == "android", + "Android filesystem may not honor requested permissions." + ) + def test_parent_mode_combined_with_umask(self): + # parent_mode, like mode, is combined with the process umask; it does + # not bypass it. + parent = os.path.join(os_helper.TESTFN, 'dir1') + path = os.path.join(parent, 'dir2') + with os_helper.temp_umask(0o022): + os.makedirs(path, 0o777, parent_mode=0o777) + self.assertTrue(os.path.isdir(path)) + if os.name != 'nt': + # 0o777 is masked down to 0o755 by the 0o022 umask, for both + # the leaf (mode) and the parent (parent_mode). + self.assertEqual(os.stat(path).st_mode & 0o777, 0o755) + self.assertEqual(os.stat(parent).st_mode & 0o777, 0o755) + @unittest.skipIf( support.is_wasi, "WASI's umask is a stub." @@ -2210,15 +2298,9 @@ def test_win32_mkdir_700(self): ) def tearDown(self): - path = os.path.join(os_helper.TESTFN, 'dir1', 'dir2', 'dir3', - 'dir4', 'dir5', 'dir6') - # If the tests failed, the bottom-most directory ('../dir6') - # may not have been created, so we look for the outermost directory - # that exists. - while not os.path.exists(path) and path != os_helper.TESTFN: - path = os.path.dirname(path) - - os.removedirs(path) + # Remove the whole tree regardless of which sub-directories a test + # created and regardless of their permission bits. + os_helper.rmtree(os_helper.TESTFN) @unittest.skipUnless(hasattr(os, "chown"), "requires os.chown()") diff --git a/Lib/test/test_pathlib/test_pathlib.py b/Lib/test/test_pathlib/test_pathlib.py index 09d1b5d725e5ba..2cb4876f5c6400 100644 --- a/Lib/test/test_pathlib/test_pathlib.py +++ b/Lib/test/test_pathlib/test_pathlib.py @@ -2492,6 +2492,116 @@ def my_mkdir(path, mode=0o777): self.assertNotIn(str(p12), concurrently_created) self.assertTrue(p.exists()) + @unittest.skipIf( + is_emscripten or is_wasi, + "umask is not implemented on Emscripten/WASI." + ) + @unittest.skipIf( + sys.platform == "android", + "Android filesystem may not honor requested permissions." + ) + def test_mkdir_parents_umask(self): + # Test that parent directories respect umask when parent_mode is not set + p = self.cls(self.base, 'umasktest', 'child') + self.assertFalse(p.exists()) + if os.name != 'nt': + with os_helper.temp_umask(0o002): + p.mkdir(0o755, parents=True) + self.assertTrue(p.exists()) + # Leaf directory gets the specified mode + self.assertEqual(p.stat().st_mode & 0o777, 0o755) + # Parent directory respects umask (0o777 & ~0o002 = 0o775) + self.assertEqual(p.parent.stat().st_mode & 0o777, 0o775) + + @unittest.skipIf( + is_emscripten or is_wasi, + "umask is not implemented on Emscripten/WASI." + ) + @unittest.skipIf( + sys.platform == "android", + "Android filesystem may not honor requested permissions." + ) + def test_mkdir_with_parent_mode(self): + # Test the parent_mode parameter + p = self.cls(self.base, 'newdirPM', 'subdirPM') + self.assertFalse(p.exists()) + if os.name != 'nt': + with os_helper.temp_umask(0o022): + # Specify different modes for parent and leaf directories + p.mkdir(0o755, parents=True, parent_mode=0o750) + self.assertTrue(p.exists()) + self.assertTrue(p.is_dir()) + # Leaf directory gets the mode parameter + self.assertEqual(p.stat().st_mode & 0o777, 0o755) + # Parent directory gets the parent_mode parameter + self.assertEqual(p.parent.stat().st_mode & 0o777, 0o750) + + @unittest.skipIf( + is_emscripten or is_wasi, + "umask is not implemented on Emscripten/WASI." + ) + @unittest.skipIf( + sys.platform == "android", + "Android filesystem may not honor requested permissions." + ) + def test_mkdir_parent_mode_deep_hierarchy(self): + # Test parent_mode with deep directory hierarchy + p = self.cls(self.base, 'level1PM', 'level2PM', 'level3PM') + self.assertFalse(p.exists()) + if os.name != 'nt': + with os_helper.temp_umask(0o022): + p.mkdir(0o755, parents=True, parent_mode=0o700) + self.assertTrue(p.exists()) + # Check that all parent directories have parent_mode + level1 = self.cls(self.base, 'level1PM') + level2 = level1 / 'level2PM' + self.assertEqual(level1.stat().st_mode & 0o777, 0o700) + self.assertEqual(level2.stat().st_mode & 0o777, 0o700) + # Leaf directory has the regular mode + self.assertEqual(p.stat().st_mode & 0o777, 0o755) + + @unittest.skipIf( + is_emscripten or is_wasi, + "umask is not implemented on Emscripten/WASI." + ) + @unittest.skipIf( + sys.platform == "android", + "Android filesystem may not honor requested permissions." + ) + def test_mkdir_parent_mode_combined_with_umask(self): + # parent_mode, like mode, is combined with the process umask; it does + # not bypass it. + p = self.cls(self.base, 'umaskPM', 'child') + self.assertFalse(p.exists()) + if os.name != 'nt': + with os_helper.temp_umask(0o022): + p.mkdir(0o777, parents=True, parent_mode=0o777) + self.assertTrue(p.exists()) + # 0o777 is masked down to 0o755 by the 0o022 umask, for both + # the leaf (mode) and the parent (parent_mode). + self.assertEqual(p.stat().st_mode & 0o777, 0o755) + self.assertEqual(p.parent.stat().st_mode & 0o777, 0o755) + + @unittest.skipIf( + is_emscripten or is_wasi, + "umask is not implemented on Emscripten/WASI." + ) + @unittest.skipIf( + sys.platform == "android", + "Android filesystem may not honor requested permissions." + ) + def test_mkdir_parent_mode_same_as_mode(self): + # Test setting parent_mode same as mode + p = self.cls(self.base, 'samedirPM', 'subdirPM') + self.assertFalse(p.exists()) + if os.name != 'nt': + with os_helper.temp_umask(0o022): + p.mkdir(0o705, parents=True, parent_mode=0o705) + self.assertTrue(p.exists()) + # Both directories should have the same mode + self.assertEqual(p.stat().st_mode & 0o777, 0o705) + self.assertEqual(p.parent.stat().st_mode & 0o777, 0o705) + @needs_symlinks def test_symlink_to(self): P = self.cls(self.base) diff --git a/Misc/NEWS.d/next/Library/2025-08-30-07-44-30.gh-issue-86533.pathlib.rst b/Misc/NEWS.d/next/Library/2025-08-30-07-44-30.gh-issue-86533.pathlib.rst new file mode 100644 index 00000000000000..9c32671173e0ad --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-08-30-07-44-30.gh-issue-86533.pathlib.rst @@ -0,0 +1,4 @@ +The :func:`os.makedirs` function and :meth:`pathlib.Path.mkdir` method now have +a *parent_mode* parameter to specify the mode for intermediate directories when +creating parent directories. This allows one to match the behavior from Python +3.6 and earlier for :func:`os.makedirs`. From 65b255416ae217bf0e22085be3c1976cea18bd8c Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 19 May 2026 10:44:35 +0200 Subject: [PATCH 083/818] [3.15] gh-146581: Update docs for dangerous filenames in ZIP files (GH-149994) (GH-150064) gh-146581: Update docs for dangerous filenames in ZIP files (GH-149994) (cherry picked from commit ba0aca3bffce431fe2fbd53ca4cd6a717a2e2c19) Co-authored-by: Serhiy Storchaka Co-authored-by: Sebastian Gassner --- Doc/library/shutil.rst | 4 ++-- Doc/library/zipfile.rst | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Doc/library/shutil.rst b/Doc/library/shutil.rst index d289ba58c24065..e0300a38e2f357 100644 --- a/Doc/library/shutil.rst +++ b/Doc/library/shutil.rst @@ -749,8 +749,8 @@ provided. They rely on the :mod:`zipfile` and :mod:`tarfile` modules. Never extract archives from untrusted sources without prior inspection. It is possible that files are created outside of the path specified in - the *extract_dir* argument, e.g. members that have absolute filenames - starting with "/" or filenames with two dots "..". + the *extract_dir* argument, for example, members that have absolute filenames + or filenames with ".." components. Since Python 3.14, the defaults for both built-in formats (zip and tar files) will prevent the most dangerous of such security issues, diff --git a/Doc/library/zipfile.rst b/Doc/library/zipfile.rst index 9999ac26999910..ebafcb977803d4 100644 --- a/Doc/library/zipfile.rst +++ b/Doc/library/zipfile.rst @@ -411,9 +411,9 @@ ZipFile objects .. warning:: Never extract archives from untrusted sources without prior inspection. - It is possible that files are created outside of *path*, e.g. members - that have absolute filenames starting with ``"/"`` or filenames with two - dots ``".."``. This module attempts to prevent that. + It is possible that files are created outside of *path*, for example, members + that have absolute filenames or filenames with ".." components. + This module attempts to prevent that. See :meth:`extract` note. .. versionchanged:: 3.6 @@ -590,7 +590,7 @@ Path objects The :class:`Path` class does not sanitize filenames within the ZIP archive. Unlike the :meth:`ZipFile.extract` and :meth:`ZipFile.extractall` methods, it is the caller's responsibility to validate or sanitize filenames to prevent path traversal - vulnerabilities (e.g., filenames containing ".." or absolute paths). When handling + vulnerabilities (for example, absolute paths or paths with ".." components). When handling untrusted archives, consider resolving filenames using :func:`os.path.abspath` and checking against the target directory with :func:`os.path.commonpath`. From bec4336badaac36c8080ff3e55676362775f61d8 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 19 May 2026 19:48:48 +0200 Subject: [PATCH 084/818] [3.15] gh-69619: Clarify whitespace definition in str.strip docs (#150049) (cherry picked from commit 17eb17d43f66a0f7985fca05c7c9684bc01fabcd) Co-authored-by: Daniil --- Doc/library/stdtypes.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index e3bd1a46891adc..b0388c4e1f0bd4 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -2747,6 +2747,8 @@ expression support in the :mod:`re` module). The *chars* argument is not a prefix or suffix; rather, all combinations of its values are stripped. + Whitespace characters are defined by :meth:`str.isspace`. + For example: .. doctest:: From 3227857de8ad895fdef7c3d18a9e031f29980029 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 19 May 2026 22:38:47 +0200 Subject: [PATCH 085/818] [3.15] gh-149945: Fix potential OOM for gzip with large header (GH-149979) (GH-150093) Do not read the whole filename and comment to memory for calculating the CRC. (cherry picked from commit 51a5715df9c56f616944cf1b39323bd6ae009143) Co-authored-by: Serhiy Storchaka --- Lib/gzip.py | 50 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 30 insertions(+), 20 deletions(-) diff --git a/Lib/gzip.py b/Lib/gzip.py index a89ebf806c8572..1e05f43c0c9e24 100644 --- a/Lib/gzip.py +++ b/Lib/gzip.py @@ -484,14 +484,22 @@ def _read_exact(fp, n): return data -def _read_until_null(fp, append_to): +def _read_until_null(fp, crc=None): '''Read until the first encountered null byte in fp. - Append to given byte array object''' - while True: - s = fp.read(1) - append_to += s - if not s or s == b'\000': - break + If crc is not None, update and return the CRC. + ''' + if crc is None: + while True: + s = fp.read(1) + if not s or s == b'\000': + break + else: + while True: + s = fp.read(1) + crc = zlib.crc32(s, crc) + if not s or s == b'\000': + break + return crc def _read_gzip_header(fp): @@ -517,30 +525,32 @@ def _read_gzip_header(fp): return last_mtime if flag == FNAME: # Read and discard a null-terminated string containing the filename - while True: - s = fp.read(1) - if not s or s==b'\000': - break + _read_until_null(fp) return last_mtime # Processing for more complex flags. Save header parts for FHCRC checking. - header = bytearray(magic + base_header) + if flag & FHCRC: + crc = zlib.crc32(magic + base_header) + else: + crc = None if flag & FEXTRA: extra_len_bytes = _read_exact(fp, 2) extra_len, = struct.unpack(" Date: Tue, 19 May 2026 22:57:21 +0200 Subject: [PATCH 086/818] [3.15] gh-124111: Keep tests passing for Tcl prior to 9.0 (GH-150102) Also disables the UWP build in CI, since it was breaking (and is no longer released). (cherry picked from commit ec9ce3ee98c68f235be6d075fa4bbd8f56d20256) Co-authored-by: Steve Dower --- .github/workflows/reusable-windows.yml | 2 -- Lib/test/test_tcl.py | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/reusable-windows.yml b/.github/workflows/reusable-windows.yml index 4c8d0c8a2f984f..c6e8128884e90c 100644 --- a/.github/workflows/reusable-windows.yml +++ b/.github/workflows/reusable-windows.yml @@ -22,8 +22,6 @@ permissions: env: FORCE_COLOR: 1 - IncludeUwp: >- - true jobs: build: diff --git a/Lib/test/test_tcl.py b/Lib/test/test_tcl.py index 81a5477b496b5c..70731d3222ced9 100644 --- a/Lib/test/test_tcl.py +++ b/Lib/test/test_tcl.py @@ -55,7 +55,7 @@ def test_eval_null_in_result(self): def test_eval_surrogates_in_result(self): tcl = self.interp result = tcl.eval(r'set a "<\ud83d\udcbb>"') - if sys.platform == 'win32': + if sys.platform == 'win32' and tcl_version >= (9, 0): self.assertEqual('<\ud83d\udcbb>', result) else: self.assertEqual('<\U0001f4bb>', result) @@ -294,7 +294,7 @@ def test_evalfile_surrogates_in_result(self): """) tcl.evalfile(filename) result = tcl.eval('set b') - if sys.platform == 'win32': + if sys.platform == 'win32' and tcl_version >= (9, 0): self.assertEqual('<\ud83d\udcbb>', result) else: self.assertEqual('<\U0001f4bb>', result) From f46b39797519d7c98f5561fbb06b99a76338642a Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 19 May 2026 23:11:13 +0200 Subject: [PATCH 087/818] [3.15] gh-149983: Fix PyErr_NoMemory call without GIL in winconsoleio.c (GH-149984) (GH-150113) (cherry picked from commit 3d2aa899bad1c0e274640dc0c4323f1744e73435) Co-authored-by: AN Long --- Modules/_io/winconsoleio.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Modules/_io/winconsoleio.c b/Modules/_io/winconsoleio.c index 677d7e85d4e626..4a3fc586fa3a14 100644 --- a/Modules/_io/winconsoleio.c +++ b/Modules/_io/winconsoleio.c @@ -673,12 +673,13 @@ read_console_w(HANDLE handle, DWORD maxlen, DWORD *readlen) { maxlen += 1; Py_BLOCK_THREADS newbuf = (wchar_t*)PyMem_Realloc(buf, maxlen * sizeof(wchar_t)); - Py_UNBLOCK_THREADS if (!newbuf) { sig = -1; PyErr_NoMemory(); + Py_UNBLOCK_THREADS break; } + Py_UNBLOCK_THREADS buf = newbuf; /* Only advance by n and not BUFSIZ in this case */ off += n; From 6847f4bc60f984a8d8e619de4b824d1b1da9524a Mon Sep 17 00:00:00 2001 From: Dino Viehland Date: Tue, 19 May 2026 14:23:30 -0700 Subject: [PATCH 088/818] [3.15] gh-150052: Resolve un-loaded lazily loaded submodules via module.__getattr__ instead of publishing lazy values (#150055) --- Include/internal/pycore_import.h | 2 + Lib/test/test_lazy_import/__init__.py | 42 +++--- Objects/moduleobject.c | 34 +++++ Python/import.c | 198 ++++++++------------------ 4 files changed, 123 insertions(+), 153 deletions(-) diff --git a/Include/internal/pycore_import.h b/Include/internal/pycore_import.h index 32ed3a62b2b4a7..a1078828afa572 100644 --- a/Include/internal/pycore_import.h +++ b/Include/internal/pycore_import.h @@ -39,6 +39,8 @@ extern PyObject * _PyImport_GetAbsName( // Symbol is exported for the JIT on Windows builds. PyAPI_FUNC(PyObject *) _PyImport_LoadLazyImportTstate( PyThreadState *tstate, PyObject *lazy_import); +extern PyObject * _PyImport_TryLoadLazySubmodule( + PyObject *mod_name, PyObject *attr_name); extern PyObject * _PyImport_LazyImportModuleLevelObject( PyThreadState *tstate, PyObject *name, PyObject *builtins, PyObject *globals, PyObject *locals, PyObject *fromlist, int level); diff --git a/Lib/test/test_lazy_import/__init__.py b/Lib/test/test_lazy_import/__init__.py index 366cb203f8f256..9f2cc92bcfcc78 100644 --- a/Lib/test/test_lazy_import/__init__.py +++ b/Lib/test/test_lazy_import/__init__.py @@ -450,6 +450,14 @@ def test_lazy_import_pkg(self): self.assertIn("test.test_lazy_import.data.pkg.bar", sys.modules) self.assertIn("BAR_MODULE_LOADED", out.getvalue()) + def test_lazy_submodule_stored_in_parent_dict(self): + """Accessing a lazy submodule should store it in the parent's __dict__.""" + import test.test_lazy_import.data.lazy_import_pkg + + pkg = sys.modules["test.test_lazy_import.data.pkg"] + self.assertIn("bar", pkg.__dict__) + self.assertIs(pkg.__dict__["bar"], sys.modules["test.test_lazy_import.data.pkg.bar"]) + def test_lazy_import_pkg_cross_import(self): """Cross-imports within package should preserve lazy imports.""" import test.test_lazy_import.data.pkg.c @@ -462,6 +470,18 @@ def test_lazy_import_pkg_cross_import(self): self.assertEqual(type(g["x"]), int) self.assertEqual(type(g["b"]), types.LazyImportType) + @support.requires_subprocess() + def test_lazy_from_import_does_not_pollute_parent(self): + """Lazy from import should not add the name to the parent module's dict.""" + code = textwrap.dedent(""" + lazy from json import nonexistent_attr + import json + assert "nonexistent_attr" not in json.__dict__, ( + "lazy from import should not publish attributes on the parent module" + ) + """) + assert_python_ok("-c", code) + @support.requires_subprocess() def test_package_from_import_with_module_getattr(self): """Lazy from import should respect a package's __getattr__.""" @@ -613,19 +633,14 @@ def tearDown(self): sys.set_lazy_imports("normal") def test_import_error_shows_chained_traceback(self): - """ImportError during reification should chain to show both definition and access.""" - # Errors at reification must show where the lazy import was defined - # AND where the access happened, per PEP 810 "Reification" section + """Accessing a nonexistent lazy submodule via parent attr raises AttributeError.""" code = textwrap.dedent(""" import sys lazy import test.test_lazy_import.data.nonexistent_module try: x = test.test_lazy_import.data.nonexistent_module - except ImportError as e: - # Should have __cause__ showing the original error - # The exception chain shows both where import was defined and where access happened - assert e.__cause__ is not None, "Expected chained exception" + except AttributeError as e: print("OK") """) result = subprocess.run( @@ -673,7 +688,7 @@ def test_reification_retries_on_failure(self): # First access - should fail try: x = test.test_lazy_import.data.broken_module - except ValueError: + except AttributeError: pass # The lazy object should still be a lazy proxy (not reified) @@ -683,7 +698,7 @@ def test_reification_retries_on_failure(self): # Second access - should also fail (retry the import) try: x = test.test_lazy_import.data.broken_module - except ValueError: + except AttributeError: print("OK - retry worked") """) result = subprocess.run( @@ -696,7 +711,6 @@ def test_reification_retries_on_failure(self): def test_error_during_module_execution_propagates(self): """Errors in module code during reification should propagate correctly.""" - # Module that raises during import should propagate with chaining code = textwrap.dedent(""" import sys lazy import test.test_lazy_import.data.broken_module @@ -704,12 +718,8 @@ def test_error_during_module_execution_propagates(self): try: _ = test.test_lazy_import.data.broken_module print("FAIL - should have raised") - except ValueError as e: - # The ValueError from the module should be the cause - if "always fails" in str(e) or (e.__cause__ and "always fails" in str(e.__cause__)): - print("OK") - else: - print(f"FAIL - wrong error: {e}") + except AttributeError: + print("OK") """) result = subprocess.run( [sys.executable, "-c", code], diff --git a/Objects/moduleobject.c b/Objects/moduleobject.c index f7b83c1d111cde..f447403ef31b43 100644 --- a/Objects/moduleobject.c +++ b/Objects/moduleobject.c @@ -1299,6 +1299,33 @@ _PyModule_IsPossiblyShadowing(PyObject *origin) return result; } +// Check if `name` is a lazily pending submodule of module `m`. +// Returns a new reference on success, or NULL with no error set. +static PyObject * +try_load_lazy_submodule(PyModuleObject *m, PyObject *name) +{ + PyObject *mod_name; + int rc = PyDict_GetItemRef(m->md_dict, &_Py_ID(__name__), &mod_name); + if (rc <= 0) { + return NULL; + } + if (!PyUnicode_Check(mod_name)) { + Py_DECREF(mod_name); + return NULL; + } + PyObject *result = _PyImport_TryLoadLazySubmodule(mod_name, name); + Py_DECREF(mod_name); + if (result == NULL) { + PyErr_Clear(); + return NULL; + } + if (PyDict_SetItem(m->md_dict, name, result) < 0) { + Py_DECREF(result); + return NULL; + } + return result; +} + PyObject* _Py_module_getattro_impl(PyModuleObject *m, PyObject *name, int suppress) { @@ -1363,6 +1390,13 @@ _Py_module_getattro_impl(PyModuleObject *m, PyObject *name, int suppress) PyErr_Clear(); } assert(m->md_dict != NULL); + attr = try_load_lazy_submodule(m, name); + if (attr != NULL) { + return attr; + } + if (PyErr_Occurred()) { + return NULL; + } if (PyDict_GetItemRef(m->md_dict, &_Py_ID(__getattr__), &getattr) < 0) { return NULL; } diff --git a/Python/import.c b/Python/import.c index c5cc7b52922d5b..ef6f5274a23665 100644 --- a/Python/import.c +++ b/Python/import.c @@ -4332,16 +4332,6 @@ PyImport_ImportModuleLevelObject(PyObject *name, PyObject *globals, return final_mod; } -static PyObject * -get_mod_dict(PyObject *module) -{ - if (PyModule_Check(module)) { - return Py_NewRef(_PyModule_GetDict(module)); - } - - return PyObject_GetAttr(module, &_Py_ID(__dict__)); -} - // ensure we have the set for the parent module name in sys.lazy_modules. // Returns a new reference. static PyObject * @@ -4364,18 +4354,16 @@ ensure_lazy_pending_submodules(PyDictObject *lazy_modules, PyObject *parent) return lazy_submodules; } -// Ensures that we have a LazyImportObject on the parent module for -// all children modules which have been lazily imported. If the parent -// module overrides the child attribute then the value is not replaced. +// Records all parent-child relationships in lazy_pending_submodules +// for a lazily imported module name. When a parent module's attribute +// is accessed, _Py_module_getattro_impl will check lazy_pending_submodules +// and trigger the import. static int -register_lazy_on_parent(PyThreadState *tstate, PyObject *name, - PyObject *builtins) +register_lazy_on_parent(PyThreadState *tstate, PyObject *name) { int ret = -1; PyObject *parent = NULL; PyObject *child = NULL; - PyObject *parent_module = NULL; - PyObject *parent_dict = NULL; PyInterpreterState *interp = tstate->interp; PyObject *lazy_pending_submodules = LAZY_PENDING_SUBMODULES(interp); @@ -4396,9 +4384,6 @@ register_lazy_on_parent(PyThreadState *tstate, PyObject *name, goto done; } parent = PyUnicode_Substring(name, 0, dot); - // If `parent` is NULL then this has hit the end of the import, no - // more "parent.child" in the import name. The entire import will be - // resolved lazily. if (parent == NULL) { goto done; } @@ -4408,7 +4393,6 @@ register_lazy_on_parent(PyThreadState *tstate, PyObject *name, goto done; } - // Record the child as being lazily imported from the parent. PyObject *lazy_submodules = ensure_lazy_pending_submodules( (PyDictObject *)lazy_pending_submodules, parent); if (lazy_submodules == NULL) { @@ -4421,44 +4405,11 @@ register_lazy_on_parent(PyThreadState *tstate, PyObject *name, } Py_DECREF(lazy_submodules); - // Add the lazy import for the child to the parent. - Py_XSETREF(parent_module, PyImport_GetModule(parent)); - if (parent_module != NULL) { - Py_XSETREF(parent_dict, get_mod_dict(parent_module)); - if (parent_dict == NULL) { - goto done; - } - if (PyDict_CheckExact(parent_dict)) { - int contains = PyDict_Contains(parent_dict, child); - if (contains < 0) { - goto done; - } - if (!contains) { - PyObject *lazy_module_attr = _PyLazyImport_New( - tstate->current_frame, builtins, parent, child - ); - if (lazy_module_attr == NULL) { - goto done; - } - if (PyDict_SetItem(parent_dict, child, - lazy_module_attr) < 0) { - Py_DECREF(lazy_module_attr); - goto done; - } - Py_DECREF(lazy_module_attr); - } - } - ret = 0; - goto done; - } - Py_SETREF(name, parent); parent = NULL; } done: - Py_XDECREF(parent_dict); - Py_XDECREF(parent_module); Py_XDECREF(child); Py_XDECREF(parent); Py_XDECREF(name); @@ -4467,7 +4418,7 @@ register_lazy_on_parent(PyThreadState *tstate, PyObject *name, static int register_from_lazy_on_parent(PyThreadState *tstate, PyObject *abs_name, - PyObject *from, PyObject *builtins) + PyObject *from) { PyObject *fromname = PyUnicode_FromFormat("%U.%U", abs_name, from); if (fromname == NULL) { @@ -4481,11 +4432,59 @@ register_from_lazy_on_parent(PyThreadState *tstate, PyObject *abs_name, return -1; } - int res = register_lazy_on_parent(tstate, fromname, builtins); + int res = register_lazy_on_parent(tstate, fromname); Py_DECREF(fromname); return res; } +PyObject * +_PyImport_TryLoadLazySubmodule(PyObject *mod_name, PyObject *attr_name) +{ + PyInterpreterState *interp = _PyInterpreterState_GET(); + PyObject *lazy_pending = LAZY_PENDING_SUBMODULES(interp); + if (lazy_pending == NULL) { + return NULL; + } + + PyObject *pending_set; + int rc = PyDict_GetItemRef(lazy_pending, mod_name, &pending_set); + if (rc <= 0) { + return NULL; + } + + int contains = PySet_Contains(pending_set, attr_name); + if (contains <= 0) { + Py_DECREF(pending_set); + return NULL; + } + + PyObject *full_name = PyUnicode_FromFormat("%U.%U", mod_name, attr_name); + if (full_name == NULL) { + Py_DECREF(pending_set); + return NULL; + } + + PyObject *mod = PyImport_ImportModuleLevelObject( + full_name, NULL, NULL, NULL, 0); + if (mod == NULL) { + Py_DECREF(pending_set); + Py_DECREF(full_name); + return NULL; + } + Py_DECREF(mod); + + if (PySet_Discard(pending_set, attr_name) < 0) { + Py_DECREF(pending_set); + Py_DECREF(full_name); + return NULL; + } + Py_DECREF(pending_set); + + PyObject *submod = PyImport_GetModule(full_name); + Py_DECREF(full_name); + return submod; +} + PyObject * _PyImport_LazyImportModuleLevelObject(PyThreadState *tstate, PyObject *name, PyObject *builtins, @@ -4580,8 +4579,7 @@ _PyImport_LazyImportModuleLevelObject(PyThreadState *tstate, } if (fromlist && PyUnicode_Check(fromlist)) { - if (register_from_lazy_on_parent(tstate, abs_name, fromlist, - builtins) < 0) { + if (register_from_lazy_on_parent(tstate, abs_name, fromlist) < 0) { goto error; } } @@ -4589,14 +4587,13 @@ _PyImport_LazyImportModuleLevelObject(PyThreadState *tstate, PyTuple_GET_SIZE(fromlist)) { for (Py_ssize_t i = 0; i < PyTuple_GET_SIZE(fromlist); i++) { if (register_from_lazy_on_parent(tstate, abs_name, - PyTuple_GET_ITEM(fromlist, i), - builtins) < 0) + PyTuple_GET_ITEM(fromlist, i)) < 0) { goto error; } } } - else if (register_lazy_on_parent(tstate, abs_name, builtins) < 0) { + else if (register_lazy_on_parent(tstate, abs_name) < 0) { goto error; } @@ -5605,46 +5602,6 @@ _imp_source_hash_impl(PyObject *module, long key, Py_buffer *source) return PyBytes_FromStringAndSize(hash.data, sizeof(hash.data)); } -static int -publish_lazy_imports_on_module(PyThreadState *tstate, - PyObject *lazy_submodules, - PyObject *name, - PyObject *module_dict) -{ - PyObject *builtins = _PyEval_GetBuiltins(tstate); - PyObject *attr_name; - Py_ssize_t pos = 0; - Py_hash_t hash; - - // Enumerate the set of lazy submodules which have been imported from the - // parent module. - while (_PySet_NextEntryRef(lazy_submodules, &pos, &attr_name, &hash)) { - if (_PyDict_Contains_KnownHash(module_dict, attr_name, hash)) { - Py_DECREF(attr_name); - continue; - } - // Create a new lazy module attr for the subpackage which was - // previously lazily imported. - PyObject *lazy_module_attr = _PyLazyImport_New(tstate->current_frame, builtins, - name, attr_name); - if (lazy_module_attr == NULL) { - Py_DECREF(attr_name); - return -1; - } - - // Publish on the module that was just imported. - if (PyDict_SetItem(module_dict, attr_name, - lazy_module_attr) < 0) { - Py_DECREF(lazy_module_attr); - Py_DECREF(attr_name); - return -1; - } - Py_DECREF(lazy_module_attr); - Py_DECREF(attr_name); - } - return 0; -} - /*[clinic input] _imp._set_lazy_attributes modobj: object @@ -5658,44 +5615,11 @@ _imp__set_lazy_attributes_impl(PyObject *module, PyObject *modobj, PyObject *name) /*[clinic end generated code: output=3369bb3242b1f043 input=38ea6f30956dd7d6]*/ { - PyThreadState *tstate = _PyThreadState_GET(); - PyObject *module_dict = NULL; - PyObject *ret = NULL; - PyObject *lazy_pending_modules = LAZY_PENDING_SUBMODULES(tstate->interp); - assert(lazy_pending_modules != NULL); - - PyObject *lazy_submodules; - if (PySet_Discard(LAZY_MODULES(tstate->interp), name) < 0) { - return NULL; - } else if (PyDict_GetItemRef(lazy_pending_modules, name, &lazy_submodules) < 0) { + PyInterpreterState *interp = _PyInterpreterState_GET(); + if (PySet_Discard(LAZY_MODULES(interp), name) < 0) { return NULL; } - else if (lazy_submodules == NULL) { - Py_RETURN_NONE; - } - - module_dict = get_mod_dict(modobj); - if (module_dict == NULL || !PyDict_CheckExact(module_dict)) { - Py_DECREF(lazy_submodules); - goto done; - } - - assert(PyAnySet_CheckExact(lazy_submodules)); - Py_BEGIN_CRITICAL_SECTION(lazy_submodules); - publish_lazy_imports_on_module(tstate, lazy_submodules, name, module_dict); - Py_END_CRITICAL_SECTION(); - Py_DECREF(lazy_submodules); - - if (PyDict_DelItem(lazy_pending_modules, name) < 0) { - goto error; - } - -done: - ret = Py_NewRef(Py_None); - -error: - Py_XDECREF(module_dict); - return ret; + Py_RETURN_NONE; } PyDoc_STRVAR(doc_imp, From de401ef6a5fc9d064ec89d6ee15844af95d4fbe8 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 20 May 2026 00:05:19 +0200 Subject: [PATCH 089/818] [3.15] gh-150114: Reduce memory usage of test_free_threading.test_iteration (gh-150115) (#150124) Reduce NUMITEMS from 100000 to 5000. Peak RSS for the full test_free_threading suite drops from ~850 MB to ~175 MB. (cherry picked from commit 61f12211fc40aef4a2dcccb9c94aae8108042edb) Co-authored-by: Sam Gross --- Lib/test/test_free_threading/test_iteration.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_free_threading/test_iteration.py b/Lib/test/test_free_threading/test_iteration.py index a51ad0cf83a006..44d3e9ccfdd14e 100644 --- a/Lib/test/test_free_threading/test_iteration.py +++ b/Lib/test/test_free_threading/test_iteration.py @@ -12,7 +12,7 @@ NUMITEMS = 1000 NUMTHREADS = 2 else: - NUMITEMS = 100000 + NUMITEMS = 5000 NUMTHREADS = 5 NUMMUTATORS = 2 From d6dda0d23c4a2c7db360235b2198c8f18e0f5596 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 20 May 2026 02:46:42 +0200 Subject: [PATCH 090/818] [3.15] gh-150042: queue.SimpleQueue.put: fix minor refleak. (GH-150043) (GH-150127) If queue.SimpleQueue.put can't handoff the item to a waiting thread, and fails to allocate memory when adding the item to a ringbuf, it would leak a reference. Fixed. (cherry picked from commit 79088e0d82931c21fa72eadc416a18b7b0fdf9c1) Co-authored-by: larryhastings --- ...-05-18-16-54-54.gh-issue-150042.LSr5W8.rst | 1 + Modules/_queuemodule.c | 37 ++++++++----------- 2 files changed, 17 insertions(+), 21 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-05-18-16-54-54.gh-issue-150042.LSr5W8.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-18-16-54-54.gh-issue-150042.LSr5W8.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-18-16-54-54.gh-issue-150042.LSr5W8.rst new file mode 100644 index 00000000000000..18a4fbd9dadd60 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-18-16-54-54.gh-issue-150042.LSr5W8.rst @@ -0,0 +1 @@ +Fix refleak in queue.SimpleQueue.put if memory allocation fails. diff --git a/Modules/_queuemodule.c b/Modules/_queuemodule.c index ed925f3525a9a7..d5ba36273c8262 100644 --- a/Modules/_queuemodule.c +++ b/Modules/_queuemodule.c @@ -154,8 +154,6 @@ RingBuf_Get(RingBuf *buf) } // Returns 0 on success or -1 if the buffer failed to grow. -// -// Steals a reference to item. static int RingBuf_Put(RingBuf *buf, PyObject *item) { @@ -165,11 +163,10 @@ RingBuf_Put(RingBuf *buf, PyObject *item) // Buffer is full, grow it. if (resize_ringbuf(buf, buf->items_cap * 2) < 0) { PyErr_NoMemory(); - Py_DECREF(item); return -1; } } - buf->items[buf->put_idx] = item; + buf->items[buf->put_idx] = Py_NewRef(item); buf->put_idx = (buf->put_idx + 1) % buf->items_cap; buf->num_items++; return 0; @@ -276,16 +273,13 @@ maybe_handoff_item(void *arg, void *park_arg, int has_more_waiters) { HandoffData *data = (HandoffData*)arg; PyObject **item = (PyObject**)park_arg; - if (item == NULL) { - // No threads were waiting - data->handed_off = false; - } - else { + data->queue->has_threads_waiting = has_more_waiters; + + data->handed_off = item != NULL; + if (data->handed_off) { // There was at least one waiting thread, hand off the item - *item = data->item; - data->handed_off = true; + *item = Py_NewRef(data->item); } - data->queue->has_threads_waiting = has_more_waiters; } /*[clinic input] @@ -307,21 +301,22 @@ _queue_SimpleQueue_put_impl(simplequeueobject *self, PyObject *item, int block, PyObject *timeout) /*[clinic end generated code: output=4333136e88f90d8b input=a16dbb33363c0fa8]*/ { - HandoffData data = { - .handed_off = 0, - .item = Py_NewRef(item), - .queue = self, - }; if (self->has_threads_waiting) { + HandoffData data = { + .handed_off = 0, + .item = item, + .queue = self, + }; // Try to hand the item off directly if there are threads waiting _PyParkingLot_Unpark(&self->has_threads_waiting, maybe_handoff_item, &data); - } - if (!data.handed_off) { - if (RingBuf_Put(&self->buf, item) < 0) { - return NULL; + if (data.handed_off) { + Py_RETURN_NONE; } } + if (RingBuf_Put(&self->buf, item) < 0) { + return NULL; + } Py_RETURN_NONE; } From 4baf3e5b0dede9c8d954ad0ac2ad01047a573c3d Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 20 May 2026 02:54:59 +0200 Subject: [PATCH 091/818] [3.15] gh-134887: Add references to `locale` module for locale-aware number formatting references in `string` module docs (GH-134888) (GH-150120) (cherry picked from commit 47723af4e74ae1a65108837fe15795e2f70f9d02) Co-authored-by: Stefanie Molin <24376333+stefmolin@users.noreply.github.com> --- Doc/library/string.rst | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/Doc/library/string.rst b/Doc/library/string.rst index 08ccdfa3f454f8..be968a3c53d843 100644 --- a/Doc/library/string.rst +++ b/Doc/library/string.rst @@ -472,7 +472,9 @@ of a number respectively. It can be one of the following: | | this option is not supported. | +---------+----------------------------------------------------------+ -For a locale aware separator, use the ``'n'`` presentation type instead. +For a locale-aware separator, use the ``'n'`` +:ref:`float presentation type ` or +:ref:`integer presentation type ` instead. .. versionchanged:: 3.1 Added the ``','`` option (see also :pep:`378`). @@ -518,9 +520,14 @@ The available integer presentation types are: | | In case ``'#'`` is specified, the prefix ``'0x'`` will | | | be upper-cased to ``'0X'`` as well. | +---------+----------------------------------------------------------+ - | ``'n'`` | Number. This is the same as ``'d'``, except that it uses | + | ``'n'`` | .. _n-format-integer: | + | | | + | | Number. This is the same as ``'d'``, except that it uses | | | the current locale setting to insert the appropriate | - | | digit group separators. | + | | digit group separators. Note that the default locale is | + | | not the system locale. Depending on your use case, you | + | | may wish to set :const:`~locale.LC_NUMERIC` with | + | | :func:`locale.setlocale` before using ``'n'``. | +---------+----------------------------------------------------------+ | None | The same as ``'d'``. | +---------+----------------------------------------------------------+ @@ -603,10 +610,15 @@ The available presentation types for :class:`float` and | | ``'E'`` if the number gets too large. The | | | representations of infinity and NaN are uppercased, too. | +---------+----------------------------------------------------------+ - | ``'n'`` | Number. This is the same as ``'g'``, except that it uses | + | ``'n'`` | .. _n-format-float: | + | | | + | | Number. This is the same as ``'g'``, except that it uses | | | the current locale setting to insert the appropriate | - | | digit group separators | - | | for the integral part of a number. | + | | digit group separators for the integral part of a | + | | number. Note that the default locale is not the system | + | | locale. Depending on your use case, you may wish to set | + | | :const:`~locale.LC_NUMERIC` with | + | | :func:`locale.setlocale` before using ``'n'``. | +---------+----------------------------------------------------------+ | ``'%'`` | Percentage. Multiplies the number by 100 and displays | | | in fixed (``'f'``) format, followed by a percent sign. | From eb7be9ab52593f7a27d2046cd44b1fdfd6cac430 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 20 May 2026 03:00:54 +0200 Subject: [PATCH 092/818] [3.15] gh-72088: clarify `inspect.ismethod` and `inspect.isfunction` (and related) usage with class-level access (GH-150013) (GH-150119) (cherry picked from commit 0aa59ce2d4f007a9d19740eb2f6230ed302096f7) Co-authored-by: Stefanie Molin <24376333+stefmolin@users.noreply.github.com> Co-authored-by: CHINMAY <89741289+Das-Chinmay@users.noreply.github.com> --- Doc/library/inspect.rst | 45 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 42 insertions(+), 3 deletions(-) diff --git a/Doc/library/inspect.rst b/Doc/library/inspect.rst index 48ae9147587c64..92840e702fbbfe 100644 --- a/Doc/library/inspect.rst +++ b/Doc/library/inspect.rst @@ -424,12 +424,39 @@ attributes (see :ref:`import-mod-attrs` for module attributes): Return ``True`` if the object is a bound method written in Python. + .. note:: -.. function:: ispackage(object) + For example, given this class:: - Return ``True`` if the object is a :term:`package`. + >>> class Greeter: + ... def say_hello(self): + ... print('hello!') - .. versionadded:: 3.14 + A bound method (also known as an *instance method*) is created when + accessing ``say_hello`` (a :term:`function` defined in the + ``Greeter`` namespace) through an instance of the ``Greeter`` class:: + + >>> instance = Greeter() + + >>> instance.say_hello + > + >>> ismethod(instance.say_hello) + True + >>> isfunction(instance.say_hello) + False + + Accessing ``say_hello`` through the ``Greeter`` class will return the + function itself. For this function, :func:`ismethod` will return + ``False``, but :func:`isfunction` will return ``True``:: + + >>> Greeter.say_hello + + >>> ismethod(Greeter.say_hello) + False + >>> isfunction(Greeter.say_hello) + True + + See :ref:`typesmethods` for details. .. function:: isfunction(object) @@ -437,11 +464,23 @@ attributes (see :ref:`import-mod-attrs` for module attributes): Return ``True`` if the object is a Python function, which includes functions created by a :term:`lambda` expression. + See the note for :func:`~inspect.ismethod` for an example. + + +.. function:: ispackage(object) + + Return ``True`` if the object is a :term:`package`. + + .. versionadded:: 3.14 + .. function:: isgeneratorfunction(object) Return ``True`` if the object is a Python generator function. + It also returns ``True`` for bound methods created from Python generator functions + (see :ref:`typesmethods` for more information). + .. versionchanged:: 3.8 Functions wrapped in :func:`functools.partial` now return ``True`` if the wrapped function is a Python generator function. From 653f12b2bfdbbe104f9463816d5f0c02e60e7c1d Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 20 May 2026 03:03:47 +0200 Subject: [PATCH 093/818] [3.15] gh-143387: Update docs to reflect the behavior and note the changed version. (GH-150095) (#150106) gh-143387: Update docs to reflect the behavior and note the changed version. (GH-150095) (cherry picked from commit 192796cfd4793cd7c9e88261795394ab016d5984) Co-authored-by: Jason R. Coombs --- Doc/library/importlib.metadata.rst | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/Doc/library/importlib.metadata.rst b/Doc/library/importlib.metadata.rst index 63de4f91f4ba5f..e11db37b9fad50 100644 --- a/Doc/library/importlib.metadata.rst +++ b/Doc/library/importlib.metadata.rst @@ -105,6 +105,13 @@ You can also get a :ref:`distribution's version number `, list its current Python environment. +.. exception:: MetadataNotFound + + Subclass of :class:`FileNotFoundError` raised when attempting to load metadata + from a distribution folder that is empty or otherwise does not contain a + metadata file. + + Functional API ============== @@ -224,6 +231,9 @@ Distribution metadata Raises :exc:`PackageNotFoundError` if the named distribution package is not installed in the current Python environment. + Raises :exc:`MetadataNotFound` if a distribution package is + present but no METADATA file is present. + .. class:: PackageMetadata A concrete implementation of the @@ -252,6 +262,12 @@ all the metadata in a JSON-compatible form per :PEP:`566`:: The full set of available metadata is not described here. See the PyPA `Core metadata specification `_ for additional details. +.. versionchanged:: 3.15 + Previously and incidentally, if a METADATA file was missing from a distribution, an + empty ``PackageMetadata`` would be returned, indistinguishable from + an empty METADATA file. Now, a missing METADATA file triggers a + ``MetadataNotFound`` exception. + .. versionchanged:: 3.10 The ``Description`` is now included in the metadata when presented through the payload. Line continuation characters have been removed. @@ -465,6 +481,9 @@ The same applies for :func:`entry_points` and :func:`files`. .. attribute:: metadata :type: PackageMetadata + Raises :exc:`MetadataNotFound` if the METADATA file is not present in + the distribution. + There are all kinds of additional metadata available on :class:`!Distribution` instances as a :class:`PackageMetadata` instance:: From c555e260615d8d820f6a98e60a1d0ad0a1f13141 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 20 May 2026 13:48:24 +0200 Subject: [PATCH 094/818] [3.15] gh-148260: Use at least 1 MiB stack size on musl (GH-149993) (#150150) gh-148260: Use at least 1 MiB stack size on musl (GH-149993) On Linux when Python is linked to the musl C library, use a thread stack size of at least 1 MiB instead of musl default which is 128 kiB. (cherry picked from commit df6c157e51430e8e7458012417c534ad8c33119f) Co-authored-by: Victor Stinner --- ...-05-18-16-00-41.gh-issue-148260.UwFiIX.rst | 3 + configure | 55 +++++++++++++++++++ configure.ac | 48 ++++++++++++++++ 3 files changed, 106 insertions(+) create mode 100644 Misc/NEWS.d/next/Build/2026-05-18-16-00-41.gh-issue-148260.UwFiIX.rst diff --git a/Misc/NEWS.d/next/Build/2026-05-18-16-00-41.gh-issue-148260.UwFiIX.rst b/Misc/NEWS.d/next/Build/2026-05-18-16-00-41.gh-issue-148260.UwFiIX.rst new file mode 100644 index 00000000000000..8248c24cbd511a --- /dev/null +++ b/Misc/NEWS.d/next/Build/2026-05-18-16-00-41.gh-issue-148260.UwFiIX.rst @@ -0,0 +1,3 @@ +On Linux when Python is linked to the musl C library, use a thread stack +size of at least 1 MiB instead of musl default which is 128 kiB. Patch by +Victor Stinner. diff --git a/configure b/configure index 8979ec294bcdf0..acba294d55de8f 100755 --- a/configure +++ b/configure @@ -9866,6 +9866,61 @@ fi ;; esac +if test "$ac_sys_system" = "Linux" -a "$cross_compiling" = no; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for thread stack size" >&5 +printf %s "checking for thread stack size... " >&6; } +if test ${ac_cv_thread_stack_size+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) + cat > conftest.c < + +int main() +{ + pthread_attr_t attrs; + size_t size; + + int rc = pthread_attr_init(&attrs); + if (rc != 0) { + return 2; + } + + rc = pthread_attr_getstacksize(&attrs, &size); + if (rc != 0) { + return 2; + } + + if (size < 1024 * 1024) { + return 1; + } + return 0; +} +EOF + + ac_cv_thread_stack_size=unknown + if $CC -pthread $CFLAGS conftest.c -o conftest &>/dev/null; then + ./conftest &>/dev/null + exitcode=$? + if test $exitcode -eq 1; then + ac_cv_thread_stack_size=1048576 + elif test $exitcode -eq 0; then + ac_cv_thread_stack_size="default" + fi + fi + rm -f conftest.c conftest + ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_thread_stack_size" >&5 +printf "%s\n" "$ac_cv_thread_stack_size" >&6; } + + if test "$ac_cv_thread_stack_size" != "default" -a "$ac_cv_thread_stack_size" != "unknown"; then + LDFLAGS="$LDFLAGS -Wl,-z,stack-size=$ac_cv_thread_stack_size" + fi +fi + case $enable_wasm_dynamic_linking in #( yes) : ac_cv_func_dlopen=yes ;; #( diff --git a/configure.ac b/configure.ac index 842e010f20cb74..d909c2fc92894e 100644 --- a/configure.ac +++ b/configure.ac @@ -2462,6 +2462,54 @@ AS_CASE([$ac_sys_system], ] ) +dnl On Linux, check the thread stack size. musl (ex: Alpine Linux) uses +dnl a default thread stack size of 128 kB, whereas the glibc uses 8 MiB. +dnl Python needs at least 1 MiB. +if test "$ac_sys_system" = "Linux" -a "$cross_compiling" = no; then + AC_CACHE_CHECK([for thread stack size], [ac_cv_thread_stack_size], [ + cat > conftest.c < + +int main() +{ + pthread_attr_t attrs; + size_t size; + + int rc = pthread_attr_init(&attrs); + if (rc != 0) { + return 2; + } + + rc = pthread_attr_getstacksize(&attrs, &size); + if (rc != 0) { + return 2; + } + + if (size < 1024 * 1024) { + return 1; + } + return 0; +} +EOF + + ac_cv_thread_stack_size=unknown + if $CC -pthread $CFLAGS conftest.c -o conftest &>/dev/null; then + ./conftest &>/dev/null + exitcode=$? + if test $exitcode -eq 1; then + ac_cv_thread_stack_size=1048576 + elif test $exitcode -eq 0; then + ac_cv_thread_stack_size="default" + fi + fi + rm -f conftest.c conftest + ]) + + if test "$ac_cv_thread_stack_size" != "default" -a "$ac_cv_thread_stack_size" != "unknown"; then + LDFLAGS="$LDFLAGS -Wl,-z,stack-size=$ac_cv_thread_stack_size" + fi +fi + AS_CASE([$enable_wasm_dynamic_linking], [yes], [ac_cv_func_dlopen=yes], [no], [ac_cv_func_dlopen=no], From 7f29fa5032cc5a9d02cccbb39a3f7cd116e0f145 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 20 May 2026 13:51:54 +0200 Subject: [PATCH 095/818] [3.15] gh-149807: Fix hash(frozendict): compute (key, value) pair hash (GH-149841) (#150149) gh-149807: Fix hash(frozendict): compute (key, value) pair hash (GH-149841) (cherry picked from commit 244300162d2e863a0588d1754e224d68931ada37) Co-authored-by: Victor Stinner --- Lib/test/test_dict.py | 25 ++++++++++ ...-05-14-19-41-03.gh-issue-149807.IwGaCo.rst | 2 + Objects/dictobject.c | 50 +++++++++++++++---- Objects/tupleobject.c | 3 ++ 4 files changed, 69 insertions(+), 11 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-05-14-19-41-03.gh-issue-149807.IwGaCo.rst diff --git a/Lib/test/test_dict.py b/Lib/test/test_dict.py index 4efb066d4fd01c..f26586809238f0 100644 --- a/Lib/test/test_dict.py +++ b/Lib/test/test_dict.py @@ -1903,10 +1903,35 @@ def test_hash(self): self.assertEqual(hash(frozendict(x=1, y=2)), hash(frozendict(y=2, x=1))) + # Check that hash() computes the hash of (key, value) pairs + cases = [ + frozendict(a=False, b=True, c=True), + frozendict(a=True, b=False, c=True), + frozendict(a=True, b=True, c=False), + frozendict({False: "a", "b": True, "c": True}), + frozendict({"a": "b", False: True, True: "c"}), + ] + hashes = {hash(fd) for fd in cases} + self.assertEqual(len(hashes), len(cases)) + fd = frozendict(x=[1], y=[2]) with self.assertRaisesRegex(TypeError, "unhashable type: 'list'"): hash(fd) + @support.cpython_only + def test_hash_cpython(self): + # Check that hash(frozendict) implementation is: + # hash(frozenset(fd.items())) + for fd in ( + frozendict(), + frozendict(x=1, y=2), + frozendict(y=2, x=1), + frozendict(a=False, b=True, c=True), + frozendict.fromkeys('abc'), + ): + with self.subTest(fd=fd): + self.assertEqual(hash(fd), hash(frozenset(fd.items()))) + def test_fromkeys(self): self.assertEqual(frozendict.fromkeys('abc'), frozendict(a=None, b=None, c=None)) diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-14-19-41-03.gh-issue-149807.IwGaCo.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-14-19-41-03.gh-issue-149807.IwGaCo.rst new file mode 100644 index 00000000000000..a94c737e73619d --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-14-19-41-03.gh-issue-149807.IwGaCo.rst @@ -0,0 +1,2 @@ +Fix ``hash(frozendict)``: compute the hash of each ``(key, value)`` pair +correctly. Patch by Victor Stinner. diff --git a/Objects/dictobject.c b/Objects/dictobject.c index a7d67812bec925..3830fedd42bd27 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -8230,6 +8230,39 @@ _shuffle_bits(Py_uhash_t h) return ((h ^ 89869747UL) ^ (h << 16)) * 3644798167UL; } +// Compute hash((key, value)). +// Code copied from tuple_hash(). +static Py_hash_t +frozendict_pair_hash(Py_hash_t key_hash, PyObject *value) +{ + assert(key_hash != -1); + + const Py_ssize_t len = 2; + Py_uhash_t acc = _PyTuple_HASH_XXPRIME_5; + + Py_uhash_t lane = key_hash; + acc += lane * _PyTuple_HASH_XXPRIME_2; + acc = _PyTuple_HASH_XXROTATE(acc); + acc *= _PyTuple_HASH_XXPRIME_1; + + lane = PyObject_Hash(value); + if (lane == (Py_uhash_t)-1) { + return -1; + } + acc += lane * _PyTuple_HASH_XXPRIME_2; + acc = _PyTuple_HASH_XXROTATE(acc); + acc *= _PyTuple_HASH_XXPRIME_1; + + /* Add input length, mangled to keep the historical value of hash(()). */ + acc += len ^ (_PyTuple_HASH_XXPRIME_5 ^ 3527539UL); + + if (acc == (Py_uhash_t)-1) { + acc = 1546275796; + } + return acc; +} + + // Code copied from frozenset_hash() static Py_hash_t frozendict_hash(PyObject *op) @@ -8243,20 +8276,15 @@ frozendict_hash(PyObject *op) PyDictObject *mp = _PyAnyDict_CAST(op); Py_uhash_t hash = 0; - PyObject *key, *value; // borrowed refs + PyObject *value; // borrowed ref Py_ssize_t pos = 0; - while (PyDict_Next(op, &pos, &key, &value)) { - Py_hash_t key_hash = PyObject_Hash(key); - if (key_hash == -1) { - return -1; - } - hash ^= _shuffle_bits(key_hash); - - Py_hash_t value_hash = PyObject_Hash(value); - if (value_hash == -1) { + Py_hash_t key_hash; + while (_PyDict_Next(op, &pos, NULL, &value, &key_hash)) { + Py_hash_t pair_hash = frozendict_pair_hash(key_hash, value); + if (pair_hash == -1) { return -1; } - hash ^= _shuffle_bits(value_hash); + hash ^= _shuffle_bits(pair_hash); } /* Factor in the number of active entries */ diff --git a/Objects/tupleobject.c b/Objects/tupleobject.c index 753c270f525976..6de9487432a398 100644 --- a/Objects/tupleobject.c +++ b/Objects/tupleobject.c @@ -363,6 +363,9 @@ tuple_repr(PyObject *self) https://github.com/Cyan4973/xxHash/blob/master/doc/xxhash_spec.md The constants for the hash function are defined in pycore_tuple.h. + + If you update this code, update also frozendict_pair_hash() which copied + this code. */ static Py_hash_t From 034c536d56aa89350dcdd29bf14bc54042abca04 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 20 May 2026 13:59:10 +0200 Subject: [PATCH 096/818] [3.15] gh-149584: Fix excessive overhead in the Tachyon profiler regarding the cache behavior (GH-149649) (#150152) --- Lib/profiling/sampling/sample.py | 27 ++ Lib/test/test_external_inspection.py | 7 + ...-05-10-19-26-50.gh-issue-149584.x7Qm9A.rst | 4 + Modules/_remote_debugging/_remote_debugging.h | 83 ++++- Modules/_remote_debugging/clinic/module.c.h | 9 +- Modules/_remote_debugging/code_objects.c | 13 + Modules/_remote_debugging/frame_cache.c | 26 ++ Modules/_remote_debugging/frames.c | 101 ++++--- Modules/_remote_debugging/module.c | 284 +++++++++++++++--- Modules/_remote_debugging/threads.c | 112 ++++++- Python/remote_debug.h | 98 ++++-- .../benchmark_external_inspection.py | 100 +++++- 12 files changed, 738 insertions(+), 126 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-05-10-19-26-50.gh-issue-149584.x7Qm9A.rst diff --git a/Lib/profiling/sampling/sample.py b/Lib/profiling/sampling/sample.py index b9e7e2625d09e4..2d379e1e16a35e 100644 --- a/Lib/profiling/sampling/sample.py +++ b/Lib/profiling/sampling/sample.py @@ -327,6 +327,33 @@ def _print_unwinder_stats(self): print(f" Hits: {code_hits:n} ({ANSIColors.GREEN}{fmt(code_hits_pct)}%{ANSIColors.RESET})") print(f" Misses: {code_misses:n} ({ANSIColors.RED}{fmt(code_misses_pct)}%{ANSIColors.RESET})") + batched_attempts = stats.get('batched_read_attempts', 0) + batched_successes = stats.get('batched_read_successes', 0) + batched_misses = stats.get('batched_read_misses', 0) + segments_requested = stats.get('batched_read_segments_requested', 0) + segments_completed = stats.get('batched_read_segments_completed', 0) + if batched_attempts > 0: + batched_success_rate = stats.get('batched_read_success_rate', 0.0) + batched_miss_rate = 100.0 - batched_success_rate + segment_completion_rate = stats.get( + 'batched_read_segment_completion_rate', 0.0 + ) + + print(f" {ANSIColors.CYAN}Batched Reads:{ANSIColors.RESET}") + print(f" Attempts: {batched_attempts:n}") + print( + f" Successes: {batched_successes:n} " + f"({ANSIColors.GREEN}{fmt(batched_success_rate)}%{ANSIColors.RESET})" + ) + print( + f" Misses: {batched_misses:n} " + f"({ANSIColors.RED}{fmt(batched_miss_rate)}%{ANSIColors.RESET})" + ) + print( + f" Segments read: {segments_completed:n}/{segments_requested:n} " + f"({ANSIColors.GREEN}{fmt(segment_completion_rate)}%{ANSIColors.RESET})" + ) + # Memory operations memory_reads = stats.get('memory_reads', 0) memory_bytes = stats.get('memory_bytes_read', 0) diff --git a/Lib/test/test_external_inspection.py b/Lib/test/test_external_inspection.py index a29e6cdbbf6c78..6b1529aa173f01 100644 --- a/Lib/test/test_external_inspection.py +++ b/Lib/test/test_external_inspection.py @@ -3767,6 +3767,13 @@ def test_get_stats(self): "frames_read_from_cache", "frames_read_from_memory", "frame_cache_hit_rate", + "batched_read_attempts", + "batched_read_successes", + "batched_read_misses", + "batched_read_segments_requested", + "batched_read_segments_completed", + "batched_read_success_rate", + "batched_read_segment_completion_rate", ] for key in expected_keys: self.assertIn(key, stats) diff --git a/Misc/NEWS.d/next/Library/2026-05-10-19-26-50.gh-issue-149584.x7Qm9A.rst b/Misc/NEWS.d/next/Library/2026-05-10-19-26-50.gh-issue-149584.x7Qm9A.rst new file mode 100644 index 00000000000000..6734250fdd6af3 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-05-10-19-26-50.gh-issue-149584.x7Qm9A.rst @@ -0,0 +1,4 @@ +Fix excessive overhead in the Tachyon profiler when inspecting a remote +process by avoiding repeated remote page-cache scans, batching predicted +remote reads, and reusing cached profiler result objects. Patch by Pablo +Galindo and Maurycy Pawłowski-Wieroński. diff --git a/Modules/_remote_debugging/_remote_debugging.h b/Modules/_remote_debugging/_remote_debugging.h index 7369cd1514c296..d91ce54a18c813 100644 --- a/Modules/_remote_debugging/_remote_debugging.h +++ b/Modules/_remote_debugging/_remote_debugging.h @@ -30,6 +30,7 @@ extern "C" { #include "internal/pycore_llist.h" // struct llist_node #include "internal/pycore_long.h" // _PyLong_GetZero #include "internal/pycore_pyerrors.h" // _PyErr_FormatFromCause +#include "internal/pycore_pyhash.h" // _Py_HashPointerRaw #include "internal/pycore_stackref.h" // Py_TAG_BITS #include "../../Python/remote_debug.h" @@ -215,6 +216,8 @@ typedef struct { PyObject *file_name; int first_lineno; PyObject *linetable; // bytes + PyObject *last_frame_info; + ptrdiff_t last_addrq; uintptr_t addr_code_adaptive; } CachedCodeMetadata; @@ -224,11 +227,41 @@ typedef struct { typedef struct { uint64_t thread_id; // 0 = empty slot + uintptr_t thread_state_addr; uintptr_t addrs[FRAME_CACHE_MAX_FRAMES]; Py_ssize_t num_addrs; + PyObject *thread_id_obj; // owned reference, NULL if empty PyObject *frame_list; // owned reference, NULL if empty } FrameCacheEntry; +#define INTERPRETER_THREAD_CACHE_SIZE 32 +#if (INTERPRETER_THREAD_CACHE_SIZE & (INTERPRETER_THREAD_CACHE_SIZE - 1)) != 0 +# error "INTERPRETER_THREAD_CACHE_SIZE must be a power of two" +#endif + +// The two per-interpreter L2 caches below are split into per-field tables so +// that a writer rebinding one slot cannot leave stale data in a field owned by +// the other when the slot is reused across interpreters. +typedef struct { + uintptr_t interpreter_addr; + uintptr_t thread_state_addr; +} InterpreterTstateCacheEntry; +typedef struct { + uintptr_t interpreter_addr; + uint64_t code_object_generation; +} InterpreterGenerationCacheEntry; + +// Carries already-read thread state and/or frame buffers across helpers so the +// downstream callee can skip a remote read. Address fields are caller-supplied +// inputs; buffer pointers (tstate, frame) are NULL unless a prior batched read +// successfully populated them. +typedef struct { + const char *tstate; + uintptr_t tstate_addr; + const char *frame; + uintptr_t frame_addr; +} RemoteReadPrefetch; + /* Statistics for profiling performance analysis */ typedef struct { uint64_t total_samples; // Total number of get_stack_trace calls @@ -242,14 +275,44 @@ typedef struct { uint64_t code_object_cache_hits; // Code object cache hits uint64_t code_object_cache_misses; // Code object cache misses uint64_t stale_cache_invalidations; // Times stale entries were cleared + uint64_t batched_read_attempts; // Batched remote-read attempts + uint64_t batched_read_successes; // Attempts that read all requested segments + uint64_t batched_read_misses; // Attempts that fell back or partially read + uint64_t batched_read_segments_requested; // Segments requested by batched reads + uint64_t batched_read_segments_completed; // Segments completed by batched reads } UnwinderStats; +#if defined(__GNUC__) || defined(__clang__) +# define REMOTE_DEBUG_UNLIKELY(value) __builtin_expect(!!(value), 0) +#else +# define REMOTE_DEBUG_UNLIKELY(value) (value) +#endif + /* Stats tracking macros - no-op when stats collection is disabled */ #define STATS_INC(unwinder, field) \ - do { if ((unwinder)->collect_stats) (unwinder)->stats.field++; } while(0) + do { if (REMOTE_DEBUG_UNLIKELY((unwinder)->collect_stats)) (unwinder)->stats.field++; } while(0) #define STATS_ADD(unwinder, field, val) \ - do { if ((unwinder)->collect_stats) (unwinder)->stats.field += (val); } while(0) + do { if (REMOTE_DEBUG_UNLIKELY((unwinder)->collect_stats)) (unwinder)->stats.field += (val); } while(0) + +#if HAVE_PROCESS_VM_READV +# define STATS_BATCHED_READ(unwinder, requested, completed) \ + do { \ + if (REMOTE_DEBUG_UNLIKELY((unwinder)->collect_stats)) { \ + (unwinder)->stats.batched_read_attempts++; \ + (unwinder)->stats.batched_read_segments_requested += (uint64_t)(requested); \ + (unwinder)->stats.batched_read_segments_completed += (uint64_t)(completed); \ + if ((completed) == (requested)) { \ + (unwinder)->stats.batched_read_successes++; \ + } \ + else { \ + (unwinder)->stats.batched_read_misses++; \ + } \ + } \ + } while(0) +#else +# define STATS_BATCHED_READ(unwinder, requested, completed) ((void)0) +#endif typedef struct { PyTypeObject *RemoteDebugging_Type; @@ -290,7 +353,6 @@ typedef struct { struct _Py_AsyncioModuleDebugOffsets async_debug_offsets; uintptr_t interpreter_addr; uintptr_t tstate_addr; - uint64_t code_object_generation; _Py_hashtable_t *code_object_cache; int debug; int only_active_thread; @@ -302,9 +364,17 @@ typedef struct { int cache_frames; int collect_stats; // whether to collect statistics uint32_t stale_invalidation_counter; // counter for throttling frame_cache_invalidate_stale + // L1 single-entry shortcut over cached_tstates[]: most workloads sample one + // interpreter, so check these pairs before hashing into the table below. + uintptr_t cached_tstate_interpreter_addr; + uintptr_t cached_tstate_addr; + uintptr_t cached_generation_interpreter_addr; + uint64_t cached_code_object_generation; RemoteDebuggingState *cached_state; FrameCacheEntry *frame_cache; // preallocated array of FRAME_CACHE_MAX_THREADS entries UnwinderStats stats; // statistics for performance analysis + InterpreterTstateCacheEntry cached_tstates[INTERPRETER_THREAD_CACHE_SIZE]; + InterpreterGenerationCacheEntry cached_generations[INTERPRETER_THREAD_CACHE_SIZE]; #ifdef Py_GIL_DISABLED uint32_t tlbc_generation; _Py_hashtable_t *tlbc_cache; @@ -361,11 +431,13 @@ typedef struct { typedef struct { /* Inputs */ uintptr_t frame_addr; // Starting frame address + uintptr_t thread_state_addr; // Owning thread state address uintptr_t base_frame_addr; // Sentinel at bottom (for validation) uintptr_t gc_frame; // GC frame address (0 if not tracking) uintptr_t last_profiled_frame; // Last cached frame (0 if no cache) StackChunkList *chunks; // Pre-copied stack chunks int skip_first_frame; // Skip frame_addr itself (continue from its caller) + RemoteReadPrefetch prefetch; // Optional already-read thread/frame buffers /* Outputs */ PyObject *frame_info; // List to append FrameInfo objects @@ -548,6 +620,7 @@ extern int process_frame_chain( extern int frame_cache_init(RemoteUnwinderObject *unwinder); extern void frame_cache_cleanup(RemoteUnwinderObject *unwinder); extern FrameCacheEntry *frame_cache_find(RemoteUnwinderObject *unwinder, uint64_t thread_id); +extern FrameCacheEntry *frame_cache_find_by_tstate(RemoteUnwinderObject *unwinder, uintptr_t tstate_addr); extern int clear_last_profiled_frames(RemoteUnwinderObject *unwinder); extern void frame_cache_invalidate_stale(RemoteUnwinderObject *unwinder, PyObject *result); extern int frame_cache_lookup_and_extend( @@ -566,6 +639,7 @@ extern int frame_cache_store( PyObject *frame_list, const uintptr_t *addrs, Py_ssize_t num_addrs, + uintptr_t thread_state_addr, uintptr_t base_frame_addr, uintptr_t last_frame_visited); @@ -605,7 +679,8 @@ extern PyObject* unwind_stack_for_thread( uintptr_t *current_tstate, uintptr_t gil_holder_tstate, uintptr_t gc_frame, - uintptr_t main_thread_tstate + uintptr_t main_thread_tstate, + const RemoteReadPrefetch *prefetch ); /* Thread stopping functions (for blocking mode) */ diff --git a/Modules/_remote_debugging/clinic/module.c.h b/Modules/_remote_debugging/clinic/module.c.h index d56622fb82ab56..78b1d3e8d80962 100644 --- a/Modules/_remote_debugging/clinic/module.c.h +++ b/Modules/_remote_debugging/clinic/module.c.h @@ -411,8 +411,15 @@ PyDoc_STRVAR(_remote_debugging_RemoteUnwinder_get_stats__doc__, " - code_object_cache_hits: Code object cache hits\n" " - code_object_cache_misses: Code object cache misses\n" " - stale_cache_invalidations: Times stale cache entries were cleared\n" +" - batched_read_attempts: Batched remote-read attempts\n" +" - batched_read_successes: Attempts that read all requested segments\n" +" - batched_read_misses: Attempts that fell back or partially read\n" +" - batched_read_segments_requested: Segments requested by batched reads\n" +" - batched_read_segments_completed: Segments completed by batched reads\n" " - frame_cache_hit_rate: Percentage of samples that hit the cache\n" " - code_object_cache_hit_rate: Percentage of code object lookups that hit cache\n" +" - batched_read_success_rate: Percentage of batched reads that completed all segments\n" +" - batched_read_segment_completion_rate: Percentage of requested segments read by batched reads\n" "\n" "Raises:\n" " RuntimeError: If stats collection was not enabled (stats=False)"); @@ -1540,4 +1547,4 @@ _remote_debugging_get_gc_stats(PyObject *module, PyObject *const *args, Py_ssize exit: return return_value; } -/*[clinic end generated code: output=5e2a29746a0c5d65 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=884914b100e9c90c input=a9049054013a1b77]*/ diff --git a/Modules/_remote_debugging/code_objects.c b/Modules/_remote_debugging/code_objects.c index 97c6ba772e88f1..3af58f2b3c379e 100644 --- a/Modules/_remote_debugging/code_objects.c +++ b/Modules/_remote_debugging/code_objects.c @@ -405,6 +405,8 @@ parse_code_object(RemoteUnwinderObject *unwinder, meta->func_name = func; meta->file_name = file; meta->linetable = linetable; + meta->last_frame_info = NULL; + meta->last_addrq = -1; meta->first_lineno = GET_MEMBER(int, code_object, unwinder->debug_offsets.code_object.firstlineno); meta->addr_code_adaptive = real_address + (uintptr_t)unwinder->debug_offsets.code_object.co_code_adaptive; @@ -482,6 +484,12 @@ parse_code_object(RemoteUnwinderObject *unwinder, addrq = (uint16_t *)ip - (uint16_t *)meta->addr_code_adaptive; #endif ; // Empty statement to avoid C23 extension warning + + if (!unwinder->opcodes && meta->last_frame_info != NULL && meta->last_addrq == addrq) { + *result = Py_NewRef(meta->last_frame_info); + return 0; + } + LocationInfo info = {0}; bool ok = parse_linetable(addrq, PyBytes_AS_STRING(meta->linetable), PyBytes_GET_SIZE(meta->linetable), @@ -529,6 +537,11 @@ parse_code_object(RemoteUnwinderObject *unwinder, goto error; } + if (!unwinder->opcodes) { + Py_XSETREF(meta->last_frame_info, Py_NewRef(tuple)); + meta->last_addrq = addrq; + } + *result = tuple; return 0; diff --git a/Modules/_remote_debugging/frame_cache.c b/Modules/_remote_debugging/frame_cache.c index b6566d7cff7b54..19fc406bca9ac9 100644 --- a/Modules/_remote_debugging/frame_cache.c +++ b/Modules/_remote_debugging/frame_cache.c @@ -30,6 +30,7 @@ frame_cache_cleanup(RemoteUnwinderObject *unwinder) return; } for (int i = 0; i < FRAME_CACHE_MAX_THREADS; i++) { + Py_CLEAR(unwinder->frame_cache[i].thread_id_obj); Py_CLEAR(unwinder->frame_cache[i].frame_list); } PyMem_Free(unwinder->frame_cache); @@ -53,6 +54,21 @@ frame_cache_find(RemoteUnwinderObject *unwinder, uint64_t thread_id) return NULL; } +FrameCacheEntry * +frame_cache_find_by_tstate(RemoteUnwinderObject *unwinder, uintptr_t tstate_addr) +{ + if (!unwinder->frame_cache || tstate_addr == 0) { + return NULL; + } + for (int i = 0; i < FRAME_CACHE_MAX_THREADS; i++) { + if (unwinder->frame_cache[i].thread_state_addr == tstate_addr) { + assert(unwinder->frame_cache[i].num_addrs <= FRAME_CACHE_MAX_FRAMES); + return &unwinder->frame_cache[i]; + } + } + return NULL; +} + // Allocate a cache slot for a thread // Returns NULL if cache is full (graceful degradation) static FrameCacheEntry * @@ -127,8 +143,10 @@ frame_cache_invalidate_stale(RemoteUnwinderObject *unwinder, PyObject *result) } if (!found) { // Clear this entry + Py_CLEAR(unwinder->frame_cache[i].thread_id_obj); Py_CLEAR(unwinder->frame_cache[i].frame_list); unwinder->frame_cache[i].thread_id = 0; + unwinder->frame_cache[i].thread_state_addr = 0; unwinder->frame_cache[i].num_addrs = 0; STATS_INC(unwinder, stale_cache_invalidations); } @@ -216,6 +234,7 @@ frame_cache_store( PyObject *frame_list, const uintptr_t *addrs, Py_ssize_t num_addrs, + uintptr_t thread_state_addr, uintptr_t base_frame_addr, uintptr_t last_frame_visited) { @@ -257,6 +276,13 @@ frame_cache_store( return -1; } entry->thread_id = thread_id; + entry->thread_state_addr = thread_state_addr; + if (entry->thread_id_obj == NULL) { + entry->thread_id_obj = PyLong_FromUnsignedLongLong(thread_id); + if (entry->thread_id_obj == NULL) { + return -1; + } + } memcpy(entry->addrs, addrs, num_addrs * sizeof(uintptr_t)); entry->num_addrs = num_addrs; assert(entry->num_addrs == num_addrs); diff --git a/Modules/_remote_debugging/frames.c b/Modules/_remote_debugging/frames.c index bbdfce3f7201d9..8d8019396b3e31 100644 --- a/Modules/_remote_debugging/frames.c +++ b/Modules/_remote_debugging/frames.c @@ -186,30 +186,16 @@ is_frame_valid( return 1; } -int -parse_frame_object( +static int +parse_frame_buffer( RemoteUnwinderObject *unwinder, PyObject** result, - uintptr_t address, + const char *frame, uintptr_t* address_of_code_object, uintptr_t* previous_frame ) { - char frame[SIZEOF_INTERP_FRAME]; *address_of_code_object = 0; - Py_ssize_t bytes_read = _Py_RemoteDebug_PagedReadRemoteMemory( - &unwinder->handle, - address, - SIZEOF_INTERP_FRAME, - frame - ); - if (bytes_read < 0) { - set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read interpreter frame"); - return -1; - } - STATS_INC(unwinder, memory_reads); - STATS_ADD(unwinder, memory_bytes_read, SIZEOF_INTERP_FRAME); - *previous_frame = GET_MEMBER(uintptr_t, frame, unwinder->debug_offsets.interpreter_frame.previous); uintptr_t code_object = GET_MEMBER_NO_TAG(uintptr_t, frame, unwinder->debug_offsets.interpreter_frame.executable); int frame_valid = is_frame_valid(unwinder, (uintptr_t)frame, code_object); @@ -237,6 +223,31 @@ parse_frame_object( return parse_code_object(unwinder, result, &code_ctx); } +int +parse_frame_object( + RemoteUnwinderObject *unwinder, + PyObject** result, + uintptr_t address, + uintptr_t* address_of_code_object, + uintptr_t* previous_frame +) { + char frame[SIZEOF_INTERP_FRAME]; + Py_ssize_t bytes_read = _Py_RemoteDebug_ReadRemoteMemory( + &unwinder->handle, + address, + SIZEOF_INTERP_FRAME, + frame + ); + if (bytes_read < 0) { + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read interpreter frame"); + return -1; + } + STATS_INC(unwinder, memory_reads); + STATS_ADD(unwinder, memory_bytes_read, SIZEOF_INTERP_FRAME); + + return parse_frame_buffer(unwinder, result, frame, address_of_code_object, previous_frame); +} + int parse_frame_from_chunks( RemoteUnwinderObject *unwinder, @@ -312,15 +323,32 @@ process_frame_chain( } assert(frame_count <= MAX_FRAMES); - if (parse_frame_from_chunks(unwinder, &frame, frame_addr, &next_frame_addr, &stackpointer, ctx->chunks) < 0) { + if (ctx->chunks && ctx->chunks->count > 0) { + if (parse_frame_from_chunks(unwinder, &frame, frame_addr, &next_frame_addr, &stackpointer, ctx->chunks) == 0) { + goto parsed_frame; + } PyErr_Clear(); + } + { uintptr_t address_of_code_object = 0; - if (parse_frame_object(unwinder, &frame, frame_addr, &address_of_code_object, &next_frame_addr) < 0) { + int parse_result; + if (ctx->prefetch.frame && ctx->prefetch.frame_addr == frame_addr) { + parse_result = parse_frame_buffer( + unwinder, &frame, ctx->prefetch.frame, + &address_of_code_object, &next_frame_addr); + } + else { + parse_result = parse_frame_object( + unwinder, &frame, frame_addr, + &address_of_code_object, &next_frame_addr); + } + if (parse_result < 0) { set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to parse frame object in chain"); return -1; } } +parsed_frame: // Skip first frame if requested (used for cache miss continuation) if (ctx->skip_first_frame && frame_count == 1) { Py_XDECREF(frame); @@ -501,41 +529,37 @@ try_full_cache_hit( PyObject *current_frame = NULL; uintptr_t code_object_addr = 0; uintptr_t previous_frame = 0; - int parse_result = parse_frame_object(unwinder, ¤t_frame, ctx->frame_addr, + int parse_result; + if (ctx->prefetch.frame && ctx->prefetch.frame_addr == ctx->frame_addr) { + parse_result = parse_frame_buffer(unwinder, ¤t_frame, + ctx->prefetch.frame, &code_object_addr, &previous_frame); + } + else { + parse_result = parse_frame_object(unwinder, ¤t_frame, ctx->frame_addr, + &code_object_addr, &previous_frame); + } if (parse_result < 0) { return -1; } - Py_ssize_t cached_size = PyList_GET_SIZE(entry->frame_list); - PyObject *parent_slice = NULL; - if (cached_size > 1) { - parent_slice = PyList_GetSlice(entry->frame_list, 1, cached_size); - if (!parent_slice) { - Py_XDECREF(current_frame); - return -1; - } - } - if (current_frame != NULL) { if (PyList_Append(ctx->frame_info, current_frame) < 0) { Py_DECREF(current_frame); - Py_XDECREF(parent_slice); return -1; } Py_DECREF(current_frame); STATS_ADD(unwinder, frames_read_from_memory, 1); } - if (parent_slice) { - Py_ssize_t cur_size = PyList_GET_SIZE(ctx->frame_info); - int result = PyList_SetSlice(ctx->frame_info, cur_size, cur_size, parent_slice); - Py_DECREF(parent_slice); - if (result < 0) { + Py_ssize_t cached_size = PyList_GET_SIZE(entry->frame_list); + for (Py_ssize_t i = 1; i < cached_size; i++) { + PyObject *cached_frame = PyList_GET_ITEM(entry->frame_list, i); + if (PyList_Append(ctx->frame_info, cached_frame) < 0) { return -1; } - STATS_ADD(unwinder, frames_read_from_cache, cached_size - 1); } + STATS_ADD(unwinder, frames_read_from_cache, cached_size > 1 ? cached_size - 1 : 0); STATS_INC(unwinder, frame_cache_hits); return 1; @@ -606,7 +630,8 @@ collect_frames_with_cache( } if (frame_cache_store(unwinder, thread_id, ctx->frame_info, ctx->frame_addrs, ctx->num_addrs, - ctx->base_frame_addr, ctx->last_frame_visited) < 0) { + ctx->thread_state_addr, ctx->base_frame_addr, + ctx->last_frame_visited) < 0) { return -1; } diff --git a/Modules/_remote_debugging/module.c b/Modules/_remote_debugging/module.c index efdd2e1a2d7b7a..ae2f7e7f31ba77 100644 --- a/Modules/_remote_debugging/module.c +++ b/Modules/_remote_debugging/module.c @@ -166,6 +166,7 @@ cached_code_metadata_destroy(void *ptr) Py_DECREF(meta->func_name); Py_DECREF(meta->file_name); Py_DECREF(meta->linetable); + Py_XDECREF(meta->last_frame_info); PyMem_RawFree(meta); } @@ -360,6 +361,10 @@ _remote_debugging_RemoteUnwinder___init___impl(RemoteUnwinderObject *self, self->cache_frames = cache_frames; self->collect_stats = stats; self->stale_invalidation_counter = 0; + self->cached_tstate_interpreter_addr = 0; + self->cached_tstate_addr = 0; + memset(self->cached_tstates, 0, sizeof(self->cached_tstates)); + memset(self->cached_generations, 0, sizeof(self->cached_generations)); self->debug = debug; self->only_active_thread = only_active_thread; self->mode = mode; @@ -473,6 +478,172 @@ _remote_debugging_RemoteUnwinder___init___impl(RemoteUnwinderObject *self, return 0; } +static inline size_t +interpreter_thread_cache_index(uintptr_t interpreter_addr) +{ + // Direct-mapped table indexed by the remote interpreter address. Each entry + // stores the full address and verifies it on lookup, so hash collisions + // degrade to misses and cannot return a value from the wrong interpreter. + return (size_t)_Py_HashPointerRaw((const void *)interpreter_addr) + & (INTERPRETER_THREAD_CACHE_SIZE - 1); +} + +static inline uintptr_t +get_cached_tstate_for_interpreter( + RemoteUnwinderObject *self, + uintptr_t interpreter_addr) +{ + if (interpreter_addr == 0) { + return 0; + } + + if (self->cached_tstate_interpreter_addr == interpreter_addr) { + return self->cached_tstate_addr; + } + + InterpreterTstateCacheEntry *entry = + &self->cached_tstates[interpreter_thread_cache_index(interpreter_addr)]; + if (entry->interpreter_addr == interpreter_addr) { + self->cached_tstate_interpreter_addr = interpreter_addr; + self->cached_tstate_addr = entry->thread_state_addr; + return entry->thread_state_addr; + } + return 0; +} + +static inline void +set_cached_tstate_for_interpreter( + RemoteUnwinderObject *self, + uintptr_t interpreter_addr, + uintptr_t thread_state_addr) +{ + if (interpreter_addr == 0 || thread_state_addr == 0) { + return; + } + + self->cached_tstate_interpreter_addr = interpreter_addr; + self->cached_tstate_addr = thread_state_addr; + + InterpreterTstateCacheEntry *entry = + &self->cached_tstates[interpreter_thread_cache_index(interpreter_addr)]; + entry->interpreter_addr = interpreter_addr; + entry->thread_state_addr = thread_state_addr; +} + +static void +refresh_generation_caches_from_interp_state( + RemoteUnwinderObject *self, + uintptr_t interpreter_addr, + const char *interp_state_buffer) +{ + uint64_t code_object_generation = GET_MEMBER(uint64_t, interp_state_buffer, + self->debug_offsets.interpreter_state.code_object_generation); + + if (self->cached_generation_interpreter_addr == interpreter_addr) { + if (code_object_generation != self->cached_code_object_generation) { + self->cached_code_object_generation = code_object_generation; + _Py_hashtable_clear(self->code_object_cache); + } + } + else { + InterpreterGenerationCacheEntry *entry = + &self->cached_generations[interpreter_thread_cache_index(interpreter_addr)]; + // A slot rebound from another interpreter must be treated as changed: + // the code_object_cache is global, so even if the new generation + // numerically matches what the previous occupant had, stale entries + // from that occupant could still be served. + int changed = entry->interpreter_addr != interpreter_addr + || entry->code_object_generation != code_object_generation; + entry->interpreter_addr = interpreter_addr; + entry->code_object_generation = code_object_generation; + if (changed) { + _Py_hashtable_clear(self->code_object_cache); + } + self->cached_generation_interpreter_addr = interpreter_addr; + self->cached_code_object_generation = code_object_generation; + } + +#ifdef Py_GIL_DISABLED + uint32_t current_tlbc_generation = GET_MEMBER(uint32_t, interp_state_buffer, + self->debug_offsets.interpreter_state.tlbc_generation); + if (current_tlbc_generation != self->tlbc_generation) { + self->tlbc_generation = current_tlbc_generation; + _Py_hashtable_clear(self->tlbc_cache); + } +#endif +} + +static int +refresh_generation_caches_for_interpreter( + RemoteUnwinderObject *self, + uintptr_t interpreter_addr) +{ + char interp_state_buffer[INTERP_STATE_BUFFER_SIZE]; + if (_Py_RemoteDebug_ReadRemoteMemory( + &self->handle, + interpreter_addr, + INTERP_STATE_BUFFER_SIZE, + interp_state_buffer) < 0) { + set_exception_cause(self, PyExc_RuntimeError, + "Failed to read interpreter state buffer"); + return -1; + } + refresh_generation_caches_from_interp_state(self, interpreter_addr, interp_state_buffer); + return 0; +} + +static int +read_interp_state_and_maybe_thread_frame( + RemoteUnwinderObject *unwinder, + uintptr_t interpreter_addr, + char *interp_state_buffer, + char *tstate_buffer, + char *frame_buffer, + RemoteReadPrefetch *prefetch) +{ + prefetch->tstate = NULL; + prefetch->frame = NULL; + if (prefetch->tstate_addr != 0) { + size_t tstate_size = (size_t)unwinder->debug_offsets.thread_state.size; + _Py_RemoteReadSegment segments[3] = { + {interpreter_addr, interp_state_buffer, INTERP_STATE_BUFFER_SIZE}, + {prefetch->tstate_addr, tstate_buffer, tstate_size}, + {prefetch->frame_addr, frame_buffer, SIZEOF_INTERP_FRAME}, + }; + int nsegs = prefetch->frame_addr != 0 ? 3 : 2; + Py_ssize_t nread = _Py_RemoteDebug_BatchedReadRemoteMemory( + &unwinder->handle, segments, nsegs); + int completed = 0; + if (nread >= (Py_ssize_t)INTERP_STATE_BUFFER_SIZE) { + completed = 1; + Py_ssize_t with_tstate = (Py_ssize_t)INTERP_STATE_BUFFER_SIZE + + (Py_ssize_t)tstate_size; + if (nread >= with_tstate) { + completed = 2; + } + if (nsegs == 3 + && nread == with_tstate + (Py_ssize_t)SIZEOF_INTERP_FRAME) { + completed = 3; + } + } + STATS_BATCHED_READ(unwinder, nsegs, completed); + if (completed >= 1) { + if (completed >= 2) { + prefetch->tstate = tstate_buffer; + } + if (completed >= 3) { + prefetch->frame = frame_buffer; + } + return 0; + } + } + return _Py_RemoteDebug_ReadRemoteMemory( + &unwinder->handle, + interpreter_addr, + INTERP_STATE_BUFFER_SIZE, + interp_state_buffer); +} + /*[clinic input] @permit_long_docstring_body @critical_section @@ -537,15 +708,32 @@ _remote_debugging_RemoteUnwinder_get_stack_trace_impl(RemoteUnwinderObject *self while (current_interpreter != 0) { // Read interpreter state to get the interpreter ID char interp_state_buffer[INTERP_STATE_BUFFER_SIZE]; - if (_Py_RemoteDebug_PagedReadRemoteMemory( - &self->handle, + char prefetched_tstate[SIZEOF_THREAD_STATE]; + char prefetched_frame[SIZEOF_INTERP_FRAME]; + RemoteReadPrefetch prefetch = {0}; + if (self->cache_frames) { + prefetch.tstate_addr = get_cached_tstate_for_interpreter( + self, current_interpreter); + } + if (prefetch.tstate_addr != 0) { + FrameCacheEntry *entry = frame_cache_find_by_tstate(self, prefetch.tstate_addr); + if (entry && entry->num_addrs > 0) { + prefetch.frame_addr = entry->addrs[0]; + } + } + + if (read_interp_state_and_maybe_thread_frame( + self, current_interpreter, - INTERP_STATE_BUFFER_SIZE, - interp_state_buffer) < 0) { + interp_state_buffer, + prefetched_tstate, + prefetched_frame, + &prefetch) < 0) { set_exception_cause(self, PyExc_RuntimeError, "Failed to read interpreter state buffer"); Py_CLEAR(result); goto exit; } + refresh_generation_caches_from_interp_state(self, current_interpreter, interp_state_buffer); uintptr_t gc_frame = 0; if (self->gc) { @@ -557,25 +745,6 @@ _remote_debugging_RemoteUnwinder_get_stack_trace_impl(RemoteUnwinderObject *self int64_t interpreter_id = GET_MEMBER(int64_t, interp_state_buffer, self->debug_offsets.interpreter_state.id); - // Get code object generation from buffer - uint64_t code_object_generation = GET_MEMBER(uint64_t, interp_state_buffer, - self->debug_offsets.interpreter_state.code_object_generation); - - if (code_object_generation != self->code_object_generation) { - self->code_object_generation = code_object_generation; - _Py_hashtable_clear(self->code_object_cache); - } - -#ifdef Py_GIL_DISABLED - // Check TLBC generation and invalidate cache if needed - uint32_t current_tlbc_generation = GET_MEMBER(uint32_t, interp_state_buffer, - self->debug_offsets.interpreter_state.tlbc_generation); - if (current_tlbc_generation != self->tlbc_generation) { - self->tlbc_generation = current_tlbc_generation; - _Py_hashtable_clear(self->tlbc_cache); - } -#endif - // Create a list to hold threads for this interpreter PyObject *interpreter_threads = PyList_New(0); if (!interpreter_threads) { @@ -611,6 +780,9 @@ _remote_debugging_RemoteUnwinder_get_stack_trace_impl(RemoteUnwinderObject *self // Target specific thread (only process first interpreter) current_tstate = self->tstate_addr; } + if (current_tstate != 0 && self->cache_frames) { + set_cached_tstate_for_interpreter(self, current_interpreter, current_tstate); + } // Acquire main thread state information uintptr_t main_thread_tstate = GET_MEMBER(uintptr_t, interp_state_buffer, @@ -621,7 +793,8 @@ _remote_debugging_RemoteUnwinder_get_stack_trace_impl(RemoteUnwinderObject *self PyObject* frame_info = unwind_stack_for_thread(self, ¤t_tstate, gil_holder_tstate, gc_frame, - main_thread_tstate); + main_thread_tstate, + &prefetch); if (!frame_info) { // Check if this was an intentional skip due to mode-based filtering if ((self->mode == PROFILING_MODE_CPU || self->mode == PROFILING_MODE_GIL || @@ -771,6 +944,9 @@ _remote_debugging_RemoteUnwinder_get_all_awaited_by_impl(RemoteUnwinderObject *s if (ensure_async_debug_offsets(self) < 0) { return NULL; } + if (refresh_generation_caches_for_interpreter(self, self->interpreter_addr) < 0) { + return NULL; + } PyObject *result = PyList_New(0); if (result == NULL) { @@ -860,6 +1036,9 @@ _remote_debugging_RemoteUnwinder_get_async_stack_trace_impl(RemoteUnwinderObject if (ensure_async_debug_offsets(self) < 0) { return NULL; } + if (refresh_generation_caches_for_interpreter(self, self->interpreter_addr) < 0) { + return NULL; + } PyObject *result = PyList_New(0); if (result == NULL) { @@ -904,8 +1083,15 @@ RemoteUnwinder was created with stats=True. - code_object_cache_hits: Code object cache hits - code_object_cache_misses: Code object cache misses - stale_cache_invalidations: Times stale cache entries were cleared + - batched_read_attempts: Batched remote-read attempts + - batched_read_successes: Attempts that read all requested segments + - batched_read_misses: Attempts that fell back or partially read + - batched_read_segments_requested: Segments requested by batched reads + - batched_read_segments_completed: Segments completed by batched reads - frame_cache_hit_rate: Percentage of samples that hit the cache - code_object_cache_hit_rate: Percentage of code object lookups that hit cache + - batched_read_success_rate: Percentage of batched reads that completed all segments + - batched_read_segment_completion_rate: Percentage of requested segments read by batched reads Raises: RuntimeError: If stats collection was not enabled (stats=False) @@ -913,7 +1099,7 @@ RemoteUnwinder was created with stats=True. static PyObject * _remote_debugging_RemoteUnwinder_get_stats_impl(RemoteUnwinderObject *self) -/*[clinic end generated code: output=21e36477122be2a0 input=75fef4134c12a8c9]*/ +/*[clinic end generated code: output=21e36477122be2a0 input=0392d62b278e9c35]*/ { if (!self->collect_stats) { PyErr_SetString(PyExc_RuntimeError, @@ -948,9 +1134,24 @@ _remote_debugging_RemoteUnwinder_get_stats_impl(RemoteUnwinderObject *self) ADD_STAT(code_object_cache_hits); ADD_STAT(code_object_cache_misses); ADD_STAT(stale_cache_invalidations); + ADD_STAT(batched_read_attempts); + ADD_STAT(batched_read_successes); + ADD_STAT(batched_read_misses); + ADD_STAT(batched_read_segments_requested); + ADD_STAT(batched_read_segments_completed); #undef ADD_STAT +#define ADD_DERIVED_STAT(name, value) do { \ + PyObject *val = PyFloat_FromDouble(value); \ + if (!val || PyDict_SetItemString(result, name, val) < 0) { \ + Py_XDECREF(val); \ + Py_DECREF(result); \ + return NULL; \ + } \ + Py_DECREF(val); \ +} while(0) + // Calculate and add derived statistics // Hit rate is calculated as (hits + partial_hits) / total_cache_lookups double frame_cache_hit_rate = 0.0; @@ -959,26 +1160,33 @@ _remote_debugging_RemoteUnwinder_get_stats_impl(RemoteUnwinderObject *self) frame_cache_hit_rate = 100.0 * (double)(self->stats.frame_cache_hits + self->stats.frame_cache_partial_hits) / (double)total_cache_lookups; } - PyObject *hit_rate = PyFloat_FromDouble(frame_cache_hit_rate); - if (!hit_rate || PyDict_SetItemString(result, "frame_cache_hit_rate", hit_rate) < 0) { - Py_XDECREF(hit_rate); - Py_DECREF(result); - return NULL; - } - Py_DECREF(hit_rate); + ADD_DERIVED_STAT("frame_cache_hit_rate", frame_cache_hit_rate); double code_object_hit_rate = 0.0; uint64_t total_code_lookups = self->stats.code_object_cache_hits + self->stats.code_object_cache_misses; if (total_code_lookups > 0) { code_object_hit_rate = 100.0 * (double)self->stats.code_object_cache_hits / (double)total_code_lookups; } - PyObject *code_hit_rate = PyFloat_FromDouble(code_object_hit_rate); - if (!code_hit_rate || PyDict_SetItemString(result, "code_object_cache_hit_rate", code_hit_rate) < 0) { - Py_XDECREF(code_hit_rate); - Py_DECREF(result); - return NULL; + ADD_DERIVED_STAT("code_object_cache_hit_rate", code_object_hit_rate); + + double batched_read_success_rate = 0.0; + if (self->stats.batched_read_attempts > 0) { + batched_read_success_rate = + 100.0 * (double)self->stats.batched_read_successes + / (double)self->stats.batched_read_attempts; } - Py_DECREF(code_hit_rate); + ADD_DERIVED_STAT("batched_read_success_rate", batched_read_success_rate); + + double batched_read_segment_completion_rate = 0.0; + if (self->stats.batched_read_segments_requested > 0) { + batched_read_segment_completion_rate = + 100.0 * (double)self->stats.batched_read_segments_completed + / (double)self->stats.batched_read_segments_requested; + } + ADD_DERIVED_STAT("batched_read_segment_completion_rate", + batched_read_segment_completion_rate); + +#undef ADD_DERIVED_STAT return result; } diff --git a/Modules/_remote_debugging/threads.c b/Modules/_remote_debugging/threads.c index d775234b8d78d7..ae120a26d5f4ec 100644 --- a/Modules/_remote_debugging/threads.c +++ b/Modules/_remote_debugging/threads.c @@ -289,28 +289,110 @@ typedef struct { unsigned int :24; } _thread_status; +static int +read_thread_state_and_maybe_frame( + RemoteUnwinderObject *unwinder, + uintptr_t tstate_addr, + size_t tstate_size, + char *tstate_buffer, + uintptr_t predicted_frame_addr, + char *frame_buffer, + int *frame_read) +{ + *frame_read = 0; + if (predicted_frame_addr != 0) { + _Py_RemoteReadSegment segments[2] = { + {tstate_addr, tstate_buffer, tstate_size}, + {predicted_frame_addr, frame_buffer, SIZEOF_INTERP_FRAME}, + }; + Py_ssize_t nread = _Py_RemoteDebug_BatchedReadRemoteMemory( + &unwinder->handle, segments, 2); + int completed = 0; + if (nread >= (Py_ssize_t)tstate_size) { + completed = 1; + if (nread == (Py_ssize_t)(tstate_size + SIZEOF_INTERP_FRAME)) { + completed = 2; + } + } + STATS_BATCHED_READ(unwinder, 2, completed); + if (completed >= 1) { + *frame_read = completed == 2; + return 0; + } + } + return _Py_RemoteDebug_ReadRemoteMemory( + &unwinder->handle, tstate_addr, tstate_size, tstate_buffer); +} + PyObject* unwind_stack_for_thread( RemoteUnwinderObject *unwinder, uintptr_t *current_tstate, uintptr_t gil_holder_tstate, uintptr_t gc_frame, - uintptr_t main_thread_tstate + uintptr_t main_thread_tstate, + const RemoteReadPrefetch *prefetch ) { PyObject *frame_info = NULL; PyObject *thread_id = NULL; PyObject *result = NULL; StackChunkList chunks = {0}; - char ts[SIZEOF_THREAD_STATE]; - int bytes_read = _Py_RemoteDebug_PagedReadRemoteMemory( - &unwinder->handle, *current_tstate, (size_t)unwinder->debug_offsets.thread_state.size, ts); - if (bytes_read < 0) { - set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read thread state"); - goto error; + char local_ts[SIZEOF_THREAD_STATE]; + char local_prefetched_frame[SIZEOF_INTERP_FRAME]; + const char *ts; + RemoteReadPrefetch ctx_prefetch = {0}; + if (prefetch->tstate && prefetch->tstate_addr == *current_tstate) { + ts = prefetch->tstate; + if (prefetch->frame) { + ctx_prefetch.frame = prefetch->frame; + ctx_prefetch.frame_addr = prefetch->frame_addr; + } + } + else if (unwinder->cache_frames) { + uintptr_t predicted_frame_addr = 0; + int have_prefetched_frame = 0; + FrameCacheEntry *entry = frame_cache_find_by_tstate(unwinder, *current_tstate); + if (entry && entry->num_addrs > 0) { + predicted_frame_addr = entry->addrs[0]; + } + + int rc = read_thread_state_and_maybe_frame( + unwinder, + *current_tstate, + (size_t)unwinder->debug_offsets.thread_state.size, + local_ts, + predicted_frame_addr, + local_prefetched_frame, + &have_prefetched_frame); + if (rc < 0) { + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read thread state"); + goto error; + } + ts = local_ts; + if (have_prefetched_frame) { + ctx_prefetch.frame = local_prefetched_frame; + ctx_prefetch.frame_addr = predicted_frame_addr; + } + } + else { + int rc = _Py_RemoteDebug_ReadRemoteMemory( + &unwinder->handle, + *current_tstate, + (size_t)unwinder->debug_offsets.thread_state.size, + local_ts); + if (rc < 0) { + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read thread state"); + goto error; + } + ts = local_ts; } STATS_INC(unwinder, memory_reads); STATS_ADD(unwinder, memory_bytes_read, unwinder->debug_offsets.thread_state.size); + if (ctx_prefetch.frame) { + STATS_INC(unwinder, memory_reads); + STATS_ADD(unwinder, memory_bytes_read, SIZEOF_INTERP_FRAME); + } long tid = GET_MEMBER(long, ts, unwinder->debug_offsets.thread_state.native_thread_id); @@ -432,9 +514,11 @@ unwind_stack_for_thread( uintptr_t addrs[FRAME_CACHE_MAX_FRAMES]; FrameWalkContext ctx = { .frame_addr = frame_addr, + .thread_state_addr = *current_tstate, .base_frame_addr = base_frame_addr, .gc_frame = gc_frame, .chunks = &chunks, + .prefetch = ctx_prefetch, .frame_info = frame_info, .frame_addrs = addrs, .num_addrs = 0, @@ -467,10 +551,18 @@ unwind_stack_for_thread( *current_tstate = GET_MEMBER(uintptr_t, ts, unwinder->debug_offsets.thread_state.next); - thread_id = PyLong_FromLongLong(tid); + if (unwinder->cache_frames) { + FrameCacheEntry *entry = frame_cache_find(unwinder, (uint64_t)tid); + if (entry && entry->thread_id_obj) { + thread_id = Py_NewRef(entry->thread_id_obj); + } + } if (thread_id == NULL) { - set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to create thread ID"); - goto error; + thread_id = PyLong_FromLongLong(tid); + if (thread_id == NULL) { + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to create thread ID"); + goto error; + } } RemoteDebuggingState *state = RemoteDebugging_GetStateFromObject((PyObject*)unwinder); diff --git a/Python/remote_debug.h b/Python/remote_debug.h index 6c089a834dcd40..7b2c4f3bcb8077 100644 --- a/Python/remote_debug.h +++ b/Python/remote_debug.h @@ -147,6 +147,7 @@ typedef struct { int memfd; #endif page_cache_entry_t pages[MAX_PAGES]; + int page_cache_count; Py_ssize_t page_size; } proc_handle_t; @@ -185,14 +186,16 @@ _Py_RemoteDebug_FreePageCache(proc_handle_t *handle) handle->pages[i].data = NULL; handle->pages[i].valid = 0; } + handle->page_cache_count = 0; } UNUSED static void _Py_RemoteDebug_ClearCache(proc_handle_t *handle) { - for (int i = 0; i < MAX_PAGES; i++) { + for (int i = 0; i < handle->page_cache_count; i++) { handle->pages[i].valid = 0; } + handle->page_cache_count = 0; } #if defined(__APPLE__) && defined(TARGET_OS_OSX) && TARGET_OS_OSX @@ -222,6 +225,7 @@ _Py_RemoteDebug_InitProcHandle(proc_handle_t *handle, pid_t pid) { handle->memfd = -1; #endif handle->page_size = get_page_size(); + handle->page_cache_count = 0; for (int i = 0; i < MAX_PAGES; i++) { handle->pages[i].data = NULL; handle->pages[i].valid = 0; @@ -1287,8 +1291,9 @@ _Py_RemoteDebug_PagedReadRemoteMemory(proc_handle_t *handle, return _Py_RemoteDebug_ReadRemoteMemory(handle, addr, size, out); } - // Search for valid cached page - for (int i = 0; i < MAX_PAGES; i++) { + // Search only the pages used since the last clear. The cache is cleared + // between profiler samples, so entries are packed at the front. + for (int i = 0; i < handle->page_cache_count; i++) { page_cache_entry_t *entry = &handle->pages[i]; if (entry->valid && entry->page_addr == page_base) { memcpy(out, entry->data + offset_in_page, size); @@ -1296,33 +1301,31 @@ _Py_RemoteDebug_PagedReadRemoteMemory(proc_handle_t *handle, } } - // Find reusable slot - for (int i = 0; i < MAX_PAGES; i++) { - page_cache_entry_t *entry = &handle->pages[i]; - if (!entry->valid) { + if (handle->page_cache_count < MAX_PAGES) { + page_cache_entry_t *entry = &handle->pages[handle->page_cache_count]; + if (entry->data == NULL) { + entry->data = PyMem_RawMalloc(page_size); if (entry->data == NULL) { - entry->data = PyMem_RawMalloc(page_size); - if (entry->data == NULL) { - PyErr_NoMemory(); - _set_debug_exception_cause(PyExc_MemoryError, - "Cannot allocate %zu bytes for page cache entry " - "during read from PID %d at address 0x%lx", - page_size, handle->pid, addr); - return -1; - } - } - - if (_Py_RemoteDebug_ReadRemoteMemory(handle, page_base, page_size, entry->data) < 0) { - // Try to just copy the exact amount as a fallback - PyErr_Clear(); - goto fallback; + PyErr_NoMemory(); + _set_debug_exception_cause(PyExc_MemoryError, + "Cannot allocate %zu bytes for page cache entry " + "during read from PID %d at address 0x%lx", + page_size, handle->pid, addr); + return -1; } + } - entry->page_addr = page_base; - entry->valid = 1; - memcpy(out, entry->data + offset_in_page, size); - return 0; + if (_Py_RemoteDebug_ReadRemoteMemory(handle, page_base, page_size, entry->data) < 0) { + // Try to just copy the exact amount as a fallback + PyErr_Clear(); + goto fallback; } + + entry->page_addr = page_base; + entry->valid = 1; + handle->page_cache_count++; + memcpy(out, entry->data + offset_in_page, size); + return 0; } fallback: @@ -1330,6 +1333,49 @@ _Py_RemoteDebug_PagedReadRemoteMemory(proc_handle_t *handle, return _Py_RemoteDebug_ReadRemoteMemory(handle, addr, size, out); } +typedef struct { + uintptr_t remote_addr; + void *local_buf; + size_t size; +} _Py_RemoteReadSegment; + +#define _PY_REMOTE_DEBUG_MAX_BATCHED_SEGMENTS 4 + +// Batched read of multiple remote regions in a single syscall when supported. +// Returns total bytes read (>= 0) on success, -1 if batched reads are +// unavailable or the syscall failed. Callers compare the return value against +// cumulative segment sizes to determine which segments were fully populated. +UNUSED static Py_ssize_t +_Py_RemoteDebug_BatchedReadRemoteMemory( + proc_handle_t *handle, + const _Py_RemoteReadSegment *segments, + int nsegs) +{ +#if defined(__linux__) && HAVE_PROCESS_VM_READV + if (handle->memfd == -1 + && nsegs > 0 + && nsegs <= _PY_REMOTE_DEBUG_MAX_BATCHED_SEGMENTS) { + struct iovec local[_PY_REMOTE_DEBUG_MAX_BATCHED_SEGMENTS]; + struct iovec remote[_PY_REMOTE_DEBUG_MAX_BATCHED_SEGMENTS]; + for (int i = 0; i < nsegs; i++) { + local[i].iov_base = segments[i].local_buf; + local[i].iov_len = segments[i].size; + remote[i].iov_base = (void *)segments[i].remote_addr; + remote[i].iov_len = segments[i].size; + } + ssize_t nread = process_vm_readv(handle->pid, local, nsegs, remote, nsegs, 0); + if (nread >= 0) { + return (Py_ssize_t)nread; + } + } +#else + (void)handle; + (void)segments; + (void)nsegs; +#endif + return -1; +} + UNUSED static int _Py_RemoteDebug_ReadDebugOffsets( proc_handle_t *handle, diff --git a/Tools/inspection/benchmark_external_inspection.py b/Tools/inspection/benchmark_external_inspection.py index fee3435496da0b..8e367422a961da 100644 --- a/Tools/inspection/benchmark_external_inspection.py +++ b/Tools/inspection/benchmark_external_inspection.py @@ -151,6 +151,45 @@ def create_threads(n): time.sleep(0.05) ''' +ASYNC_CODE = '''\ +import asyncio +import contextlib +import math + +def compute_slice(seed): + result = 0.0 + for i in range(2000): + result += math.sin(seed + i) * math.sqrt(i + 1) + return result + +async def leaf_task(seed): + total = 0.0 + while True: + total += compute_slice(seed) + await asyncio.sleep(0) + +async def parent_task(seed): + child = asyncio.create_task(leaf_task(seed + 1000), name=f"leaf-{seed}") + try: + while True: + compute_slice(seed) + await asyncio.sleep(0.001) + finally: + child.cancel() + with contextlib.suppress(asyncio.CancelledError): + await child + +async def main(): + tasks = [ + asyncio.create_task(parent_task(i), name=f"parent-{i}") + for i in range(8) + ] + await asyncio.gather(*tasks) + +if __name__ == "__main__": + asyncio.run(main()) +''' + CODE_EXAMPLES = { "basic": { "code": CODE, @@ -164,10 +203,29 @@ def create_threads(n): "code": CODE_WITH_TONS_OF_THREADS, "description": "Tons of threads doing mixed CPU/IO work", }, + "asyncio": { + "code": ASYNC_CODE, + "description": "Asyncio tasks with active and awaited coroutine chains", + }, +} + +OPERATIONS = { + "stack_trace": { + "method": "get_stack_trace", + "label": "get_stack_trace()", + }, + "async_stack_trace": { + "method": "get_async_stack_trace", + "label": "get_async_stack_trace()", + }, + "all_awaited_by": { + "method": "get_all_awaited_by", + "label": "get_all_awaited_by()", + }, } -def benchmark(unwinder, duration_seconds=10, blocking=False): +def benchmark(unwinder, duration_seconds=10, blocking=False, operation="stack_trace"): """Benchmark mode - measure raw sampling speed for specified duration""" sample_count = 0 fail_count = 0 @@ -175,11 +233,14 @@ def benchmark(unwinder, duration_seconds=10, blocking=False): start_time = time.perf_counter() end_time = start_time + duration_seconds total_attempts = 0 + operation_info = OPERATIONS[operation] + operation_method = getattr(unwinder, operation_info["method"]) colors = get_colors(can_colorize()) print( - f"{colors.BOLD_BLUE}Benchmarking sampling speed for {duration_seconds} seconds...{colors.RESET}" + f"{colors.BOLD_BLUE}Benchmarking {operation_info['label']} speed " + f"for {duration_seconds} seconds...{colors.RESET}" ) try: @@ -190,8 +251,8 @@ def benchmark(unwinder, duration_seconds=10, blocking=False): if blocking: unwinder.pause_threads() try: - stack_trace = unwinder.get_stack_trace() - if stack_trace: + sample = operation_method() + if sample: sample_count += 1 finally: if blocking: @@ -239,6 +300,7 @@ def benchmark(unwinder, duration_seconds=10, blocking=False): (sample_count / total_attempts) * 100 if total_attempts > 0 else 0 ), "total_work_time": total_work_time, + "operation": operation_info["label"], "avg_work_time_us": ( (total_work_time / total_attempts) * 1e6 if total_attempts > 0 else 0 ), @@ -252,7 +314,7 @@ def print_benchmark_results(results): colors = get_colors(can_colorize()) print(f"\n{colors.BOLD_GREEN}{'='*60}{colors.RESET}") - print(f"{colors.BOLD_GREEN}get_stack_trace() Benchmark Results{colors.RESET}") + print(f"{colors.BOLD_GREEN}{results['operation']} Benchmark Results{colors.RESET}") print(f"{colors.BOLD_GREEN}{'='*60}{colors.RESET}") # Basic statistics @@ -329,6 +391,8 @@ def parse_arguments(): %(prog)s -d 60 # Run basic benchmark for 60 seconds %(prog)s --code deep_static # Run deep static call stack benchmark %(prog)s --code deep_static -d 30 # Run deep static benchmark for 30 seconds + %(prog)s --operation async_stack_trace + %(prog)s --operation all_awaited_by Available code examples: {examples_desc} @@ -348,8 +412,15 @@ def parse_arguments(): "--code", "-c", choices=list(CODE_EXAMPLES.keys()), - default="basic", - help="Code example to benchmark (default: basic)", + default=None, + help="Code example to benchmark (default: basic, or asyncio for async operations)", + ) + + parser.add_argument( + "--operation", + choices=list(OPERATIONS.keys()), + default="stack_trace", + help="Remote unwinder operation to benchmark (default: stack_trace)", ) parser.add_argument( @@ -365,7 +436,10 @@ def parse_arguments(): help="Stop all threads before sampling for consistent snapshots", ) - return parser.parse_args() + args = parser.parse_args() + if args.code is None: + args.code = "asyncio" if args.operation != "stack_trace" else "basic" + return args def create_target_process(temp_file, code_example="basic"): @@ -420,6 +494,9 @@ def main(): print( f"{colors.CYAN}Benchmark Duration:{colors.RESET} {colors.YELLOW}{args.duration}{colors.RESET} seconds" ) + print( + f"{colors.CYAN}Operation:{colors.RESET} {colors.GREEN}{OPERATIONS[args.operation]['label']}{colors.RESET}" + ) print( f"{colors.CYAN}Blocking Mode:{colors.RESET} {colors.GREEN if args.blocking else colors.YELLOW}{'enabled' if args.blocking else 'disabled'}{colors.RESET}" ) @@ -451,7 +528,12 @@ def main(): unwinder = _remote_debugging.RemoteUnwinder( process.pid, cache_frames=True, **kwargs ) - results = benchmark(unwinder, duration_seconds=args.duration, blocking=args.blocking) + results = benchmark( + unwinder, + duration_seconds=args.duration, + blocking=args.blocking, + operation=args.operation, + ) finally: cleanup_process(process, temp_file_path) From 9c2620964e46cc9d3e31f3cdea329e44ebbb86fb Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 20 May 2026 14:00:49 +0200 Subject: [PATCH 097/818] [3.15] gh-150034: Print JSONL filename when profiling finishes (GH-150035) (#150151) --- Lib/profiling/sampling/jsonl_collector.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Lib/profiling/sampling/jsonl_collector.py b/Lib/profiling/sampling/jsonl_collector.py index 7d26129b80de86..5aa42ef09024dc 100644 --- a/Lib/profiling/sampling/jsonl_collector.py +++ b/Lib/profiling/sampling/jsonl_collector.py @@ -164,6 +164,7 @@ def export(self, filename): self._iter_final_agg_entries(), ) self._write_message(output, self._build_end_record()) + print(f"JSONL profile written to {filename}") def _build_meta_record(self): record = { From 61444f60a1d82f8458d078c600405dff7256f196 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 20 May 2026 15:55:30 +0200 Subject: [PATCH 098/818] [3.15] gh-150146: Fix NULL dereference in `_Py_subs_parameters` (GH-150147) (#150153) gh-150146: Fix NULL dereference in `_Py_subs_parameters` (GH-150147) (cherry picked from commit f621ba16b72510e1abc9646a844a632df4ac275c) Co-authored-by: sobolevn --- Lib/test/test_genericalias.py | 13 ++++++++++--- .../2026-05-20-13-06-17.gh-issue-150146.i5m_SL.rst | 5 +++++ Objects/genericaliasobject.c | 3 +++ 3 files changed, 18 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-05-20-13-06-17.gh-issue-150146.i5m_SL.rst diff --git a/Lib/test/test_genericalias.py b/Lib/test/test_genericalias.py index a5969b7a47d948..7816775620bc01 100644 --- a/Lib/test/test_genericalias.py +++ b/Lib/test/test_genericalias.py @@ -55,15 +55,14 @@ from unittest.case import _AssertRaisesContext from queue import Queue, SimpleQueue from weakref import WeakSet, ReferenceType, ref -import typing -from typing import Unpack try: from tkinter import Event except ImportError: Event = None from string.templatelib import Template, Interpolation -from typing import TypeVar +import typing +from typing import TypeVar, Unpack T = TypeVar('T') K = TypeVar('K') V = TypeVar('V') @@ -621,6 +620,14 @@ def test_nested_paramspec_specialization(self): self.assertEqual(deeply_nested_specialized.__args__, ([str, [float], int], float)) self.assertEqual(deeply_nested_specialized.__parameters__, ()) + def test_gh150146(self): + # It used to crash: + for container in [memoryview, list, tuple]: + with self.subTest(container=container): + x = container[TypeVar("")] + with self.assertRaises(TypeError): + x[*typing.Mapping[..., ...]] + class TypeIterationTests(unittest.TestCase): _UNITERABLE_TYPES = (list, tuple) diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-20-13-06-17.gh-issue-150146.i5m_SL.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-20-13-06-17.gh-issue-150146.i5m_SL.rst new file mode 100644 index 00000000000000..f373f0bee7023e --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-20-13-06-17.gh-issue-150146.i5m_SL.rst @@ -0,0 +1,5 @@ +Fix a crash on a complex type variable substitution. + +``from typing import TypeVar; memoryview[TypeVar("")][*typing.Mapping[..., +...]]`` used to fail due to missing ``NULL`` check on ``_unpack_args`` C +function call. diff --git a/Objects/genericaliasobject.c b/Objects/genericaliasobject.c index e3bc8eb2739e3f..9c797e8dd6fd2c 100644 --- a/Objects/genericaliasobject.c +++ b/Objects/genericaliasobject.c @@ -412,6 +412,9 @@ _Py_subs_parameters(PyObject *self, PyObject *args, PyObject *parameters, PyObje self); } item = _unpack_args(item); + if (item == NULL) { + return NULL; + } for (Py_ssize_t i = 0; i < nparams; i++) { PyObject *param = PyTuple_GET_ITEM(parameters, i); PyObject *prepare, *tmp; From ad2f0cb997a3711ae3a729cfc453d8004ba1a34e Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 20 May 2026 17:17:28 +0200 Subject: [PATCH 099/818] [3.15] PEP 810 - Update some error strings (GH-150126) (#150135) --- Objects/lazyimportobject.c | 2 +- Python/import.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Objects/lazyimportobject.c b/Objects/lazyimportobject.c index 451f335e033f16..fa1eb25047d961 100644 --- a/Objects/lazyimportobject.c +++ b/Objects/lazyimportobject.c @@ -135,7 +135,7 @@ PyDoc_STRVAR(lazy_import_doc, "lazy_import(builtins, name, fromlist=None, /)\n" "--\n" "\n" -"Represents a deferred import that will be resolved on first use.\n" +"Represents a lazy import that will be resolved on first use.\n" "\n" "Instances of this object accessed from the global scope will be\n" "automatically imported based upon their name and then replaced with\n" diff --git a/Python/import.c b/Python/import.c index ef6f5274a23665..352941a836ef21 100644 --- a/Python/import.c +++ b/Python/import.c @@ -4055,7 +4055,7 @@ _PyImport_LoadLazyImportTstate(PyThreadState *tstate, PyObject *lazy_import) // Create a cause exception showing where the lazy import was declared. PyObject *msg = PyUnicode_FromFormat( - "deferred import of '%U' raised an exception during resolution", + "lazy import of '%U' raised an exception during resolution", import_name ); Py_DECREF(import_name); // Done with import_name. From fb6984f305db00aa2dad623cf7b1236eddbd0387 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 20 May 2026 21:48:04 +0200 Subject: [PATCH 100/818] [3.15] gh-143387: Add news blurb for importlib.metadata highlighting the change. (GH-150169) (#150171) gh-143387: Add news blurb for importlib.metadata highlighting the change. (GH-150169) (cherry picked from commit cb3b4b98d8d141c9de0462a0fa7e227a2104c1c7) Co-authored-by: Jason R. Coombs --- Doc/whatsnew/3.15.rst | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst index 9bef7aa61d23cd..1670f033401f2b 100644 --- a/Doc/whatsnew/3.15.rst +++ b/Doc/whatsnew/3.15.rst @@ -1208,6 +1208,19 @@ http.server (Contributed by Anton I. Sipos in :gh:`135057`.) +importlib.metadata +------------------ + +* Previously, when accessing a distribution metadata directory not + containing a metadata file, ``metadata()`` and ``Distribution.metadata()`` + would return an empty ``PackageMetadata`` object as if the file + was present but empty. Now, a ``MetadataNotFound`` exception is raised. + See `importlib_metadata#493 `_ + for background and rationale and and :gh:`143387` for rationale on the + compatibility concerns. + (Contributed by Jason R. Coombs.) + + inspect ------- From ca0da94f09d22794da6c5c8f8cdc622cf5536965 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 20 May 2026 21:49:13 +0200 Subject: [PATCH 101/818] [3.15] gh-134261: ZipFile - Don't rely on local time for reproducible builds & tests (GH-134264) (#150137) gh-134261: ZipFile - Don't rely on local time for reproducible builds & tests (GH-134264) --------- (cherry picked from commit 9dcf94e906906ff39c7955227c2b044b515ee162) Co-authored-by: Caleb <23644849+ctrlaltf2@users.noreply.github.com> Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com> Co-authored-by: Emma Smith Co-authored-by: Jason R. Coombs --- Lib/test/test_zipfile/test_core.py | 17 +++++++++-------- Lib/zipfile/__init__.py | 9 ++++++--- ...25-05-19-21-08-25.gh-issue-134261.ravGYm.rst | 1 + 3 files changed, 16 insertions(+), 11 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2025-05-19-21-08-25.gh-issue-134261.ravGYm.rst diff --git a/Lib/test/test_zipfile/test_core.py b/Lib/test/test_zipfile/test_core.py index 0d407371f40a0f..30550263ad50aa 100644 --- a/Lib/test/test_zipfile/test_core.py +++ b/Lib/test/test_zipfile/test_core.py @@ -1886,11 +1886,8 @@ def test_write_with_source_date_epoch(self): with zipfile.ZipFile(TESTFN, "r") as zf: zip_info = zf.getinfo("test_source_date_epoch.txt") - get_time = time.localtime(int(os.environ['SOURCE_DATE_EPOCH']))[:6] - # Compare each element of the date_time tuple - # Allow for a 1-second difference - for z_time, g_time in zip(zip_info.date_time, get_time): - self.assertAlmostEqual(z_time, g_time, delta=1) + expected_utc = (2025, 1, 1, 7, 19, 58) + self.assertEqual(zip_info.date_time, expected_utc) def test_write_without_source_date_epoch(self): with os_helper.EnvironmentVarGuard() as env: @@ -1901,9 +1898,13 @@ def test_write_without_source_date_epoch(self): with zipfile.ZipFile(TESTFN, "r") as zf: zip_info = zf.getinfo("test_no_source_date_epoch.txt") - current_time = time.localtime()[:6] - for z_time, c_time in zip(zip_info.date_time, current_time): - self.assertAlmostEqual(z_time, c_time, delta=2) + self.assertTimestampAlmostEqual(time.localtime(), zip_info.date_time, tolerance=2) + + def assertTimestampAlmostEqual(self, time1, time2, tolerance): + import datetime + dt1 = datetime.datetime(*time1[:6]) + dt2 = datetime.datetime(*time2[:6]) + self.assertLessEqual((dt1 - dt2).total_seconds(), tolerance) def test_close(self): """Check that the zipfile is closed after the 'with' block.""" diff --git a/Lib/zipfile/__init__.py b/Lib/zipfile/__init__.py index 86c3bc36b695c7..c5c6ac03fb7b8c 100644 --- a/Lib/zipfile/__init__.py +++ b/Lib/zipfile/__init__.py @@ -663,9 +663,12 @@ def _for_archive(self, archive): Return self. """ # gh-91279: Set the SOURCE_DATE_EPOCH to a specific timestamp - epoch = os.environ.get('SOURCE_DATE_EPOCH') - get_time = int(epoch) if epoch else time.time() - self.date_time = time.localtime(get_time)[:6] + source_date_epoch = os.environ.get('SOURCE_DATE_EPOCH') + + if source_date_epoch: + self.date_time = time.gmtime(int(source_date_epoch))[:6] + else: + self.date_time = time.localtime(time.time())[:6] self.compress_type = archive.compression self.compress_level = archive.compresslevel diff --git a/Misc/NEWS.d/next/Library/2025-05-19-21-08-25.gh-issue-134261.ravGYm.rst b/Misc/NEWS.d/next/Library/2025-05-19-21-08-25.gh-issue-134261.ravGYm.rst new file mode 100644 index 00000000000000..bf552fee814acb --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-05-19-21-08-25.gh-issue-134261.ravGYm.rst @@ -0,0 +1 @@ +zip: On reproducible builds, ZipFile uses UTC instead of the local time when writing file datetimes to avoid underflows. From dea552c1b67192020d8be7f47d6e8ef974100ed2 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 20 May 2026 22:10:21 +0200 Subject: [PATCH 102/818] [3.15] Add summary table to the `unicodedata` doc (GH-149957) (#150161) (cherry picked from commit 87a879f4d0ec2e545e84c898c5ce452a6c87b09e) Co-authored-by: Stan Ulbrych --- Doc/library/unicodedata.rst | 43 ++++++++++++++++++++++++++++++++++--- 1 file changed, 40 insertions(+), 3 deletions(-) diff --git a/Doc/library/unicodedata.rst b/Doc/library/unicodedata.rst index f5c11fd849f58b..25bf872e0ab55a 100644 --- a/Doc/library/unicodedata.rst +++ b/Doc/library/unicodedata.rst @@ -18,8 +18,7 @@ this database is compiled from the `UCD version 17.0.0 The module uses the same names and symbols as defined by Unicode Standard Annex #44, `"Unicode Character Database" -`_. It defines the -following functions: +`_. .. seealso:: @@ -27,6 +26,44 @@ following functions: this module. +============================================================ =========================================================== +**Lookup** +------------------------------------------------------------------------------------------------------------------------- +:func:`lookup(name) ` Look up character by name +:func:`name(chr) ` Return the name assigned to a character + +**Numeric values** +------------------------------------------------------------------------------------------------------------------------- +:func:`decimal(chr) ` Decimal value of a character +:func:`digit(chr) ` Digit value of a character +:func:`numeric(chr) ` Numeric value of a character + +**Properties** +------------------------------------------------------------------------------------------------------------------------- +:func:`bidirectional(chr) ` Bidirectional class of a character +:func:`block(chr) ` Unicode block of a character +:func:`category(chr) ` General category of a character +:func:`combining(chr) ` Canonical combining class of a character +:func:`decomposition(chr) ` Character decomposition mapping +:func:`east_asian_width(chr) ` East Asian width of a character +:func:`extended_pictographic(chr) ` Check if a character has the Extended_Pictographic property +:func:`grapheme_cluster_break(chr) ` Grapheme_Cluster_Break property of a character +:func:`indic_conjunct_break(chr) ` Indic_Conjunct_Break property of a character +:func:`isxidcontinue(chr) ` Check if a character is a valid identifier continuation +:func:`isxidstart(chr) ` Check if a character is a valid identifier start +:func:`mirrored(chr) ` Mirrored property of a character + +**Normalization** +------------------------------------------------------------------------------------------------------------------------- +:func:`normalize(form, unistr) ` Return the normalized form of a string +:func:`is_normalized(form, unistr) ` Check if a Unicode string is normalized + +**Text segmentation** +------------------------------------------------------------------------------------------------------------------------- +:func:`iter_graphemes(unistr) ` Iterate over grapheme clusters in a string +============================================================ =========================================================== + + .. function:: lookup(name, /) Look up character by name. If a character with the given name is found, return @@ -273,7 +310,7 @@ following functions: .. versionadded:: 3.15 -In addition, the module exposes the following constant: +In addition, the module exposes the following constants: .. data:: unidata_version From a56a27100084c3011667ded3e93d552b4020ca68 Mon Sep 17 00:00:00 2001 From: sobolevn Date: Thu, 21 May 2026 12:53:00 +0300 Subject: [PATCH 103/818] [3.15] gh-149981: Test lazy import corner cases with module-level `__getattr__` (GH-149982) (#150185) (cherry picked from commit 6dbf4ba403cd38d0219d3c7514f61c2ac8f6a74f) --- Lib/test/test_lazy_import/__init__.py | 106 ++++++++++++++++++ .../data/module_with_getattr.py | 8 ++ .../test_lazy_import/data/pkg/__init__.py | 8 ++ 3 files changed, 122 insertions(+) diff --git a/Lib/test/test_lazy_import/__init__.py b/Lib/test/test_lazy_import/__init__.py index 9f2cc92bcfcc78..4340efd31095ea 100644 --- a/Lib/test/test_lazy_import/__init__.py +++ b/Lib/test/test_lazy_import/__init__.py @@ -97,6 +97,59 @@ def test_from_import_with_module_getattr(self): """) assert_python_ok("-c", code) + @support.requires_subprocess() + def test_from_import_with_module_getattr_raising(self): + """Lazy from import should respect module-level __getattr__.""" + code = textwrap.dedent(""" + lazy from test.test_lazy_import.data.module_with_getattr import raising_attr + + try: + raising_attr + except ValueError as exc: + assert str(exc) == 'from_getattr', exc + else: + assert False, f'ValueError is not raised: {raising_attr}' + """) + assert_python_ok("-c", code) + + @support.requires_subprocess() + def test_from_import_with_module_getattr_missing(self): + """Lazy from import should respect module-level __getattr__.""" + for attr in ("missing_attr", "import_error_attr"): + with self.subTest(attr=attr): + code = textwrap.dedent(f""" + lazy from test.test_lazy_import.data.module_with_getattr import {attr} + + try: + {attr} + except ImportError as exc: + assert '{attr}' in str(exc), exc + assert exc.__cause__ is not None + else: + assert False, ('ImportError is not raised', {attr}) + """) + assert_python_ok("-c", code) + + @support.requires_subprocess() + def test_from_import_with_module_getattr_warning(self): + """Lazy from import should respect module-level __getattr__.""" + code = textwrap.dedent(""" + import warnings + + with warnings.catch_warnings(record=True) as log: + lazy from test.test_lazy_import.data.module_with_getattr import warning_attr + + assert log == [] + + with warnings.catch_warnings(record=True) as log: + warning_attr + assert warning_attr == 'from_warning_attr', warning_attr + assert len(log) == 1, log + assert isinstance(log[0].message, UserWarning), log + assert str(log[0].message) == 'from_getattr', log + """) + assert_python_ok("-c", code) + @support.requires_subprocess() def test_from_import_with_imported_module_getattr(self): """Lazy from import should not shadow an imported module's __getattr__.""" @@ -482,6 +535,59 @@ def test_lazy_from_import_does_not_pollute_parent(self): """) assert_python_ok("-c", code) + @support.requires_subprocess() + def test_package_from_import_with_module_getattr_raising(self): + """Lazy from import should respect a package's __getattr__.""" + code = textwrap.dedent(""" + lazy from test.test_lazy_import.data.pkg import raising_attr + + try: + raising_attr + except ValueError as exc: + assert str(exc) == 'from_getattr', exc + else: + assert False, f'ValueError is not raised: {raising_attr}' + """) + assert_python_ok("-c", code) + + @support.requires_subprocess() + def test_package_from_import_with_module_getattr_missing(self): + """Lazy from import should respect package's __getattr__.""" + for attr in ("missing_attr", "import_error_attr"): + with self.subTest(attr=attr): + code = textwrap.dedent(f""" + lazy from test.test_lazy_import.data.pkg import {attr} + + try: + {attr} + except ImportError as exc: + assert '{attr}' in str(exc), exc + assert exc.__cause__ is not None + else: + assert False, ('ImportError is not raised', {attr}) + """) + assert_python_ok("-c", code) + + @support.requires_subprocess() + def test_from_import_with_module_getattr_warning(self): + """Lazy from import should respect package's __getattr__.""" + code = textwrap.dedent(""" + import warnings + + with warnings.catch_warnings(record=True) as log: + lazy from test.test_lazy_import.data.pkg import warning_attr + + assert log == [] + + with warnings.catch_warnings(record=True) as log: + warning_attr + assert warning_attr == 'from_warning_attr', warning_attr + assert len(log) == 1, log + assert isinstance(log[0].message, UserWarning), log + assert str(log[0].message) == 'from_getattr', log + """) + assert_python_ok("-c", code) + @support.requires_subprocess() def test_package_from_import_with_module_getattr(self): """Lazy from import should respect a package's __getattr__.""" diff --git a/Lib/test/test_lazy_import/data/module_with_getattr.py b/Lib/test/test_lazy_import/data/module_with_getattr.py index 2ac01a90d76e62..db3a2301075c2e 100644 --- a/Lib/test/test_lazy_import/data/module_with_getattr.py +++ b/Lib/test/test_lazy_import/data/module_with_getattr.py @@ -1,4 +1,12 @@ def __getattr__(name): if name == "dynamic_attr": return "from_getattr" + elif name == "raising_attr": + raise ValueError("from_getattr") + elif name == "import_error_attr": + raise ImportError(name) + elif name == "warning_attr": + import warnings + warnings.warn("from_getattr", category=UserWarning) + return "from_warning_attr" raise AttributeError(name) diff --git a/Lib/test/test_lazy_import/data/pkg/__init__.py b/Lib/test/test_lazy_import/data/pkg/__init__.py index e526aab94131b8..5f7b8662596cac 100644 --- a/Lib/test/test_lazy_import/data/pkg/__init__.py +++ b/Lib/test/test_lazy_import/data/pkg/__init__.py @@ -3,4 +3,12 @@ def __getattr__(name): if name == "dynamic_attr": return "from_getattr" + elif name == "raising_attr": + raise ValueError("from_getattr") + elif name == "import_error_attr": + raise ImportError(name) + elif name == "warning_attr": + import warnings + warnings.warn("from_getattr", category=UserWarning) + return "from_warning_attr" raise AttributeError(name) From 9d042ad9aec4fce19f87f7a7729c0a4a85ee4967 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 21 May 2026 17:22:24 +0200 Subject: [PATCH 104/818] [3.15] gh-149219: Test `frozendict` in `Lib/test/test_crossinterp.py` (GH-149220) (#150186) gh-149219: Test `frozendict` in `Lib/test/test_crossinterp.py` (GH-149220) (cherry picked from commit c35b0f2b624ecc4d649a808acdb07a7fbcea60ac) Co-authored-by: sobolevn --- Lib/test/test_crossinterp.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Lib/test/test_crossinterp.py b/Lib/test/test_crossinterp.py index 4e536211168747..f4bf5a66ad2155 100644 --- a/Lib/test/test_crossinterp.py +++ b/Lib/test/test_crossinterp.py @@ -157,6 +157,10 @@ def ignore_byteswarning(): {}, {1: 7, 2: 8, 3: 9}, {1: [1], 2: (2,), 3: {3: 4}}, + # frozendict + frozendict(), + frozendict({1: 7, 2: 8, 3: 9}), + frozendict({1: [1], 2: (2,), 3: {3: 4}, 4: frozendict({5: 6})}), # set set(), {1, 2, 3}, From e6e3b9f490b6a24dcbb461418f214e54431191f0 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 21 May 2026 22:02:10 +0200 Subject: [PATCH 105/818] [3.15] gh-107398: Fix tarfile stream mode exception when process the file with the gzip extra field (GH-126304) (GH-150199) (cherry picked from commit 65f99329edf5d0df3ee14d9a242e1a4c8b842211) Co-authored-by: Nadeshiko Manju Co-authored-by: Serhiy Storchaka --- Lib/tarfile.py | 2 +- Lib/test/test_tarfile.py | 33 +++++++++++++++++-- ...-11-02-02-02-31.gh-issue-107398.uUtA6Q.rst | 1 + 3 files changed, 33 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2024-11-02-02-02-31.gh-issue-107398.uUtA6Q.rst diff --git a/Lib/tarfile.py b/Lib/tarfile.py index 1394a26f2096ff..5e43b4c19c0a8a 100644 --- a/Lib/tarfile.py +++ b/Lib/tarfile.py @@ -498,7 +498,7 @@ def _init_read_gz(self): if flag & 4: xlen = ord(self.__read(1)) + 256 * ord(self.__read(1)) - self.read(xlen) + self.__read(xlen) if flag & 8: while True: s = self.__read(1) diff --git a/Lib/test/test_tarfile.py b/Lib/test/test_tarfile.py index 192c948edc6056..4be207e8cbf4e6 100644 --- a/Lib/test/test_tarfile.py +++ b/Lib/test/test_tarfile.py @@ -893,10 +893,39 @@ def test_extractall_hardlink_on_symlink(self): self._assert_on_file_content(hardlink_filepath, sha256_regtype) +class GzipReadTestBase: + + def test_read_with_extra_field(self): + with open(self.tarname, 'rb') as f: + data = bytearray(f.read()) + flags = data[3] + self.assertEqual(flags, 8) + data[3] = flags | 4 + data[10:10] = b'\x05\x00extra' + with open(tmpname, 'wb') as f: + f.write(data) + print(self.mode) + with tarfile.open(tmpname, mode=self.mode): + pass + + def test_read_with_file_comment(self): + with open(self.tarname, 'rb') as f: + data = bytearray(f.read()) + flags = data[3] + self.assertEqual(flags, 8) + data[3] = flags | 16 + i = data.index(0, 10) + 1 + data[i:i] = b'comment\x00' + with open(tmpname, 'wb') as f: + f.write(data) + with tarfile.open(tmpname, mode=self.mode): + pass + + class MiscReadTest(MiscReadTestBase, unittest.TestCase): test_fail_comp = None -class GzipMiscReadTest(GzipTest, MiscReadTestBase, unittest.TestCase): +class GzipMiscReadTest(GzipTest, GzipReadTestBase, MiscReadTestBase, unittest.TestCase): pass class Bz2MiscReadTest(Bz2Test, MiscReadTestBase, unittest.TestCase): @@ -970,7 +999,7 @@ def test_compare_members(self): finally: tar1.close() -class GzipStreamReadTest(GzipTest, StreamReadTest): +class GzipStreamReadTest(GzipTest, GzipReadTestBase, StreamReadTest): pass class Bz2StreamReadTest(Bz2Test, StreamReadTest): diff --git a/Misc/NEWS.d/next/Library/2024-11-02-02-02-31.gh-issue-107398.uUtA6Q.rst b/Misc/NEWS.d/next/Library/2024-11-02-02-02-31.gh-issue-107398.uUtA6Q.rst new file mode 100644 index 00000000000000..d5af322d68d309 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-11-02-02-02-31.gh-issue-107398.uUtA6Q.rst @@ -0,0 +1 @@ +Fix :mod:`tarfile` stream mode exception when process the file with the gzip extra field. From 233cf75d6db0d8a915114c4cc4f8182afe510ed1 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 22 May 2026 00:31:41 +0200 Subject: [PATCH 106/818] [3.15] gh-149819: fix .pth and .start file processing in subprocess when inheriting PYTHONPATH (GH-150177) (#150202) gh-149819: fix .pth and .start file processing in subprocess when inheriting PYTHONPATH (GH-150177) * gh-149819: Fix .pth files not loaded in Python subprocesses After PR gh-149583 (Fix double evaluation of .pth and .site files in venvs), .pth files are no longer loaded in subprocesses started with subprocess.run([sys.executable, ...]). The root cause: main() seeds known_paths from removeduppaths() with all sys.path entries inherited from the parent process. addsitedir() then skips .pth processing for every directory already in known_paths. Fix: - main(): call removeduppaths() for dedup but start known_paths as a fresh empty set, so that addsitedir() processes .pth files in every site-packages directory regardless of inherited sys.path. - addsitedir(): move known_paths.add() before the sys.path.append and guard the append with 'sitedir not in sys.path' to avoid creating duplicate entries when called with a fresh known_paths. This preserves the gh-75723 dedup guarantee while allowing subprocesses to load .pth files. * Fill out the tests for GH#149888 * Extend _make_start() and _make_pth() to take an optional `basedir` which is used instead of `site.tmpdir` if given. * Add test_pth_processed_when_sitedir_already_on_path() to test the core GH#149819 bug: .pth files in subprocesses aren't handled if PYTHONPATH pointing to the .pth directory is inherited. * Similarly add test_start_processed_when_sitedir_already_on_path() to verify that .start files in the same circumstances are also now processed. * Update Lib/site.py * Oops! Remove redundant code --------- (cherry picked from commit 3c298e2e385fc6f462abaada2fd680deb1a2b58e) Co-authored-by: Barry Warsaw Co-authored-by: BugBounty Mind Co-authored-by: scoder --- Lib/site.py | 17 ++-- Lib/test/test_site.py | 98 +++++++++++++++++-- ...-05-15-16-28-00.gh-issue-149819.fixpth.rst | 4 + 3 files changed, 105 insertions(+), 14 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-05-15-16-28-00.gh-issue-149819.fixpth.rst diff --git a/Lib/site.py b/Lib/site.py index 64e8192a9ac81a..239ee0d6f57bce 100644 --- a/Lib/site.py +++ b/Lib/site.py @@ -490,13 +490,16 @@ def addsitedir(sitedir, known_paths=None, *, defer_processing_start_files=False) reset = False sitedir, sitedircase = makepath(sitedir) - # If the normcase'd new sitedir isn't already known, append it to - # sys.path, keep a record of it, and process all .pth and .start files - # found in that directory. If the new sitedir is known, be sure not - # to process all of those more than once! gh-75723 + # If the normcase'd new sitedir isn't already known, record it to + # prevent re-processing, append it to sys.path (only if not already + # present), and process all .pth and .start files found in that + # directory. Use a direct sys.path membership check for the append + # guard so that callers (like main()) can pass a fresh known_paths + # set while avoiding duplicate sys.path entries (gh-149819). if sitedircase not in known_paths: - sys.path.append(sitedir) known_paths.add(sitedircase) + if sitedir not in sys.path: + sys.path.append(sitedir) try: names = os.listdir(sitedir) @@ -1000,13 +1003,13 @@ def main(): global ENABLE_USER_SITE orig_path = sys.path[:] - known_paths = removeduppaths() + removeduppaths() if orig_path != sys.path: # removeduppaths() might make sys.path absolute. # Fix __file__ of already imported modules too. abs_paths() - known_paths = venv(known_paths) + known_paths = venv(known_paths=set()) if ENABLE_USER_SITE is None: ENABLE_USER_SITE = check_enableusersite() known_paths = addusersitepackages(known_paths, defer_processing_start_files=True) diff --git a/Lib/test/test_site.py b/Lib/test/test_site.py index 0e6f352f49cd38..e2a81b82321ede 100644 --- a/Lib/test/test_site.py +++ b/Lib/test/test_site.py @@ -456,6 +456,7 @@ def cleanup(self, prep=False): if os.path.exists(self.bad_dir_path): os.rmdir(self.bad_dir_path) + class ImportSideEffectTests(unittest.TestCase): """Test side-effects from importing 'site'.""" @@ -545,7 +546,6 @@ def test_customization_modules_on_startup(self): output = subprocess.check_output([sys.executable, '-s', '-c', '""']) self.assertNotIn(eyecatcher, output.decode('utf-8')) - @unittest.skipUnless(hasattr(urllib.request, "HTTPSHandler"), 'need SSL support to download license') @test.support.requires_resource('network') @@ -926,18 +926,28 @@ def setUp(self): def _reset_startup_state(self): site._startup_state = None - def _make_start(self, content, name='testpkg'): - """Write a .start file and return its basename.""" + def _make_start(self, content, name='testpkg', basedir=None): + """Write a .start file and return its basename. + + ``basedir`` defaults to ``self.tmpdir``. Pass an explicit directory + when the .start file needs to live somewhere other than the test's + primary tmpdir (e.g. a nested user-site). + """ basename = f"{name}.start" - filepath = os.path.join(self.tmpdir, basename) + filepath = os.path.join(self.tmpdir if basedir is None else basedir, basename) with open(filepath, 'w', encoding='utf-8') as f: f.write(content) return basename - def _make_pth(self, content, name='testpkg'): - """Write a .pth file and return its basename.""" + def _make_pth(self, content, name='testpkg', basedir=None): + """Write a .pth file and return its basename. + + ``basedir`` defaults to ``self.tmpdir``. Pass an explicit directory + when the .pth file needs to live somewhere other than the test's + primary tmpdir (e.g. a nested user-site). + """ basename = f"{name}.pth" - filepath = os.path.join(self.tmpdir, basename) + filepath = os.path.join(self.tmpdir if basedir is None else basedir, basename) with open(filepath, 'w', encoding='utf-8') as f: f.write(content) return basename @@ -1640,6 +1650,80 @@ def bootstrap(): self.assertIn(overlay, sys.path) self.assertIn(pkgdir, sys.path) + # gh-149819 + @unittest.skipUnless(site.ENABLE_USER_SITE, "requires user-site") + @support.requires_subprocess() + def test_pth_processed_when_sitedir_already_on_path(self): + # A .pth file in a site-packages directory must still be processed by + # site.main() when that directory is already on sys.path at + # interpreter start up, for example in a subprocess that inherits + # PYTHONPATH from its parent. Before the fix, main() seeded + # known_paths with all entries derived from removeduppaths(), and + # addsitedir() then skipped .pth processing for any directory already + # in known_paths. + user_base = self.tmpdir + user_site = site._get_path(user_base) + os.makedirs(user_site) + sentinel = "GH149819_PTH_RAN" + # Writing some text to stderr is the simplest observable side effect. + self._make_pth(f"""\ +import sys; sys.stderr.write({sentinel!r}); sys.stderr.flush() +""", + name='gh149819', + basedir=user_site) + with EnvironmentVarGuard() as env: + # PYTHONUSERBASE points USER_SITE at our temp directory so + # site.main() will call addsitedir() on it, rather than on the + # host interpreter's real user-site. + env['PYTHONUSERBASE'] = user_base + # PYTHONPATH puts that same directory on sys.path before + # site.main() runs in the subprocess. This is what triggers the + # bug: removeduppaths() records it in known_paths, and the unfixed + # addsitedir() then skips .pth processing. + env['PYTHONPATH'] = user_site + result = subprocess.run( + [sys.executable, '-c', ''], + capture_output=True, + check=True, + ) + self.assertIn(sentinel.encode(), result.stderr) + + @unittest.skipUnless(site.ENABLE_USER_SITE, "requires user-site") + @support.requires_subprocess() + def test_start_processed_when_sitedir_already_on_path(self): + # Companion to test_pth_processed_when_sitedir_already_on_path: + # the same dedup-guard skip in addsitedir() suppressed both .pth + # and .start file processing, so verify .start entry points also + # run for a site-packages directory inherited via PYTHONPATH. + user_base = self.tmpdir + user_site = site._get_path(user_base) + os.makedirs(user_site) + sentinel = "GH149819_START_RAN" + # The .start entry point resolves to a callable, so we write a + # tiny importable module that outputs the sentinel text. It lands in + # /extdir. That path is added to PYTHONPATH below so + # the subprocess can import it. + extdir = self._make_mod(f"""\ +import sys +def run(): + sys.stderr.write({sentinel!r}) + sys.stderr.flush() +""", name='gh149819mod') + self._make_start( + 'gh149819mod:run\n', name='gh149819', basedir=user_site + ) + with EnvironmentVarGuard() as env: + # See above for details. + env['PYTHONUSERBASE'] = user_base + env['PYTHONPATH'] = os.pathsep.join([user_site, extdir]) + result = subprocess.run( + [sys.executable, '-c', ''], + capture_output=True, + check=True, + ) + self.assertIn(sentinel.encode(), result.stderr) + + if __name__ == "__main__": unittest.main() diff --git a/Misc/NEWS.d/next/Library/2026-05-15-16-28-00.gh-issue-149819.fixpth.rst b/Misc/NEWS.d/next/Library/2026-05-15-16-28-00.gh-issue-149819.fixpth.rst new file mode 100644 index 00000000000000..66e6da0ecf0d87 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-05-15-16-28-00.gh-issue-149819.fixpth.rst @@ -0,0 +1,4 @@ +Fix regression in :func:`site.addsitedir` where ``.pth`` files were no +longer processed in Python subprocesses. This happened because +:func:`site.main` seeded ``known_paths`` with entries inherited from +the parent process, causing ``addsitedir`` to skip ``.pth`` processing. From 072246a7803246f562bea6d099d2c3640d59db96 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 22 May 2026 04:18:28 +0200 Subject: [PATCH 107/818] [3.15] gh-148294: Make configure find g++ correctly (GH-150212) The `AC_PATH_TOOL` calls had included a duplicated argument, causing a "`PATH`" consisting of `notfound` to be searched instead of `$PATH`. (cherry picked from commit c613f72eeef83340cb369287f7c1a195e086d1d5) Co-authored-by: sendaoYan --- ...-05-21-15-14-59.gh-issue-148294.VtFaW4.rst | 2 ++ configure | 24 +++++++++---------- configure.ac | 8 +++---- 3 files changed, 18 insertions(+), 16 deletions(-) create mode 100644 Misc/NEWS.d/next/Build/2026-05-21-15-14-59.gh-issue-148294.VtFaW4.rst diff --git a/Misc/NEWS.d/next/Build/2026-05-21-15-14-59.gh-issue-148294.VtFaW4.rst b/Misc/NEWS.d/next/Build/2026-05-21-15-14-59.gh-issue-148294.VtFaW4.rst new file mode 100644 index 00000000000000..861261dd97269f --- /dev/null +++ b/Misc/NEWS.d/next/Build/2026-05-21-15-14-59.gh-issue-148294.VtFaW4.rst @@ -0,0 +1,2 @@ +Corrected the use of ``AC_PATH_TOOL`` in ``configure.ac`` to allow a C++ +compiler to be found on :envvar:`!PATH`. diff --git a/configure b/configure index acba294d55de8f..9ad2171460f7ac 100755 --- a/configure +++ b/configure @@ -6645,7 +6645,7 @@ else case e in #( ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in notfound +for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( @@ -6694,7 +6694,7 @@ else case e in #( ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in notfound +for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( @@ -6726,7 +6726,7 @@ printf "%s\n" "no" >&6; } fi if test "x$ac_pt_CXX" = x; then - CXX="g++" + CXX="notfound" else case $cross_compiling:$ac_tool_warned in yes:) @@ -6755,7 +6755,7 @@ else case e in #( ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in notfound +for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( @@ -6804,7 +6804,7 @@ else case e in #( ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in notfound +for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( @@ -6836,7 +6836,7 @@ printf "%s\n" "no" >&6; } fi if test "x$ac_pt_CXX" = x; then - CXX="c++" + CXX="notfound" else case $cross_compiling:$ac_tool_warned in yes:) @@ -6865,7 +6865,7 @@ else case e in #( ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in notfound +for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( @@ -6914,7 +6914,7 @@ else case e in #( ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in notfound +for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( @@ -6946,7 +6946,7 @@ printf "%s\n" "no" >&6; } fi if test "x$ac_pt_CXX" = x; then - CXX="clang++" + CXX="notfound" else case $cross_compiling:$ac_tool_warned in yes:) @@ -6975,7 +6975,7 @@ else case e in #( ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in notfound +for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( @@ -7024,7 +7024,7 @@ else case e in #( ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in notfound +for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( @@ -7056,7 +7056,7 @@ printf "%s\n" "no" >&6; } fi if test "x$ac_pt_CXX" = x; then - CXX="icpc" + CXX="notfound" else case $cross_compiling:$ac_tool_warned in yes:) diff --git a/configure.ac b/configure.ac index d909c2fc92894e..a51e173e5293f2 100644 --- a/configure.ac +++ b/configure.ac @@ -1137,10 +1137,10 @@ preset_cxx="$CXX" if test -z "$CXX" then case "$ac_cv_cc_name" in - gcc) AC_PATH_TOOL([CXX], [g++], [g++], [notfound]) ;; - cc) AC_PATH_TOOL([CXX], [c++], [c++], [notfound]) ;; - clang) AC_PATH_TOOL([CXX], [clang++], [clang++], [notfound]) ;; - icc) AC_PATH_TOOL([CXX], [icpc], [icpc], [notfound]) ;; + gcc) AC_PATH_TOOL([CXX], [g++], [notfound]) ;; + cc) AC_PATH_TOOL([CXX], [c++], [notfound]) ;; + clang) AC_PATH_TOOL([CXX], [clang++], [notfound]) ;; + icc) AC_PATH_TOOL([CXX], [icpc], [notfound]) ;; esac if test "$CXX" = "notfound" then From 591c4ffdd93ff4e89c61f4b9f84fd68a1f36d8db Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 22 May 2026 08:41:43 +0200 Subject: [PATCH 108/818] [3.15] gh-149995: Update typing.py docstrings and documentation (GH-149996) (#150215) gh-149995: Update typing.py docstrings and documentation (GH-149996) Some of these docstrings read as if they were written when typing.py was first written, and things have evolved since then. A few motivations: - Call protocols protocols instead of ABCs. They are also ABCs, but the fact they are protocols is more relevant to typing. - Avoid recommending direct use of .__annotations__ and steer users to annotationlib instead. - For TypedDict, mention NotRequired before total=False since it is more general and probably more frequently useful. - For overloads, mention runtime use first instead of stub use. I think early on there was talk of allowing overload only in stubs, but it is now heavily used at runtime too and that's more likely to be relevant to users. (cherry picked from commit f159419ae2ef1aebbd90ce9427b55e27738c960c) Co-authored-by: Jelle Zijlstra --- Doc/library/typing.rst | 46 +++---- Lib/typing.py | 115 +++++++++--------- ...-05-18-07-44-46.gh-issue-149995.vvtFHn.rst | 1 + 3 files changed, 81 insertions(+), 81 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-05-18-07-44-46.gh-issue-149995.vvtFHn.rst diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index 71b395c80166cc..b2167cbc63a1ff 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -719,8 +719,8 @@ The :data:`Any` type ==================== A special kind of type is :data:`Any`. A static type checker will treat -every type as being compatible with :data:`Any` and :data:`Any` as being -compatible with every type. +every type as assignable to :data:`Any` and :data:`Any` as assignable to +every type. This means that it is possible to perform any operation or method call on a value of type :data:`Any` and assign it to any variable:: @@ -785,7 +785,7 @@ it as a return value) of a more specialized type is a type error. For example:: hash_a(42) hash_a("foo") - # Passes type checking, since Any is compatible with all types + # Passes type checking, since Any is assignable to all types hash_b(42) hash_b("foo") @@ -851,8 +851,8 @@ using ``[]``. Special type indicating an unconstrained type. - * Every type is compatible with :data:`Any`. - * :data:`Any` is compatible with every type. + * Every type is assignable to :data:`Any`. + * :data:`Any` is assignable to every type. .. versionchanged:: 3.11 :data:`Any` can now be used as a base class. This can be useful for @@ -1292,10 +1292,10 @@ These can be used as types in annotations. They all support subscription using :data:`ClassVar` accepts only types and cannot be further subscribed. - :data:`ClassVar` is not a class itself, and should not + :data:`ClassVar` is not a class itself, and cannot be used with :func:`isinstance` or :func:`issubclass`. :data:`ClassVar` does not change Python runtime behavior, but - it can be used by third-party type checkers. For example, a type checker + it can be used by static type checkers. For example, a type checker might flag the following code as an error:: enterprise_d = Starship(3000) @@ -1365,7 +1365,7 @@ These can be used as types in annotations. They all support subscription using def mutate_movie(m: Movie) -> None: m["year"] = 1999 # allowed - m["title"] = "The Matrix" # typechecker error + m["title"] = "The Matrix" # type checker error There is no runtime checking for this property. @@ -2472,9 +2472,9 @@ types. Fields with a default value must come after any fields without a default. - The resulting class has an extra attribute ``__annotations__`` giving a - dict that maps the field names to the field types. (The field names are in - the ``_fields`` attribute and the default values are in the + The types for each field name can be retrieved by calling + :func:`annotationlib.get_annotations` on the resulting class. (The field + names are in the ``_fields`` attribute and the default values are in the ``_field_defaults`` attribute, both of which are part of the :func:`~collections.namedtuple` API.) @@ -2535,7 +2535,7 @@ types. Helper class to create low-overhead :ref:`distinct types `. - A ``NewType`` is considered a distinct type by a typechecker. At runtime, + A ``NewType`` is considered a distinct type by a type checker. At runtime, however, calling a ``NewType`` returns its argument unchanged. Usage:: @@ -2616,7 +2616,7 @@ types. Mark a protocol class as a runtime protocol. Such a protocol can be used with :func:`isinstance` and :func:`issubclass`. - This allows a simple-minded structural check, very similar to "one trick ponies" + This allows a simple-minded structural check, very similar to "one-trick ponies" in :mod:`collections.abc` such as :class:`~collections.abc.Iterable`. For example:: @runtime_checkable @@ -2855,7 +2855,7 @@ types. key: T group: list[T] - A ``TypedDict`` can be introspected via annotations dicts + A ``TypedDict`` can be introspected via :func:`annotationlib.get_annotations` (see :ref:`annotations-howto` for more information on annotations best practices) and the following attributes: @@ -2898,7 +2898,7 @@ types. For backwards compatibility with Python 3.10 and below, it is also possible to use inheritance to declare both required and - non-required keys in the same ``TypedDict`` . This is done by declaring a + non-required keys in the same ``TypedDict``. This is done by declaring a ``TypedDict`` with one value for the ``total`` argument and then inheriting from it in another ``TypedDict`` with a different value for ``total``: @@ -2982,34 +2982,34 @@ with :deco:`runtime_checkable`. .. class:: SupportsAbs - An ABC with one abstract method ``__abs__`` that is covariant + A protocol with one abstract method ``__abs__`` that is covariant in its return type. .. class:: SupportsBytes - An ABC with one abstract method ``__bytes__``. + A protocol with one abstract method ``__bytes__``. .. class:: SupportsComplex - An ABC with one abstract method ``__complex__``. + A protocol with one abstract method ``__complex__``. .. class:: SupportsFloat - An ABC with one abstract method ``__float__``. + A protocol with one abstract method ``__float__``. .. class:: SupportsIndex - An ABC with one abstract method ``__index__``. + A protocol with one abstract method ``__index__``. .. versionadded:: 3.8 .. class:: SupportsInt - An ABC with one abstract method ``__int__``. + A protocol with one abstract method ``__int__``. .. class:: SupportsRound - An ABC with one abstract method ``__round__`` + A protocol with one abstract method ``__round__`` that is covariant in its return type. .. _typing-io: @@ -3763,7 +3763,7 @@ Constant .. data:: TYPE_CHECKING - A special constant that is assumed to be ``True`` by 3rd party static + A special constant that is assumed to be ``True`` by static type checkers. It's ``False`` at runtime. A module which is expensive to import, and which only contain types diff --git a/Lib/typing.py b/Lib/typing.py index 5b1e223d59641e..bd1f6448894e8f 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -5,7 +5,7 @@ * Generic, Protocol, and internal machinery to support generic aliases. All subscripted types like X[int], Union[int, str] are generic aliases. * Various "special forms" that have unique meanings in type annotations: - NoReturn, Never, ClassVar, Self, Concatenate, Unpack, and others. + Any, Never, ClassVar, Self, Concatenate, Unpack, and others. * Classes whose instances can be type arguments to generic classes and functions: TypeVar, ParamSpec, TypeVarTuple. * Public helper functions: get_type_hints, overload, cast, final, and others. @@ -604,12 +604,12 @@ def __repr__(self): class Any(metaclass=_AnyMeta): """Special type indicating an unconstrained type. - - Any is compatible with every type. - - Any assumed to have all methods. - - All values assumed to be instances of Any. + - Any is assignable to every type. + - Any assumed to have all methods and attributes. + - All values are assignable to Any. Note that all the above statements are true from the point of view of - static type checkers. At runtime, Any should not be used with instance + static type checkers. At runtime, Any cannot be used with instance checks. """ @@ -728,7 +728,7 @@ class Starship: ClassVar accepts only types and cannot be further subscribed. - Note that ClassVar is not a class itself, and should not + Note that ClassVar is not a class itself, and cannot be used with isinstance() or issubclass(). """ item = _type_check(parameters, f'{self} accepts only single type.', allow_special_forms=True) @@ -758,7 +758,7 @@ class FastConnector(Connection): @_SpecialForm def Optional(self, parameters): - """Optional[X] is equivalent to Union[X, None].""" + """Optional[X] is equivalent to X | None.""" arg = _type_check(parameters, f"{self} requires a single type.") return Union[arg, type(None)] @@ -801,7 +801,7 @@ def open_helper(file: str, mode: MODE) -> str: def TypeAlias(self, parameters): """Special form for marking type aliases. - Use TypeAlias to indicate that an assignment should + TypeAlias can be used to indicate that an assignment should be recognized as a proper type alias definition by type checkers. @@ -1809,7 +1809,7 @@ class Movie(TypedDict): def foo(**kwargs: Unpack[Movie]): ... Note that there is only some runtime checking of this operator. Not - everything the runtime allows may be accepted by static type checkers. + everything the runtime allows is accepted by static type checkers. For more information, see PEPs 646 and 692. """ @@ -2320,7 +2320,7 @@ def runtime_checkable(cls): Such protocol can be used with isinstance() and issubclass(). Raise TypeError if applied to a non-protocol class. This allows a simple-minded structural check very similar to - one trick ponies in collections.abc such as Iterable. + one-trick ponies in collections.abc such as Iterable. For example:: @@ -2390,8 +2390,8 @@ def get_type_hints(obj, globalns=None, localns=None, include_extras=False, *, format=None): """Return type hints for an object. - This is often the same as obj.__annotations__, but it handles - forward references encoded as string literals and recursively replaces all + This is often the same as annotationlib.get_annotations(obj) or obj.__annotations__, + but it handles forward references encoded as string literals and recursively replaces all 'Annotated[T, ...]' with 'T' (unless 'include_extras=True'). The argument may be a module, class, method, or function. The annotations @@ -2603,7 +2603,7 @@ def get_args(tp): def is_typeddict(tp): - """Check if an annotation is a TypedDict class. + """Check if an object is a TypedDict class. For example:: @@ -2700,10 +2700,10 @@ def _overload_dummy(*args, **kwds): def overload(func): """Decorator for overloaded functions/methods. - In a stub file, place two or more stub definitions for the same - function in a row, each decorated with @overload. - - For example:: + In a non-stub file, place two or more stub definitions for the same + function in a row, each decorated with @overload, followed + by an implementation. The implementation should *not* + be decorated with @overload:: @overload def utf8(value: None) -> None: ... @@ -2711,10 +2711,11 @@ def utf8(value: None) -> None: ... def utf8(value: bytes) -> bytes: ... @overload def utf8(value: str) -> bytes: ... + def utf8(value): + ... # implementation goes here - In a non-stub file (i.e. a regular .py file), do the same but - follow it with an implementation. The implementation should *not* - be decorated with @overload:: + In a stub file or in an abstract method (for example, in a Protocol definition), + the implementation may be omitted:: @overload def utf8(value: None) -> None: ... @@ -2722,8 +2723,6 @@ def utf8(value: None) -> None: ... def utf8(value: bytes) -> bytes: ... @overload def utf8(value: str) -> bytes: ... - def utf8(value): - ... # implementation goes here The overloads for a function can be retrieved at runtime using the get_overloads() function. @@ -2759,7 +2758,7 @@ def final(f): """Decorator to indicate final methods and final classes. Use this decorator to indicate to type checkers that the decorated - method cannot be overridden, and decorated class cannot be subclassed. + method cannot be overridden, and the decorated class cannot be subclassed. For example:: @@ -2824,7 +2823,7 @@ class Disjoint3(Disjoint1, Disjoint2): pass # Type checker error V_co = TypeVar('V_co', covariant=True) # Any type covariant containers. VT_co = TypeVar('VT_co', covariant=True) # Value type covariant containers. T_contra = TypeVar('T_contra', contravariant=True) # Ditto contravariant. -# Internal type variable used for Type[]. +# Internal type bound to class object types. CT_co = TypeVar('CT_co', covariant=True, bound=type) @@ -2912,7 +2911,7 @@ class TeamUser(User): ... And a function that takes a class argument that's a subclass of User and returns an instance of the corresponding class:: - def new_user[U](user_class: Type[U]) -> U: + def new_user[U](user_class: type[U]) -> U: user = user_class() # (Here we could write the user object to a database) return user @@ -2925,7 +2924,7 @@ def new_user[U](user_class: Type[U]) -> U: @runtime_checkable class SupportsInt(Protocol): - """An ABC with one abstract method __int__.""" + """A protocol with one abstract method __int__.""" __slots__ = () @@ -2936,7 +2935,7 @@ def __int__(self) -> int: @runtime_checkable class SupportsFloat(Protocol): - """An ABC with one abstract method __float__.""" + """A protocol with one abstract method __float__.""" __slots__ = () @@ -2947,7 +2946,7 @@ def __float__(self) -> float: @runtime_checkable class SupportsComplex(Protocol): - """An ABC with one abstract method __complex__.""" + """A protocol with one abstract method __complex__.""" __slots__ = () @@ -2958,7 +2957,7 @@ def __complex__(self) -> complex: @runtime_checkable class SupportsBytes(Protocol): - """An ABC with one abstract method __bytes__.""" + """A protocol with one abstract method __bytes__.""" __slots__ = () @@ -2969,7 +2968,7 @@ def __bytes__(self) -> bytes: @runtime_checkable class SupportsIndex(Protocol): - """An ABC with one abstract method __index__.""" + """A protocol with one abstract method __index__.""" __slots__ = () @@ -2980,7 +2979,7 @@ def __index__(self) -> int: @runtime_checkable class SupportsAbs[T](Protocol): - """An ABC with one abstract method __abs__ that is covariant in its return type.""" + """A protocol with one abstract method __abs__ that is covariant in its return type.""" __slots__ = () @@ -2991,7 +2990,7 @@ def __abs__(self) -> T: @runtime_checkable class SupportsRound[T](Protocol): - """An ABC with one abstract method __round__ that is covariant in its return type.""" + """A protocol with one abstract method __round__ that is covariant in its return type.""" __slots__ = () @@ -3108,7 +3107,7 @@ def annotate(format): def NamedTuple(typename, fields, /): - """Typed version of namedtuple. + """Typed version of collections.namedtuple. Usage:: @@ -3120,8 +3119,8 @@ class Employee(NamedTuple): Employee = collections.namedtuple('Employee', ['name', 'id']) - The resulting class has an extra __annotations__ attribute, giving a - dict that maps field names to types. (The field names are also in + The types for each field name can be retrieved by calling + annotationlib.get_annotations(Employee). (The field names are also in the _fields attribute, which is part of the namedtuple API.) An alternative equivalent functional syntax is also accepted:: @@ -3174,7 +3173,7 @@ def __new__(cls, name, bases, ns, total=True, closed=None, This method is called when TypedDict is subclassed, or when TypedDict is instantiated. This way - TypedDict supports all three syntax forms described in its docstring. + TypedDict classes can be created through both class-based and functional syntax. Subclasses and instances of TypedDict return actual dictionaries. """ for base in bases: @@ -3328,14 +3327,22 @@ def TypedDict(typename, fields, /, *, total=True, closed=None, >>> Point2D(x=1, y=2, label='first') == dict(x=1, y=2, label='first') True - The type info can be accessed via the Point2D.__annotations__ dict, and - the Point2D.__required_keys__ and Point2D.__optional_keys__ frozensets. + The type info can be accessed by calling annotationlib.get_annotations(Point2D), and + via the Point2D.__required_keys__ and Point2D.__optional_keys__ frozensets. TypedDict supports an additional equivalent form:: Point2D = TypedDict('Point2D', {'x': int, 'y': int, 'label': str}) By default, all keys must be present in a TypedDict. It is possible - to override this by specifying totality:: + to override this by using the NotRequired and Required special forms:: + + class Point2D(TypedDict): + x: int # the "x" key must always be present (Required is the default) + y: NotRequired[int] # the "y" key can be omitted + + This means that a Point2D TypedDict can have the "y" key omitted, but the "x" key must be present. + Items are required by default, so the Required special form is not necessary in this example. + In addition, the total argument to the TypedDict function can be used to make all items not required:: class Point2D(TypedDict, total=False): x: int @@ -3344,16 +3351,8 @@ class Point2D(TypedDict, total=False): This means that a Point2D TypedDict can have any of the keys omitted. A type checker is only expected to support a literal False or True as the value of the total argument. True is the default, and makes all items defined in the - class body be required. - - The Required and NotRequired special forms can also be used to mark - individual keys as being required or not required:: - - class Point2D(TypedDict): - x: int # the "x" key must always be present (Required is the default) - y: NotRequired[int] # the "y" key can be omitted - - See PEP 655 for more details on Required and NotRequired. + class body be required. The Required special form can be used to mark individual + keys as required in a total=False TypedDict. The ReadOnly special form can be used to mark individual keys as immutable for type checkers:: @@ -3387,7 +3386,7 @@ class Point3D(Point2D): by default, and it may not be used with the closed argument at the same time. - See PEP 728 for more information about closed and extra_items. + See PEPs 589, 655, 705, and 728 for more information. """ ns = {'__annotations__': dict(fields)} module = _caller() @@ -3417,7 +3416,7 @@ class Movie(TypedDict, total=False): year: int m = Movie( - title='The Matrix', # typechecker error if key is omitted + title='The Matrix', # type checker error if key is omitted year=1999, ) @@ -3439,7 +3438,7 @@ class Movie(TypedDict): year: NotRequired[int] m = Movie( - title='The Matrix', # typechecker error if key is omitted + title='The Matrix', # type checker error if key is omitted year=1999, ) """ @@ -3459,7 +3458,7 @@ class Movie(TypedDict): def mutate_movie(m: Movie) -> None: m["year"] = 1992 # allowed - m["title"] = "The Matrix" # typechecker error + m["title"] = "The Matrix" # type checker error There is no runtime checking for this property. """ @@ -3546,8 +3545,8 @@ class IO(Generic[AnyStr]): classes (text vs. binary, read vs. write vs. read/write, append-only, unbuffered). The TextIO and BinaryIO subclasses below capture the distinctions between text vs. binary, which is - pervasive in the interface; however we currently do not offer a - way to track the other distinctions in the type system. + pervasive in the interface. For more precise types, define a custom + Protocol. """ __slots__ = () @@ -3637,7 +3636,7 @@ def __exit__(self, type, value, traceback, /) -> None: class BinaryIO(IO[bytes]): - """Typed version of the return of open() in binary mode.""" + """Typed approximation of the return of open() in binary mode.""" __slots__ = () @@ -3651,7 +3650,7 @@ def __enter__(self) -> BinaryIO: class TextIO(IO[str]): - """Typed version of the return of open() in text mode.""" + """Typed approximation of the return of open() in text mode.""" __slots__ = () @@ -3718,7 +3717,7 @@ def dataclass_transform( field_specifiers: tuple[type[Any] | Callable[..., Any], ...] = (), **kwargs: Any, ) -> _IdentityCallable: - """Decorator to mark an object as providing dataclass-like behaviour. + """Decorator to mark an object as providing dataclass-like behavior. The decorator can be applied to a function, class, or metaclass. diff --git a/Misc/NEWS.d/next/Library/2026-05-18-07-44-46.gh-issue-149995.vvtFHn.rst b/Misc/NEWS.d/next/Library/2026-05-18-07-44-46.gh-issue-149995.vvtFHn.rst new file mode 100644 index 00000000000000..a8e412b578da37 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-05-18-07-44-46.gh-issue-149995.vvtFHn.rst @@ -0,0 +1 @@ +Update various docstrings in :mod:`typing`. From b039d1bd976819320af15494a11c973e0eca02f1 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 22 May 2026 09:48:42 +0200 Subject: [PATCH 109/818] [3.15] gh-133998: Fix gzip file creation when time is out of range (GH-134278) (GH-150221) (cherry picked from commit 1daad8a1630c9ee011f6ff3796c4e7aef243463b) Co-authored-by: adang1345 Co-authored-by: Serhiy Storchaka --- Doc/library/gzip.rst | 10 ++++++--- Lib/gzip.py | 10 +++++++-- Lib/test/test_gzip.py | 21 +++++++++++++++++++ ...-05-19-20-29-35.gh-issue-133998.KmElUw.rst | 5 +++++ 4 files changed, 41 insertions(+), 5 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2025-05-19-20-29-35.gh-issue-133998.KmElUw.rst diff --git a/Doc/library/gzip.rst b/Doc/library/gzip.rst index ed9fdaf1d727b0..2c667ddc522399 100644 --- a/Doc/library/gzip.rst +++ b/Doc/library/gzip.rst @@ -108,9 +108,13 @@ The module defines the following items: is no compression. The default is ``9``. The optional *mtime* argument is the timestamp requested by gzip. The time - is in Unix format, i.e., seconds since 00:00:00 UTC, January 1, 1970. - If *mtime* is omitted or ``None``, the current time is used. Use *mtime* = 0 - to generate a compressed stream that does not depend on creation time. + is in Unix format, i.e., seconds since 00:00:00 UTC, January 1, 1970. Set + *mtime* to ``0`` to generate a compressed stream that does not depend on + creation time. If *mtime* is omitted or ``None``, the current time is used; + however, if the current time is outside the range 00:00:00 UTC, January 1, + 1970 through 06:28:15 UTC, February 7, 2106, or explicitly passed *mtime* + argument is outside the range ``0`` to ``2**32-1``, then the value ``0`` + is used instead. See below for the :attr:`mtime` attribute that is set when decompressing. diff --git a/Lib/gzip.py b/Lib/gzip.py index 1e05f43c0c9e24..8720acc4db9976 100644 --- a/Lib/gzip.py +++ b/Lib/gzip.py @@ -188,8 +188,10 @@ def __init__(self, filename=None, mode=None, The optional mtime argument is the timestamp requested by gzip. The time is in Unix format, i.e., seconds since 00:00:00 UTC, January 1, 1970. - If mtime is omitted or None, the current time is used. Use mtime = 0 - to generate a compressed stream that does not depend on creation time. + Set mtime to 0 to generate a compressed stream that does not depend on + creation time. If mtime is omitted or None, the current time is used. + If the resulting mtime is outside the range 0 to 2**32-1, then the + value 0 is used instead. """ @@ -295,6 +297,8 @@ def _write_gzip_header(self, compresslevel): mtime = self._write_mtime if mtime is None: mtime = time.time() + if not 0 <= mtime < 2**32: + mtime = 0 write32u(self.fileobj, int(mtime)) if compresslevel == _COMPRESS_LEVEL_BEST: xfl = b'\002' @@ -663,6 +667,8 @@ def compress(data, compresslevel=_COMPRESS_LEVEL_TRADEOFF, *, mtime=0): gzip_data = zlib.compress(data, level=compresslevel, wbits=31) if mtime is None: mtime = time.time() + if not 0 <= mtime < 2**32: + mtime = 0 # Reuse gzip header created by zlib, replace mtime and OS byte for # consistency. header = struct.pack("<4sLBB", gzip_data, int(mtime), gzip_data[8], 255) diff --git a/Lib/test/test_gzip.py b/Lib/test/test_gzip.py index b3b7c8f87e4f9f..cafac9d3c8be6e 100644 --- a/Lib/test/test_gzip.py +++ b/Lib/test/test_gzip.py @@ -10,6 +10,7 @@ import sys import unittest from subprocess import PIPE, Popen +from unittest import mock from test.support import catch_unraisable_exception from test.support import force_not_colorized_test_class, import_helper from test.support import os_helper @@ -350,6 +351,26 @@ def test_mtime(self): self.assertEqual(dataRead, data1) self.assertEqual(fRead.mtime, mtime) + def test_mtime_out_of_range(self): + for mtime in (-1, 2**32): + with gzip.GzipFile(self.filename, 'w', mtime=mtime) as fWrite: + fWrite.write(data1) + with gzip.GzipFile(self.filename) as fRead: + fRead.read(1) + self.assertEqual(fRead.mtime, 0) + datac = gzip.compress(data1, mtime=mtime) + with gzip.GzipFile(fileobj=io.BytesIO(datac)) as fRead: + fRead.read(1) + self.assertEqual(fRead.mtime, 0) + + for mtime in (-1, 2**32): + with mock.patch('time.time', return_value=float(mtime)): + with gzip.GzipFile(self.filename, 'w') as fWrite: + fWrite.write(data1) + with gzip.GzipFile(self.filename) as fRead: + fRead.read(1) + self.assertEqual(fRead.mtime, 0) + def test_metadata(self): mtime = 123456789 diff --git a/Misc/NEWS.d/next/Library/2025-05-19-20-29-35.gh-issue-133998.KmElUw.rst b/Misc/NEWS.d/next/Library/2025-05-19-20-29-35.gh-issue-133998.KmElUw.rst new file mode 100644 index 00000000000000..77d92628beefac --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-05-19-20-29-35.gh-issue-133998.KmElUw.rst @@ -0,0 +1,5 @@ +Fix :exc:`struct.error` exception when creating a file with +:class:`gzip.GzipFile` or compressing data with :func:`gzip.compress` +if the system time is outside the range 00:00:00 UTC, January 1, 1970 +through 06:28:15 UTC, February 7, 2106, or explicitly passed *mtime* +argument is outside the range ``0`` to ``2**32-1``. From e192a0ea521cdeac1531ddefb08df0db76c0207f Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 22 May 2026 11:46:14 +0200 Subject: [PATCH 110/818] [3.15] gh-137571: Protect against possible UnboundLocalError in gzip._GzipReader.read() (GH-150222) (GH-150229) This has not been observed in practice, but we cannot be 100% sure that it will not happen with some weird gzip data. (cherry picked from commit 28eac9a7263ad8dcfa9b536aa238549131857e0f) Co-authored-by: Serhiy Storchaka --- Lib/gzip.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/gzip.py b/Lib/gzip.py index 8720acc4db9976..0713b922522ee1 100644 --- a/Lib/gzip.py +++ b/Lib/gzip.py @@ -610,10 +610,10 @@ def read(self, size=-1): # Read a chunk of data from the file if self._decompressor.needs_input: buf = self._fp.read(READ_BUFFER_SIZE) - uncompress = self._decompressor.decompress(buf, size) else: - uncompress = self._decompressor.decompress(b"", size) + buf = b"" + uncompress = self._decompressor.decompress(buf, size) if self._decompressor.unused_data != b"": # Prepend the already read bytes to the fileobj so they can # be seen by _read_eof() and _read_gzip_header() From 50c5c07d2f465402398954232b2136bab966177c Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 22 May 2026 13:40:49 +0200 Subject: [PATCH 111/818] [3.15] gh-149902: Remove dead packaging docs link and add a new section for external resources (GH-150030) (#150241) Co-authored-by: Mia Albert Co-authored-by: Stan Ulbrych Co-authored-by: Ned Batchelder Co-authored-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> --- Doc/tools/templates/indexcontent.html | 152 ++++++++++++++++---------- 1 file changed, 97 insertions(+), 55 deletions(-) diff --git a/Doc/tools/templates/indexcontent.html b/Doc/tools/templates/indexcontent.html index 544cc4234f441e..4982bcbfe3673c 100644 --- a/Doc/tools/templates/indexcontent.html +++ b/Doc/tools/templates/indexcontent.html @@ -14,6 +14,35 @@ + {%- endblock -%} {% block body %}

{{ docstitle|e }}

@@ -21,63 +50,76 @@

{{ docstitle|e }}

{% trans %}Welcome! This is the official documentation for Python {{ release }}.{% endtrans %}

{% trans %}Documentation sections:{% endtrans %}

- - -
- - - - - - - - - - - - - -
+
+ + +
+ +

{% trans %}Other resources:{% endtrans %}

+
+ + +

{% trans %}Indices, glossary, and search:{% endtrans %}

- - -
- - - - - - -
+
+ + +

{% trans %}Project information:{% endtrans %}

- - -
- - - - - - - -
+ {% endblock %} From b79112fb349ccc0b807610dd31a50712a8bbf6d8 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 22 May 2026 16:44:08 +0200 Subject: [PATCH 112/818] [3.15] CI: Move Homebrew dependencies into Brewfile (GH-148335) (#149882) Co-authored-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> Co-authored-by: Brett Cannon --- .github/workflows/reusable-macos.yml | 5 ++--- Misc/Brewfile | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 3 deletions(-) create mode 100644 Misc/Brewfile diff --git a/.github/workflows/reusable-macos.yml b/.github/workflows/reusable-macos.yml index f10503055b2259..93b419159fa817 100644 --- a/.github/workflows/reusable-macos.yml +++ b/.github/workflows/reusable-macos.yml @@ -38,9 +38,8 @@ jobs: run: echo "IMAGE_OS_VERSION=${ImageOS}-${ImageVersion}" >> "$GITHUB_ENV" - name: Install Homebrew dependencies run: | - brew install pkg-config openssl@3.5 xz gdbm tcl-tk@9 make - # Because alternate versions are not symlinked into place by default: - brew link --overwrite tcl-tk@9 + brew bundle --file=Misc/Brewfile + brew install make - name: Configure CPython run: | MACOSX_DEPLOYMENT_TARGET=10.15 \ diff --git a/Misc/Brewfile b/Misc/Brewfile new file mode 100644 index 00000000000000..c799f099957f75 --- /dev/null +++ b/Misc/Brewfile @@ -0,0 +1,14 @@ +brew "gdbm" +brew "mpdecimal" +brew "openssl@3.5" +brew "pkg-config" +brew "tcl-tk@9" +brew "xz" +brew "zstd" + +brew "bzip2" if OS.linux? +brew "libedit" if OS.linux? +brew "libffi" if OS.linux? +brew "ncurses" if OS.linux? +brew "unzip" if OS.linux? +brew "zlib-ng-compat" if OS.linux? From f5231469b5516015de93553977303610ceb405cd Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 22 May 2026 16:44:34 +0200 Subject: [PATCH 113/818] [3.15] gh-148829: Make sentinels' repr and module customizable (GH-149654) (#150092) Implementation of python/peps#4968. (cherry picked from commit 08218030a507b2ef38db9696216bf3eb24d9a6a1) Co-authored-by: Jelle Zijlstra --- Doc/c-api/sentinel.rst | 4 +- Doc/data/python3.15.abi | 2171 +++++++++-------- Doc/data/refcounts.dat | 1 + Doc/library/functions.rst | 12 +- Include/cpython/sentinelobject.h | 3 +- .../pycore_global_objects_fini_generated.h | 1 + Include/internal/pycore_global_strings.h | 1 + .../internal/pycore_runtime_init_generated.h | 1 + .../internal/pycore_unicodeobject_generated.h | 4 + Lib/test/test_builtin.py | 23 +- Lib/test/test_capi/test_object.py | 6 + ...-05-10-16-43-50.gh-issue-148829.gscS14.rst | 2 + Modules/_testcapi/object.c | 5 +- Objects/clinic/sentinelobject.c.h | 62 +- Objects/sentinelobject.c | 42 +- 15 files changed, 1228 insertions(+), 1110 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-05-10-16-43-50.gh-issue-148829.gscS14.rst diff --git a/Doc/c-api/sentinel.rst b/Doc/c-api/sentinel.rst index 937cae18e86f50..b1b7329a5d42c5 100644 --- a/Doc/c-api/sentinel.rst +++ b/Doc/c-api/sentinel.rst @@ -31,12 +31,12 @@ Sentinel objects .. versionadded:: 3.15 -.. c:function:: PyObject* PySentinel_New(const char *name, const char *module_name) +.. c:function:: PyObject* PySentinel_New(const char *name, const char *module_name, const char *repr) Return a new :class:`sentinel` object with :attr:`~sentinel.__name__` set to *name* and :attr:`~sentinel.__module__` set to *module_name*. *name* must not be ``NULL``. If *module_name* is ``NULL``, :attr:`~sentinel.__module__` - is set to ``None``. + is set to ``None``. If *repr* is ``NULL``, ``repr()`` returns :attr:`~sentinel.__name__`. Return ``NULL`` with an exception set on failure. For pickling to work, *module_name* must be the name of an importable diff --git a/Doc/data/python3.15.abi b/Doc/data/python3.15.abi index 04211b6e4e274a..aea9ff48a62763 100644 --- a/Doc/data/python3.15.abi +++ b/Doc/data/python3.15.abi @@ -1996,7 +1996,7 @@ - + @@ -2020,13 +2020,13 @@ - + - + @@ -2983,7 +2983,7 @@ - + @@ -5844,6 +5844,11 @@ + + + + + @@ -5893,115 +5898,115 @@ - - + + - - - + + + - - + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - + + + - - - + + + - - + + - - - + + + - - - + + + - - + + - - + + - - - + + + - - - + + + - - + + - - - + + + - - - + + + - - - - + + + + - - - - + + + + - - - + + + @@ -7569,295 +7574,295 @@ - - - + + + - - - - + + + + - - - + + + - - - - - + + + + + - - - - - + + + + + - - + + - - - + + + - - - - + + + + - - - + + + - - - - + + + + - - - - - + + + + + - - - - - + + + + + - - - + + + - - - - + + + + - - - - - + + + + + - - - - + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - + + + + - - - - + + + + - - - - - + + + + + - - + + - - - - + + + + - - - - + + + + - - - - + + + + - - - + + + - - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + + - - + + - - - - - + + + + + - - - - + + + + - - + + - - - + + + - - - + + + - - - - + + + + - - - + + + - - - - + + + + - - - - + + + + - - + + - - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - + + + - - + + - - + + - - - - - - + + + + + + - - + + @@ -9154,11 +9159,6 @@ - - - - - @@ -11398,9 +11398,10 @@ - - - + + + + @@ -11811,7 +11812,7 @@ - + @@ -11917,135 +11918,135 @@ - - + + - - - - - + + + + + - - - - + + + + - - + + - - + + - - - + + + - - + + - - + + - - + + - - + + - - - + + + - - - + + + - - - + + + - - - - + + + + - - - - + + + + - - - + + + - - - + + + - - + + - - + + - - + + - - - - + + + + - - - + + + - - - - + + + + - - - + + + - + - - + + - - - - - + + + + + @@ -12456,7 +12457,7 @@ - + @@ -15603,10 +15604,10 @@ - + - + @@ -18594,7 +18595,7 @@ - + @@ -19086,8 +19087,14 @@ + + + + + + - + @@ -19308,18 +19315,18 @@ - + - + - - + + - - + + @@ -19503,7 +19510,7 @@ - + @@ -21593,427 +21600,430 @@ - + - + - - + + - - + + - + - - + + - - + + - + - + - - + + - - + + - + - - + + - - + + - - + + - + - + - + - - + + - + - - + + - - + + - + - + - + - - + + - - + + - - + + - + - - + + - + - - + + - - + + - - + + - + - + - + - - + + - + - + - + - - + + - - + + - - + + - + - + - + - + - - + + - + - + - - + + - - + + - - + + - + - - + + - - + + - + - + - + - + - + - + - + - - + + - - + + - - + + - + - - + + - + - + - - + + - - + + - + - + - - + + - + - - + + - + - - + + - - + + - - + + - + - + - - + + - + - + - + - - + + - + - + - + - + - + - - + + - - + + - - + + - - + + - - + + - + - - + + - - + + - - + + - + - + - - + + - + - + - + - - + + - + - + - + - + - - + + - + - - + + - + - + - - + + - + - + - + - + - - + + - - + + - - + + - - + + - + - + - + - + - + - + - - + + - + - - + + - + - - + + - + - + + + + @@ -22136,20 +22146,20 @@ - + - + - + - + - + - + @@ -22556,7 +22566,7 @@ - + @@ -22591,306 +22601,309 @@ - + - + - - + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - + + - + - + - + - + - + - + - + - + - + - - + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -22902,405 +22915,405 @@ - - + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - + - - + + - + - - + + - - + + - + - + - + - + - + - + - - + + - + - + - - + + - - + + - + - + - + - - + + - - + + - - + + - - + + - - + + - + - + - + - - + + - - + + - - - - - + + - + + + + - - + + - - + + - + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - + - + - + - + - + - + - + - + - + - + - - - - - + + - + + + + - + - + - - + + - - + + - - + + - - + + - - + + - + - + + + + - + - + - + - + - + - + - + @@ -23721,12 +23734,12 @@ - + - + @@ -23739,19 +23752,19 @@ - + - + - + - + - + @@ -23763,7 +23776,7 @@ - + @@ -23887,7 +23900,7 @@ - + @@ -27444,108 +27457,108 @@ - - - - - - - - - + + + + + + + + + - - - - + + + + - - - - - + + + + + - - - + + + - - - + + + - - - - + + + + - - - - - + + + + + - - - - - + + + + + - - - - + + + + - - - - + + + + - - + + - - + + - - - - - + + + + + - - - + + + - - - - + + + + - - - - - + + + + + - - - + + + @@ -30145,128 +30158,128 @@ - + - - - + + + - - + + - - + + - - + + - - + + - - - - + + + + - - - + + + - - + + - - - + + + - - - + + + - - + + - - - + + + - + - + - - - + + + - - - - + + + + - - - - - + + + + + - - - - - + + + + + - - + + - - + + - - + + - - + + - - - + + + - - + + - + - - + + - + @@ -32221,7 +32234,7 @@ - + @@ -32481,147 +32494,147 @@ - + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - - + + + - - + + - - + + - - + + - + - - + + - - + + - - - + + + - + - + - - + + - - + + - + - + - - + + - - - + + + - - - + + + - - + + - - + + - - + + - + - - + + - + - - + + - - + + - + - - + + - - + + - - + + @@ -33164,7 +33177,7 @@ - + @@ -33192,13 +33205,13 @@ - + - + diff --git a/Doc/data/refcounts.dat b/Doc/data/refcounts.dat index 663b79e45eec17..60c02aabeb89c5 100644 --- a/Doc/data/refcounts.dat +++ b/Doc/data/refcounts.dat @@ -2040,6 +2040,7 @@ PySeqIter_New:PyObject*:seq:0: PySentinel_New:PyObject*::+1: PySentinel_New:const char*:name:: PySentinel_New:const char*:module_name:: +PySentinel_New:const char*:repr:: PySequence_Check:int::: PySequence_Check:PyObject*:o:0: diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst index 1fed142d81b4f7..0393e2dc776db4 100644 --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -1827,15 +1827,21 @@ are always available. They are listed here in alphabetical order. :func:`setattr`. -.. class:: sentinel(name, /) +.. class:: sentinel(name, /, *, repr=None) Return a new unique sentinel object. *name* must be a :class:`str`, and is - used as the returned object's representation:: + used by default as the returned object's representation:: >>> MISSING = sentinel("MISSING") >>> MISSING MISSING + The optional *repr* argument can be used to specify a different representation:: + + >>> MISSING = sentinel("MISSING", repr="") + >>> MISSING + + Sentinel objects are truthy and compare equal only to themselves. They are intended to be compared with the :keyword:`is` operator. @@ -1879,7 +1885,7 @@ are always available. They are listed here in alphabetical order. .. attribute:: __module__ - The name of the module where the sentinel was created. + The name of the module where the sentinel was created. This attribute is writable. .. versionadded:: 3.15 diff --git a/Include/cpython/sentinelobject.h b/Include/cpython/sentinelobject.h index 15643ef966af86..e621d6abbfed8a 100644 --- a/Include/cpython/sentinelobject.h +++ b/Include/cpython/sentinelobject.h @@ -16,7 +16,8 @@ PyAPI_DATA(PyTypeObject) PySentinel_Type; PyAPI_FUNC(PyObject *) PySentinel_New( const char *name, - const char *module_name); + const char *module_name, + const char *repr); #ifdef __cplusplus } diff --git a/Include/internal/pycore_global_objects_fini_generated.h b/Include/internal/pycore_global_objects_fini_generated.h index f7d3dcd440aaf1..f8bab372f1e505 100644 --- a/Include/internal/pycore_global_objects_fini_generated.h +++ b/Include/internal/pycore_global_objects_fini_generated.h @@ -2031,6 +2031,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(repeat)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(repl)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(replace)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(repr)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(reqrefs)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(require_ready)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(reserved)); diff --git a/Include/internal/pycore_global_strings.h b/Include/internal/pycore_global_strings.h index 22494b1798cc53..32dfb9677ecdfe 100644 --- a/Include/internal/pycore_global_strings.h +++ b/Include/internal/pycore_global_strings.h @@ -754,6 +754,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(repeat) STRUCT_FOR_ID(repl) STRUCT_FOR_ID(replace) + STRUCT_FOR_ID(repr) STRUCT_FOR_ID(reqrefs) STRUCT_FOR_ID(require_ready) STRUCT_FOR_ID(reserved) diff --git a/Include/internal/pycore_runtime_init_generated.h b/Include/internal/pycore_runtime_init_generated.h index 892c3cdd9623a2..b5ec50968db222 100644 --- a/Include/internal/pycore_runtime_init_generated.h +++ b/Include/internal/pycore_runtime_init_generated.h @@ -2029,6 +2029,7 @@ extern "C" { INIT_ID(repeat), \ INIT_ID(repl), \ INIT_ID(replace), \ + INIT_ID(repr), \ INIT_ID(reqrefs), \ INIT_ID(require_ready), \ INIT_ID(reserved), \ diff --git a/Include/internal/pycore_unicodeobject_generated.h b/Include/internal/pycore_unicodeobject_generated.h index f0fc3c4f5b0900..00915c23f4b75c 100644 --- a/Include/internal/pycore_unicodeobject_generated.h +++ b/Include/internal/pycore_unicodeobject_generated.h @@ -2796,6 +2796,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_ID(repr); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(reqrefs); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); diff --git a/Lib/test/test_builtin.py b/Lib/test/test_builtin.py index 81967fb8a83740..d62a3a4f17f85e 100644 --- a/Lib/test/test_builtin.py +++ b/Lib/test/test_builtin.py @@ -1956,16 +1956,33 @@ def test_sentinel(self): with self.assertRaises(TypeError): class SubSentinel(sentinel): pass + + def test_sentinel_attributes(self): + missing = sentinel("MISSING") with self.assertRaises(TypeError): sentinel.attribute = "value" with self.assertRaises(AttributeError): - missing.__name__ = "CHANGED" + missing.attribute = "value" with self.assertRaises(AttributeError): - missing.__module__ = "changed" + missing.__name__ = "CHANGED" + missing.__module__ = "changed" + self.assertEqual(missing.__module__, "changed") with self.assertRaises(AttributeError): del missing.__name__ + del missing.__module__ with self.assertRaises(AttributeError): - del missing.__module__ + missing.__module__ + + def test_sentinel_repr(self): + with_repr = sentinel("WITH_REPR", repr="custom") + without_repr = sentinel("WITHOUT_REPR", repr=None) + self.assertEqual(repr(with_repr), "custom") + self.assertEqual(repr(without_repr), "WITHOUT_REPR") + self.assertEqual(str(with_repr), "custom") + self.assertEqual(str(without_repr), "WITHOUT_REPR") + + with self.assertRaisesRegex(TypeError, "repr.*str or None"): + sentinel("BAD_REPR", repr=42) def test_sentinel_pickle(self): for proto in range(pickle.HIGHEST_PROTOCOL + 1): diff --git a/Lib/test/test_capi/test_object.py b/Lib/test/test_capi/test_object.py index e6fd068dc20d8d..e5c50902a0118d 100644 --- a/Lib/test/test_capi/test_object.py +++ b/Lib/test/test_capi/test_object.py @@ -82,6 +82,12 @@ def test_pysentinel_new(self): self.assertEqual(no_module.__name__, "NO_MODULE") self.assertIs(no_module.__module__, None) + with_repr = _testcapi.pysentinel_new("WITH_REPR", __name__, "custom repr") + self.assertIs(type(with_repr), sentinel) + self.assertEqual(with_repr.__name__, "WITH_REPR") + self.assertEqual(with_repr.__module__, __name__) + self.assertEqual(repr(with_repr), "custom repr") + globals()["CAPI_SENTINEL"] = marker self.addCleanup(globals().pop, "CAPI_SENTINEL", None) self.assertIs(pickle.loads(pickle.dumps(marker)), marker) diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-10-16-43-50.gh-issue-148829.gscS14.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-10-16-43-50.gh-issue-148829.gscS14.rst new file mode 100644 index 00000000000000..3f9b1ccb518787 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-10-16-43-50.gh-issue-148829.gscS14.rst @@ -0,0 +1,2 @@ +:class:`sentinel` objects now support a ``repr=`` argument and their +:attr:`~sentinel.__module__` attribute is writable. diff --git a/Modules/_testcapi/object.c b/Modules/_testcapi/object.c index c62dc1144df688..09a548fd2e2448 100644 --- a/Modules/_testcapi/object.c +++ b/Modules/_testcapi/object.c @@ -560,10 +560,11 @@ pysentinel_new(PyObject *self, PyObject *args) { const char *name; const char *module_name = NULL; - if (!PyArg_ParseTuple(args, "s|s", &name, &module_name)) { + const char *repr = NULL; + if (!PyArg_ParseTuple(args, "s|ss", &name, &module_name, &repr)) { return NULL; } - return PySentinel_New(name, module_name); + return PySentinel_New(name, module_name, repr); } static PyObject * diff --git a/Objects/clinic/sentinelobject.c.h b/Objects/clinic/sentinelobject.c.h index 51fd35a5979e31..f8503194ae5c74 100644 --- a/Objects/clinic/sentinelobject.c.h +++ b/Objects/clinic/sentinelobject.c.h @@ -2,33 +2,71 @@ preserve [clinic start generated code]*/ -#include "pycore_modsupport.h" // _PyArg_CheckPositional() +#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +# include "pycore_gc.h" // PyGC_Head +# include "pycore_runtime.h" // _Py_ID() +#endif +#include "pycore_modsupport.h" // _PyArg_UnpackKeywords() static PyObject * -sentinel_new_impl(PyTypeObject *type, PyObject *name); +sentinel_new_impl(PyTypeObject *type, PyObject *name, PyObject *repr); static PyObject * sentinel_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) { PyObject *return_value = NULL; - PyTypeObject *base_tp = &PySentinel_Type; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(repr), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"", "repr", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "sentinel", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[2]; + PyObject * const *fastargs; + Py_ssize_t nargs = PyTuple_GET_SIZE(args); + Py_ssize_t noptargs = nargs + (kwargs ? PyDict_GET_SIZE(kwargs) : 0) - 1; PyObject *name; + PyObject *repr = Py_None; - if ((type == base_tp || type->tp_init == base_tp->tp_init) && - !_PyArg_NoKeywords("sentinel", kwargs)) { + fastargs = _PyArg_UnpackKeywords(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser, + /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!fastargs) { goto exit; } - if (!_PyArg_CheckPositional("sentinel", PyTuple_GET_SIZE(args), 1, 1)) { + if (!PyUnicode_Check(fastargs[0])) { + _PyArg_BadArgument("sentinel", "argument 1", "str", fastargs[0]); goto exit; } - if (!PyUnicode_Check(PyTuple_GET_ITEM(args, 0))) { - _PyArg_BadArgument("sentinel", "argument 1", "str", PyTuple_GET_ITEM(args, 0)); - goto exit; + name = fastargs[0]; + if (!noptargs) { + goto skip_optional_kwonly; } - name = PyTuple_GET_ITEM(args, 0); - return_value = sentinel_new_impl(type, name); + repr = fastargs[1]; +skip_optional_kwonly: + return_value = sentinel_new_impl(type, name, repr); exit: return return_value; } -/*[clinic end generated code: output=7f28fc0bf0259cba input=a9049054013a1b77]*/ +/*[clinic end generated code: output=958842ece254c82f input=a9049054013a1b77]*/ diff --git a/Objects/sentinelobject.c b/Objects/sentinelobject.c index e7e9f60e3edfbe..77bffbc397be58 100644 --- a/Objects/sentinelobject.c +++ b/Objects/sentinelobject.c @@ -14,6 +14,7 @@ typedef struct { PyObject_HEAD PyObject *name; PyObject *module; + PyObject *repr; } sentinelobject; #define sentinelobject_CAST(op) \ @@ -46,7 +47,7 @@ caller(void) } static PyObject * -sentinel_new_with_module(PyTypeObject *type, PyObject *name, PyObject *module) +sentinel_new_with_module(PyTypeObject *type, PyObject *name, PyObject *module, PyObject *repr) { assert(PyUnicode_Check(name)); @@ -56,6 +57,7 @@ sentinel_new_with_module(PyTypeObject *type, PyObject *name, PyObject *module) } self->name = Py_NewRef(name); self->module = Py_NewRef(module); + self->repr = Py_XNewRef(repr); _PyObject_GC_TRACK(self); return (PyObject *)self; } @@ -66,37 +68,56 @@ sentinel.__new__ as sentinel_new name: object(subclass_of='&PyUnicode_Type') / + * + repr: object = None [clinic start generated code]*/ static PyObject * -sentinel_new_impl(PyTypeObject *type, PyObject *name) -/*[clinic end generated code: output=4af55c6048bed30d input=3ab75704f39c119c]*/ +sentinel_new_impl(PyTypeObject *type, PyObject *name, PyObject *repr) +/*[clinic end generated code: output=1eb7fab52e57d8c8 input=28cab6c468997b35]*/ { + if (repr == Py_None) { + repr = NULL; + } + else if (!PyUnicode_Check(repr)) { + _PyArg_BadArgument("sentinel", "argument 'repr'", "str or None", repr); + return NULL; + } PyObject *module = caller(); - PyObject *self = sentinel_new_with_module(type, name, module); + PyObject *self = sentinel_new_with_module(type, name, module, repr); Py_DECREF(module); return self; } PyObject * -PySentinel_New(const char *name, const char *module_name) +PySentinel_New(const char *name, const char *module_name, const char *repr) { PyObject *name_obj = PyUnicode_FromString(name); if (name_obj == NULL) { return NULL; } + PyObject *repr_obj = NULL; + if (repr != NULL) { + repr_obj = PyUnicode_FromString(repr); + if (repr_obj == NULL) { + Py_DECREF(name_obj); + return NULL; + } + } PyObject *module_obj = module_name == NULL ? Py_None : PyUnicode_FromString(module_name); if (module_obj == NULL) { Py_DECREF(name_obj); + Py_XDECREF(repr_obj); return NULL; } PyObject *sentinel = sentinel_new_with_module( - &PySentinel_Type, name_obj, module_obj); + &PySentinel_Type, name_obj, module_obj, repr_obj); Py_DECREF(module_obj); Py_DECREF(name_obj); + Py_XDECREF(repr_obj); return sentinel; } @@ -106,6 +127,7 @@ sentinel_clear(PyObject *op) sentinelobject *self = sentinelobject_CAST(op); Py_CLEAR(self->name); Py_CLEAR(self->module); + Py_CLEAR(self->repr); return 0; } @@ -123,6 +145,7 @@ sentinel_traverse(PyObject *op, visitproc visit, void *arg) sentinelobject *self = sentinelobject_CAST(op); Py_VISIT(self->name); Py_VISIT(self->module); + Py_VISIT(self->repr); return 0; } @@ -130,6 +153,9 @@ static PyObject * sentinel_repr(PyObject *op) { sentinelobject *self = sentinelobject_CAST(op); + if (self->repr != NULL) { + return Py_NewRef(self->repr); + } return Py_NewRef(self->name); } @@ -161,7 +187,7 @@ static PyMethodDef sentinel_methods[] = { static PyMemberDef sentinel_members[] = { {"__name__", Py_T_OBJECT_EX, offsetof(sentinelobject, name), Py_READONLY}, - {"__module__", Py_T_OBJECT_EX, offsetof(sentinelobject, module), Py_READONLY}, + {"__module__", Py_T_OBJECT_EX, offsetof(sentinelobject, module), 0}, {NULL} }; @@ -170,7 +196,7 @@ static PyNumberMethods sentinel_as_number = { }; PyDoc_STRVAR(sentinel_doc, -"sentinel(name, /)\n" +"sentinel(name, /, *, repr=None)\n" "--\n\n" "Create a unique sentinel object with the given name."); From 3daf1fad7ad926ef0ba7bbc5f468fa9501df8cde Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 22 May 2026 22:49:36 +0200 Subject: [PATCH 114/818] [3.15] gh-149189: Revert "Modern defaults for `pprint` (GH-149190)" (GH-150249) (#150268) Co-authored-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> --- Doc/library/difflib.rst | 22 +- Doc/library/pprint.rst | 396 ++++++---- Doc/library/ssl.rst | 122 ++- Doc/library/unittest.mock.rst | 10 +- Doc/tutorial/stdlib2.rst | 21 +- Doc/whatsnew/3.15.rst | 9 +- Lib/difflib.py | 42 +- Lib/pprint.py | 178 +++-- Lib/test/test_descrtut.py | 98 ++- Lib/test/test_pickle.py | 6 +- Lib/test/test_pprint.py | 693 ++++++++++-------- Lib/test/test_stable_abi_ctypes.py | 28 +- .../test_unittest/testmock/testhelpers.py | 4 +- ...-05-18-17-17-20.gh-issue-149189.a8IooK.rst | 1 + 14 files changed, 868 insertions(+), 762 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-05-18-17-17-20.gh-issue-149189.a8IooK.rst diff --git a/Doc/library/difflib.rst b/Doc/library/difflib.rst index e5afa174413541..8b812c173b5953 100644 --- a/Doc/library/difflib.rst +++ b/Doc/library/difflib.rst @@ -728,18 +728,16 @@ Finally, we compare the two: >>> from pprint import pprint >>> pprint(result) - [ - ' 1. Beautiful is better than ugly.\n', - '- 2. Explicit is better than implicit.\n', - '- 3. Simple is better than complex.\n', - '+ 3. Simple is better than complex.\n', - '? ++\n', - '- 4. Complex is better than complicated.\n', - '? ^ ---- ^\n', - '+ 4. Complicated is better than complex.\n', - '? ++++ ^ ^\n', - '+ 5. Flat is better than nested.\n', - ] + [' 1. Beautiful is better than ugly.\n', + '- 2. Explicit is better than implicit.\n', + '- 3. Simple is better than complex.\n', + '+ 3. Simple is better than complex.\n', + '? ++\n', + '- 4. Complex is better than complicated.\n', + '? ^ ---- ^\n', + '+ 4. Complicated is better than complex.\n', + '? ++++ ^ ^\n', + '+ 5. Flat is better than nested.\n'] As a single multi-line string it looks like this: diff --git a/Doc/library/pprint.rst b/Doc/library/pprint.rst index d62ef1f4d1e6b1..4f043fbb3a46df 100644 --- a/Doc/library/pprint.rst +++ b/Doc/library/pprint.rst @@ -17,7 +17,7 @@ objects which are not representable as Python literals. The formatted representation keeps objects on a single line if it can, and breaks them onto multiple lines if they don't fit within the allowed width, -adjustable by the *width* parameter defaulting to 88 characters. +adjustable by the *width* parameter defaulting to 80 characters. .. versionchanged:: 3.9 Added support for pretty-printing :class:`types.SimpleNamespace`. @@ -30,8 +30,9 @@ adjustable by the *width* parameter defaulting to 88 characters. Functions --------- -.. function:: pp(object, stream=None, indent=4, width=88, depth=None, *, \ - compact=False, sort_dicts=False, underscore_numbers=False) +.. function:: pp(object, stream=None, indent=1, width=80, depth=None, *, \ + compact=False, expand=False, sort_dicts=False, \ + underscore_numbers=False) Prints the formatted representation of *object*, followed by a newline. This function may be used in the interactive interpreter @@ -66,11 +67,16 @@ Functions :param bool compact: Control the way long :term:`sequences ` are formatted. If ``False`` (the default), + each item of a sequence will be formatted on a separate line, + otherwise as many items as will fit within the *width* + will be formatted on each output line. + Incompatible with *expand*. + + :param bool expand: + If ``True``, opening parentheses and brackets will be followed by a newline and the following content will be indented by one level, similar to - pretty-printed JSON. - If ``True``, as many items as will fit within the *width* - will be formatted on each output line. + pretty-printed JSON. Incompatible with *compact*. :param bool sort_dicts: If ``True``, dictionaries will be formatted with @@ -85,25 +91,32 @@ Functions >>> import pprint >>> stuff = ['spam', 'eggs', 'lumberjack', 'knights', 'ni'] >>> stuff.insert(0, stuff) - >>> pprint.pp(stuff, width=100) - [, 'spam', 'eggs', 'lumberjack', 'knights', 'ni'] + >>> pprint.pp(stuff) + [, + 'spam', + 'eggs', + 'lumberjack', + 'knights', + 'ni'] .. versionadded:: 3.8 -.. function:: pprint(object, stream=None, indent=4, width=88, depth=None, *, \ - compact=False, sort_dicts=True, underscore_numbers=False) +.. function:: pprint(object, stream=None, indent=1, width=80, depth=None, *, \ + compact=False, expand=False, sort_dicts=True, \ + underscore_numbers=False) Alias for :func:`~pprint.pp` with *sort_dicts* set to ``True`` by default, which would automatically sort the dictionaries' keys, you might want to use :func:`~pprint.pp` instead where it is ``False`` by default. -.. function:: pformat(object, indent=4, width=88, depth=None, *, \ - compact=False, sort_dicts=True, underscore_numbers=False) +.. function:: pformat(object, indent=1, width=80, depth=None, *, \ + compact=False, expand=False, sort_dicts=True, \ + underscore_numbers=False) Return the formatted representation of *object* as a string. *indent*, - *width*, *depth*, *compact*, *sort_dicts* and *underscore_numbers* are + *width*, *depth*, *compact*, *expand*, *sort_dicts* and *underscore_numbers* are passed to the :class:`PrettyPrinter` constructor as formatting parameters and their meanings are as described in the documentation above. @@ -141,13 +154,13 @@ Functions .. _prettyprinter-objects: -PrettyPrinter objects +PrettyPrinter Objects --------------------- .. index:: single: ...; placeholder -.. class:: PrettyPrinter(indent=4, width=88, depth=None, stream=None, *, \ - compact=False, sort_dicts=True, \ +.. class:: PrettyPrinter(indent=1, width=80, depth=None, stream=None, *, \ + compact=False, expand=False, sort_dicts=True, \ underscore_numbers=False) Construct a :class:`PrettyPrinter` instance. @@ -158,23 +171,21 @@ PrettyPrinter objects >>> import pprint >>> stuff = ['spam', 'eggs', 'lumberjack', 'knights', 'ni'] >>> stuff.insert(0, stuff[:]) - >>> pp = pprint.PrettyPrinter() + >>> pp = pprint.PrettyPrinter(indent=4) >>> pp.pprint(stuff) - [ - ['spam', 'eggs', 'lumberjack', 'knights', 'ni'], + [ ['spam', 'eggs', 'lumberjack', 'knights', 'ni'], 'spam', 'eggs', 'lumberjack', 'knights', - 'ni', - ] - >>> pp = pprint.PrettyPrinter(indent=1, width=41, compact=True) + 'ni'] + >>> pp = pprint.PrettyPrinter(width=41, compact=True) >>> pp.pprint(stuff) [['spam', 'eggs', 'lumberjack', 'knights', 'ni'], 'spam', 'eggs', 'lumberjack', 'knights', 'ni'] - >>> pp = pprint.PrettyPrinter(width=41, indent=3) + >>> pp = pprint.PrettyPrinter(width=41, expand=True, indent=3) >>> pp.pprint(stuff) [ [ @@ -210,11 +221,7 @@ PrettyPrinter objects No longer attempts to write to :data:`!sys.stdout` if it is ``None``. .. versionchanged:: 3.15 - Changed default *indent* from 1 to 4 - and default *width* from 80 to 88. - The default ``compact=False`` layout is now similar to - pretty-printed JSON, with opening parentheses and brackets - followed by a newline and the contents indented by one level. + Added the *expand* parameter. :class:`PrettyPrinter` instances have the following methods: @@ -291,144 +298,219 @@ let's fetch information about a project from `PyPI `_:: In its basic form, :func:`~pprint.pp` shows the whole object:: >>> pprint.pp(project_info) - { - 'author': 'The Python Packaging Authority', - 'author_email': 'pypa-dev@googlegroups.com', - 'bugtrack_url': None, - 'classifiers': [ - 'Development Status :: 3 - Alpha', - 'Intended Audience :: Developers', - 'License :: OSI Approved :: MIT License', - 'Programming Language :: Python :: 2', - 'Programming Language :: Python :: 2.6', - 'Programming Language :: Python :: 2.7', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.2', - 'Programming Language :: Python :: 3.3', - 'Programming Language :: Python :: 3.4', - 'Topic :: Software Development :: Build Tools', - ], - 'description': 'A sample Python project\n' - '=======================\n' - '\n' - 'This is the description file for the project.\n' - '\n' - 'The file should use UTF-8 encoding and be written using ReStructured Text. It\n' - 'will be used to generate the project webpage on PyPI, and should be written for\n' - 'that purpose.\n' - '\n' - 'Typical contents for this file would include an overview of the project, basic\n' - 'usage examples, etc. Generally, including the project changelog in here is not\n' - 'a good idea, although a simple "What\'s New" section for the most recent version\n' - 'may be appropriate.', - 'description_content_type': None, - 'docs_url': None, - 'download_url': 'UNKNOWN', - 'downloads': {'last_day': -1, 'last_month': -1, 'last_week': -1}, - 'home_page': 'https://github.com/pypa/sampleproject', - 'keywords': 'sample setuptools development', - 'license': 'MIT', - 'maintainer': None, - 'maintainer_email': None, - 'name': 'sampleproject', - 'package_url': 'https://pypi.org/project/sampleproject/', - 'platform': 'UNKNOWN', - 'project_url': 'https://pypi.org/project/sampleproject/', - 'project_urls': {'Download': 'UNKNOWN', 'Homepage': 'https://github.com/pypa/sampleproject'}, - 'release_url': 'https://pypi.org/project/sampleproject/1.2.0/', - 'requires_dist': None, - 'requires_python': None, - 'summary': 'A sample Python project', - 'version': '1.2.0', - } + {'author': 'The Python Packaging Authority', + 'author_email': 'pypa-dev@googlegroups.com', + 'bugtrack_url': None, + 'classifiers': ['Development Status :: 3 - Alpha', + 'Intended Audience :: Developers', + 'License :: OSI Approved :: MIT License', + 'Programming Language :: Python :: 2', + 'Programming Language :: Python :: 2.6', + 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.2', + 'Programming Language :: Python :: 3.3', + 'Programming Language :: Python :: 3.4', + 'Topic :: Software Development :: Build Tools'], + 'description': 'A sample Python project\n' + '=======================\n' + '\n' + 'This is the description file for the project.\n' + '\n' + 'The file should use UTF-8 encoding and be written using ' + 'ReStructured Text. It\n' + 'will be used to generate the project webpage on PyPI, and ' + 'should be written for\n' + 'that purpose.\n' + '\n' + 'Typical contents for this file would include an overview of ' + 'the project, basic\n' + 'usage examples, etc. Generally, including the project ' + 'changelog in here is not\n' + 'a good idea, although a simple "What\'s New" section for the ' + 'most recent version\n' + 'may be appropriate.', + 'description_content_type': None, + 'docs_url': None, + 'download_url': 'UNKNOWN', + 'downloads': {'last_day': -1, 'last_month': -1, 'last_week': -1}, + 'home_page': 'https://github.com/pypa/sampleproject', + 'keywords': 'sample setuptools development', + 'license': 'MIT', + 'maintainer': None, + 'maintainer_email': None, + 'name': 'sampleproject', + 'package_url': 'https://pypi.org/project/sampleproject/', + 'platform': 'UNKNOWN', + 'project_url': 'https://pypi.org/project/sampleproject/', + 'project_urls': {'Download': 'UNKNOWN', + 'Homepage': 'https://github.com/pypa/sampleproject'}, + 'release_url': 'https://pypi.org/project/sampleproject/1.2.0/', + 'requires_dist': None, + 'requires_python': None, + 'summary': 'A sample Python project', + 'version': '1.2.0'} The result can be limited to a certain *depth* (ellipsis is used for deeper contents):: >>> pprint.pp(project_info, depth=1) - { - 'author': 'The Python Packaging Authority', - 'author_email': 'pypa-dev@googlegroups.com', - 'bugtrack_url': None, - 'classifiers': [...], - 'description': 'A sample Python project\n' - '=======================\n' - '\n' - 'This is the description file for the project.\n' - '\n' - 'The file should use UTF-8 encoding and be written using ReStructured Text. It\n' - 'will be used to generate the project webpage on PyPI, and should be written for\n' - 'that purpose.\n' - '\n' - 'Typical contents for this file would include an overview of the project, basic\n' - 'usage examples, etc. Generally, including the project changelog in here is not\n' - 'a good idea, although a simple "What\'s New" section for the most recent version\n' - 'may be appropriate.', - 'description_content_type': None, - 'docs_url': None, - 'download_url': 'UNKNOWN', - 'downloads': {...}, - 'home_page': 'https://github.com/pypa/sampleproject', - 'keywords': 'sample setuptools development', - 'license': 'MIT', - 'maintainer': None, - 'maintainer_email': None, - 'name': 'sampleproject', - 'package_url': 'https://pypi.org/project/sampleproject/', - 'platform': 'UNKNOWN', - 'project_url': 'https://pypi.org/project/sampleproject/', - 'project_urls': {...}, - 'release_url': 'https://pypi.org/project/sampleproject/1.2.0/', - 'requires_dist': None, - 'requires_python': None, - 'summary': 'A sample Python project', - 'version': '1.2.0', - } + {'author': 'The Python Packaging Authority', + 'author_email': 'pypa-dev@googlegroups.com', + 'bugtrack_url': None, + 'classifiers': [...], + 'description': 'A sample Python project\n' + '=======================\n' + '\n' + 'This is the description file for the project.\n' + '\n' + 'The file should use UTF-8 encoding and be written using ' + 'ReStructured Text. It\n' + 'will be used to generate the project webpage on PyPI, and ' + 'should be written for\n' + 'that purpose.\n' + '\n' + 'Typical contents for this file would include an overview of ' + 'the project, basic\n' + 'usage examples, etc. Generally, including the project ' + 'changelog in here is not\n' + 'a good idea, although a simple "What\'s New" section for the ' + 'most recent version\n' + 'may be appropriate.', + 'description_content_type': None, + 'docs_url': None, + 'download_url': 'UNKNOWN', + 'downloads': {...}, + 'home_page': 'https://github.com/pypa/sampleproject', + 'keywords': 'sample setuptools development', + 'license': 'MIT', + 'maintainer': None, + 'maintainer_email': None, + 'name': 'sampleproject', + 'package_url': 'https://pypi.org/project/sampleproject/', + 'platform': 'UNKNOWN', + 'project_url': 'https://pypi.org/project/sampleproject/', + 'project_urls': {...}, + 'release_url': 'https://pypi.org/project/sampleproject/1.2.0/', + 'requires_dist': None, + 'requires_python': None, + 'summary': 'A sample Python project', + 'version': '1.2.0'} Additionally, maximum character *width* can be suggested. If a long object cannot be split, the specified width will be exceeded:: >>> pprint.pp(project_info, depth=1, width=60) + {'author': 'The Python Packaging Authority', + 'author_email': 'pypa-dev@googlegroups.com', + 'bugtrack_url': None, + 'classifiers': [...], + 'description': 'A sample Python project\n' + '=======================\n' + '\n' + 'This is the description file for the ' + 'project.\n' + '\n' + 'The file should use UTF-8 encoding and be ' + 'written using ReStructured Text. It\n' + 'will be used to generate the project ' + 'webpage on PyPI, and should be written ' + 'for\n' + 'that purpose.\n' + '\n' + 'Typical contents for this file would ' + 'include an overview of the project, ' + 'basic\n' + 'usage examples, etc. Generally, including ' + 'the project changelog in here is not\n' + 'a good idea, although a simple "What\'s ' + 'New" section for the most recent version\n' + 'may be appropriate.', + 'description_content_type': None, + 'docs_url': None, + 'download_url': 'UNKNOWN', + 'downloads': {...}, + 'home_page': 'https://github.com/pypa/sampleproject', + 'keywords': 'sample setuptools development', + 'license': 'MIT', + 'maintainer': None, + 'maintainer_email': None, + 'name': 'sampleproject', + 'package_url': 'https://pypi.org/project/sampleproject/', + 'platform': 'UNKNOWN', + 'project_url': 'https://pypi.org/project/sampleproject/', + 'project_urls': {...}, + 'release_url': 'https://pypi.org/project/sampleproject/1.2.0/', + 'requires_dist': None, + 'requires_python': None, + 'summary': 'A sample Python project', + 'version': '1.2.0'} + +Lastly, we can format like pretty-printed JSON with the *expand* parameter. +Best results are achieved with a higher *indent* value:: + + >>> pprint.pp(project_info, indent=4, expand=True) { - 'author': 'The Python Packaging Authority', - 'author_email': 'pypa-dev@googlegroups.com', - 'bugtrack_url': None, - 'classifiers': [...], - 'description': 'A sample Python project\n' - '=======================\n' - '\n' - 'This is the description file for the project.\n' - '\n' - 'The file should use UTF-8 encoding and be written ' - 'using ReStructured Text. It\n' - 'will be used to generate the project webpage on PyPI, ' - 'and should be written for\n' - 'that purpose.\n' - '\n' - 'Typical contents for this file would include an ' - 'overview of the project, basic\n' - 'usage examples, etc. Generally, including the project ' - 'changelog in here is not\n' - 'a good idea, although a simple "What\'s New" section ' - 'for the most recent version\n' - 'may be appropriate.', - 'description_content_type': None, - 'docs_url': None, - 'download_url': 'UNKNOWN', - 'downloads': {...}, - 'home_page': 'https://github.com/pypa/sampleproject', - 'keywords': 'sample setuptools development', - 'license': 'MIT', - 'maintainer': None, - 'maintainer_email': None, - 'name': 'sampleproject', - 'package_url': 'https://pypi.org/project/sampleproject/', - 'platform': 'UNKNOWN', - 'project_url': 'https://pypi.org/project/sampleproject/', - 'project_urls': {...}, - 'release_url': 'https://pypi.org/project/sampleproject/1.2.0/', - 'requires_dist': None, - 'requires_python': None, - 'summary': 'A sample Python project', - 'version': '1.2.0', + 'author': 'The Python Packaging Authority', + 'author_email': 'pypa-dev@googlegroups.com', + 'bugtrack_url': None, + 'classifiers': [ + 'Development Status :: 3 - Alpha', + 'Intended Audience :: Developers', + 'License :: OSI Approved :: MIT License', + 'Programming Language :: Python :: 2', + 'Programming Language :: Python :: 2.6', + 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.2', + 'Programming Language :: Python :: 3.3', + 'Programming Language :: Python :: 3.4', + 'Topic :: Software Development :: Build Tools', + ], + 'description': 'A sample Python project\n' + '=======================\n' + '\n' + 'This is the description file for the project.\n' + '\n' + 'The file should use UTF-8 encoding and be written using ReStructured ' + 'Text. It\n' + 'will be used to generate the project webpage on PyPI, and should be ' + 'written for\n' + 'that purpose.\n' + '\n' + 'Typical contents for this file would include an overview of the project, ' + 'basic\n' + 'usage examples, etc. Generally, including the project changelog in here ' + 'is not\n' + 'a good idea, although a simple "What\'s New" section for the most recent ' + 'version\n' + 'may be appropriate.', + 'description_content_type': None, + 'docs_url': None, + 'download_url': 'UNKNOWN', + 'downloads': {'last_day': -1, 'last_month': -1, 'last_week': -1}, + 'dynamic': None, + 'home_page': 'https://github.com/pypa/sampleproject', + 'keywords': 'sample setuptools development', + 'license': 'MIT', + 'license_expression': None, + 'license_files': None, + 'maintainer': None, + 'maintainer_email': None, + 'name': 'sampleproject', + 'package_url': 'https://pypi.org/project/sampleproject/', + 'platform': 'UNKNOWN', + 'project_url': 'https://pypi.org/project/sampleproject/', + 'project_urls': { + 'Download': 'UNKNOWN', + 'Homepage': 'https://github.com/pypa/sampleproject', + }, + 'provides_extra': None, + 'release_url': 'https://pypi.org/project/sampleproject/1.2.0/', + 'requires_dist': None, + 'requires_python': None, + 'summary': 'A sample Python project', + 'version': '1.2.0', + 'yanked': False, + 'yanked_reason': None, } diff --git a/Doc/library/ssl.rst b/Doc/library/ssl.rst index b180673f22973e..c0f3757e583e95 100644 --- a/Doc/library/ssl.rst +++ b/Doc/library/ssl.rst @@ -2473,79 +2473,67 @@ Visual inspection shows that the certificate does identify the desired service (that is, the HTTPS host ``www.python.org``):: >>> pprint.pprint(cert) - { - 'OCSP': ('http://ocsp.digicert.com',), - 'caIssuers': ('http://cacerts.digicert.com/DigiCertSHA2ExtendedValidationServerCA.crt',), - 'crlDistributionPoints': ( - 'http://crl3.digicert.com/sha2-ev-server-g1.crl', - 'http://crl4.digicert.com/sha2-ev-server-g1.crl', - ), - 'issuer': ( - (('countryName', 'US'),), - (('organizationName', 'DigiCert Inc'),), - (('organizationalUnitName', 'www.digicert.com'),), - (('commonName', 'DigiCert SHA2 Extended Validation Server CA'),), - ), - 'notAfter': 'Sep 9 12:00:00 2016 GMT', - 'notBefore': 'Sep 5 00:00:00 2014 GMT', - 'serialNumber': '01BB6F00122B177F36CAB49CEA8B6B26', - 'subject': ( - (('businessCategory', 'Private Organization'),), - (('1.3.6.1.4.1.311.60.2.1.3', 'US'),), - (('1.3.6.1.4.1.311.60.2.1.2', 'Delaware'),), - (('serialNumber', '3359300'),), - (('streetAddress', '16 Allen Rd'),), - (('postalCode', '03894-4801'),), - (('countryName', 'US'),), - (('stateOrProvinceName', 'NH'),), - (('localityName', 'Wolfeboro'),), - (('organizationName', 'Python Software Foundation'),), - (('commonName', 'www.python.org'),), - ), - 'subjectAltName': ( - ('DNS', 'www.python.org'), - ('DNS', 'python.org'), - ('DNS', 'pypi.org'), - ('DNS', 'docs.python.org'), - ('DNS', 'testpypi.org'), - ('DNS', 'bugs.python.org'), - ('DNS', 'wiki.python.org'), - ('DNS', 'hg.python.org'), - ('DNS', 'mail.python.org'), - ('DNS', 'packaging.python.org'), - ('DNS', 'pythonhosted.org'), - ('DNS', 'www.pythonhosted.org'), - ('DNS', 'test.pythonhosted.org'), - ('DNS', 'us.pycon.org'), - ('DNS', 'id.python.org'), - ), - 'version': 3, - } + {'OCSP': ('http://ocsp.digicert.com',), + 'caIssuers': ('http://cacerts.digicert.com/DigiCertSHA2ExtendedValidationServerCA.crt',), + 'crlDistributionPoints': ('http://crl3.digicert.com/sha2-ev-server-g1.crl', + 'http://crl4.digicert.com/sha2-ev-server-g1.crl'), + 'issuer': ((('countryName', 'US'),), + (('organizationName', 'DigiCert Inc'),), + (('organizationalUnitName', 'www.digicert.com'),), + (('commonName', 'DigiCert SHA2 Extended Validation Server CA'),)), + 'notAfter': 'Sep 9 12:00:00 2016 GMT', + 'notBefore': 'Sep 5 00:00:00 2014 GMT', + 'serialNumber': '01BB6F00122B177F36CAB49CEA8B6B26', + 'subject': ((('businessCategory', 'Private Organization'),), + (('1.3.6.1.4.1.311.60.2.1.3', 'US'),), + (('1.3.6.1.4.1.311.60.2.1.2', 'Delaware'),), + (('serialNumber', '3359300'),), + (('streetAddress', '16 Allen Rd'),), + (('postalCode', '03894-4801'),), + (('countryName', 'US'),), + (('stateOrProvinceName', 'NH'),), + (('localityName', 'Wolfeboro'),), + (('organizationName', 'Python Software Foundation'),), + (('commonName', 'www.python.org'),)), + 'subjectAltName': (('DNS', 'www.python.org'), + ('DNS', 'python.org'), + ('DNS', 'pypi.org'), + ('DNS', 'docs.python.org'), + ('DNS', 'testpypi.org'), + ('DNS', 'bugs.python.org'), + ('DNS', 'wiki.python.org'), + ('DNS', 'hg.python.org'), + ('DNS', 'mail.python.org'), + ('DNS', 'packaging.python.org'), + ('DNS', 'pythonhosted.org'), + ('DNS', 'www.pythonhosted.org'), + ('DNS', 'test.pythonhosted.org'), + ('DNS', 'us.pycon.org'), + ('DNS', 'id.python.org')), + 'version': 3} Now the SSL channel is established and the certificate verified, you can proceed to talk with the server:: >>> conn.sendall(b"HEAD / HTTP/1.0\r\nHost: linuxfr.org\r\n\r\n") >>> pprint.pprint(conn.recv(1024).split(b"\r\n")) - [ - b'HTTP/1.1 200 OK', - b'Date: Sat, 18 Oct 2014 18:27:20 GMT', - b'Server: nginx', - b'Content-Type: text/html; charset=utf-8', - b'X-Frame-Options: SAMEORIGIN', - b'Content-Length: 45679', - b'Accept-Ranges: bytes', - b'Via: 1.1 varnish', - b'Age: 2188', - b'X-Served-By: cache-lcy1134-LCY', - b'X-Cache: HIT', - b'X-Cache-Hits: 11', - b'Vary: Cookie', - b'Strict-Transport-Security: max-age=63072000; includeSubDomains', - b'Connection: close', - b'', - b'', - ] + [b'HTTP/1.1 200 OK', + b'Date: Sat, 18 Oct 2014 18:27:20 GMT', + b'Server: nginx', + b'Content-Type: text/html; charset=utf-8', + b'X-Frame-Options: SAMEORIGIN', + b'Content-Length: 45679', + b'Accept-Ranges: bytes', + b'Via: 1.1 varnish', + b'Age: 2188', + b'X-Served-By: cache-lcy1134-LCY', + b'X-Cache: HIT', + b'X-Cache-Hits: 11', + b'Vary: Cookie', + b'Strict-Transport-Security: max-age=63072000; includeSubDomains', + b'Connection: close', + b'', + b''] See the discussion of :ref:`ssl-security` below. diff --git a/Doc/library/unittest.mock.rst b/Doc/library/unittest.mock.rst index 5b9f9eec93aa28..2ff1015af7a86e 100644 --- a/Doc/library/unittest.mock.rst +++ b/Doc/library/unittest.mock.rst @@ -2347,12 +2347,10 @@ chained call: >>> kall = call(1).method(arg='foo').other('bar')(2.0) >>> kall.call_list() - [ - call(1), - call().method(arg='foo'), - call().method().other('bar'), - call().method().other()(2.0), - ] + [call(1), + call().method(arg='foo'), + call().method().other('bar'), + call().method().other()(2.0)] >>> m.mock_calls == kall.call_list() True diff --git a/Doc/tutorial/stdlib2.rst b/Doc/tutorial/stdlib2.rst index 2c3ec71cd3de39..6c68ba01081379 100644 --- a/Doc/tutorial/stdlib2.rst +++ b/Doc/tutorial/stdlib2.rst @@ -30,22 +30,11 @@ and indentation to more clearly reveal data structure:: ... 'yellow'], 'blue']]] ... >>> pprint.pprint(t, width=30) - [ - [ - [ - ['black', 'cyan'], - 'white', - ['green', 'red'], - ], - [ - [ - 'magenta', - 'yellow', - ], - 'blue', - ], - ], - ] + [[[['black', 'cyan'], + 'white', + ['green', 'red']], + [['magenta', 'yellow'], + 'blue']]] The :mod:`textwrap` module formats paragraphs of text to fit a given screen width:: diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst index 1670f033401f2b..5ef4e36241af2c 100644 --- a/Doc/whatsnew/3.15.rst +++ b/Doc/whatsnew/3.15.rst @@ -1344,11 +1344,12 @@ pickletools pprint ------ -* :mod:`pprint` now uses modern defaults: ``indent=4, width=88``, - and the default ``compact=False`` output is now formatted similar to - pretty-printed :func:`json.dumps`. +* Add an *expand* keyword argument for :func:`pprint.pprint`, + :func:`pprint.pformat`, :func:`pprint.pp`. If true, the output will be + formatted similar to pretty-printed :func:`json.dumps` when + *indent* is supplied. (Contributed by Stefan Todoran, Semyon Moroz and Hugo van Kemenade in - :gh:`112632` and :gh:`149189`.) + :gh:`112632`.) * Add t-string support to :mod:`pprint`. (Contributed by Loïc Simon and Hugo van Kemenade in :gh:`134551`.) diff --git a/Lib/difflib.py b/Lib/difflib.py index 7a4ff15c34267b..ae8b284b4d3647 100644 --- a/Lib/difflib.py +++ b/Lib/difflib.py @@ -559,17 +559,15 @@ def get_grouped_opcodes(self, n=3): >>> b[23:28] = [] # Make a deletion >>> b[30] += 'y' # Make another replacement >>> pprint(list(SequenceMatcher(None,a,b).get_grouped_opcodes())) - [ - [('equal', 5, 8, 5, 8), ('insert', 8, 8, 8, 9), ('equal', 8, 11, 9, 12)], - [ - ('equal', 16, 19, 17, 20), - ('replace', 19, 20, 20, 21), - ('equal', 20, 22, 21, 23), - ('delete', 22, 27, 23, 23), - ('equal', 27, 30, 23, 26), - ], - [('equal', 31, 34, 27, 30), ('replace', 34, 35, 30, 31), ('equal', 35, 38, 31, 34)], - ] + [[('equal', 5, 8, 5, 8), ('insert', 8, 8, 8, 9), ('equal', 8, 11, 9, 12)], + [('equal', 16, 19, 17, 20), + ('replace', 19, 20, 20, 21), + ('equal', 20, 22, 21, 23), + ('delete', 22, 27, 23, 23), + ('equal', 27, 30, 23, 26)], + [('equal', 31, 34, 27, 30), + ('replace', 34, 35, 30, 31), + ('equal', 35, 38, 31, 34)]] """ codes = self.get_opcodes() @@ -786,18 +784,16 @@ class Differ: >>> from pprint import pprint as _pprint >>> _pprint(result) - [ - ' 1. Beautiful is better than ugly.\n', - '- 2. Explicit is better than implicit.\n', - '- 3. Simple is better than complex.\n', - '+ 3. Simple is better than complex.\n', - '? ++\n', - '- 4. Complex is better than complicated.\n', - '? ^ ---- ^\n', - '+ 4. Complicated is better than complex.\n', - '? ++++ ^ ^\n', - '+ 5. Flat is better than nested.\n', - ] + [' 1. Beautiful is better than ugly.\n', + '- 2. Explicit is better than implicit.\n', + '- 3. Simple is better than complex.\n', + '+ 3. Simple is better than complex.\n', + '? ++\n', + '- 4. Complex is better than complicated.\n', + '? ^ ---- ^\n', + '+ 4. Complicated is better than complex.\n', + '? ++++ ^ ^\n', + '+ 5. Flat is better than nested.\n'] As a single multi-line string it looks like this: diff --git a/Lib/pprint.py b/Lib/pprint.py index 1fd7e3ec95a073..7355021998081d 100644 --- a/Lib/pprint.py +++ b/Lib/pprint.py @@ -43,38 +43,23 @@ "PrettyPrinter", "pp"] -def pprint( - object, - stream=None, - indent=4, - width=88, - depth=None, - *, - compact=False, - sort_dicts=True, - underscore_numbers=False, -): +def pprint(object, stream=None, indent=1, width=80, depth=None, *, + compact=False, expand=False, sort_dicts=True, + underscore_numbers=False): """Pretty-print a Python object to a stream [default is sys.stdout].""" printer = PrettyPrinter( stream=stream, indent=indent, width=width, depth=depth, - compact=compact, sort_dicts=sort_dicts, + compact=compact, expand=expand, sort_dicts=sort_dicts, underscore_numbers=underscore_numbers) printer.pprint(object) -def pformat( - object, - indent=4, - width=88, - depth=None, - *, - compact=False, - sort_dicts=True, - underscore_numbers=False, -): +def pformat(object, indent=1, width=80, depth=None, *, + compact=False, expand=False, sort_dicts=True, + underscore_numbers=False): """Format a Python object into a pretty-printed representation.""" return PrettyPrinter(indent=indent, width=width, depth=depth, - compact=compact, sort_dicts=sort_dicts, + compact=compact, expand=expand, sort_dicts=sort_dicts, underscore_numbers=underscore_numbers).pformat(object) @@ -127,17 +112,9 @@ def _safe_tuple(t): class PrettyPrinter: - def __init__( - self, - indent=4, - width=88, - depth=None, - stream=None, - *, - compact=False, - sort_dicts=True, - underscore_numbers=False, - ): + def __init__(self, indent=1, width=80, depth=None, stream=None, *, + compact=False, expand=False, sort_dicts=True, + underscore_numbers=False): """Handle pretty printing operations onto a stream using a set of configured parameters. @@ -156,6 +133,12 @@ def __init__( compact If true, several items will be combined in one line. + Incompatible with expand mode. + + expand + If true, the output will be formatted similar to + pretty-printed json.dumps() when ``indent`` is supplied. + Incompatible with compact mode. sort_dicts If true, dict keys are sorted. @@ -172,6 +155,8 @@ def __init__( raise ValueError('depth must be > 0') if not width: raise ValueError('width must be != 0') + if compact and expand: + raise ValueError('compact and expand are incompatible') self._depth = depth self._indent_per_level = indent self._width = width @@ -180,6 +165,7 @@ def __init__( else: self._stream = _sys.stdout self._compact = bool(compact) + self._expand = bool(expand) self._sort_dicts = sort_dicts self._underscore_numbers = underscore_numbers @@ -232,36 +218,36 @@ def _format(self, object, stream, indent, allowance, context, level): stream.write(rep) def _format_block_start(self, start_str, indent): - if self._compact: - return start_str - return f"{start_str}\n{' ' * indent}" + if self._expand: + return f"{start_str}\n{' ' * indent}" + return start_str def _format_block_end(self, end_str, indent): - if self._compact: - return end_str - return f"\n{' ' * indent}{end_str}" + if self._expand: + return f"\n{' ' * indent}{end_str}" + return end_str def _child_indent(self, indent, prefix_len): - if self._compact: - return indent + prefix_len - return indent + if self._expand: + return indent + return indent + prefix_len def _write_indent_padding(self, write): - if self._compact: - if self._indent_per_level > 1: - write((self._indent_per_level - 1) * " ") - elif self._indent_per_level > 0: - write(self._indent_per_level * " ") + if self._expand: + if self._indent_per_level > 0: + write(self._indent_per_level * " ") + elif self._indent_per_level > 1: + write((self._indent_per_level - 1) * " ") def _pprint_dataclass(self, object, stream, indent, allowance, context, level): # Lazy import to improve module import time from dataclasses import fields as dataclass_fields cls_name = object.__class__.__name__ - if self._compact: - indent += len(cls_name) + 1 - else: + if self._expand: indent += self._indent_per_level + else: + indent += len(cls_name) + 1 items = [(f.name, getattr(object, f.name)) for f in dataclass_fields(object) if f.repr] stream.write(self._format_block_start(cls_name + '(', indent)) self._format_namespace_items(items, stream, indent, allowance, context, level) @@ -384,7 +370,7 @@ def _pprint_list(self, object, stream, indent, allowance, context, level): def _pprint_tuple(self, object, stream, indent, allowance, context, level): stream.write(self._format_block_start('(', indent)) - if len(object) == 1 and self._compact: + if len(object) == 1 and not self._expand: endchar = ',)' else: endchar = ')' @@ -405,7 +391,7 @@ def _pprint_set(self, object, stream, indent, allowance, context, level): else: stream.write(self._format_block_start(typ.__name__ + '({', indent)) endchar = '})' - if self._compact: + if not self._expand: indent += len(typ.__name__) + 1 object = sorted(object, key=_safe_key) self._format_items(object, stream, indent, allowance + len(endchar), @@ -423,10 +409,10 @@ def _pprint_str(self, object, stream, indent, allowance, context, level): chunks = [] lines = object.splitlines(True) if level == 1: - if self._compact: - indent += 1 - else: + if self._expand: indent += self._indent_per_level + else: + indent += 1 allowance += 1 max_width1 = max_width = self._width - indent for i, line in enumerate(lines): @@ -479,10 +465,10 @@ def _pprint_bytes(self, object, stream, indent, allowance, context, level): return parens = level == 1 if parens: - if self._compact: - indent += 1 - else: + if self._expand: indent += self._indent_per_level + else: + indent += 1 allowance += 1 write(self._format_block_start('(', indent)) delim = '' @@ -499,11 +485,11 @@ def _pprint_bytes(self, object, stream, indent, allowance, context, level): def _pprint_bytearray(self, object, stream, indent, allowance, context, level): write = stream.write write(self._format_block_start('bytearray(', indent)) - if self._compact: - recursive_indent = indent + 10 - else: + if self._expand: write(' ' * self._indent_per_level) recursive_indent = indent + self._indent_per_level + else: + recursive_indent = indent + 10 self._pprint_bytes(bytes(object), stream, recursive_indent, allowance + 1, context, level + 1) write(self._format_block_end(')', indent)) @@ -531,10 +517,10 @@ def _pprint_simplenamespace(self, object, stream, indent, allowance, context, le cls_name = 'namespace' else: cls_name = object.__class__.__name__ - if self._compact: - indent += len(cls_name) + 1 - else: + if self._expand: indent += self._indent_per_level + else: + indent += len(cls_name) + 1 items = object.__dict__.items() stream.write(self._format_block_start(cls_name + '(', indent)) self._format_namespace_items(items, stream, indent, allowance, context, @@ -564,7 +550,7 @@ def _format_dict_items(self, items, stream, indent, allowance, context, ) if not last: write(delimnl) - elif not self._compact: + elif self._expand: write(',') def _format_namespace_items(self, items, stream, indent, allowance, context, level): @@ -590,7 +576,7 @@ def _format_namespace_items(self, items, stream, indent, allowance, context, lev ) if not last: write(delimnl) - elif not self._compact: + elif self._expand: write(',') def _format_items(self, items, stream, indent, allowance, context, level): @@ -632,7 +618,7 @@ def _format_items(self, items, stream, indent, allowance, context, level): self._format(ent, stream, indent, allowance if last else 1, context, level) - if last and not self._compact: + if last and self._expand: write(',') def _repr(self, object, context, level): @@ -657,11 +643,11 @@ def _pprint_default_dict(self, object, stream, indent, allowance, context, level return rdf = self._repr(object.default_factory, context, level) cls = object.__class__ - if self._compact: + if self._expand: + stream.write('%s(%s, ' % (cls.__name__, rdf)) + else: indent += len(cls.__name__) + 1 stream.write('%s(%s,\n%s' % (cls.__name__, rdf, ' ' * indent)) - else: - stream.write('%s(%s, ' % (cls.__name__, rdf)) self._pprint_dict(object, stream, indent, allowance + 1, context, level) stream.write(')') @@ -695,14 +681,14 @@ def _pprint_chain_map(self, object, stream, indent, allowance, context, level): cls = object.__class__ stream.write(self._format_block_start(cls.__name__ + '(', indent + self._indent_per_level)) - if self._compact: - indent += len(cls.__name__) + 1 - else: + if self._expand: indent += self._indent_per_level + else: + indent += len(cls.__name__) + 1 for i, m in enumerate(object.maps): if i == len(object.maps) - 1: self._format(m, stream, indent, allowance + 1, context, level) - if not self._compact: + if self._expand: stream.write(',') stream.write(self._format_block_end(')', indent - self._indent_per_level)) else: @@ -717,7 +703,7 @@ def _pprint_deque(self, object, stream, indent, allowance, context, level): return cls = object.__class__ stream.write(self._format_block_start(cls.__name__ + '([', indent)) - if self._compact: + if not self._expand: indent += len(cls.__name__) + 1 if object.maxlen is None: self._format_items(object, stream, indent, allowance + 2, @@ -727,10 +713,10 @@ def _pprint_deque(self, object, stream, indent, allowance, context, level): self._format_items(object, stream, indent, 2, context, level) rml = self._repr(object.maxlen, context, level) - if self._compact: - stream.write('],\n%smaxlen=%s)' % (' ' * indent, rml)) - else: + if self._expand: stream.write('%s], maxlen=%s)' % ('\n' + ' ' * indent, rml)) + else: + stream.write('],\n%smaxlen=%s)' % (' ' * indent, rml)) _dispatch[_collections.deque.__repr__] = _pprint_deque @@ -751,10 +737,10 @@ def _pprint_user_string(self, object, stream, indent, allowance, context, level) def _pprint_template(self, object, stream, indent, allowance, context, level): cls_name = object.__class__.__name__ - if self._compact: - indent += len(cls_name) + 1 - else: + if self._expand: indent += self._indent_per_level + else: + indent += len(cls_name) + 1 items = ( ("strings", object.strings), @@ -770,20 +756,7 @@ def _pprint_template(self, object, stream, indent, allowance, context, level): def _pprint_interpolation(self, object, stream, indent, allowance, context, level): cls_name = object.__class__.__name__ - if self._compact: - indent += len(cls_name) - items = ( - object.value, - object.expression, - object.conversion, - object.format_spec, - ) - stream.write(cls_name + "(") - self._format_items( - items, stream, indent, allowance, context, level - ) - stream.write(")") - else: + if self._expand: indent += self._indent_per_level items = ( ("value", object.value), @@ -798,6 +771,19 @@ def _pprint_interpolation(self, object, stream, indent, allowance, context, leve stream.write( self._format_block_end(")", indent - self._indent_per_level) ) + else: + indent += len(cls_name) + items = ( + object.value, + object.expression, + object.conversion, + object.format_spec, + ) + stream.write(cls_name + "(") + self._format_items( + items, stream, indent, allowance, context, level + ) + stream.write(")") t = t"{0}" _dispatch[type(t).__repr__] = _pprint_template diff --git a/Lib/test/test_descrtut.py b/Lib/test/test_descrtut.py index 425fb85e93558d..828440a993a975 100644 --- a/Lib/test/test_descrtut.py +++ b/Lib/test/test_descrtut.py @@ -168,56 +168,54 @@ def merge(self, other): >>> import pprint >>> pprint.pprint(dir(list)) # like list.__dict__.keys(), but sorted - [ - '__add__', - '__class__', - '__class_getitem__', - '__contains__', - '__delattr__', - '__delitem__', - '__dir__', - '__doc__', - '__eq__', - '__format__', - '__ge__', - '__getattribute__', - '__getitem__', - '__getstate__', - '__gt__', - '__hash__', - '__iadd__', - '__imul__', - '__init__', - '__init_subclass__', - '__iter__', - '__le__', - '__len__', - '__lt__', - '__mul__', - '__ne__', - '__new__', - '__reduce__', - '__reduce_ex__', - '__repr__', - '__reversed__', - '__rmul__', - '__setattr__', - '__setitem__', - '__sizeof__', - '__str__', - '__subclasshook__', - 'append', - 'clear', - 'copy', - 'count', - 'extend', - 'index', - 'insert', - 'pop', - 'remove', - 'reverse', - 'sort', - ] + ['__add__', + '__class__', + '__class_getitem__', + '__contains__', + '__delattr__', + '__delitem__', + '__dir__', + '__doc__', + '__eq__', + '__format__', + '__ge__', + '__getattribute__', + '__getitem__', + '__getstate__', + '__gt__', + '__hash__', + '__iadd__', + '__imul__', + '__init__', + '__init_subclass__', + '__iter__', + '__le__', + '__len__', + '__lt__', + '__mul__', + '__ne__', + '__new__', + '__reduce__', + '__reduce_ex__', + '__repr__', + '__reversed__', + '__rmul__', + '__setattr__', + '__setitem__', + '__sizeof__', + '__str__', + '__subclasshook__', + 'append', + 'clear', + 'copy', + 'count', + 'extend', + 'index', + 'insert', + 'pop', + 'remove', + 'reverse', + 'sort'] The new introspection API gives more information than the old one: in addition to the regular methods, it also shows the methods that are diff --git a/Lib/test/test_pickle.py b/Lib/test/test_pickle.py index 55a3c654aa0a47..48375cf459ea0b 100644 --- a/Lib/test/test_pickle.py +++ b/Lib/test/test_pickle.py @@ -786,7 +786,11 @@ def test_invocation(self): 'b': ('character string', b'byte string'), 'c': 'string' } - expect = "{'a': [1, 2.0, (3+4j)], 'b': ('character string', b'byte string'), 'c': 'string'}" + expect = ''' + {'a': [1, 2.0, (3+4j)], + 'b': ('character string', b'byte string'), + 'c': 'string'} + ''' self.set_pickle_data(data) with self.subTest(data=data): diff --git a/Lib/test/test_pprint.py b/Lib/test/test_pprint.py index f439782f53e6fb..041c2072b9e253 100644 --- a/Lib/test/test_pprint.py +++ b/Lib/test/test_pprint.py @@ -3,7 +3,6 @@ import collections import contextlib import dataclasses -import functools import io import itertools import pprint @@ -16,10 +15,6 @@ from test.support import cpython_only from test.support.import_helper import ensure_lazy_imports -# Pin pre-3.15 width/indent for existing formatting tests. -# compact=True keeps the legacy non-JSON-style container wrapping. -_pformat = functools.partial(pprint.pformat, indent=1, width=80, compact=True) - # list, tuple and dict subclasses that do or don't overwrite __repr__ class list2(list): pass @@ -169,6 +164,7 @@ def test_init(self): self.assertRaises(ValueError, pprint.PrettyPrinter, depth=0) self.assertRaises(ValueError, pprint.PrettyPrinter, depth=-1) self.assertRaises(ValueError, pprint.PrettyPrinter, width=0) + self.assertRaises(ValueError, pprint.PrettyPrinter, compact=True, expand=True) def test_basic(self): # Verify .isrecursive() and .isreadable() w/o recursion @@ -288,10 +284,10 @@ def test_same_as_repr(self): True, False, None, ..., ): native = repr(simple) - self.assertEqual(_pformat(simple), native) - self.assertEqual(_pformat(simple, width=1, indent=0) + self.assertEqual(pprint.pformat(simple), native) + self.assertEqual(pprint.pformat(simple, width=1, indent=0) .replace('\n', ' '), native) - self.assertEqual(_pformat(simple, underscore_numbers=True), native) + self.assertEqual(pprint.pformat(simple, underscore_numbers=True), native) self.assertEqual(pprint.saferepr(simple), native) def test_container_repr_override_called(self): @@ -322,8 +318,8 @@ def test_container_repr_override_called(self): ): native = repr(cont) expected = '*' * len(native) - self.assertEqual(_pformat(cont), expected) - self.assertEqual(_pformat(cont, width=1, indent=0), expected) + self.assertEqual(pprint.pformat(cont), expected) + self.assertEqual(pprint.pformat(cont, width=1, indent=0), expected) self.assertEqual(pprint.saferepr(cont), expected) def test_basic_line_wrap(self): @@ -344,7 +340,7 @@ def test_basic_line_wrap(self): 'read_io_runtime_us': 0, 'write_io_runtime_us': 43690}""" for type in [dict, dict2]: - self.assertEqual(_pformat(type(o)), exp) + self.assertEqual(pprint.pformat(type(o)), exp) exp = """\ frozendict({'RPM_cal': 0, @@ -354,7 +350,7 @@ def test_basic_line_wrap(self): 'main_code_runtime_us': 0, 'read_io_runtime_us': 0, 'write_io_runtime_us': 43690})""" - self.assertEqual(_pformat(frozendict(o)), exp) + self.assertEqual(pprint.pformat(frozendict(o)), exp) exp = """\ frozendict2({'RPM_cal': 0, 'RPM_cal2': 48059, @@ -363,79 +359,79 @@ def test_basic_line_wrap(self): 'main_code_runtime_us': 0, 'read_io_runtime_us': 0, 'write_io_runtime_us': 43690})""" - self.assertEqual(_pformat(frozendict2(o)), exp) + self.assertEqual(pprint.pformat(frozendict2(o)), exp) o = range(100) exp = 'dict_keys([%s])' % ',\n '.join(map(str, o)) keys = dict.fromkeys(o).keys() - self.assertEqual(_pformat(keys, width=1), exp) + self.assertEqual(pprint.pformat(keys), exp) keys = frozendict.fromkeys(o).keys() - self.assertEqual(_pformat(keys, width=1), exp) + self.assertEqual(pprint.pformat(keys), exp) o = range(100) exp = 'dict_values([%s])' % ',\n '.join(map(str, o)) values = {v: v for v in o}.values() - self.assertEqual(_pformat(values, width=1), exp) + self.assertEqual(pprint.pformat(values), exp) values = frozendict({v: v for v in o}).values() - self.assertEqual(_pformat(values, width=1), exp) + self.assertEqual(pprint.pformat(values), exp) o = range(100) exp = 'dict_items([%s])' % ',\n '.join("(%s, %s)" % (i, i) for i in o) items = {v: v for v in o}.items() - self.assertEqual(_pformat(items, width=11), exp) + self.assertEqual(pprint.pformat(items), exp) items = frozendict({v: v for v in o}).items() - self.assertEqual(_pformat(items, width=11), exp) + self.assertEqual(pprint.pformat(items), exp) o = range(100) exp = 'odict_keys([%s])' % ',\n '.join(map(str, o)) keys = collections.OrderedDict.fromkeys(o).keys() - self.assertEqual(_pformat(keys, width=1), exp) + self.assertEqual(pprint.pformat(keys), exp) o = range(100) exp = 'odict_values([%s])' % ',\n '.join(map(str, o)) values = collections.OrderedDict({v: v for v in o}).values() - self.assertEqual(_pformat(values, width=1), exp) + self.assertEqual(pprint.pformat(values), exp) o = range(100) exp = 'odict_items([%s])' % ',\n '.join("(%s, %s)" % (i, i) for i in o) items = collections.OrderedDict({v: v for v in o}).items() - self.assertEqual(_pformat(items, width=11), exp) + self.assertEqual(pprint.pformat(items), exp) o = range(100) exp = 'KeysView({%s})' % (': None,\n '.join(map(str, o)) + ': None') keys_view = KeysView(dict.fromkeys(o)) - self.assertEqual(_pformat(keys_view), exp) + self.assertEqual(pprint.pformat(keys_view), exp) o = range(100) exp = 'ItemsView({%s})' % (': None,\n '.join(map(str, o)) + ': None') items_view = ItemsView(dict.fromkeys(o)) - self.assertEqual(_pformat(items_view), exp) + self.assertEqual(pprint.pformat(items_view), exp) o = range(100) exp = 'MappingView({%s})' % (': None,\n '.join(map(str, o)) + ': None') mapping_view = MappingView(dict.fromkeys(o)) - self.assertEqual(_pformat(mapping_view), exp) + self.assertEqual(pprint.pformat(mapping_view), exp) o = range(100) exp = 'ValuesView({%s})' % (': None,\n '.join(map(str, o)) + ': None') values_view = ValuesView(dict.fromkeys(o)) - self.assertEqual(_pformat(values_view), exp) + self.assertEqual(pprint.pformat(values_view), exp) o = range(100) exp = '[%s]' % ',\n '.join(map(str, o)) for type in [list, list2]: - self.assertEqual(_pformat(type(o), width=1), exp) + self.assertEqual(pprint.pformat(type(o)), exp) o = tuple(range(100)) exp = '(%s)' % ',\n '.join(map(str, o)) for type in [tuple, tuple2]: - self.assertEqual(_pformat(type(o), width=1), exp) + self.assertEqual(pprint.pformat(type(o)), exp) # indent parameter o = range(100) exp = '[ %s]' % ',\n '.join(map(str, o)) for type in [list, list2]: - self.assertEqual(_pformat(type(o), indent=4, width=1), exp) + self.assertEqual(pprint.pformat(type(o), indent=4), exp) def test_nested_indentations(self): o1 = list(range(10)) @@ -444,13 +440,13 @@ def test_nested_indentations(self): expected = """\ [ [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], {'first': 1, 'second': 2, 'third': 3}]""" - self.assertEqual(pprint.pformat(o, indent=4, width=42, compact=True), expected) + self.assertEqual(pprint.pformat(o, indent=4, width=42), expected) expected = """\ [ [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], { 'first': 1, 'second': 2, 'third': 3}]""" - self.assertEqual(pprint.pformat(o, indent=4, width=41, compact=True), expected) + self.assertEqual(pprint.pformat(o, indent=4, width=41), expected) def test_width(self): expected = """\ @@ -464,15 +460,17 @@ def test_width(self): [[[[[1, 2, 3], '1 2']]]]]""" o = eval(expected) - self.assertEqual(_pformat(o, width=15), expected) - self.assertEqual(_pformat(o, width=16), expected) - self.assertEqual(_pformat(o, width=25), expected) - self.assertEqual(_pformat(o, width=14), """\ -[[[[[[1, 2, + self.assertEqual(pprint.pformat(o, width=15), expected) + self.assertEqual(pprint.pformat(o, width=16), expected) + self.assertEqual(pprint.pformat(o, width=25), expected) + self.assertEqual(pprint.pformat(o, width=14), """\ +[[[[[[1, + 2, 3], '1 ' '2']]]], - {1: [1, 2, + {1: [1, + 2, 3], 2: [12, 34]}, @@ -482,14 +480,15 @@ def test_width(self): 'ef',), set2({1, 23}), - [[[[[1, 2, + [[[[[1, + 2, 3], '1 ' '2']]]]]""") def test_integer(self): - self.assertEqual(_pformat(1234567), '1234567') - self.assertEqual(_pformat(1234567, underscore_numbers=True), '1_234_567') + self.assertEqual(pprint.pformat(1234567), '1234567') + self.assertEqual(pprint.pformat(1234567, underscore_numbers=True), '1_234_567') class Temperature(int): def __new__(cls, celsius_degrees): @@ -497,7 +496,7 @@ def __new__(cls, celsius_degrees): def __repr__(self): kelvin_degrees = self + 273.15 return f"{kelvin_degrees:.2f}°K" - self.assertEqual(_pformat(Temperature(1000)), '1273.15°K') + self.assertEqual(pprint.pformat(Temperature(1000)), '1273.15°K') def test_sorted_dict(self): # Starting in Python 2.5, pprint sorts dict displays by key regardless @@ -505,8 +504,8 @@ def test_sorted_dict(self): # Before the change, on 32-bit Windows pformat() gave order # 'a', 'c', 'b' here, so this test failed. d = {'a': 1, 'b': 1, 'c': 1} - self.assertEqual(_pformat(d), "{'a': 1, 'b': 1, 'c': 1}") - self.assertEqual(_pformat([d, d]), + self.assertEqual(pprint.pformat(d), "{'a': 1, 'b': 1, 'c': 1}") + self.assertEqual(pprint.pformat([d, d]), "[{'a': 1, 'b': 1, 'c': 1}, {'a': 1, 'b': 1, 'c': 1}]") # The next one is kind of goofy. The sorted order depends on the @@ -514,42 +513,63 @@ def test_sorted_dict(self): # Python 2.5, this was in the test_same_as_repr() test. It's worth # keeping around for now because it's one of few tests of pprint # against a crazy mix of types. - self.assertEqual(_pformat({"xy\tab\n": (3,), 5: [[]], (): {}}), + self.assertEqual(pprint.pformat({"xy\tab\n": (3,), 5: [[]], (): {}}), r"{5: [[]], 'xy\tab\n': (3,), (): {}}") def test_sort_dict(self): d = dict.fromkeys('cba') - self.assertEqual(_pformat(d, sort_dicts=False), "{'c': None, 'b': None, 'a': None}") - self.assertEqual(_pformat([d, d], sort_dicts=False), + self.assertEqual(pprint.pformat(d, sort_dicts=False), "{'c': None, 'b': None, 'a': None}") + self.assertEqual(pprint.pformat([d, d], sort_dicts=False), "[{'c': None, 'b': None, 'a': None}, {'c': None, 'b': None, 'a': None}]") def test_ordered_dict(self): d = collections.OrderedDict() - self.assertEqual(_pformat(d, width=1), 'OrderedDict()') + self.assertEqual(pprint.pformat(d, width=1), 'OrderedDict()') d = collections.OrderedDict([]) - self.assertEqual(_pformat(d, width=1), 'OrderedDict()') + self.assertEqual(pprint.pformat(d, width=1), 'OrderedDict()') words = 'the quick brown fox jumped over a lazy dog'.split() d = collections.OrderedDict(zip(words, itertools.count())) - self.assertEqual(_pformat(d), + self.assertEqual(pprint.pformat(d), """\ -OrderedDict([('the', 0), ('quick', 1), ('brown', 2), ('fox', 3), ('jumped', 4), - ('over', 5), ('a', 6), ('lazy', 7), ('dog', 8)])""") - self.assertEqual( - _pformat(d.keys(), sort_dicts=False), - "odict_keys(['the', 'quick', 'brown', 'fox', 'jumped', 'over', 'a', 'lazy', 'dog'])", - ) - self.assertEqual(_pformat(d.items(), sort_dicts=False), +OrderedDict([('the', 0), + ('quick', 1), + ('brown', 2), + ('fox', 3), + ('jumped', 4), + ('over', 5), + ('a', 6), + ('lazy', 7), + ('dog', 8)])""") + self.assertEqual(pprint.pformat(d.keys(), sort_dicts=False), +"""\ +odict_keys(['the', + 'quick', + 'brown', + 'fox', + 'jumped', + 'over', + 'a', + 'lazy', + 'dog'])""") + self.assertEqual(pprint.pformat(d.items(), sort_dicts=False), """\ -odict_items([('the', 0), ('quick', 1), ('brown', 2), ('fox', 3), ('jumped', 4), ('over', 5), - ('a', 6), ('lazy', 7), ('dog', 8)])""") - self.assertEqual(_pformat(d.values(), sort_dicts=False), +odict_items([('the', 0), + ('quick', 1), + ('brown', 2), + ('fox', 3), + ('jumped', 4), + ('over', 5), + ('a', 6), + ('lazy', 7), + ('dog', 8)])""") + self.assertEqual(pprint.pformat(d.values(), sort_dicts=False), "odict_values([0, 1, 2, 3, 4, 5, 6, 7, 8])") def test_mapping_proxy(self): words = 'the quick brown fox jumped over a lazy dog'.split() d = dict(zip(words, itertools.count())) m = types.MappingProxyType(d) - self.assertEqual(_pformat(m), """\ + self.assertEqual(pprint.pformat(m), """\ mappingproxy({'a': 6, 'brown': 2, 'dog': 8, @@ -561,81 +581,49 @@ def test_mapping_proxy(self): 'the': 0})""") d = collections.OrderedDict(zip(words, itertools.count())) m = types.MappingProxyType(d) - self.assertEqual(_pformat(m), """\ -mappingproxy(OrderedDict([('the', 0), ('quick', 1), ('brown', 2), ('fox', 3), - ('jumped', 4), ('over', 5), ('a', 6), ('lazy', 7), + self.assertEqual(pprint.pformat(m), """\ +mappingproxy(OrderedDict([('the', 0), + ('quick', 1), + ('brown', 2), + ('fox', 3), + ('jumped', 4), + ('over', 5), + ('a', 6), + ('lazy', 7), ('dog', 8)]))""") def test_dict_views(self): for dict_class in (dict, collections.OrderedDict, collections.Counter): empty = dict_class({}) short = dict_class(dict(zip('edcba', 'edcba'))) - lengths = {"empty": empty, "short": short} + long = dict_class(dict((chr(x), chr(x)) for x in range(90, 64, -1))) + lengths = {"empty": empty, "short": short, "long": long} prefix = "odict" if dict_class is collections.OrderedDict else "dict" for name, d in lengths.items(): with self.subTest(length=name, prefix=prefix): + is_short = len(d) < 6 + joiner = ", " if is_short else ",\n " k = d.keys() v = d.values() i = d.items() - self.assertEqual(_pformat(k, sort_dicts=True), + self.assertEqual(pprint.pformat(k, sort_dicts=True), prefix + "_keys([%s])" % - ", ".join(repr(key) for key in sorted(k))) - self.assertEqual(_pformat(v, sort_dicts=True), + joiner.join(repr(key) for key in sorted(k))) + self.assertEqual(pprint.pformat(v, sort_dicts=True), prefix + "_values([%s])" % - ", ".join(repr(val) for val in sorted(v))) - self.assertEqual(_pformat(i, sort_dicts=True), + joiner.join(repr(val) for val in sorted(v))) + self.assertEqual(pprint.pformat(i, sort_dicts=True), prefix + "_items([%s])" % - ", ".join(repr(item) for item in sorted(i))) - self.assertEqual(_pformat(k, sort_dicts=False), + joiner.join(repr(item) for item in sorted(i))) + self.assertEqual(pprint.pformat(k, sort_dicts=False), prefix + "_keys([%s])" % - ", ".join(repr(key) for key in k)) - self.assertEqual(_pformat(v, sort_dicts=False), + joiner.join(repr(key) for key in k)) + self.assertEqual(pprint.pformat(v, sort_dicts=False), prefix + "_values([%s])" % - ", ".join(repr(val) for val in v)) - self.assertEqual(_pformat(i, sort_dicts=False), + joiner.join(repr(val) for val in v)) + self.assertEqual(pprint.pformat(i, sort_dicts=False), prefix + "_items([%s])" % - ", ".join(repr(item) for item in i)) - - # Long case: views wrap with compact-mode packing. - long = dict((chr(x), chr(x)) for x in range(90, 64, -1)) - sorted_keys = ( - "['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',\n" - " 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']" - ) - unsorted_keys = ( - "['Z', 'Y', 'X', 'W', 'V', 'U', 'T', 'S', 'R', 'Q', 'P', 'O', 'N', 'M', 'L', 'K',\n" - " 'J', 'I', 'H', 'G', 'F', 'E', 'D', 'C', 'B', 'A']" - ) - sorted_items = ( - "[('A', 'A'), ('B', 'B'), ('C', 'C'), ('D', 'D'), ('E', 'E'), ('F', 'F'),\n" - " ('G', 'G'), ('H', 'H'), ('I', 'I'), ('J', 'J'), ('K', 'K'), ('L', 'L'),\n" - " ('M', 'M'), ('N', 'N'), ('O', 'O'), ('P', 'P'), ('Q', 'Q'), ('R', 'R'),\n" - " ('S', 'S'), ('T', 'T'), ('U', 'U'), ('V', 'V'), ('W', 'W'), ('X', 'X'),\n" - " ('Y', 'Y'), ('Z', 'Z')]" - ) - unsorted_items = ( - "[('Z', 'Z'), ('Y', 'Y'), ('X', 'X'), ('W', 'W'), ('V', 'V'), ('U', 'U'),\n" - " ('T', 'T'), ('S', 'S'), ('R', 'R'), ('Q', 'Q'), ('P', 'P'), ('O', 'O'),\n" - " ('N', 'N'), ('M', 'M'), ('L', 'L'), ('K', 'K'), ('J', 'J'), ('I', 'I'),\n" - " ('H', 'H'), ('G', 'G'), ('F', 'F'), ('E', 'E'), ('D', 'D'), ('C', 'C'),\n" - " ('B', 'B'), ('A', 'A')]" - ) - for dict_class in (dict, collections.OrderedDict, collections.Counter): - d = dict_class(long) - prefix = "odict" if dict_class is collections.OrderedDict else "dict" - with self.subTest(length="long", prefix=prefix): - self.assertEqual(_pformat(d.keys(), sort_dicts=True), - f"{prefix}_keys({sorted_keys})") - self.assertEqual(_pformat(d.values(), sort_dicts=True), - f"{prefix}_values({sorted_keys})") - self.assertEqual(_pformat(d.items(), sort_dicts=True), - f"{prefix}_items({sorted_items})") - self.assertEqual(_pformat(d.keys(), sort_dicts=False), - f"{prefix}_keys({unsorted_keys})") - self.assertEqual(_pformat(d.values(), sort_dicts=False), - f"{prefix}_values({unsorted_keys})") - self.assertEqual(_pformat(d.items(), sort_dicts=False), - f"{prefix}_items({unsorted_items})") + joiner.join(repr(item) for item in i)) def test_abc_views(self): empty = {} @@ -653,55 +641,55 @@ class MV(MappingView): pass s = sorted(i) joined_items = "({%s})" % joiner.join(["%r: %r" % (k, v) for (k, v) in i]) sorted_items = "({%s})" % joiner.join(["%r: %r" % (k, v) for (k, v) in s]) - self.assertEqual(_pformat(KeysView(d), sort_dicts=True), + self.assertEqual(pprint.pformat(KeysView(d), sort_dicts=True), KeysView.__name__ + sorted_items) - self.assertEqual(_pformat(ItemsView(d), sort_dicts=True), + self.assertEqual(pprint.pformat(ItemsView(d), sort_dicts=True), ItemsView.__name__ + sorted_items) - self.assertEqual(_pformat(MappingView(d), sort_dicts=True), + self.assertEqual(pprint.pformat(MappingView(d), sort_dicts=True), MappingView.__name__ + sorted_items) - self.assertEqual(_pformat(MV(d), sort_dicts=True), + self.assertEqual(pprint.pformat(MV(d), sort_dicts=True), MV.__name__ + sorted_items) - self.assertEqual(_pformat(ValuesView(d), sort_dicts=True), + self.assertEqual(pprint.pformat(ValuesView(d), sort_dicts=True), ValuesView.__name__ + sorted_items) - self.assertEqual(_pformat(KeysView(d), sort_dicts=False), + self.assertEqual(pprint.pformat(KeysView(d), sort_dicts=False), KeysView.__name__ + joined_items) - self.assertEqual(_pformat(ItemsView(d), sort_dicts=False), + self.assertEqual(pprint.pformat(ItemsView(d), sort_dicts=False), ItemsView.__name__ + joined_items) - self.assertEqual(_pformat(MappingView(d), sort_dicts=False), + self.assertEqual(pprint.pformat(MappingView(d), sort_dicts=False), MappingView.__name__ + joined_items) - self.assertEqual(_pformat(MV(d), sort_dicts=False), + self.assertEqual(pprint.pformat(MV(d), sort_dicts=False), MV.__name__ + joined_items) - self.assertEqual(_pformat(ValuesView(d), sort_dicts=False), + self.assertEqual(pprint.pformat(ValuesView(d), sort_dicts=False), ValuesView.__name__ + joined_items) def test_nested_views(self): d = {1: MappingView({1: MappingView({1: MappingView({1: 2})})})} self.assertEqual(repr(d), "{1: MappingView({1: MappingView({1: MappingView({1: 2})})})}") - self.assertEqual(_pformat(d), + self.assertEqual(pprint.pformat(d), "{1: MappingView({1: MappingView({1: MappingView({1: 2})})})}") - self.assertEqual(_pformat(d, depth=2), + self.assertEqual(pprint.pformat(d, depth=2), "{1: MappingView({1: {...}})}") d = {} d1 = {1: d.values()} d2 = {1: d1.values()} d3 = {1: d2.values()} - self.assertEqual(_pformat(d3), + self.assertEqual(pprint.pformat(d3), "{1: dict_values([dict_values([dict_values([])])])}") - self.assertEqual(_pformat(d3, depth=2), + self.assertEqual(pprint.pformat(d3, depth=2), "{1: dict_values([{...}])}") def test_unorderable_items_views(self): """Check that views with unorderable items have stable sorting.""" d = dict((((3+1j), 3), ((1+1j), (1+0j)), (1j, 0j), (500, None), (499, None))) iv = ItemsView(d) - self.assertEqual(_pformat(iv), - _pformat(iv)) - self.assertTrue(_pformat(iv).endswith(", 499: None, 500: None})"), - _pformat(iv)) - self.assertEqual(_pformat(d.items()), # Won't be equal unless _safe_tuple - _pformat(d.items())) # is used in _safe_repr - self.assertTrue(_pformat(d.items()).endswith(", (499, None), (500, None)])")) + self.assertEqual(pprint.pformat(iv), + pprint.pformat(iv)) + self.assertTrue(pprint.pformat(iv).endswith(", 499: None, 500: None})"), + pprint.pformat(iv)) + self.assertEqual(pprint.pformat(d.items()), # Won't be equal unless _safe_tuple + pprint.pformat(d.items())) # is used in _safe_repr + self.assertTrue(pprint.pformat(d.items()).endswith(", (499, None), (500, None)])")) def test_mapping_view_subclass_no_mapping(self): class BMV(MappingView): @@ -710,7 +698,7 @@ def __init__(self, d): self.mapping = self._mapping del self._mapping - self.assertRaises(AttributeError, _pformat, BMV({})) + self.assertRaises(AttributeError, pprint.pformat, BMV({})) def test_mapping_subclass_repr(self): """Test that mapping ABC views use their ._mapping's __repr__.""" @@ -734,10 +722,10 @@ def __repr__(self): self.assertEqual(repr(m), "MyMapping(['test', 1])") short_view_repr = "%s(MyMapping(['test', 1]))" self.assertEqual(repr(m.keys()), short_view_repr % "KeysView") - self.assertEqual(_pformat(m.items()), short_view_repr % "ItemsView") - self.assertEqual(_pformat(m.keys()), short_view_repr % "KeysView") - self.assertEqual(_pformat(MappingView(m)), short_view_repr % "MappingView") - self.assertEqual(_pformat(m.values()), short_view_repr % "ValuesView") + self.assertEqual(pprint.pformat(m.items()), short_view_repr % "ItemsView") + self.assertEqual(pprint.pformat(m.keys()), short_view_repr % "KeysView") + self.assertEqual(pprint.pformat(MappingView(m)), short_view_repr % "MappingView") + self.assertEqual(pprint.pformat(m.values()), short_view_repr % "ValuesView") alpha = "abcdefghijklmnopqrstuvwxyz" m = MyMapping(alpha) @@ -745,19 +733,19 @@ def __repr__(self): long_view_repr = "%%s(MyMapping([%s]))" % alpha_repr self.assertEqual(repr(m), "MyMapping([%s])" % alpha_repr) self.assertEqual(repr(m.keys()), long_view_repr % "KeysView") - self.assertEqual(_pformat(m.items()), long_view_repr % "ItemsView") - self.assertEqual(_pformat(m.keys()), long_view_repr % "KeysView") - self.assertEqual(_pformat(MappingView(m)), long_view_repr % "MappingView") - self.assertEqual(_pformat(m.values()), long_view_repr % "ValuesView") + self.assertEqual(pprint.pformat(m.items()), long_view_repr % "ItemsView") + self.assertEqual(pprint.pformat(m.keys()), long_view_repr % "KeysView") + self.assertEqual(pprint.pformat(MappingView(m)), long_view_repr % "MappingView") + self.assertEqual(pprint.pformat(m.values()), long_view_repr % "ValuesView") def test_empty_simple_namespace(self): ns = types.SimpleNamespace() - formatted = _pformat(ns) + formatted = pprint.pformat(ns) self.assertEqual(formatted, "namespace()") def test_small_simple_namespace(self): ns = types.SimpleNamespace(a=1, b=2) - formatted = _pformat(ns) + formatted = pprint.pformat(ns) self.assertEqual(formatted, "namespace(a=1, b=2)") def test_simple_namespace(self): @@ -772,7 +760,7 @@ def test_simple_namespace(self): lazy=7, dog=8, ) - formatted = pprint.pformat(ns, width=60, indent=4, compact=True) + formatted = pprint.pformat(ns, width=60, indent=4) self.assertEqual(formatted, """\ namespace(the=0, quick=1, @@ -797,7 +785,7 @@ class AdvancedNamespace(types.SimpleNamespace): pass lazy=7, dog=8, ) - formatted = _pformat(ns, width=60) + formatted = pprint.pformat(ns, width=60) self.assertEqual(formatted, """\ AdvancedNamespace(the=0, quick=1, @@ -811,17 +799,17 @@ class AdvancedNamespace(types.SimpleNamespace): pass def test_empty_dataclass(self): dc = dataclasses.make_dataclass("MyDataclass", ())() - formatted = _pformat(dc) + formatted = pprint.pformat(dc) self.assertEqual(formatted, "MyDataclass()") def test_small_dataclass(self): dc = dataclass1("text", 123) - formatted = _pformat(dc) + formatted = pprint.pformat(dc) self.assertEqual(formatted, "dataclass1(field1='text', field2=123, field3=False)") def test_larger_dataclass(self): dc = dataclass1("some fairly long text", int(1e10), True) - formatted = pprint.pformat([dc, dc], width=60, indent=4, compact=True) + formatted = pprint.pformat([dc, dc], width=60, indent=4) self.assertEqual(formatted, """\ [ dataclass1(field1='some fairly long text', field2=10000000000, @@ -832,12 +820,12 @@ def test_larger_dataclass(self): def test_dataclass_with_repr(self): dc = dataclass2() - formatted = _pformat(dc, width=20) + formatted = pprint.pformat(dc, width=20) self.assertEqual(formatted, "custom repr that doesn't fit within pprint width") def test_dataclass_no_repr(self): dc = dataclass3() - formatted = _pformat(dc, width=10) + formatted = pprint.pformat(dc, width=10) self.assertRegex( formatted, fr"<{re.escape(__name__)}.dataclass3 object at \w+>", @@ -846,7 +834,7 @@ def test_dataclass_no_repr(self): def test_recursive_dataclass(self): dc = dataclass4(None) dc.a = dc - formatted = _pformat(dc, width=10) + formatted = pprint.pformat(dc, width=10) self.assertEqual(formatted, """\ dataclass4(a=..., b=1)""") @@ -856,7 +844,7 @@ def test_cyclic_dataclass(self): dc6 = dataclass6(None) dc5.a = dc6 dc6.c = dc5 - formatted = _pformat(dc5, width=10) + formatted = pprint.pformat(dc5, width=10) self.assertEqual(formatted, """\ dataclass5(a=dataclass6(c=..., d=1), @@ -870,7 +858,7 @@ def test_subclassing(self): {'names with spaces': 'should be presented using repr()', others.should.not.be: like.this}""" - dotted_printer = DottedPrettyPrinter(indent=1, compact=True) + dotted_printer = DottedPrettyPrinter() self.assertEqual(dotted_printer.pformat(o), exp) # length(repr(obj)) < width @@ -882,29 +870,47 @@ def test_subclassing(self): self.assertEqual(dotted_printer.pformat(o2), exp2) def test_set_reprs(self): - self.assertEqual(_pformat(set()), 'set()') - self.assertEqual(_pformat(set(range(3))), '{0, 1, 2}') - self.assertEqual(_pformat(set(range(7)), width=20), '''\ -{0, 1, 2, 3, 4, 5, + self.assertEqual(pprint.pformat(set()), 'set()') + self.assertEqual(pprint.pformat(set(range(3))), '{0, 1, 2}') + self.assertEqual(pprint.pformat(set(range(7)), width=20), '''\ +{0, + 1, + 2, + 3, + 4, + 5, 6}''') - self.assertEqual(_pformat(set2(range(7)), width=20), '''\ -set2({0, 1, 2, 3, 4, - 5, 6})''') - self.assertEqual(_pformat(set3(range(7)), width=20), + self.assertEqual(pprint.pformat(set2(range(7)), width=20), '''\ +set2({0, + 1, + 2, + 3, + 4, + 5, + 6})''') + self.assertEqual(pprint.pformat(set3(range(7)), width=20), 'set3({0, 1, 2, 3, 4, 5, 6})') - self.assertEqual(_pformat(frozenset()), 'frozenset()') - self.assertEqual(_pformat(frozenset(range(3))), + self.assertEqual(pprint.pformat(frozenset()), 'frozenset()') + self.assertEqual(pprint.pformat(frozenset(range(3))), 'frozenset({0, 1, 2})') - self.assertEqual(_pformat(frozenset(range(7)), width=20), '''\ -frozenset({0, 1, 2, - 3, 4, 5, + self.assertEqual(pprint.pformat(frozenset(range(7)), width=20), '''\ +frozenset({0, + 1, + 2, + 3, + 4, + 5, 6})''') - self.assertEqual(_pformat(frozenset2(range(7)), width=20), '''\ -frozenset2({0, 1, 2, - 3, 4, 5, + self.assertEqual(pprint.pformat(frozenset2(range(7)), width=20), '''\ +frozenset2({0, + 1, + 2, + 3, + 4, + 5, 6})''') - self.assertEqual(_pformat(frozenset3(range(7)), width=20), + self.assertEqual(pprint.pformat(frozenset3(range(7)), width=20), 'frozenset3({0, 1, 2, 3, 4, 5, 6})') def test_set_of_sets_reprs(self): @@ -936,21 +942,21 @@ def test_set_of_sets_reprs(self): fs0 = frozenset() fs1 = frozenset(('abc', 'xyz')) data = frozenset((fs0, fs1)) - self.assertEqual(_pformat(data), + self.assertEqual(pprint.pformat(data), 'frozenset({%r, %r})' % (fs0, fs1)) - self.assertEqual(_pformat(data), repr(data)) + self.assertEqual(pprint.pformat(data), repr(data)) fs2 = frozenset(('one', 'two')) data = {fs2: frozenset((fs0, fs1))} - self.assertEqual(_pformat(data), + self.assertEqual(pprint.pformat(data), "{%r: frozenset({%r, %r})}" % (fs2, fs0, fs1)) - self.assertEqual(_pformat(data), repr(data)) + self.assertEqual(pprint.pformat(data), repr(data)) # Single-line, unordered: fs1 = frozenset(("xyz", "qwerty")) fs2 = frozenset(("abcd", "spam")) fs = frozenset((fs1, fs2)) - self.assertEqual(_pformat(fs), repr(fs)) + self.assertEqual(pprint.pformat(fs), repr(fs)) # Multiline, unordered: def check(res, invariants): @@ -960,7 +966,7 @@ def check(res, invariants): fs1 = frozenset(('regular string', 'other string')) fs2 = frozenset(('third string', 'one more string')) check( - _pformat(frozenset((fs1, fs2))), + pprint.pformat(frozenset((fs1, fs2))), [ """ frozenset({%r, @@ -975,7 +981,7 @@ def check(res, invariants): # Everything is multiline, unordered: check( - _pformat( + pprint.pformat( frozenset(( frozenset(( "xyz very-very long string", @@ -1022,16 +1028,16 @@ def test_depth(self): nested_tuple = (1, (2, (3, (4, (5, 6))))) nested_dict = {1: {2: {3: {4: {5: {6: 6}}}}}} nested_list = [1, [2, [3, [4, [5, [6, []]]]]]] - self.assertEqual(_pformat(nested_tuple), repr(nested_tuple)) - self.assertEqual(_pformat(nested_dict), repr(nested_dict)) - self.assertEqual(_pformat(nested_list), repr(nested_list)) + self.assertEqual(pprint.pformat(nested_tuple), repr(nested_tuple)) + self.assertEqual(pprint.pformat(nested_dict), repr(nested_dict)) + self.assertEqual(pprint.pformat(nested_list), repr(nested_list)) lv1_tuple = '(1, (...))' lv1_dict = '{1: {...}}' lv1_list = '[1, [...]]' - self.assertEqual(_pformat(nested_tuple, depth=1), lv1_tuple) - self.assertEqual(_pformat(nested_dict, depth=1), lv1_dict) - self.assertEqual(_pformat(nested_list, depth=1), lv1_list) + self.assertEqual(pprint.pformat(nested_tuple, depth=1), lv1_tuple) + self.assertEqual(pprint.pformat(nested_dict, depth=1), lv1_dict) + self.assertEqual(pprint.pformat(nested_list, depth=1), lv1_list) def test_sort_unorderable_values(self): # Issue 3976: sorted pprints fail for unorderable values. @@ -1041,24 +1047,24 @@ def test_sort_unorderable_values(self): skeys = sorted(keys, key=id) clean = lambda s: s.replace(' ', '').replace('\n','') - self.assertEqual(clean(_pformat(set(keys))), + self.assertEqual(clean(pprint.pformat(set(keys))), '{' + ','.join(map(repr, skeys)) + '}') - self.assertEqual(clean(_pformat(frozenset(keys))), + self.assertEqual(clean(pprint.pformat(frozenset(keys))), 'frozenset({' + ','.join(map(repr, skeys)) + '})') - self.assertEqual(clean(_pformat(dict.fromkeys(keys))), + self.assertEqual(clean(pprint.pformat(dict.fromkeys(keys))), '{' + ','.join('%r:None' % k for k in skeys) + '}') - self.assertEqual(clean(_pformat(dict.fromkeys(keys).keys())), + self.assertEqual(clean(pprint.pformat(dict.fromkeys(keys).keys())), 'dict_keys([' + ','.join('%r' % k for k in skeys) + '])') - self.assertEqual(clean(_pformat(dict.fromkeys(keys).items())), + self.assertEqual(clean(pprint.pformat(dict.fromkeys(keys).items())), 'dict_items([' + ','.join('(%r,None)' % k for k in skeys) + '])') # Issue 10017: TypeError on user-defined types as dict keys. - self.assertEqual(_pformat({Unorderable: 0, 1: 0}), + self.assertEqual(pprint.pformat({Unorderable: 0, 1: 0}), '{1: 0, ' + repr(Unorderable) +': 0}') # Issue 14998: TypeError on tuples with NoneTypes as dict keys. keys = [(1,), (None,)] - self.assertEqual(_pformat(dict.fromkeys(keys, 0)), + self.assertEqual(pprint.pformat(dict.fromkeys(keys, 0)), '{%r: 0, %r: 0}' % tuple(sorted(keys, key=id))) def test_sort_orderable_and_unorderable_values(self): @@ -1071,24 +1077,24 @@ def test_sort_orderable_and_unorderable_values(self): self.assertEqual(sorted([b, a]), [a, b]) self.assertEqual(sorted([a, b]), [a, b]) # set - self.assertEqual(_pformat(set([b, a]), width=1), + self.assertEqual(pprint.pformat(set([b, a]), width=1), '{%r,\n %r}' % (a, b)) - self.assertEqual(_pformat(set([a, b]), width=1), + self.assertEqual(pprint.pformat(set([a, b]), width=1), '{%r,\n %r}' % (a, b)) # dict - self.assertEqual(_pformat(dict.fromkeys([b, a]), width=1), + self.assertEqual(pprint.pformat(dict.fromkeys([b, a]), width=1), '{%r: None,\n %r: None}' % (a, b)) - self.assertEqual(_pformat(dict.fromkeys([a, b]), width=1), + self.assertEqual(pprint.pformat(dict.fromkeys([a, b]), width=1), '{%r: None,\n %r: None}' % (a, b)) def test_str_wrap(self): # pprint tries to wrap strings intelligently fox = 'the quick brown fox jumped over a lazy dog' - self.assertEqual(_pformat(fox, width=19), """\ + self.assertEqual(pprint.pformat(fox, width=19), """\ ('the quick brown ' 'fox jumped over ' 'a lazy dog')""") - self.assertEqual(_pformat({'a': 1, 'b': fox, 'c': 2}, + self.assertEqual(pprint.pformat({'a': 1, 'b': fox, 'c': 2}, width=25), """\ {'a': 1, 'b': 'the quick brown ' @@ -1101,28 +1107,28 @@ def test_str_wrap(self): # - non-ASCII is allowed # - an apostrophe doesn't disrupt the pprint special = "Portons dix bons \"whiskys\"\nà l'avocat goujat\t qui fumait au zoo" - self.assertEqual(_pformat(special, width=68), repr(special)) - self.assertEqual(_pformat(special, width=31), """\ + self.assertEqual(pprint.pformat(special, width=68), repr(special)) + self.assertEqual(pprint.pformat(special, width=31), """\ ('Portons dix bons "whiskys"\\n' "à l'avocat goujat\\t qui " 'fumait au zoo')""") - self.assertEqual(_pformat(special, width=20), """\ + self.assertEqual(pprint.pformat(special, width=20), """\ ('Portons dix bons ' '"whiskys"\\n' "à l'avocat " 'goujat\\t qui ' 'fumait au zoo')""") - self.assertEqual(_pformat([[[[[special]]]]], width=35), """\ + self.assertEqual(pprint.pformat([[[[[special]]]]], width=35), """\ [[[[['Portons dix bons "whiskys"\\n' "à l'avocat goujat\\t qui " 'fumait au zoo']]]]]""") - self.assertEqual(_pformat([[[[[special]]]]], width=25), """\ + self.assertEqual(pprint.pformat([[[[[special]]]]], width=25), """\ [[[[['Portons dix bons ' '"whiskys"\\n' "à l'avocat " 'goujat\\t qui ' 'fumait au zoo']]]]]""") - self.assertEqual(_pformat([[[[[special]]]]], width=23), """\ + self.assertEqual(pprint.pformat([[[[[special]]]]], width=23), """\ [[[[['Portons dix ' 'bons "whiskys"\\n' "à l'avocat " @@ -1131,14 +1137,14 @@ def test_str_wrap(self): 'zoo']]]]]""") # An unwrappable string is formatted as its repr unwrappable = "x" * 100 - self.assertEqual(_pformat(unwrappable, width=80), repr(unwrappable)) - self.assertEqual(_pformat(''), "''") + self.assertEqual(pprint.pformat(unwrappable, width=80), repr(unwrappable)) + self.assertEqual(pprint.pformat(''), "''") # Check that the pprint is a usable repr special *= 10 for width in range(3, 40): - formatted = _pformat(special, width=width) + formatted = pprint.pformat(special, width=width) self.assertEqual(eval(formatted), special) - formatted = _pformat([special] * 2, width=width) + formatted = pprint.pformat([special] * 2, width=width) self.assertEqual(eval(formatted), [special] * 2) def test_compact(self): @@ -1151,7 +1157,7 @@ def test_compact(self): 14, 15], [], [0], [0, 1], [0, 1, 2], [0, 1, 2, 3], [0, 1, 2, 3, 4]]""" - self.assertEqual(_pformat(o, width=47, compact=True), expected) + self.assertEqual(pprint.pformat(o, width=47, compact=True), expected) def test_compact_width(self): levels = 20 @@ -1160,117 +1166,117 @@ def test_compact_width(self): for i in range(levels - 1): o = [o] for w in range(levels * 2 + 1, levels + 3 * number - 1): - lines = _pformat(o, width=w, compact=True).splitlines() + lines = pprint.pformat(o, width=w, compact=True).splitlines() maxwidth = max(map(len, lines)) self.assertLessEqual(maxwidth, w) self.assertGreater(maxwidth, w - 3) def test_bytes_wrap(self): - self.assertEqual(_pformat(b'', width=1), "b''") - self.assertEqual(_pformat(b'abcd', width=1), "b'abcd'") + self.assertEqual(pprint.pformat(b'', width=1), "b''") + self.assertEqual(pprint.pformat(b'abcd', width=1), "b'abcd'") letters = b'abcdefghijklmnopqrstuvwxyz' - self.assertEqual(_pformat(letters, width=29), repr(letters)) - self.assertEqual(_pformat(letters, width=19), """\ + self.assertEqual(pprint.pformat(letters, width=29), repr(letters)) + self.assertEqual(pprint.pformat(letters, width=19), """\ (b'abcdefghijkl' b'mnopqrstuvwxyz')""") - self.assertEqual(_pformat(letters, width=18), """\ + self.assertEqual(pprint.pformat(letters, width=18), """\ (b'abcdefghijkl' b'mnopqrstuvwx' b'yz')""") - self.assertEqual(_pformat(letters, width=16), """\ + self.assertEqual(pprint.pformat(letters, width=16), """\ (b'abcdefghijkl' b'mnopqrstuvwx' b'yz')""") special = bytes(range(16)) - self.assertEqual(_pformat(special, width=61), repr(special)) - self.assertEqual(_pformat(special, width=48), """\ + self.assertEqual(pprint.pformat(special, width=61), repr(special)) + self.assertEqual(pprint.pformat(special, width=48), """\ (b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b' b'\\x0c\\r\\x0e\\x0f')""") - self.assertEqual(_pformat(special, width=32), """\ + self.assertEqual(pprint.pformat(special, width=32), """\ (b'\\x00\\x01\\x02\\x03' b'\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b' b'\\x0c\\r\\x0e\\x0f')""") - self.assertEqual(_pformat(special, width=1), """\ + self.assertEqual(pprint.pformat(special, width=1), """\ (b'\\x00\\x01\\x02\\x03' b'\\x04\\x05\\x06\\x07' b'\\x08\\t\\n\\x0b' b'\\x0c\\r\\x0e\\x0f')""") - self.assertEqual(_pformat({'a': 1, 'b': letters, 'c': 2}, + self.assertEqual(pprint.pformat({'a': 1, 'b': letters, 'c': 2}, width=21), """\ {'a': 1, 'b': b'abcdefghijkl' b'mnopqrstuvwx' b'yz', 'c': 2}""") - self.assertEqual(_pformat({'a': 1, 'b': letters, 'c': 2}, + self.assertEqual(pprint.pformat({'a': 1, 'b': letters, 'c': 2}, width=20), """\ {'a': 1, 'b': b'abcdefgh' b'ijklmnop' b'qrstuvwxyz', 'c': 2}""") - self.assertEqual(_pformat([[[[[[letters]]]]]], width=25), """\ + self.assertEqual(pprint.pformat([[[[[[letters]]]]]], width=25), """\ [[[[[[b'abcdefghijklmnop' b'qrstuvwxyz']]]]]]""") - self.assertEqual(_pformat([[[[[[special]]]]]], width=41), """\ + self.assertEqual(pprint.pformat([[[[[[special]]]]]], width=41), """\ [[[[[[b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07' b'\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f']]]]]]""") # Check that the pprint is a usable repr for width in range(1, 64): - formatted = _pformat(special, width=width) + formatted = pprint.pformat(special, width=width) self.assertEqual(eval(formatted), special) - formatted = _pformat([special] * 2, width=width) + formatted = pprint.pformat([special] * 2, width=width) self.assertEqual(eval(formatted), [special] * 2) def test_bytearray_wrap(self): - self.assertEqual(_pformat(bytearray(), width=1), "bytearray(b'')") + self.assertEqual(pprint.pformat(bytearray(), width=1), "bytearray(b'')") letters = bytearray(b'abcdefghijklmnopqrstuvwxyz') - self.assertEqual(_pformat(letters, width=40), repr(letters)) - self.assertEqual(_pformat(letters, width=28), """\ + self.assertEqual(pprint.pformat(letters, width=40), repr(letters)) + self.assertEqual(pprint.pformat(letters, width=28), """\ bytearray(b'abcdefghijkl' b'mnopqrstuvwxyz')""") - self.assertEqual(_pformat(letters, width=27), """\ + self.assertEqual(pprint.pformat(letters, width=27), """\ bytearray(b'abcdefghijkl' b'mnopqrstuvwx' b'yz')""") - self.assertEqual(_pformat(letters, width=25), """\ + self.assertEqual(pprint.pformat(letters, width=25), """\ bytearray(b'abcdefghijkl' b'mnopqrstuvwx' b'yz')""") special = bytearray(range(16)) - self.assertEqual(_pformat(special, width=72), repr(special)) - self.assertEqual(_pformat(special, width=57), """\ + self.assertEqual(pprint.pformat(special, width=72), repr(special)) + self.assertEqual(pprint.pformat(special, width=57), """\ bytearray(b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b' b'\\x0c\\r\\x0e\\x0f')""") - self.assertEqual(_pformat(special, width=41), """\ + self.assertEqual(pprint.pformat(special, width=41), """\ bytearray(b'\\x00\\x01\\x02\\x03' b'\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b' b'\\x0c\\r\\x0e\\x0f')""") - self.assertEqual(_pformat(special, width=1), """\ + self.assertEqual(pprint.pformat(special, width=1), """\ bytearray(b'\\x00\\x01\\x02\\x03' b'\\x04\\x05\\x06\\x07' b'\\x08\\t\\n\\x0b' b'\\x0c\\r\\x0e\\x0f')""") - self.assertEqual(_pformat({'a': 1, 'b': letters, 'c': 2}, + self.assertEqual(pprint.pformat({'a': 1, 'b': letters, 'c': 2}, width=31), """\ {'a': 1, 'b': bytearray(b'abcdefghijkl' b'mnopqrstuvwx' b'yz'), 'c': 2}""") - self.assertEqual(_pformat([[[[[letters]]]]], width=37), """\ + self.assertEqual(pprint.pformat([[[[[letters]]]]], width=37), """\ [[[[[bytearray(b'abcdefghijklmnop' b'qrstuvwxyz')]]]]]""") - self.assertEqual(_pformat([[[[[special]]]]], width=50), """\ + self.assertEqual(pprint.pformat([[[[[special]]]]], width=50), """\ [[[[[bytearray(b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07' b'\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f')]]]]]""") def test_default_dict(self): d = collections.defaultdict(int) - self.assertEqual(_pformat(d, width=1), "defaultdict(, {})") + self.assertEqual(pprint.pformat(d, width=1), "defaultdict(, {})") words = 'the quick brown fox jumped over a lazy dog'.split() d = collections.defaultdict(int, zip(words, itertools.count())) - self.assertEqual(_pformat(d), + self.assertEqual(pprint.pformat(d), """\ defaultdict(, {'a': 6, @@ -1285,15 +1291,15 @@ def test_default_dict(self): def test_counter(self): d = collections.Counter() - self.assertEqual(_pformat(d, width=1), "Counter()") + self.assertEqual(pprint.pformat(d, width=1), "Counter()") d = collections.Counter('senselessness') - self.assertEqual(_pformat(d, width=40), + self.assertEqual(pprint.pformat(d, width=40), """\ Counter({'s': 6, 'e': 4, 'n': 2, 'l': 1})""") - self.assertEqual(_pformat(d, indent=2, width=1), + self.assertEqual(pprint.pformat(d, indent=2, width=1), """\ Counter({ 's': 6, 'e': 4, @@ -1302,11 +1308,11 @@ def test_counter(self): def test_chainmap(self): d = collections.ChainMap() - self.assertEqual(_pformat(d, width=1), "ChainMap({})") + self.assertEqual(pprint.pformat(d, width=1), "ChainMap({})") words = 'the quick brown fox jumped over a lazy dog'.split() items = list(zip(words, itertools.count())) d = collections.ChainMap(dict(items)) - self.assertEqual(_pformat(d), + self.assertEqual(pprint.pformat(d), """\ ChainMap({'a': 6, 'brown': 2, @@ -1318,7 +1324,7 @@ def test_chainmap(self): 'quick': 1, 'the': 0})""") d = collections.ChainMap(dict(items), collections.OrderedDict(items)) - self.assertEqual(_pformat(d), + self.assertEqual(pprint.pformat(d), """\ ChainMap({'a': 6, 'brown': 2, @@ -1329,10 +1335,16 @@ def test_chainmap(self): 'over': 5, 'quick': 1, 'the': 0}, - OrderedDict([('the', 0), ('quick', 1), ('brown', 2), ('fox', 3), - ('jumped', 4), ('over', 5), ('a', 6), ('lazy', 7), + OrderedDict([('the', 0), + ('quick', 1), + ('brown', 2), + ('fox', 3), + ('jumped', 4), + ('over', 5), + ('a', 6), + ('lazy', 7), ('dog', 8)]))""") - self.assertEqual(_pformat(d.keys()), + self.assertEqual(pprint.pformat(d.keys()), """\ KeysView(ChainMap({'a': 6, 'brown': 2, @@ -1343,10 +1355,16 @@ def test_chainmap(self): 'over': 5, 'quick': 1, 'the': 0}, - OrderedDict([('the', 0), ('quick', 1), ('brown', 2), ('fox', 3), - ('jumped', 4), ('over', 5), ('a', 6), ('lazy', 7), + OrderedDict([('the', 0), + ('quick', 1), + ('brown', 2), + ('fox', 3), + ('jumped', 4), + ('over', 5), + ('a', 6), + ('lazy', 7), ('dog', 8)])))""") - self.assertEqual(_pformat(d.items()), + self.assertEqual(pprint.pformat(d.items()), """\ ItemsView(ChainMap({'a': 6, 'brown': 2, @@ -1357,10 +1375,16 @@ def test_chainmap(self): 'over': 5, 'quick': 1, 'the': 0}, - OrderedDict([('the', 0), ('quick', 1), ('brown', 2), ('fox', 3), - ('jumped', 4), ('over', 5), ('a', 6), ('lazy', 7), + OrderedDict([('the', 0), + ('quick', 1), + ('brown', 2), + ('fox', 3), + ('jumped', 4), + ('over', 5), + ('a', 6), + ('lazy', 7), ('dog', 8)])))""") - self.assertEqual(_pformat(d.values()), + self.assertEqual(pprint.pformat(d.values()), """\ ValuesView(ChainMap({'a': 6, 'brown': 2, @@ -1371,34 +1395,52 @@ def test_chainmap(self): 'over': 5, 'quick': 1, 'the': 0}, - OrderedDict([('the', 0), ('quick', 1), ('brown', 2), ('fox', 3), - ('jumped', 4), ('over', 5), ('a', 6), ('lazy', 7), + OrderedDict([('the', 0), + ('quick', 1), + ('brown', 2), + ('fox', 3), + ('jumped', 4), + ('over', 5), + ('a', 6), + ('lazy', 7), ('dog', 8)])))""") def test_deque(self): d = collections.deque() - self.assertEqual(_pformat(d, width=1), "deque([])") + self.assertEqual(pprint.pformat(d, width=1), "deque([])") d = collections.deque(maxlen=7) - self.assertEqual(_pformat(d, width=1), "deque([], maxlen=7)") + self.assertEqual(pprint.pformat(d, width=1), "deque([], maxlen=7)") words = 'the quick brown fox jumped over a lazy dog'.split() d = collections.deque(zip(words, itertools.count())) - self.assertEqual(_pformat(d), + self.assertEqual(pprint.pformat(d), """\ -deque([('the', 0), ('quick', 1), ('brown', 2), ('fox', 3), ('jumped', 4), - ('over', 5), ('a', 6), ('lazy', 7), ('dog', 8)])""") +deque([('the', 0), + ('quick', 1), + ('brown', 2), + ('fox', 3), + ('jumped', 4), + ('over', 5), + ('a', 6), + ('lazy', 7), + ('dog', 8)])""") d = collections.deque(zip(words, itertools.count()), maxlen=7) - self.assertEqual(_pformat(d), + self.assertEqual(pprint.pformat(d), """\ -deque([('brown', 2), ('fox', 3), ('jumped', 4), ('over', 5), ('a', 6), - ('lazy', 7), ('dog', 8)], +deque([('brown', 2), + ('fox', 3), + ('jumped', 4), + ('over', 5), + ('a', 6), + ('lazy', 7), + ('dog', 8)], maxlen=7)""") def test_user_dict(self): d = collections.UserDict() - self.assertEqual(_pformat(d, width=1), "{}") + self.assertEqual(pprint.pformat(d, width=1), "{}") words = 'the quick brown fox jumped over a lazy dog'.split() d = collections.UserDict(zip(words, itertools.count())) - self.assertEqual(_pformat(d), + self.assertEqual(pprint.pformat(d), """\ {'a': 6, 'brown': 2, @@ -1409,7 +1451,7 @@ def test_user_dict(self): 'over': 5, 'quick': 1, 'the': 0}""") - self.assertEqual(_pformat(d.keys()), """\ + self.assertEqual(pprint.pformat(d.keys()), """\ KeysView({'a': 6, 'brown': 2, 'dog': 8, @@ -1419,7 +1461,7 @@ def test_user_dict(self): 'over': 5, 'quick': 1, 'the': 0})""") - self.assertEqual(_pformat(d.items()), """\ + self.assertEqual(pprint.pformat(d.items()), """\ ItemsView({'a': 6, 'brown': 2, 'dog': 8, @@ -1429,7 +1471,7 @@ def test_user_dict(self): 'over': 5, 'quick': 1, 'the': 0})""") - self.assertEqual(_pformat(d.values()), """\ + self.assertEqual(pprint.pformat(d.values()), """\ ValuesView({'a': 6, 'brown': 2, 'dog': 8, @@ -1442,24 +1484,31 @@ def test_user_dict(self): def test_user_list(self): d = collections.UserList() - self.assertEqual(_pformat(d, width=1), "[]") + self.assertEqual(pprint.pformat(d, width=1), "[]") words = 'the quick brown fox jumped over a lazy dog'.split() d = collections.UserList(zip(words, itertools.count())) - self.assertEqual(_pformat(d), + self.assertEqual(pprint.pformat(d), """\ -[('the', 0), ('quick', 1), ('brown', 2), ('fox', 3), ('jumped', 4), ('over', 5), - ('a', 6), ('lazy', 7), ('dog', 8)]""") +[('the', 0), + ('quick', 1), + ('brown', 2), + ('fox', 3), + ('jumped', 4), + ('over', 5), + ('a', 6), + ('lazy', 7), + ('dog', 8)]""") def test_user_string(self): d = collections.UserString('') - self.assertEqual(_pformat(d, width=1), "''") + self.assertEqual(pprint.pformat(d, width=1), "''") d = collections.UserString('the quick brown fox jumped over a lazy dog') - self.assertEqual(_pformat(d, width=20), + self.assertEqual(pprint.pformat(d, width=20), """\ ('the quick brown ' 'fox jumped over ' 'a lazy dog')""") - self.assertEqual(_pformat({1: d}, width=20), + self.assertEqual(pprint.pformat({1: d}, width=20), """\ {1: 'the quick ' 'brown fox ' @@ -1468,22 +1517,22 @@ def test_user_string(self): def test_template(self): d = t"" - self.assertEqual(_pformat(d), + self.assertEqual(pprint.pformat(d), "Template(strings=('',), interpolations=())") - self.assertEqual(_pformat(d), repr(d)) - self.assertEqual(_pformat(d, width=1), + self.assertEqual(pprint.pformat(d), repr(d)) + self.assertEqual(pprint.pformat(d, width=1), """\ Template(strings=('',), interpolations=())""") name = "World" d = t"Hello {name}" - self.assertEqual(_pformat(d), + self.assertEqual(pprint.pformat(d), """\ Template(strings=('Hello ', ''), interpolations=(Interpolation('World', 'name', None, ''),))""") ver = {3.13: False, 3.14: True} d = t"Hello { {"name": "Python", "version": ver}!s:z}!" - self.assertEqual(_pformat(d, width=1), + self.assertEqual(pprint.pformat(d, width=1), """\ Template(strings=('Hello ', '!'), @@ -1501,13 +1550,13 @@ def test_template(self): def test_expand_template(self): d = t"" self.assertEqual( - pprint.pformat(d), + pprint.pformat(d, expand=True), "Template(strings=('',), interpolations=())", ) name = "World" d = t"Hello {name}" self.assertEqual( - pprint.pformat(d, width=40, indent=4), + pprint.pformat(d, width=40, indent=4, expand=True), """\ Template( strings=('Hello ', ''), @@ -1524,7 +1573,7 @@ def test_expand_template(self): ver = {3.13: False, 3.14: True} d = t"Hello { {"name": "Python", "version": ver}!s:z}!" self.assertEqual( - pprint.pformat(d, width=40, indent=4), + pprint.pformat(d, width=40, indent=4, expand=True), """\ Template( strings=('Hello ', '!'), @@ -1565,7 +1614,8 @@ class DummyDataclass: corge=7, garply=(1, 2, 3, 4), ) - self.assertEqual(pprint.pformat(dummy_dataclass, width=40, indent=4), + self.assertEqual(pprint.pformat(dummy_dataclass, width=40, indent=4, + expand=True), """\ DummyDataclass( foo='foo', @@ -1585,7 +1635,8 @@ def test_expand_dict(self): "quux": ["foo", "bar", "baz"], "corge": 7, } - self.assertEqual(pprint.pformat(dummy_dict, width=40, indent=4, sort_dicts=False), + self.assertEqual(pprint.pformat(dummy_dict, width=40, indent=4, + expand=True, sort_dicts=False), """\ { 'foo': 'bar', @@ -1603,7 +1654,8 @@ def test_expand_ordered_dict(self): ("baz", 123), ] ) - self.assertEqual(pprint.pformat(dummy_ordered_dict, width=20, indent=4), + self.assertEqual(pprint.pformat(dummy_ordered_dict, width=20, indent=4, + expand=True), """\ OrderedDict([ ('foo', 1), @@ -1618,7 +1670,8 @@ def test_expand_list(self): "baz", "qux", ] - self.assertEqual(pprint.pformat(dummy_list, width=20, indent=4), + self.assertEqual(pprint.pformat(dummy_list, width=20, indent=4, + expand=True), """\ [ 'foo', @@ -1636,7 +1689,8 @@ def test_expand_tuple(self): 5, 6, ) - self.assertEqual(pprint.pformat(dummy_tuple, width=20, indent=4), + self.assertEqual(pprint.pformat(dummy_tuple, width=20, indent=4, + expand=True), """\ ( 'foo', @@ -1649,7 +1703,7 @@ def test_expand_tuple(self): def test_expand_single_element_tuple(self): self.assertEqual( - pprint.pformat((1,), width=1, indent=4), + pprint.pformat((1,), width=1, indent=4, expand=True), """\ ( 1, @@ -1663,7 +1717,8 @@ def test_expand_set(self): "qux", (1, 2, 3), } - self.assertEqual(pprint.pformat(dummy_set, width=20, indent=4), + self.assertEqual(pprint.pformat(dummy_set, width=20, indent=4, + expand=True), """\ { 'bar', @@ -1686,7 +1741,8 @@ def test_expand_frozenset(self): frozenset(dummy_set), } ) - self.assertEqual(pprint.pformat(dummy_frozenset, width=40, indent=4), + self.assertEqual(pprint.pformat(dummy_frozenset, width=40, indent=4, + expand=True), """\ frozenset({ frozenset({(1, 2, 3)}), @@ -1701,7 +1757,7 @@ def test_expand_frozendict(self): {"foo": "bar", "baz": 123, "qux": [1, 2]} ) self.assertEqual( - pprint.pformat(dummy_frozendict, width=20, indent=4), + pprint.pformat(dummy_frozendict, width=20, indent=4, expand=True), """\ frozendict({ 'baz': 123, @@ -1712,7 +1768,8 @@ def test_expand_frozendict(self): def test_expand_bytes(self): dummy_bytes = b"Hello world! foo bar baz 123 456 789" - self.assertEqual(pprint.pformat(dummy_bytes, width=20, indent=4), + self.assertEqual(pprint.pformat(dummy_bytes, width=20, indent=4, + expand=True), """\ ( b'Hello world!' @@ -1723,7 +1780,8 @@ def test_expand_bytes(self): def test_expand_bytearray(self): dummy_bytes = b"Hello world! foo bar baz 123 456 789" dummy_byte_array = bytearray(dummy_bytes) - self.assertEqual(pprint.pformat(dummy_byte_array, width=40, indent=4), + self.assertEqual(pprint.pformat(dummy_byte_array, width=40, indent=4, + expand=True), """\ bytearray( b'Hello world! foo bar baz 123 456' @@ -1739,7 +1797,8 @@ def test_expand_mappingproxy(self): "corge": 7, } dummy_mappingproxy = types.MappingProxyType(dummy_dict) - self.assertEqual(pprint.pformat(dummy_mappingproxy, width=40, indent=4), + self.assertEqual(pprint.pformat(dummy_mappingproxy, width=40, indent=4, + expand=True), """\ mappingproxy({ 'baz': 123, @@ -1760,7 +1819,8 @@ def test_expand_namespace(self): ), ) - self.assertEqual(pprint.pformat(dummy_namespace, width=40, indent=4), + self.assertEqual(pprint.pformat(dummy_namespace, width=40, indent=4, + expand=True), """\ namespace( foo='bar', @@ -1778,7 +1838,8 @@ def test_expand_defaultdict(self): dummy_defaultdict["foo"].append("baz") dummy_defaultdict["foo"].append("qux") dummy_defaultdict["bar"] = {"foo": "bar", "baz": None} - self.assertEqual(pprint.pformat(dummy_defaultdict, width=40, indent=4), + self.assertEqual(pprint.pformat(dummy_defaultdict, width=40, indent=4, + expand=True), """\ defaultdict(, { 'bar': {'baz': None, 'foo': 'bar'}, @@ -1795,7 +1856,8 @@ def test_expand_counter(self): 'd': 2, 'e': 1, })""" - self.assertEqual(pprint.pformat(dummy_counter, width=40, indent=4), expected) + self.assertEqual(pprint.pformat(dummy_counter, width=40, indent=4, + expand=True), expected) expected2 = """\ Counter({ @@ -1805,7 +1867,8 @@ def test_expand_counter(self): 'd': 2, 'e': 1, })""" - self.assertEqual(pprint.pformat(dummy_counter, width=20, indent=2), expected2) + self.assertEqual(pprint.pformat(dummy_counter, width=20, indent=2, + expand=True), expected2) def test_expand_chainmap(self): dummy_dict = { @@ -1821,7 +1884,8 @@ def test_expand_chainmap(self): {"corge": dummy_dict}, ) dummy_chainmap.maps.append({"garply": "waldo"}) - self.assertEqual(pprint.pformat(dummy_chainmap, width=40, indent=4), + self.assertEqual(pprint.pformat(dummy_chainmap, width=40, indent=4, + expand=True), """\ ChainMap( {'foo': 'bar'}, @@ -1863,7 +1927,8 @@ def test_expand_deque(self): dummy_deque.append(dummy_dict) dummy_deque.extend(dummy_list) dummy_deque.appendleft(dummy_set) - self.assertEqual(pprint.pformat(dummy_deque, width=40, indent=4), + self.assertEqual(pprint.pformat(dummy_deque, width=40, indent=4, + expand=True), """\ deque([ {(1, 2, 3)}, @@ -1894,7 +1959,8 @@ def __init__(self, *args, **kwargs): "corge": 7 }) dummy_userdict.access_count = 5 - self.assertEqual(pprint.pformat(dummy_userdict, width=40, indent=4), + self.assertEqual(pprint.pformat(dummy_userdict, width=40, indent=4, + expand=True), """\ { 'baz': 123, @@ -1914,7 +1980,8 @@ def __init__(self, *args, **kwargs): dummy_userlist = DummyUserList(["first", 2, {"key": "value"}, [4, 5, 6]]) - self.assertEqual(pprint.pformat(dummy_userlist, width=40, indent=4), + self.assertEqual(pprint.pformat(dummy_userlist, width=40, indent=4, + expand=True), """\ [ 'first', @@ -1926,7 +1993,7 @@ def __init__(self, *args, **kwargs): def test_expand_dict_keys(self): d = {"foo": 1, "bar": 2, "baz": 3, "qux": 4, "quux": 5} self.assertEqual( - pprint.pformat(d.keys(), width=20, indent=4), + pprint.pformat(d.keys(), width=20, indent=4, expand=True), """\ dict_keys([ 'bar', @@ -1940,7 +2007,7 @@ def test_expand_dict_keys(self): def test_expand_dict_values(self): d = {"foo": 1, "bar": 2, "baz": 3, "qux": 4, "quux": 5} self.assertEqual( - pprint.pformat(d.values(), width=20, indent=4), + pprint.pformat(d.values(), width=20, indent=4, expand=True), """\ dict_values([ 1, @@ -1954,7 +2021,7 @@ def test_expand_dict_values(self): def test_expand_dict_items(self): d = {"foo": 1, "bar": 2, "baz": 3, "qux": 4, "quux": 5} self.assertEqual( - pprint.pformat(d.items(), width=20, indent=4), + pprint.pformat(d.items(), width=20, indent=4, expand=True), """\ dict_items([ ('bar', 2), @@ -1968,7 +2035,7 @@ def test_expand_dict_items(self): def test_expand_str(self): s = "The quick brown fox jumped over the lazy dog " * 3 self.assertEqual( - pprint.pformat(s, width=40, indent=4), + pprint.pformat(s, width=40, indent=4, expand=True), """\ ( 'The quick brown fox jumped over ' diff --git a/Lib/test/test_stable_abi_ctypes.py b/Lib/test/test_stable_abi_ctypes.py index ac5c4296c663d0..09ee2d53f98f58 100644 --- a/Lib/test/test_stable_abi_ctypes.py +++ b/Lib/test/test_stable_abi_ctypes.py @@ -1032,19 +1032,15 @@ def test_windows_feature_macros(self): 'PyOS_CheckStack', ) -EXPECTED_FEATURE_MACROS = set([ - 'HAVE_FORK', - 'MS_WINDOWS', - 'PY_HAVE_THREAD_NATIVE_ID', - 'Py_REF_DEBUG', - 'Py_TRACE_REFS', - 'USE_STACKCHECK', -]) -WINDOWS_FEATURE_MACROS = { - 'HAVE_FORK': False, - 'MS_WINDOWS': True, - 'PY_HAVE_THREAD_NATIVE_ID': True, - 'Py_REF_DEBUG': 'maybe', - 'Py_TRACE_REFS': 'maybe', - 'USE_STACKCHECK': 'maybe', -} +EXPECTED_FEATURE_MACROS = set(['HAVE_FORK', + 'MS_WINDOWS', + 'PY_HAVE_THREAD_NATIVE_ID', + 'Py_REF_DEBUG', + 'Py_TRACE_REFS', + 'USE_STACKCHECK']) +WINDOWS_FEATURE_MACROS = {'HAVE_FORK': False, + 'MS_WINDOWS': True, + 'PY_HAVE_THREAD_NATIVE_ID': True, + 'Py_REF_DEBUG': 'maybe', + 'Py_TRACE_REFS': 'maybe', + 'USE_STACKCHECK': 'maybe'} diff --git a/Lib/test/test_unittest/testmock/testhelpers.py b/Lib/test/test_unittest/testmock/testhelpers.py index f8643552011f4e..0e82c723ec3eaa 100644 --- a/Lib/test/test_unittest/testmock/testhelpers.py +++ b/Lib/test/test_unittest/testmock/testhelpers.py @@ -1162,7 +1162,9 @@ def test_call_list_str(self): mock.foo.bar().baz('fish', cat='dog') expected = ( - "[call(1, 2), call.foo(a=3), call.foo.bar()," + "[call(1, 2),\n" + " call.foo(a=3),\n" + " call.foo.bar(),\n" " call.foo.bar().baz('fish', cat='dog')]" ) self.assertEqual(str(mock.mock_calls), expected) diff --git a/Misc/NEWS.d/next/Library/2026-05-18-17-17-20.gh-issue-149189.a8IooK.rst b/Misc/NEWS.d/next/Library/2026-05-18-17-17-20.gh-issue-149189.a8IooK.rst new file mode 100644 index 00000000000000..bad027f2c71c6f --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-05-18-17-17-20.gh-issue-149189.a8IooK.rst @@ -0,0 +1 @@ +Revert the changes to :mod:`pprint` defaults. Patch by Hugo van Kemenade. From 081187f169556fb1b2d6a9b96f7b7e509f6ad985 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 22 May 2026 23:17:51 +0200 Subject: [PATCH 115/818] [3.15] gh-82907: Document mtime=0 for reproducible tarfile gzip output (GH-150269) (GH-150271) (cherry picked from commit 9df2b6ccc719b0bc0167da65b72b57f9da39398b) Co-authored-by: Omkar Kabde --- Doc/library/tarfile.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Doc/library/tarfile.rst b/Doc/library/tarfile.rst index 6f1e01cf5aa6ee..9b9783d8e58013 100644 --- a/Doc/library/tarfile.rst +++ b/Doc/library/tarfile.rst @@ -144,7 +144,9 @@ Some facts and figures: For modes ``'w:gz'`` and ``'w|gz'``, :func:`tarfile.open` accepts the keyword argument *mtime* to create a gzip archive header with that mtime. By - default, the mtime is set to the time of creation of the archive. + default, the mtime is set to the time of creation of the archive. Use + *mtime* ``0`` to generate a compressed stream that does not depend on + creation time, for reproducible output. For special purposes, there is a second format for *mode*: ``'filemode|[compression]'``. :func:`tarfile.open` will return a :class:`TarFile` From 795dd3bd3500c49c6a08281a15a9472a28f416d3 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Sat, 23 May 2026 08:57:27 +0200 Subject: [PATCH 116/818] [3.15] Revert "[3.15] gh-146452: Improve locking granularity in pickle's batch_dict_exact and fix race condition (GH-150025) (#150039)" (#150262) Revert "[3.15] gh-146452: Improve locking granularity in pickle's batch_dict_exact and fix race condition (GH-150025) (#150039)" This reverts commit 66ade2861fec1d6c18998710938a1c71fde5f76b. --- ...-05-18-15-30-34.gh-issue-146452.RM0EVJ.rst | 2 -- Modules/_pickle.c | 35 ++++--------------- 2 files changed, 7 insertions(+), 30 deletions(-) delete mode 100644 Misc/NEWS.d/next/Library/2026-05-18-15-30-34.gh-issue-146452.RM0EVJ.rst diff --git a/Misc/NEWS.d/next/Library/2026-05-18-15-30-34.gh-issue-146452.RM0EVJ.rst b/Misc/NEWS.d/next/Library/2026-05-18-15-30-34.gh-issue-146452.RM0EVJ.rst deleted file mode 100644 index 66f9acf6c710a7..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-05-18-15-30-34.gh-issue-146452.RM0EVJ.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix race condition when pickling dictionaries in free threaded builds. Also -reduce critical section cover. diff --git a/Modules/_pickle.c b/Modules/_pickle.c index 15d95c658d6f90..9874f9475ac029 100644 --- a/Modules/_pickle.c +++ b/Modules/_pickle.c @@ -3450,9 +3450,6 @@ batch_dict(PickleState *state, PicklerObject *self, PyObject *iter, PyObject *or * Returns 0 on success, -1 on error. * * Note that this currently doesn't work for protocol 0. - - * gh-146452: Wrap the dict iteration in a critical sections to prevent - * concurrent mutation from invalidating PyDict_Next() iteration state. */ static int batch_dict_exact(PickleState *state, PicklerObject *self, PyObject *obj) @@ -3469,24 +3466,15 @@ batch_dict_exact(PickleState *state, PicklerObject *self, PyObject *obj) assert(self->proto > 0); dict_size = PyDict_GET_SIZE(obj); + assert(dict_size); /* Write in batches of BATCHSIZE. */ Py_ssize_t total = 0; do { if (dict_size - total == 1) { - int next; - Py_BEGIN_CRITICAL_SECTION(obj); - next = PyDict_Next(obj, &ppos, &key, &value); - if (next) { - Py_INCREF(key); - Py_INCREF(value); - } - Py_END_CRITICAL_SECTION(); - if (!next) { - PyErr_SetString(PyExc_RuntimeError, - "dictionary changed size during iteration"); - goto error; - } + PyDict_Next(obj, &ppos, &key, &value); + Py_INCREF(key); + Py_INCREF(value); if (save(state, self, key, 0) < 0) { goto error; } @@ -3504,18 +3492,9 @@ batch_dict_exact(PickleState *state, PicklerObject *self, PyObject *obj) i = 0; if (_Pickler_Write(self, &mark_op, 1) < 0) return -1; - int next; - while (1) { - Py_BEGIN_CRITICAL_SECTION(obj); - next = PyDict_Next(obj, &ppos, &key, &value); - if (next) { - Py_INCREF(key); - Py_INCREF(value); - } - Py_END_CRITICAL_SECTION(); - if (!next) { - break; - } + while (PyDict_Next(obj, &ppos, &key, &value)) { + Py_INCREF(key); + Py_INCREF(value); if (save(state, self, key, 0) < 0) { goto error; } From 77cc4428a772b190ce10ec4d383594de09a03a45 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 23 May 2026 09:33:21 +0200 Subject: [PATCH 117/818] [3.15] gh-146452: Fix pickle segfault on concurrent mutation of dict in pickle (GH-146470) (#150292) gh-146452: Fix pickle segfault on concurrent mutation of dict in pickle (GH-146470) (cherry picked from commit e62a61177f8b793d787e337034a740ca75c1ab44) Co-authored-by: Farhan Saif Co-authored-by: Kumar Aditya --- Lib/test/test_free_threading/test_pickle.py | 44 +++++++++++++++++++ ...3-26-09-30-00.gh-issue-146452.Y2N6qZ8J.rst | 2 + Modules/_pickle.c | 14 +++++- 3 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 Lib/test/test_free_threading/test_pickle.py create mode 100644 Misc/NEWS.d/next/Library/2026-03-26-09-30-00.gh-issue-146452.Y2N6qZ8J.rst diff --git a/Lib/test/test_free_threading/test_pickle.py b/Lib/test/test_free_threading/test_pickle.py new file mode 100644 index 00000000000000..85a644dc72ecb4 --- /dev/null +++ b/Lib/test/test_free_threading/test_pickle.py @@ -0,0 +1,44 @@ +import pickle +import threading +import unittest + +from test.support import threading_helper + + +@threading_helper.requires_working_threading() +class TestPickleFreeThreading(unittest.TestCase): + + def test_pickle_dumps_with_concurrent_dict_mutation(self): + # gh-146452: Pickling a dict while another thread mutates it + # used to segfault. batch_dict_exact() iterated dict items via + # PyDict_Next() which returns borrowed references, and a + # concurrent pop/replace could free the value before Py_INCREF + # got to it. + shared = {str(i): list(range(20)) for i in range(50)} + + def dumper(): + for _ in range(1000): + try: + pickle.dumps(shared) + except RuntimeError: + # "dictionary changed size during iteration" is expected + pass + + def mutator(): + for j in range(1000): + key = str(j % 50) + shared[key] = list(range(j % 20)) + if j % 10 == 0: + shared.pop(key, None) + shared[key] = [j] + + threads = [] + for _ in range(10): + threads.append(threading.Thread(target=dumper)) + threads.append(threading.Thread(target=mutator)) + + with threading_helper.start_threads(threads): + pass + +if __name__ == "__main__": + unittest.main() diff --git a/Misc/NEWS.d/next/Library/2026-03-26-09-30-00.gh-issue-146452.Y2N6qZ8J.rst b/Misc/NEWS.d/next/Library/2026-03-26-09-30-00.gh-issue-146452.Y2N6qZ8J.rst new file mode 100644 index 00000000000000..99f3cce33497a1 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-03-26-09-30-00.gh-issue-146452.Y2N6qZ8J.rst @@ -0,0 +1,2 @@ +Fix segfault in :mod:`pickle` when pickling a dictionary concurrently +mutated by another thread in the free-threaded build. diff --git a/Modules/_pickle.c b/Modules/_pickle.c index 9874f9475ac029..7b87be23269d40 100644 --- a/Modules/_pickle.c +++ b/Modules/_pickle.c @@ -3452,7 +3452,7 @@ batch_dict(PickleState *state, PicklerObject *self, PyObject *iter, PyObject *or * Note that this currently doesn't work for protocol 0. */ static int -batch_dict_exact(PickleState *state, PicklerObject *self, PyObject *obj) +batch_dict_exact_impl(PickleState *state, PicklerObject *self, PyObject *obj) { PyObject *key = NULL, *value = NULL; int i; @@ -3525,6 +3525,18 @@ batch_dict_exact(PickleState *state, PicklerObject *self, PyObject *obj) return -1; } +/* gh-146452: Wrap the dict iteration in a critical section to prevent + concurrent mutation from invalidating PyDict_Next() iteration state. */ +static int +batch_dict_exact(PickleState *state, PicklerObject *self, PyObject *obj) +{ + int ret; + Py_BEGIN_CRITICAL_SECTION(obj); + ret = batch_dict_exact_impl(state, self, obj); + Py_END_CRITICAL_SECTION(); + return ret; +} + static int save_dict(PickleState *state, PicklerObject *self, PyObject *obj) { From d9d8ee503a729f34d7ffc4585ecb4fc0a3445825 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 23 May 2026 10:34:48 +0200 Subject: [PATCH 118/818] [3.15] gh-150232: update Thread group parameter doc (GH-150283) (#150297) gh-150232: update Thread group parameter doc (GH-150283) (cherry picked from commit 82191c6d2cdacad6751262a40a44d2cd6d390977) Co-authored-by: My-ABC <569817555@qq.com> --- Doc/library/threading.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/threading.rst b/Doc/library/threading.rst index eca3e76d84a1cf..5d9a7b6314b166 100644 --- a/Doc/library/threading.rst +++ b/Doc/library/threading.rst @@ -515,7 +515,7 @@ since it is impossible to detect the termination of alien threads. This constructor should always be called with keyword arguments. Arguments are: - *group* should be ``None``; reserved for future extension when a + *group* must be ``None`` as it is reserved for future extension when a :class:`!ThreadGroup` class is implemented. *target* is the callable object to be invoked by the :meth:`run` method. From 8a162b2e270bc371f0c229e8511e7c19b3742f52 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 23 May 2026 10:53:12 +0200 Subject: [PATCH 119/818] [3.15] gh-148450: `abc.register` needs to update `type_version` when `tp_flags` is changed (GH-148623) (#150300) gh-148450: `abc.register` needs to update `type_version` when `tp_flags` is changed (GH-148623) (cherry picked from commit e7eaed56149aa08f7fd5012784cc1deef8e483de) Co-authored-by: Hai Zhu --- Lib/test/test_type_cache.py | 20 +++++++++++++++++++ ...-04-15-15-48-04.gh-issue-148450.2MEVqH.rst | 1 + Objects/typeobject.c | 16 +++++++++++++++ 3 files changed, 37 insertions(+) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-04-15-15-48-04.gh-issue-148450.2MEVqH.rst diff --git a/Lib/test/test_type_cache.py b/Lib/test/test_type_cache.py index 22ad9f6243eda9..849a2afd8ed798 100644 --- a/Lib/test/test_type_cache.py +++ b/Lib/test/test_type_cache.py @@ -1,4 +1,5 @@ """ Tests for the internal type cache in CPython. """ +import collections.abc import dis import unittest import warnings @@ -114,6 +115,25 @@ class HolderSub(Holder): Holder.set_value() HolderSub.value + def test_abc_register_invalidates_subclass_versions(self): + class Parent: + pass + + class Child(Parent): + pass + + type_assign_version(Parent) + type_assign_version(Child) + parent_version = type_get_version(Parent) + child_version = type_get_version(Child) + if parent_version == 0 or child_version == 0: + self.skipTest("Could not assign valid type versions") + + collections.abc.Mapping.register(Parent) + + self.assertEqual(type_get_version(Parent), 0) + self.assertEqual(type_get_version(Child), 0) + @support.cpython_only class TypeCacheWithSpecializationTests(unittest.TestCase): def tearDown(self): diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-04-15-15-48-04.gh-issue-148450.2MEVqH.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-04-15-15-48-04.gh-issue-148450.2MEVqH.rst new file mode 100644 index 00000000000000..2a7d0d9bb3a7f7 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-04-15-15-48-04.gh-issue-148450.2MEVqH.rst @@ -0,0 +1 @@ +Fix ``abc.register()`` so it invalidates type version tags for registered classes. diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 7cca137f74be58..fc679ef747e856 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -6490,9 +6490,25 @@ set_flags_recursive(PyTypeObject *self, unsigned long mask, unsigned long flags) void _PyType_SetFlagsRecursive(PyTypeObject *self, unsigned long mask, unsigned long flags) { + BEGIN_TYPE_LOCK(); + /* Ideally, changing flags and invalidating the old version tag would + happen in one step. But type_modified_unlocked() is re-entrant and + cannot run with the world stopped, so we must invalidate first. + Immutable/static-builtin types are skipped because + set_flags_recursive() does not modify them. */ + if (!PyType_HasFeature(self, Py_TPFLAGS_IMMUTABLETYPE) && + (self->tp_flags & mask) != flags) + { + type_modified_unlocked(self); + } + /* Keep TYPE_LOCK held while waiting for stop-the-world so no thread + can reassign a version tag before the flag update. */ + type_lock_prevent_release(); types_stop_world(); set_flags_recursive(self, mask, flags); types_start_world(); + type_lock_allow_release(); + END_TYPE_LOCK(); } /* This is similar to PyObject_GenericGetAttr(), From ca59d7511e2484fc55b1686b5a8e745322db73ec Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 23 May 2026 11:25:56 +0200 Subject: [PATCH 120/818] [3.15] gh-149816: add missing critical section on self in buffered_iternext (GH-150295) (#150305) gh-149816: add missing critical section on self in buffered_iternext (GH-150295) (cherry picked from commit e8545ed3eafbf349b51ea308126a67dc70416a62) Co-authored-by: Kumar Aditya --- Modules/_io/bufferedio.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c index 0fdae7b2d21004..5537947f6a51c1 100644 --- a/Modules/_io/bufferedio.c +++ b/Modules/_io/bufferedio.c @@ -1509,7 +1509,9 @@ buffered_iternext(PyObject *op) tp == state->PyBufferedRandom_Type) { /* Skip method call overhead for speed */ + Py_BEGIN_CRITICAL_SECTION(self); line = _buffered_readline(self, -1); + Py_END_CRITICAL_SECTION(); } else { line = PyObject_CallMethodNoArgs((PyObject *)self, From 6f993631501eef77ab4bad6a4f9b5ea1f6351c89 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 23 May 2026 17:30:19 +0200 Subject: [PATCH 121/818] [3.15] gh-150258: Show relative percentage on Tachyon flamegraph (GH-150266) (#150312) gh-150258: Show relative percentage on Tachyon flamegraph (GH-150266) When running profiling, users rarely care about the global percentage of the runtime. Often, they want to select a function and measure child percentages relative to that. This PR updates the flamegraph tooltips to show both "Percentage" and "Relative Percentage" when the user clicks a specific function. (cherry picked from commit fad06746051f6bd95a255d49e38ebf049e965109) Co-authored-by: Eduardo Villalpando Mello --- .../sampling/_flamegraph_assets/flamegraph.js | 12 ++++++++++++ .../2026-05-22-18-51-09.gh-issue-150258.dh8GVK.rst | 1 + 2 files changed, 13 insertions(+) create mode 100644 Misc/NEWS.d/next/Tools-Demos/2026-05-22-18-51-09.gh-issue-150258.dh8GVK.rst diff --git a/Lib/profiling/sampling/_flamegraph_assets/flamegraph.js b/Lib/profiling/sampling/_flamegraph_assets/flamegraph.js index 1611bf754424c1..840acf2c27d120 100644 --- a/Lib/profiling/sampling/_flamegraph_assets/flamegraph.js +++ b/Lib/profiling/sampling/_flamegraph_assets/flamegraph.js @@ -7,6 +7,7 @@ let invertedData = null; let currentThreadFilter = 'all'; let isInverted = false; let useModuleNames = true; +let zoomedNodeValue = null; // Heat colors are now defined in CSS variables (--heat-1 through --heat-8) // and automatically switch with theme changes - no JS color arrays needed! @@ -316,6 +317,7 @@ function createPythonTooltip(data) { const selfSamples = d.data.self || 0; const selfMs = (selfSamples / 1000).toFixed(2); const percentage = ((d.data.value / data.value) * 100).toFixed(2); + const relativePercentage = Math.min(100, ((d.data.value / (zoomedNodeValue ?? data.value)) * 100)).toFixed(2); const calls = d.data.calls || 0; const childCount = d.children ? d.children.length : 0; const source = d.data.source; @@ -439,6 +441,11 @@ function createPythonTooltip(data) { Percentage: ${percentage}% + ${relativePercentage != percentage && relativePercentage != "100.00" ? ` + Relative Percentage: + ${relativePercentage}% + ` : ''} + ${calls > 0 ? ` Function Calls: ${calls.toLocaleString()} @@ -620,6 +627,9 @@ function createFlamegraph(tooltip, rootValue, data) { const percentage = d.data.value / rootValue; const level = getHeatLevel(percentage); return heatColors[level]; + }) + .onClick(function (d) { + zoomedNodeValue = d.data.value; }); return chart; @@ -629,6 +639,7 @@ function renderFlamegraph(chart, data) { d3.select("#chart").datum(data).call(chart); window.flamegraphChart = chart; window.flamegraphData = data; + zoomedNodeValue = null; populateStats(data); } @@ -1269,6 +1280,7 @@ function filterDataByThread(data, threadId) { function resetZoom() { if (window.flamegraphChart) { + zoomedNodeValue = null; window.flamegraphChart.resetZoom(); } } diff --git a/Misc/NEWS.d/next/Tools-Demos/2026-05-22-18-51-09.gh-issue-150258.dh8GVK.rst b/Misc/NEWS.d/next/Tools-Demos/2026-05-22-18-51-09.gh-issue-150258.dh8GVK.rst new file mode 100644 index 00000000000000..02cad6c4f53d92 --- /dev/null +++ b/Misc/NEWS.d/next/Tools-Demos/2026-05-22-18-51-09.gh-issue-150258.dh8GVK.rst @@ -0,0 +1 @@ +Update the tooltip on the Tachyon flame graph to show both absolute and relative percentages. From 6b17d1a783d3c0a9c8a35a94e24a2987807728ef Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 23 May 2026 21:27:27 +0200 Subject: [PATCH 122/818] [3.15] gh-150178: Fix refcount leaks in hamt allocation failure paths (GH-150179) (#150303) gh-150178: Fix refcount leaks in hamt allocation failure paths (GH-150179) (cherry picked from commit 32823af153b76b7042fbce28ea8a6e0c3c4f1ca8) Co-authored-by: pengyu lee --- Python/hamt.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Python/hamt.c b/Python/hamt.c index e4719e71a5259a..95998ae5062ac7 100644 --- a/Python/hamt.c +++ b/Python/hamt.c @@ -702,6 +702,7 @@ hamt_node_bitmap_assoc(PyHamtNode_Bitmap *self, PyHamtNode_Bitmap *ret = hamt_node_bitmap_clone(self); if (ret == NULL) { + Py_DECREF(sub_node); return NULL; } Py_SETREF(ret->b_array[val_idx], (PyObject*)sub_node); @@ -994,6 +995,7 @@ hamt_node_bitmap_without(PyHamtNode_Bitmap *self, PyHamtNode_Bitmap *clone = hamt_node_bitmap_clone(self); if (clone == NULL) { + Py_DECREF(sub_node); return W_ERROR; } From 22c994cc928a18fd3d92b8901417e84ebcd9a5e8 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 24 May 2026 09:18:58 +0200 Subject: [PATCH 123/818] [3.15] gh-149335: Avoid JIT trace buffer asserts with overhead above `FITNESS_INITIAL` (GH-149633) (#150245) gh-149335: Avoid JIT trace buffer asserts with overhead above `FITNESS_INITIAL` (GH-149633) (cherry picked from commit 441af3a93426c5e7e3c056fee27e6f4505988584) Co-authored-by: Hai Zhu --- Include/internal/pycore_optimizer.h | 3 +-- Include/internal/pycore_uop.h | 10 +++++--- Lib/test/test_capi/test_opt.py | 38 +++++++++++++++++++++++++++++ Python/pystate.c | 2 +- 4 files changed, 47 insertions(+), 6 deletions(-) diff --git a/Include/internal/pycore_optimizer.h b/Include/internal/pycore_optimizer.h index 69f913ec9c3038..8c35c4416fe3c8 100644 --- a/Include/internal/pycore_optimizer.h +++ b/Include/internal/pycore_optimizer.h @@ -31,9 +31,8 @@ extern "C" { * 4. A push followed by a matching return is net-zero on frame-specific * fitness, excluding per-slot costs. */ -#define MAX_TARGET_LENGTH (UOP_MAX_TRACE_LENGTH / 2) #define OPTIMIZER_EFFECTIVENESS 2 -#define FITNESS_INITIAL (MAX_TARGET_LENGTH * OPTIMIZER_EFFECTIVENESS) +#define MAX_TARGET_LENGTH (FITNESS_INITIAL / OPTIMIZER_EFFECTIVENESS) /* Exit quality thresholds: trace stops when fitness < exit_quality. * Higher = trace is more willing to stop here. */ diff --git a/Include/internal/pycore_uop.h b/Include/internal/pycore_uop.h index 320508e8b7a95e..e7f0d2c214a764 100644 --- a/Include/internal/pycore_uop.h +++ b/Include/internal/pycore_uop.h @@ -36,14 +36,18 @@ typedef struct _PyUOpInstruction{ #endif } _PyUOpInstruction; -// This is the length of the trace we translate initially. +// Fitness is the target length of the trace we translate initially. The uop +// buffer has a small amount of extra space for entry/loop-closing overhead. #if defined(Py_DEBUG) && defined(_Py_JIT) // With asserts, the stencils are a lot larger -#define UOP_MAX_TRACE_LENGTH 1000 +#define FITNESS_INITIAL 1000 #else -#define UOP_MAX_TRACE_LENGTH 2500 +#define FITNESS_INITIAL 2500 #endif +#define UOP_TRACE_BUFFER_OVERHEAD 10 +#define UOP_MAX_TRACE_LENGTH (FITNESS_INITIAL + UOP_TRACE_BUFFER_OVERHEAD) + /* Bloom filter with m = 256 * https://en.wikipedia.org/wiki/Bloom_filter */ #ifdef HAVE_GCC_UINT128_T diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py index 2f606c2c6eba2d..9f0427172b5048 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -5922,6 +5922,44 @@ def __next__(self): """), PYTHON_JIT="1", PYTHON_JIT_STRESS="1") self.assertEqual(result[0].rc, 0, result) + def test_149335_trace_buffer_guard(self): + # https://github.com/python/cpython/issues/149335 + + result = script_helper.run_python_until_end('-c', textwrap.dedent(""" + import sys + + def f1(): + for i_3178 in 0, 2, 10: + mv162 = 162 + + mv3 = mv1 = mv_165 = mv16 = \ + mv167 = mv168 = \ + mv169 = \ + mv_1403_170 = \ + 169 + + mv_1403_170 + + mv_172 = mv_3 = mv_4 = mv175 = mv176 = mv17 = mv178 = mv179 = mv0 = mv1 = mv182 = ( + mv3 + ) = mv4 = mv185 = mv186 = mv187 = mv18 = mv189 = mv0 = mv1 = mv192 = mv3 = mv4 = ( + mv195 + ) = mv196 = mv197 = mv_198 = mv19 = mv0 = mv1 = mv2 = mv3 = mv4 = mv05 = mv06 = ( + mv07 + ) = mv08 = mv09 = mv0 = mv1 = mv2 = mv3 = mv4 = mv15 = mv16 = mv17 = mv18 = mv19 = ( + mv0 + ) = mv1 = mv_2 = mv3 = mv4 = mv_25 = mv_26 = mv_27 = mv_28 = mv_29 = mv0 = mv1 = ( + mv2 + ) = mv_1403 = mv4 = mv35 = mv36 = mv37 = mv38 = mv39 = mv0 = -sys.maxsize / 3 + + mv1 = mv_12 = mv3 = mv_14 = mv45 = sys.float_info.epsilon + mv46 = sys.float_info.epsilon + + for i in range(15000): + f1() + """), PYTHON_JIT="1") + self.assertEqual(result[0].rc, 0, result) + def test_144068_daemon_thread_jit_cleanup(self): result = script_helper.run_python_until_end('-c', textwrap.dedent(""" import threading diff --git a/Python/pystate.c b/Python/pystate.c index ff712019affbf9..530bd567b770be 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -634,7 +634,7 @@ init_interpreter(PyInterpreterState *interp, // Trace fitness configuration init_policy(&interp->opt_config.fitness_initial, "PYTHON_JIT_FITNESS_INITIAL", - FITNESS_INITIAL, EXIT_QUALITY_CLOSE_LOOP, UOP_MAX_TRACE_LENGTH - 1); + FITNESS_INITIAL, EXIT_QUALITY_CLOSE_LOOP, FITNESS_INITIAL); interp->opt_config.specialization_enabled = !is_env_enabled("PYTHON_SPECIALIZATION_OFF"); interp->opt_config.uops_optimize_enabled = !is_env_disabled("PYTHON_UOPS_OPTIMIZE"); From c3d21e5a11769ae318cb5c4c96a381a22629654e Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 24 May 2026 14:02:45 +0200 Subject: [PATCH 124/818] [3.15] gh-148932: Docs / `profiling.sampling` Windows limitations (GH-150272) (#150330) gh-148932: Docs / `profiling.sampling` Windows limitations (GH-150272) (cherry picked from commit 0f32750fe26428de5e439803cf57f51847c81ce8) Co-authored-by: Eduardo Villalpando Mello --- Doc/library/profiling.sampling.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Doc/library/profiling.sampling.rst b/Doc/library/profiling.sampling.rst index aeb1a429b58515..39b6ea4e31cde7 100644 --- a/Doc/library/profiling.sampling.rst +++ b/Doc/library/profiling.sampling.rst @@ -387,6 +387,11 @@ This requires one of: On Windows, the profiler requires administrative privileges or the ``SeDebugPrivilege`` privilege to read another process's memory. +*Note*: On Windows, ``python -m profiling.sampling`` fails inside a virtual +environment because the venv's ``python.exe`` is just a launcher shim that +re-executes the base interpreter as a child process. The shim itself isn't +a Python process and has no ``PyRuntime`` section to attach to. Instead, +run it from the global Python installation. Version compatibility --------------------- From 1b7ab11cd68b645e8be5f18730644a0245d76b47 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 24 May 2026 15:09:13 +0200 Subject: [PATCH 125/818] [3.15] gh-150285: Fix too long docstrings in the _remote_debugging module (GH-150289) (#150334) gh-150285: Fix too long docstrings in the _remote_debugging module (GH-150289) (cherry picked from commit cdc499ae775e5204ef6bbb0a63bb00e85b0b6b72) Co-authored-by: Serhiy Storchaka --- Modules/_remote_debugging/clinic/module.c.h | 197 +++++++++------- Modules/_remote_debugging/module.c | 235 +++++++++++--------- 2 files changed, 251 insertions(+), 181 deletions(-) diff --git a/Modules/_remote_debugging/clinic/module.c.h b/Modules/_remote_debugging/clinic/module.c.h index 78b1d3e8d80962..d01f3d13e85f09 100644 --- a/Modules/_remote_debugging/clinic/module.c.h +++ b/Modules/_remote_debugging/clinic/module.c.h @@ -21,33 +21,37 @@ PyDoc_STRVAR(_remote_debugging_RemoteUnwinder___init____doc__, "\n" "Args:\n" " pid: Process ID of the target Python process to debug\n" -" all_threads: If True, initialize state for all threads in the process.\n" -" If False, only initialize for the main thread.\n" +" all_threads: If True, initialize state for all threads in the\n" +" process. If False, only initialize for the main thread.\n" " only_active_thread: If True, only sample the thread holding the GIL.\n" -" mode: Profiling mode: 0=WALL (wall-time), 1=CPU (cpu-time), 2=GIL (gil-time).\n" -" Cannot be used together with all_threads=True.\n" -" debug: If True, chain exceptions to explain the sequence of events that\n" -" lead to the exception.\n" -" skip_non_matching_threads: If True, skip threads that don\'t match the selected mode.\n" -" If False, include all threads regardless of mode.\n" -" native: If True, include artificial \"\" frames to denote calls to\n" -" non-Python code.\n" -" gc: If True, include artificial \"\" frames to denote active garbage\n" -" collection.\n" -" opcodes: If True, gather bytecode opcode information for instruction-level\n" -" profiling.\n" -" cache_frames: If True, enable frame caching optimization to avoid re-reading\n" -" unchanged parent frames between samples.\n" -" stats: If True, collect statistics about cache hits, memory reads, etc.\n" -" Use get_stats() to retrieve the collected statistics.\n" -"\n" -"The RemoteUnwinder provides functionality to inspect and debug a running Python\n" -"process, including examining thread states, stack frames and other runtime data.\n" +" mode: Profiling mode: 0=WALL (wall-time), 1=CPU (cpu-time), 2=GIL\n" +" (gil-time). Cannot be used together with all_threads=True.\n" +" debug: If True, chain exceptions to explain the sequence of events\n" +" that lead to the exception.\n" +" skip_non_matching_threads: If True, skip threads that don\'t match\n" +" the selected mode. If False, include all threads regardless of\n" +" mode.\n" +" native: If True, include artificial \"\" frames to denote\n" +" calls to non-Python code.\n" +" gc: If True, include artificial \"\" frames to denote active\n" +" garbage collection.\n" +" opcodes: If True, gather bytecode opcode information for\n" +" instruction-level profiling.\n" +" cache_frames: If True, enable frame caching optimization to avoid\n" +" re-reading unchanged parent frames between samples.\n" +" stats: If True, collect statistics about cache hits, memory reads,\n" +" etc. Use get_stats() to retrieve the collected statistics.\n" +"\n" +"The RemoteUnwinder provides functionality to inspect and debug a running\n" +"Python process, including examining thread states, stack frames and\n" +"other runtime data.\n" "\n" "Raises:\n" " PermissionError: If access to the target process is denied\n" -" OSError: If unable to attach to the target process or access its memory\n" -" RuntimeError: If unable to read debug information from the target process\n" +" OSError: If unable to attach to the target process or access its\n" +" memory\n" +" RuntimeError: If unable to read debug information from the target\n" +" process\n" " ValueError: If both all_threads and only_active_thread are True"); static int @@ -217,16 +221,21 @@ PyDoc_STRVAR(_remote_debugging_RemoteUnwinder_get_stack_trace__doc__, "\n" "Returns stack traces for all interpreters and threads in process.\n" "\n" -"Each element in the returned list is a tuple of (interpreter_id, thread_list), where:\n" +"Each element in the returned list is a tuple of (interpreter_id,\n" +"thread_list), where:\n" "- interpreter_id is the interpreter identifier\n" -"- thread_list is a list of tuples (thread_id, frame_list) for threads in that interpreter\n" +"- thread_list is a list of tuples (thread_id, frame_list) for\n" +" threads in that interpreter\n" " - thread_id is the OS thread identifier\n" -" - frame_list is a list of tuples (function_name, filename, line_number) representing\n" -" the Python stack frames for that thread, ordered from most recent to oldest\n" +" - frame_list is a list of tuples (function_name, filename,\n" +" line_number) representing the Python stack frames for that\n" +" thread, ordered from most recent to oldest\n" "\n" "The threads returned depend on the initialization parameters:\n" -"- If only_active_thread was True: returns only the thread holding the GIL across all interpreters\n" -"- If all_threads was True: returns all threads across all interpreters\n" +"- If only_active_thread was True: returns only the thread holding\n" +" the GIL across all interpreters\n" +"- If all_threads was True: returns all threads across all\n" +" interpreters\n" "- Otherwise: returns only the main thread of each interpreter\n" "\n" "Example:\n" @@ -250,10 +259,12 @@ PyDoc_STRVAR(_remote_debugging_RemoteUnwinder_get_stack_trace__doc__, " ]\n" "\n" "Raises:\n" -" RuntimeError: If there is an error copying memory from the target process\n" +" RuntimeError: If there is an error copying memory from the\n" +" target process\n" " OSError: If there is an error accessing the target process\n" " PermissionError: If access to the target process is denied\n" -" UnicodeDecodeError: If there is an error decoding strings from the target process"); +" UnicodeDecodeError: If there is an error decoding strings from\n" +" the target process"); #define _REMOTE_DEBUGGING_REMOTEUNWINDER_GET_STACK_TRACE_METHODDEF \ {"get_stack_trace", (PyCFunction)_remote_debugging_RemoteUnwinder_get_stack_trace, METH_NOARGS, _remote_debugging_RemoteUnwinder_get_stack_trace__doc__}, @@ -279,20 +290,25 @@ PyDoc_STRVAR(_remote_debugging_RemoteUnwinder_get_all_awaited_by__doc__, "\n" "Get all tasks and their awaited_by relationships from the remote process.\n" "\n" -"This provides a tree structure showing which tasks are waiting for other tasks.\n" +"This provides a tree structure showing which tasks are waiting for\n" +"other tasks.\n" "\n" "For each task, returns:\n" -"1. The call stack frames leading to where the task is currently executing\n" +"1. The call stack frames leading to where the task is currently\n" +" executing\n" "2. The name of the task\n" -"3. A list of tasks that this task is waiting for, with their own frames/names/etc\n" +"3. A list of tasks that this task is waiting for, with their own\n" +" frames/names/etc\n" "\n" "Returns a list of [frames, task_name, subtasks] where:\n" -"- frames: List of (func_name, filename, lineno) showing the call stack\n" +"- frames: List of (func_name, filename, lineno) showing the call\n" +" stack\n" "- task_name: String identifier for the task\n" "- subtasks: List of tasks being awaited by this task, in same format\n" "\n" "Raises:\n" -" RuntimeError: If AsyncioDebug section is not available in the remote process\n" +" RuntimeError: If AsyncioDebug section is not available in the\n" +" remote process\n" " MemoryError: If memory allocation fails\n" " OSError: If reading from the remote process fails\n" "\n" @@ -336,14 +352,16 @@ PyDoc_STRVAR(_remote_debugging_RemoteUnwinder_get_async_stack_trace__doc__, "\n" "Get the currently running async tasks and their dependency graphs from the remote process.\n" "\n" -"This returns information about running tasks and all tasks that are waiting for them,\n" -"forming a complete dependency graph for each thread\'s active task.\n" +"This returns information about running tasks and all tasks that are\n" +"waiting for them, forming a complete dependency graph for each\n" +"thread\'s active task.\n" "\n" -"For each thread with a running task, returns the running task plus all tasks that\n" -"transitively depend on it (tasks waiting for the running task, tasks waiting for\n" -"those tasks, etc.).\n" +"For each thread with a running task, returns the running task plus\n" +"all tasks that transitively depend on it (tasks waiting for the\n" +"running task, tasks waiting for those tasks, etc.).\n" "\n" -"Returns a list of per-thread results, where each thread result contains:\n" +"Returns a list of per-thread results, where each thread result\n" +"contains:\n" "- Thread ID\n" "- List of task information for the running task and all its waiters\n" "\n" @@ -354,11 +372,13 @@ PyDoc_STRVAR(_remote_debugging_RemoteUnwinder_get_async_stack_trace__doc__, "- List of tasks waiting for this task (recursive structure)\n" "\n" "Raises:\n" -" RuntimeError: If AsyncioDebug section is not available in the target process\n" +" RuntimeError: If AsyncioDebug section is not available in the\n" +" target process\n" " MemoryError: If memory allocation fails\n" " OSError: If reading from the remote process fails\n" "\n" -"Example output (similar structure to get_all_awaited_by but only for running tasks):\n" +"Example output (similar structure to get_all_awaited_by but only for\n" +"running tasks):\n" "[\n" " (140234, [\n" " (4345585712, \'main_task\',\n" @@ -403,23 +423,34 @@ PyDoc_STRVAR(_remote_debugging_RemoteUnwinder_get_stats__doc__, " - total_samples: Total number of get_stack_trace calls\n" " - frame_cache_hits: Full cache hits (entire stack unchanged)\n" " - frame_cache_misses: Cache misses requiring full walk\n" -" - frame_cache_partial_hits: Partial hits (stopped at cached frame)\n" +" - frame_cache_partial_hits: Partial hits (stopped at cached\n" +" frame)\n" " - frames_read_from_cache: Total frames retrieved from cache\n" -" - frames_read_from_memory: Total frames read from remote memory\n" +" - frames_read_from_memory: Total frames read from remote\n" +" memory\n" " - memory_reads: Total remote memory read operations\n" " - memory_bytes_read: Total bytes read from remote memory\n" " - code_object_cache_hits: Code object cache hits\n" " - code_object_cache_misses: Code object cache misses\n" -" - stale_cache_invalidations: Times stale cache entries were cleared\n" +" - stale_cache_invalidations: Times stale cache entries were\n" +" cleared\n" " - batched_read_attempts: Batched remote-read attempts\n" -" - batched_read_successes: Attempts that read all requested segments\n" -" - batched_read_misses: Attempts that fell back or partially read\n" -" - batched_read_segments_requested: Segments requested by batched reads\n" -" - batched_read_segments_completed: Segments completed by batched reads\n" -" - frame_cache_hit_rate: Percentage of samples that hit the cache\n" -" - code_object_cache_hit_rate: Percentage of code object lookups that hit cache\n" -" - batched_read_success_rate: Percentage of batched reads that completed all segments\n" -" - batched_read_segment_completion_rate: Percentage of requested segments read by batched reads\n" +" - batched_read_successes: Attempts that read all requested\n" +" segments\n" +" - batched_read_misses: Attempts that fell back or partially\n" +" read\n" +" - batched_read_segments_requested: Segments requested by\n" +" batched reads\n" +" - batched_read_segments_completed: Segments completed by\n" +" batched reads\n" +" - frame_cache_hit_rate: Percentage of samples that hit the\n" +" cache\n" +" - code_object_cache_hit_rate: Percentage of code object\n" +" lookups that hit cache\n" +" - batched_read_success_rate: Percentage of batched reads\n" +" that completed all segments\n" +" - batched_read_segment_completion_rate: Percentage of\n" +" requested segments read by batched reads\n" "\n" "Raises:\n" " RuntimeError: If stats collection was not enabled (stats=False)"); @@ -449,9 +480,11 @@ PyDoc_STRVAR(_remote_debugging_RemoteUnwinder_pause_threads__doc__, "Pause all threads in the target process.\n" "\n" "This stops all threads in the target process to allow for consistent\n" -"memory reads during sampling. Must be paired with a call to resume_threads().\n" +"memory reads during sampling. Must be paired with a call to\n" +"resume_threads().\n" "\n" -"Returns True if threads were successfully paused, False if they were already paused.\n" +"Returns True if threads were successfully paused, False if they were\n" +"already paused.\n" "\n" "Raises:\n" " RuntimeError: If there is an error stopping the threads"); @@ -480,9 +513,11 @@ PyDoc_STRVAR(_remote_debugging_RemoteUnwinder_resume_threads__doc__, "\n" "Resume all threads in the target process.\n" "\n" -"This resumes threads that were previously paused with pause_threads().\n" +"This resumes threads that were previously paused with\n" +"pause_threads().\n" "\n" -"Returns True if threads were successfully resumed, False if they were not paused."); +"Returns True if threads were successfully resumed, False if they\n" +"were not paused."); #define _REMOTE_DEBUGGING_REMOTEUNWINDER_RESUME_THREADS_METHODDEF \ {"resume_threads", (PyCFunction)_remote_debugging_RemoteUnwinder_resume_threads, METH_NOARGS, _remote_debugging_RemoteUnwinder_resume_threads__doc__}, @@ -510,16 +545,18 @@ PyDoc_STRVAR(_remote_debugging_GCMonitor___init____doc__, "\n" "Args:\n" " pid: Process ID of the target Python process to monitor\n" -" debug: If True, chain exceptions to explain the sequence of events that\n" -" lead to the exception.\n" +" debug: If True, chain exceptions to explain the sequence of\n" +" events that lead to the exception.\n" "\n" -"The GCMonitor provides functionality to read GC statistics from a running\n" -"Python process.\n" +"The GCMonitor provides functionality to read GC statistics from\n" +"a running Python process.\n" "\n" "Raises:\n" " PermissionError: If access to the target process is denied\n" -" OSError: If unable to attach to the target process or access its memory\n" -" RuntimeError: If unable to read debug information from the target process"); +" OSError: If unable to attach to the target process or access\n" +" its memory\n" +" RuntimeError: If unable to read debug information from the\n" +" target process"); static int _remote_debugging_GCMonitor___init___impl(GCMonitorObject *self, int pid, @@ -612,8 +649,8 @@ PyDoc_STRVAR(_remote_debugging_GCMonitor_get_gc_stats__doc__, " - duration: Total collection time, in seconds.\n" "\n" "Raises:\n" -" RuntimeError: If the target process cannot be inspected or if its\n" -" debug offsets or GC stats layout are incompatible."); +" RuntimeError: If the target process cannot be inspected or if\n" +" its debug offsets or GC stats layout are incompatible."); #define _REMOTE_DEBUGGING_GCMONITOR_GET_GC_STATS_METHODDEF \ {"get_gc_stats", _PyCFunction_CAST(_remote_debugging_GCMonitor_get_gc_stats), METH_FASTCALL|METH_KEYWORDS, _remote_debugging_GCMonitor_get_gc_stats__doc__}, @@ -688,7 +725,8 @@ PyDoc_STRVAR(_remote_debugging_BinaryWriter___init____doc__, "Arguments:\n" " filename: Path to output file\n" " sample_interval_us: Sampling interval in microseconds\n" -" start_time_us: Start timestamp in microseconds (from time.monotonic() * 1e6)\n" +" start_time_us: Start timestamp in microseconds (from\n" +" time.monotonic() * 1e6)\n" " compression: 0=none, 1=zstd (default: 0)\n" "\n" "Use as a context manager or call finalize() when done."); @@ -774,7 +812,8 @@ PyDoc_STRVAR(_remote_debugging_BinaryWriter_write_sample__doc__, "\n" "Arguments:\n" " stack_frames: List of InterpreterInfo objects\n" -" timestamp_us: Current timestamp in microseconds (from time.monotonic() * 1e6)"); +" timestamp_us: Current timestamp in microseconds (from\n" +" time.monotonic() * 1e6)"); #define _REMOTE_DEBUGGING_BINARYWRITER_WRITE_SAMPLE_METHODDEF \ {"write_sample", _PyCFunction_CAST(_remote_debugging_BinaryWriter_write_sample), METH_FASTCALL|METH_KEYWORDS, _remote_debugging_BinaryWriter_write_sample__doc__}, @@ -976,8 +1015,9 @@ PyDoc_STRVAR(_remote_debugging_BinaryWriter_get_stats__doc__, "\n" "Get encoding statistics for the writer.\n" "\n" -"Returns a dict with encoding statistics including repeat/full/suffix/pop-push\n" -"record counts, frames written/saved, and compression ratio."); +"Returns a dict with encoding statistics including\n" +"repeat/full/suffix/pop-push record counts, frames written/saved, and\n" +"compression ratio."); #define _REMOTE_DEBUGGING_BINARYWRITER_GET_STATS_METHODDEF \ {"get_stats", (PyCFunction)_remote_debugging_BinaryWriter_get_stats, METH_NOARGS, _remote_debugging_BinaryWriter_get_stats__doc__}, @@ -1155,8 +1195,8 @@ PyDoc_STRVAR(_remote_debugging_BinaryReader_get_stats__doc__, "\n" "Get reconstruction statistics from replay.\n" "\n" -"Returns a dict with statistics about record types decoded and samples\n" -"reconstructed during replay."); +"Returns a dict with statistics about record types decoded and\n" +"samples reconstructed during replay."); #define _REMOTE_DEBUGGING_BINARYREADER_GET_STATS_METHODDEF \ {"get_stats", (PyCFunction)_remote_debugging_BinaryReader_get_stats, METH_NOARGS, _remote_debugging_BinaryReader_get_stats__doc__}, @@ -1319,11 +1359,12 @@ PyDoc_STRVAR(_remote_debugging_get_child_pids__doc__, " If True, return all descendants (children, grandchildren, etc.).\n" " If False, return only direct children.\n" "\n" -"Returns a list of child process IDs. Returns an empty list if no children\n" -"are found.\n" +"Returns a list of child process IDs. Returns an empty list if no\n" +"children are found.\n" "\n" -"This function provides a snapshot of child processes at a moment in time.\n" -"Child processes may exit or new ones may be created after the list is returned.\n" +"This function provides a snapshot of child processes at a moment in\n" +"time. Child processes may exit or new ones may be created after the\n" +"list is returned.\n" "\n" "Raises:\n" " OSError: If unable to enumerate processes\n" @@ -1547,4 +1588,4 @@ _remote_debugging_get_gc_stats(PyObject *module, PyObject *const *args, Py_ssize exit: return return_value; } -/*[clinic end generated code: output=884914b100e9c90c input=a9049054013a1b77]*/ +/*[clinic end generated code: output=a3df14a6ab7f2998 input=a9049054013a1b77]*/ diff --git a/Modules/_remote_debugging/module.c b/Modules/_remote_debugging/module.c index ae2f7e7f31ba77..3e60a7c2f794ad 100644 --- a/Modules/_remote_debugging/module.c +++ b/Modules/_remote_debugging/module.c @@ -280,7 +280,6 @@ class _remote_debugging.RemoteUnwinder "RemoteUnwinderObject *" "&RemoteUnwinder /*[clinic input] @permit_long_summary -@permit_long_docstring_body _remote_debugging.RemoteUnwinder.__init__ pid: int * @@ -299,33 +298,37 @@ Initialize a new RemoteUnwinder object for debugging a remote Python process. Args: pid: Process ID of the target Python process to debug - all_threads: If True, initialize state for all threads in the process. - If False, only initialize for the main thread. + all_threads: If True, initialize state for all threads in the + process. If False, only initialize for the main thread. only_active_thread: If True, only sample the thread holding the GIL. - mode: Profiling mode: 0=WALL (wall-time), 1=CPU (cpu-time), 2=GIL (gil-time). - Cannot be used together with all_threads=True. - debug: If True, chain exceptions to explain the sequence of events that - lead to the exception. - skip_non_matching_threads: If True, skip threads that don't match the selected mode. - If False, include all threads regardless of mode. - native: If True, include artificial "" frames to denote calls to - non-Python code. - gc: If True, include artificial "" frames to denote active garbage - collection. - opcodes: If True, gather bytecode opcode information for instruction-level - profiling. - cache_frames: If True, enable frame caching optimization to avoid re-reading - unchanged parent frames between samples. - stats: If True, collect statistics about cache hits, memory reads, etc. - Use get_stats() to retrieve the collected statistics. - -The RemoteUnwinder provides functionality to inspect and debug a running Python -process, including examining thread states, stack frames and other runtime data. + mode: Profiling mode: 0=WALL (wall-time), 1=CPU (cpu-time), 2=GIL + (gil-time). Cannot be used together with all_threads=True. + debug: If True, chain exceptions to explain the sequence of events + that lead to the exception. + skip_non_matching_threads: If True, skip threads that don't match + the selected mode. If False, include all threads regardless of + mode. + native: If True, include artificial "" frames to denote + calls to non-Python code. + gc: If True, include artificial "" frames to denote active + garbage collection. + opcodes: If True, gather bytecode opcode information for + instruction-level profiling. + cache_frames: If True, enable frame caching optimization to avoid + re-reading unchanged parent frames between samples. + stats: If True, collect statistics about cache hits, memory reads, + etc. Use get_stats() to retrieve the collected statistics. + +The RemoteUnwinder provides functionality to inspect and debug a running +Python process, including examining thread states, stack frames and +other runtime data. Raises: PermissionError: If access to the target process is denied - OSError: If unable to attach to the target process or access its memory - RuntimeError: If unable to read debug information from the target process + OSError: If unable to attach to the target process or access its + memory + RuntimeError: If unable to read debug information from the target + process ValueError: If both all_threads and only_active_thread are True [clinic start generated code]*/ @@ -338,7 +341,7 @@ _remote_debugging_RemoteUnwinder___init___impl(RemoteUnwinderObject *self, int native, int gc, int opcodes, int cache_frames, int stats) -/*[clinic end generated code: output=0031f743f4b9ad52 input=8fb61b24102dec6e]*/ +/*[clinic end generated code: output=0031f743f4b9ad52 input=9d25ae328d62626d]*/ { // Validate that all_threads and only_active_thread are not both True if (all_threads && only_active_thread) { @@ -645,22 +648,26 @@ read_interp_state_and_maybe_thread_frame( } /*[clinic input] -@permit_long_docstring_body @critical_section _remote_debugging.RemoteUnwinder.get_stack_trace Returns stack traces for all interpreters and threads in process. -Each element in the returned list is a tuple of (interpreter_id, thread_list), where: +Each element in the returned list is a tuple of (interpreter_id, +thread_list), where: - interpreter_id is the interpreter identifier -- thread_list is a list of tuples (thread_id, frame_list) for threads in that interpreter +- thread_list is a list of tuples (thread_id, frame_list) for + threads in that interpreter - thread_id is the OS thread identifier - - frame_list is a list of tuples (function_name, filename, line_number) representing - the Python stack frames for that thread, ordered from most recent to oldest + - frame_list is a list of tuples (function_name, filename, + line_number) representing the Python stack frames for that + thread, ordered from most recent to oldest The threads returned depend on the initialization parameters: -- If only_active_thread was True: returns only the thread holding the GIL across all interpreters -- If all_threads was True: returns all threads across all interpreters +- If only_active_thread was True: returns only the thread holding + the GIL across all interpreters +- If all_threads was True: returns all threads across all + interpreters - Otherwise: returns only the main thread of each interpreter Example: @@ -684,16 +691,18 @@ The threads returned depend on the initialization parameters: ] Raises: - RuntimeError: If there is an error copying memory from the target process + RuntimeError: If there is an error copying memory from the + target process OSError: If there is an error accessing the target process PermissionError: If access to the target process is denied - UnicodeDecodeError: If there is an error decoding strings from the target process + UnicodeDecodeError: If there is an error decoding strings from + the target process [clinic start generated code]*/ static PyObject * _remote_debugging_RemoteUnwinder_get_stack_trace_impl(RemoteUnwinderObject *self) -/*[clinic end generated code: output=666192b90c69d567 input=bcff01c73cccc1c0]*/ +/*[clinic end generated code: output=666192b90c69d567 input=86a992b853f48aa9]*/ { STATS_INC(self, total_samples); @@ -893,26 +902,30 @@ _remote_debugging_RemoteUnwinder_get_stack_trace_impl(RemoteUnwinderObject *self /*[clinic input] @permit_long_summary -@permit_long_docstring_body @critical_section _remote_debugging.RemoteUnwinder.get_all_awaited_by Get all tasks and their awaited_by relationships from the remote process. -This provides a tree structure showing which tasks are waiting for other tasks. +This provides a tree structure showing which tasks are waiting for +other tasks. For each task, returns: -1. The call stack frames leading to where the task is currently executing +1. The call stack frames leading to where the task is currently + executing 2. The name of the task -3. A list of tasks that this task is waiting for, with their own frames/names/etc +3. A list of tasks that this task is waiting for, with their own + frames/names/etc Returns a list of [frames, task_name, subtasks] where: -- frames: List of (func_name, filename, lineno) showing the call stack +- frames: List of (func_name, filename, lineno) showing the call + stack - task_name: String identifier for the task - subtasks: List of tasks being awaited by this task, in same format Raises: - RuntimeError: If AsyncioDebug section is not available in the remote process + RuntimeError: If AsyncioDebug section is not available in the + remote process MemoryError: If memory allocation fails OSError: If reading from the remote process fails @@ -939,7 +952,7 @@ Example output: static PyObject * _remote_debugging_RemoteUnwinder_get_all_awaited_by_impl(RemoteUnwinderObject *self) -/*[clinic end generated code: output=6a49cd345e8aec53 input=307f754cbe38250c]*/ +/*[clinic end generated code: output=6a49cd345e8aec53 input=c22bfee0612e0b69]*/ { if (ensure_async_debug_offsets(self) < 0) { return NULL; @@ -984,20 +997,21 @@ _remote_debugging_RemoteUnwinder_get_all_awaited_by_impl(RemoteUnwinderObject *s /*[clinic input] @permit_long_summary -@permit_long_docstring_body @critical_section _remote_debugging.RemoteUnwinder.get_async_stack_trace Get the currently running async tasks and their dependency graphs from the remote process. -This returns information about running tasks and all tasks that are waiting for them, -forming a complete dependency graph for each thread's active task. +This returns information about running tasks and all tasks that are +waiting for them, forming a complete dependency graph for each +thread's active task. -For each thread with a running task, returns the running task plus all tasks that -transitively depend on it (tasks waiting for the running task, tasks waiting for -those tasks, etc.). +For each thread with a running task, returns the running task plus +all tasks that transitively depend on it (tasks waiting for the +running task, tasks waiting for those tasks, etc.). -Returns a list of per-thread results, where each thread result contains: +Returns a list of per-thread results, where each thread result +contains: - Thread ID - List of task information for the running task and all its waiters @@ -1008,11 +1022,13 @@ Each task info contains: - List of tasks waiting for this task (recursive structure) Raises: - RuntimeError: If AsyncioDebug section is not available in the target process + RuntimeError: If AsyncioDebug section is not available in the + target process MemoryError: If memory allocation fails OSError: If reading from the remote process fails -Example output (similar structure to get_all_awaited_by but only for running tasks): +Example output (similar structure to get_all_awaited_by but only for +running tasks): [ # Thread 140234 results (140234, [ @@ -1031,7 +1047,7 @@ Example output (similar structure to get_all_awaited_by but only for running tas static PyObject * _remote_debugging_RemoteUnwinder_get_async_stack_trace_impl(RemoteUnwinderObject *self) -/*[clinic end generated code: output=6433d52b55e87bbe input=6129b7d509a887c9]*/ +/*[clinic end generated code: output=6433d52b55e87bbe input=bc802e4221c99399]*/ { if (ensure_async_debug_offsets(self) < 0) { return NULL; @@ -1060,7 +1076,6 @@ _remote_debugging_RemoteUnwinder_get_async_stack_trace_impl(RemoteUnwinderObject } /*[clinic input] -@permit_long_docstring_body @critical_section _remote_debugging.RemoteUnwinder.get_stats @@ -1075,23 +1090,34 @@ RemoteUnwinder was created with stats=True. - total_samples: Total number of get_stack_trace calls - frame_cache_hits: Full cache hits (entire stack unchanged) - frame_cache_misses: Cache misses requiring full walk - - frame_cache_partial_hits: Partial hits (stopped at cached frame) + - frame_cache_partial_hits: Partial hits (stopped at cached + frame) - frames_read_from_cache: Total frames retrieved from cache - - frames_read_from_memory: Total frames read from remote memory + - frames_read_from_memory: Total frames read from remote + memory - memory_reads: Total remote memory read operations - memory_bytes_read: Total bytes read from remote memory - code_object_cache_hits: Code object cache hits - code_object_cache_misses: Code object cache misses - - stale_cache_invalidations: Times stale cache entries were cleared + - stale_cache_invalidations: Times stale cache entries were + cleared - batched_read_attempts: Batched remote-read attempts - - batched_read_successes: Attempts that read all requested segments - - batched_read_misses: Attempts that fell back or partially read - - batched_read_segments_requested: Segments requested by batched reads - - batched_read_segments_completed: Segments completed by batched reads - - frame_cache_hit_rate: Percentage of samples that hit the cache - - code_object_cache_hit_rate: Percentage of code object lookups that hit cache - - batched_read_success_rate: Percentage of batched reads that completed all segments - - batched_read_segment_completion_rate: Percentage of requested segments read by batched reads + - batched_read_successes: Attempts that read all requested + segments + - batched_read_misses: Attempts that fell back or partially + read + - batched_read_segments_requested: Segments requested by + batched reads + - batched_read_segments_completed: Segments completed by + batched reads + - frame_cache_hit_rate: Percentage of samples that hit the + cache + - code_object_cache_hit_rate: Percentage of code object + lookups that hit cache + - batched_read_success_rate: Percentage of batched reads + that completed all segments + - batched_read_segment_completion_rate: Percentage of + requested segments read by batched reads Raises: RuntimeError: If stats collection was not enabled (stats=False) @@ -1099,7 +1125,7 @@ RemoteUnwinder was created with stats=True. static PyObject * _remote_debugging_RemoteUnwinder_get_stats_impl(RemoteUnwinderObject *self) -/*[clinic end generated code: output=21e36477122be2a0 input=0392d62b278e9c35]*/ +/*[clinic end generated code: output=21e36477122be2a0 input=87905c65038fb06e]*/ { if (!self->collect_stats) { PyErr_SetString(PyExc_RuntimeError, @@ -1192,16 +1218,17 @@ _remote_debugging_RemoteUnwinder_get_stats_impl(RemoteUnwinderObject *self) } /*[clinic input] -@permit_long_docstring_body @critical_section _remote_debugging.RemoteUnwinder.pause_threads Pause all threads in the target process. This stops all threads in the target process to allow for consistent -memory reads during sampling. Must be paired with a call to resume_threads(). +memory reads during sampling. Must be paired with a call to +resume_threads(). -Returns True if threads were successfully paused, False if they were already paused. +Returns True if threads were successfully paused, False if they were +already paused. Raises: RuntimeError: If there is an error stopping the threads @@ -1209,7 +1236,7 @@ Returns True if threads were successfully paused, False if they were already pau static PyObject * _remote_debugging_RemoteUnwinder_pause_threads_impl(RemoteUnwinderObject *self) -/*[clinic end generated code: output=aaf2bdc0a725750c input=d8a266f19a81c67e]*/ +/*[clinic end generated code: output=aaf2bdc0a725750c input=b91dde5517c9dde2]*/ { #ifdef Py_REMOTE_DEBUG_SUPPORTS_BLOCKING if (self->threads_stopped) { @@ -1231,20 +1258,21 @@ _remote_debugging_RemoteUnwinder_pause_threads_impl(RemoteUnwinderObject *self) } /*[clinic input] -@permit_long_docstring_body @critical_section _remote_debugging.RemoteUnwinder.resume_threads Resume all threads in the target process. -This resumes threads that were previously paused with pause_threads(). +This resumes threads that were previously paused with +pause_threads(). -Returns True if threads were successfully resumed, False if they were not paused. +Returns True if threads were successfully resumed, False if they +were not paused. [clinic start generated code]*/ static PyObject * _remote_debugging_RemoteUnwinder_resume_threads_impl(RemoteUnwinderObject *self) -/*[clinic end generated code: output=8d6781ea37095536 input=16baaaab007f4259]*/ +/*[clinic end generated code: output=8d6781ea37095536 input=130758d55d46897a]*/ { #ifdef Py_REMOTE_DEBUG_SUPPORTS_BLOCKING if (!self->threads_stopped) { @@ -1382,7 +1410,6 @@ class _remote_debugging.GCMonitor "GCMonitorObject *" "&GCMonitor_Type" /*[clinic input] @permit_long_summary -@permit_long_docstring_body _remote_debugging.GCMonitor.__init__ pid: int * @@ -1392,22 +1419,24 @@ Initialize a new GCMonitor object for monitoring GC events from remote process. Args: pid: Process ID of the target Python process to monitor - debug: If True, chain exceptions to explain the sequence of events that - lead to the exception. + debug: If True, chain exceptions to explain the sequence of + events that lead to the exception. -The GCMonitor provides functionality to read GC statistics from a running -Python process. +The GCMonitor provides functionality to read GC statistics from +a running Python process. Raises: PermissionError: If access to the target process is denied - OSError: If unable to attach to the target process or access its memory - RuntimeError: If unable to read debug information from the target process + OSError: If unable to attach to the target process or access + its memory + RuntimeError: If unable to read debug information from the + target process [clinic start generated code]*/ static int _remote_debugging_GCMonitor___init___impl(GCMonitorObject *self, int pid, int debug) -/*[clinic end generated code: output=2cdf351c2f6335db input=1185a48535b808be]*/ +/*[clinic end generated code: output=2cdf351c2f6335db input=03da0b2d3282ae1b]*/ { return init_runtime_offsets(&self->offsets, pid, debug); } @@ -1438,14 +1467,14 @@ Returns a list of GCStatsInfo objects with GC statistics data. - duration: Total collection time, in seconds. Raises: - RuntimeError: If the target process cannot be inspected or if its - debug offsets or GC stats layout are incompatible. + RuntimeError: If the target process cannot be inspected or if + its debug offsets or GC stats layout are incompatible. [clinic start generated code]*/ static PyObject * _remote_debugging_GCMonitor_get_gc_stats_impl(GCMonitorObject *self, int all_interpreters) -/*[clinic end generated code: output=f73f365725224f7a input=12f7c1a288cf2741]*/ +/*[clinic end generated code: output=f73f365725224f7a input=ec016bc4be6dd003]*/ { RemoteDebuggingState *st = RemoteDebugging_GetStateFromType(Py_TYPE(self)); return get_gc_stats(&self->offsets, all_interpreters, st->GCStatsInfo_Type); @@ -1682,7 +1711,6 @@ class _remote_debugging.BinaryWriter "BinaryWriterObject *" "&PyBinaryWriter_Typ /*[clinic end generated code: output=da39a3ee5e6b4b0d input=e948838b90a2003c]*/ /*[clinic input] -@permit_long_docstring_body _remote_debugging.BinaryWriter.__init__ filename: object sample_interval_us: unsigned_long_long @@ -1695,7 +1723,8 @@ High-performance binary writer for profiling data. Arguments: filename: Path to output file sample_interval_us: Sampling interval in microseconds - start_time_us: Start timestamp in microseconds (from time.monotonic() * 1e6) + start_time_us: Start timestamp in microseconds (from + time.monotonic() * 1e6) compression: 0=none, 1=zstd (default: 0) Use as a context manager or call finalize() when done. @@ -1707,7 +1736,7 @@ _remote_debugging_BinaryWriter___init___impl(BinaryWriterObject *self, unsigned long long sample_interval_us, unsigned long long start_time_us, int compression) -/*[clinic end generated code: output=00446656ea2e5986 input=b92f0c77ba4cd274]*/ +/*[clinic end generated code: output=00446656ea2e5986 input=2e3f298c69fc7666]*/ { if (self->writer) { binary_writer_destroy(self->writer); @@ -1722,7 +1751,6 @@ _remote_debugging_BinaryWriter___init___impl(BinaryWriterObject *self, } /*[clinic input] -@permit_long_docstring_body _remote_debugging.BinaryWriter.write_sample stack_frames: object timestamp_us: unsigned_long_long @@ -1731,14 +1759,15 @@ Write a sample to the binary file. Arguments: stack_frames: List of InterpreterInfo objects - timestamp_us: Current timestamp in microseconds (from time.monotonic() * 1e6) + timestamp_us: Current timestamp in microseconds (from + time.monotonic() * 1e6) [clinic start generated code]*/ static PyObject * _remote_debugging_BinaryWriter_write_sample_impl(BinaryWriterObject *self, PyObject *stack_frames, unsigned long long timestamp_us) -/*[clinic end generated code: output=24d5b86679b4128f input=4e6d832d360bea46]*/ +/*[clinic end generated code: output=24d5b86679b4128f input=5033f1ae7fa135f1]*/ { if (!self->writer) { PyErr_SetString(PyExc_ValueError, "Writer is closed"); @@ -1861,18 +1890,18 @@ _remote_debugging_BinaryWriter___exit___impl(BinaryWriterObject *self, } /*[clinic input] -@permit_long_docstring_body _remote_debugging.BinaryWriter.get_stats Get encoding statistics for the writer. -Returns a dict with encoding statistics including repeat/full/suffix/pop-push -record counts, frames written/saved, and compression ratio. +Returns a dict with encoding statistics including +repeat/full/suffix/pop-push record counts, frames written/saved, and +compression ratio. [clinic start generated code]*/ static PyObject * _remote_debugging_BinaryWriter_get_stats_impl(BinaryWriterObject *self) -/*[clinic end generated code: output=06522cd52544df89 input=837c874ffdebd24c]*/ +/*[clinic end generated code: output=06522cd52544df89 input=a8bb8c8682ccd34b]*/ { if (!self->writer) { PyErr_SetString(PyExc_ValueError, "Writer is closed"); @@ -2037,13 +2066,13 @@ _remote_debugging.BinaryReader.get_stats Get reconstruction statistics from replay. -Returns a dict with statistics about record types decoded and samples -reconstructed during replay. +Returns a dict with statistics about record types decoded and +samples reconstructed during replay. [clinic start generated code]*/ static PyObject * _remote_debugging_BinaryReader_get_stats_impl(BinaryReaderObject *self) -/*[clinic end generated code: output=628b9ab5e4c4fd36 input=d8dd6654abd6c3c0]*/ +/*[clinic end generated code: output=628b9ab5e4c4fd36 input=15b8d8f89ccf3726]*/ { if (!self->reader) { PyErr_SetString(PyExc_ValueError, "Reader is closed"); @@ -2195,7 +2224,6 @@ _remote_debugging_zstd_available_impl(PyObject *module) * ============================================================================ */ /*[clinic input] -@permit_long_docstring_body _remote_debugging.get_child_pids pid: int @@ -2207,11 +2235,12 @@ _remote_debugging.get_child_pids Get all child process IDs of the given process. -Returns a list of child process IDs. Returns an empty list if no children -are found. +Returns a list of child process IDs. Returns an empty list if no +children are found. -This function provides a snapshot of child processes at a moment in time. -Child processes may exit or new ones may be created after the list is returned. +This function provides a snapshot of child processes at a moment in +time. Child processes may exit or new ones may be created after the +list is returned. Raises: OSError: If unable to enumerate processes @@ -2221,7 +2250,7 @@ Child processes may exit or new ones may be created after the list is returned. static PyObject * _remote_debugging_get_child_pids_impl(PyObject *module, int pid, int recursive) -/*[clinic end generated code: output=1ae2289c6b953e4b input=19d8d5d6e2b59e6e]*/ +/*[clinic end generated code: output=1ae2289c6b953e4b input=c6437b52e2fdd880]*/ { return enumerate_child_pids((pid_t)pid, recursive); } From 29cbb44200be6f4fdcea676ffaf6935f4cabf66e Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 24 May 2026 15:23:25 +0200 Subject: [PATCH 126/818] [3.15] gh-150285: Fix too long docstrings in the curses module (GH-150286) (GH-150331) (cherry picked from commit 4c0fe2d134f6ddaa4c705ffba073d9d5874b7fe4) Co-authored-by: Serhiy Storchaka --- Lib/curses/textpad.py | 12 +- Modules/_curses_panel.c | 11 +- Modules/_cursesmodule.c | 415 ++++++++++++++++--------------- Modules/clinic/_curses_panel.c.h | 8 +- Modules/clinic/_cursesmodule.c.h | 282 +++++++++++---------- 5 files changed, 381 insertions(+), 347 deletions(-) diff --git a/Lib/curses/textpad.py b/Lib/curses/textpad.py index aa87061b8d749e..3a98fd6043a124 100644 --- a/Lib/curses/textpad.py +++ b/Lib/curses/textpad.py @@ -23,7 +23,8 @@ class Textbox: Ctrl-A Go to left edge of window. Ctrl-B Cursor left, wrapping to previous line if appropriate. Ctrl-D Delete character under cursor. - Ctrl-E Go to right edge (stripspaces off) or end of line (stripspaces on). + Ctrl-E Go to right edge (stripspaces off) or end of line + (stripspaces on). Ctrl-F Cursor right, wrapping to next line when appropriate. Ctrl-G Terminate, returning the window contents. Ctrl-H Delete character backward. @@ -34,11 +35,12 @@ class Textbox: Ctrl-O Insert a blank line at cursor location. Ctrl-P Cursor up; move up one line. - Move operations do nothing if the cursor is at an edge where the movement - is not possible. The following synonyms are supported where possible: + Move operations do nothing if the cursor is at an edge where the + movement is not possible. The following synonyms are supported where + possible: - KEY_LEFT = Ctrl-B, KEY_RIGHT = Ctrl-F, KEY_UP = Ctrl-P, KEY_DOWN = Ctrl-N - KEY_BACKSPACE = Ctrl-h + KEY_LEFT = Ctrl-B, KEY_RIGHT = Ctrl-F, KEY_UP = Ctrl-P, + KEY_DOWN = Ctrl-N, KEY_BACKSPACE = Ctrl-h """ def __init__(self, win, insert_mode=False): self.win = win diff --git a/Modules/_curses_panel.c b/Modules/_curses_panel.c index 83802605e1f4dc..52411e413533ce 100644 --- a/Modules/_curses_panel.c +++ b/Modules/_curses_panel.c @@ -360,17 +360,17 @@ _curses_panel_panel_bottom_impl(PyCursesPanelObject *self) } /*[clinic input] -@permit_long_docstring_body _curses_panel.panel.hide Hide the panel. -This does not delete the object, it just makes the window on screen invisible. +This does not delete the object, it just makes the window on screen +invisible. [clinic start generated code]*/ static PyObject * _curses_panel_panel_hide_impl(PyCursesPanelObject *self) -/*[clinic end generated code: output=a7bbbd523e1eab49 input=9071b463a39a1a6a]*/ +/*[clinic end generated code: output=a7bbbd523e1eab49 input=9456aca9b264dde1]*/ { int rtn = hide_panel(self->pan); return curses_panel_panel_check_err(self, rtn, "hide_panel", "hide"); @@ -772,12 +772,13 @@ _curses_panel.update_panels Updates the virtual screen after changes in the panel stack. -This does not call curses.doupdate(), so you'll have to do this yourself. +This does not call curses.doupdate(), so you'll have to do this +yourself. [clinic start generated code]*/ static PyObject * _curses_panel_update_panels_impl(PyObject *module) -/*[clinic end generated code: output=2f3b4c2e03d90ded input=5299624c9a708621]*/ +/*[clinic end generated code: output=2f3b4c2e03d90ded input=0d0db79f05ec3ef4]*/ { PyCursesInitialised; update_panels(); diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index 000d7318557a6e..4438e384aab9b2 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -1359,7 +1359,6 @@ _curses_window_bkgdset_impl(PyCursesWindowObject *self, PyObject *ch, } /*[clinic input] -@permit_long_docstring_body _curses.window.border ls: object(c_default="NULL") = _curses.ACS_VLINE @@ -1382,10 +1381,10 @@ _curses.window.border Draw a border around the edges of the window. -Each parameter specifies the character to use for a specific part of the -border. The characters can be specified as integers or as one-character -strings. A 0 value for any parameter will cause the default character to be -used for that parameter. +Each parameter specifies the character to use for a specific part of +the border. The characters can be specified as integers or as +one-character strings. A 0 value for any parameter will cause the +default character to be used for that parameter. [clinic start generated code]*/ static PyObject * @@ -1393,7 +1392,7 @@ _curses_window_border_impl(PyCursesWindowObject *self, PyObject *ls, PyObject *rs, PyObject *ts, PyObject *bs, PyObject *tl, PyObject *tr, PyObject *bl, PyObject *br) -/*[clinic end generated code: output=670ef38d3d7c2aa3 input=adaafca87488ee35]*/ +/*[clinic end generated code: output=670ef38d3d7c2aa3 input=42568c1458221d24]*/ { chtype ch[8]; int i, rtn; @@ -1436,14 +1435,15 @@ _curses.window.box Draw a border around the edges of the window. -Similar to border(), but both ls and rs are verch and both ts and bs are -horch. The default corner characters are always used by this function. +Similar to border(), but both ls and rs are verch and both ts and bs +are horch. The default corner characters are always used by this +function. [clinic start generated code]*/ static PyObject * _curses_window_box_impl(PyCursesWindowObject *self, int group_right_1, PyObject *verch, PyObject *horch) -/*[clinic end generated code: output=f3fcb038bb287192 input=f00435f9c8c98f60]*/ +/*[clinic end generated code: output=f3fcb038bb287192 input=e11acb7dbf6790b6]*/ { chtype ch1 = 0, ch2 = 0; if (group_right_1) { @@ -1596,7 +1596,6 @@ _curses_window_delch_impl(PyCursesWindowObject *self, int group_right_1, } /*[clinic input] -@permit_long_docstring_body _curses.window.derwin [ @@ -1613,15 +1612,15 @@ _curses.window.derwin Create a sub-window (window-relative coordinates). -derwin() is the same as calling subwin(), except that begin_y and begin_x -are relative to the origin of the window, rather than relative to the entire -screen. +derwin() is the same as calling subwin(), except that begin_y and +begin_x are relative to the origin of the window, rather than +relative to the entire screen. [clinic start generated code]*/ static PyObject * _curses_window_derwin_impl(PyCursesWindowObject *self, int group_left_1, int nlines, int ncols, int begin_y, int begin_x) -/*[clinic end generated code: output=7924b112d9f70d6e input=ebe95ded1c284c8e]*/ +/*[clinic end generated code: output=7924b112d9f70d6e input=6efb50722be444ba]*/ { WINDOW *win; @@ -1731,7 +1730,6 @@ curses_check_signals_on_input_error(PyCursesWindowObject *self, } /*[clinic input] -@permit_long_docstring_body _curses.window.getch [ @@ -1744,15 +1742,16 @@ _curses.window.getch Get a character code from terminal keyboard. -The integer returned does not have to be in ASCII range: function keys, -keypad keys and so on return numbers higher than 256. In no-delay mode, -1 -is returned if there is no input, else getch() waits until a key is pressed. +The integer returned does not have to be in ASCII range: function +keys, keypad keys and so on return numbers higher than 256. In +no-delay mode, -1 is returned if there is no input, else getch() +waits until a key is pressed. [clinic start generated code]*/ static PyObject * _curses_window_getch_impl(PyCursesWindowObject *self, int group_right_1, int y, int x) -/*[clinic end generated code: output=e1639e87d545e676 input=9a053077373e2a30]*/ +/*[clinic end generated code: output=e1639e87d545e676 input=0dc5ff40e079787a]*/ { int rtn; @@ -1779,7 +1778,6 @@ _curses_window_getch_impl(PyCursesWindowObject *self, int group_right_1, } /*[clinic input] -@permit_long_docstring_body _curses.window.getkey [ @@ -1792,15 +1790,16 @@ _curses.window.getkey Get a character (string) from terminal keyboard. -Returning a string instead of an integer, as getch() does. Function keys, -keypad keys and other special keys return a multibyte string containing the -key name. In no-delay mode, an exception is raised if there is no input. +Returning a string instead of an integer, as getch() does. Function +keys, keypad keys and other special keys return a multibyte string +containing the key name. In no-delay mode, an exception is raised +if there is no input. [clinic start generated code]*/ static PyObject * _curses_window_getkey_impl(PyCursesWindowObject *self, int group_right_1, int y, int x) -/*[clinic end generated code: output=8490a182db46b10f input=5177f03fb6c31ea6]*/ +/*[clinic end generated code: output=8490a182db46b10f input=bd24a7da1ed9c73b]*/ { int rtn; @@ -2021,7 +2020,6 @@ _curses_window_hline_impl(PyCursesWindowObject *self, int group_left_1, } /*[clinic input] -@permit_long_docstring_body _curses.window.insch [ @@ -2042,15 +2040,15 @@ _curses.window.insch Insert a character before the current or specified position. -All characters to the right of the cursor are shifted one position right, with -the rightmost characters on the line being lost. +All characters to the right of the cursor are shifted one position +right, with the rightmost characters on the line being lost. [clinic start generated code]*/ static PyObject * _curses_window_insch_impl(PyCursesWindowObject *self, int group_left_1, int y, int x, PyObject *ch, int group_right_1, long attr) -/*[clinic end generated code: output=ade8cfe3a3bf3e34 input=3f2a230cb09fed5a]*/ +/*[clinic end generated code: output=ade8cfe3a3bf3e34 input=d662a0f96f33e15a]*/ { int rtn; chtype ch_ = 0; @@ -2072,7 +2070,6 @@ _curses_window_insch_impl(PyCursesWindowObject *self, int group_left_1, } /*[clinic input] -@permit_long_docstring_body _curses.window.inch [ @@ -2085,13 +2082,14 @@ _curses.window.inch Return the character at the given position in the window. -The bottom 8 bits are the character proper, and upper bits are the attributes. +The bottom 8 bits are the character proper, and upper bits are the +attributes. [clinic start generated code]*/ static PyObject * _curses_window_inch_impl(PyCursesWindowObject *self, int group_right_1, int y, int x) -/*[clinic end generated code: output=97ca8581baaafd06 input=a5846f315464dc86]*/ +/*[clinic end generated code: output=97ca8581baaafd06 input=7a03956d94dc9a69]*/ { chtype rtn; const char *funcname; @@ -2183,18 +2181,18 @@ _curses.window.insstr Insert the string before the current or specified position. -Insert a character string (as many characters as will fit on the line) -before the character under the cursor. All characters to the right of -the cursor are shifted right, with the rightmost characters on the line -being lost. The cursor position does not change (after moving to y, x, -if specified). +Insert a character string (as many characters as will fit on the +line) before the character under the cursor. All characters to the +right of the cursor are shifted right, with the rightmost characters +on the line being lost. The cursor position does not change (after +moving to y, x, if specified). [clinic start generated code]*/ static PyObject * _curses_window_insstr_impl(PyCursesWindowObject *self, int group_left_1, int y, int x, PyObject *str, int group_right_1, long attr) -/*[clinic end generated code: output=c259a5265ad0b777 input=6827cddc6340a7f3]*/ +/*[clinic end generated code: output=c259a5265ad0b777 input=dbfbdd3892155ea6]*/ { int rtn; int strtype; @@ -2260,7 +2258,6 @@ _curses_window_insstr_impl(PyCursesWindowObject *self, int group_left_1, } /*[clinic input] -@permit_long_docstring_body _curses.window.insnstr [ @@ -2284,19 +2281,19 @@ _curses.window.insnstr Insert at most n characters of the string. -Insert a character string (as many characters as will fit on the line) -before the character under the cursor, up to n characters. If n is zero -or negative, the entire string is inserted. All characters to the right -of the cursor are shifted right, with the rightmost characters on the line -being lost. The cursor position does not change (after moving to y, x, if -specified). +Insert a character string (as many characters as will fit on the +line) before the character under the cursor, up to n characters. If +n is zero or negative, the entire string is inserted. All +characters to the right of the cursor are shifted right, with the +rightmost characters on the line being lost. The cursor position +does not change (after moving to y, x, if specified). [clinic start generated code]*/ static PyObject * _curses_window_insnstr_impl(PyCursesWindowObject *self, int group_left_1, int y, int x, PyObject *str, int n, int group_right_1, long attr) -/*[clinic end generated code: output=971a32ea6328ec8b input=dcdc554102fbcd5d]*/ +/*[clinic end generated code: output=971a32ea6328ec8b input=fd0a9b65b84b385f]*/ { int rtn; int strtype; @@ -2361,7 +2358,7 @@ _curses_window_insnstr_impl(PyCursesWindowObject *self, int group_left_1, } /*[clinic input] -@permit_long_docstring_body +@permit_long_summary _curses.window.is_linetouched line: int @@ -2370,12 +2367,13 @@ _curses.window.is_linetouched Return True if the specified line was modified, otherwise return False. -Raise a curses.error exception if line is not valid for the given window. +Raise a curses.error exception if line is not valid for the given +window. [clinic start generated code]*/ static PyObject * _curses_window_is_linetouched_impl(PyCursesWindowObject *self, int line) -/*[clinic end generated code: output=ad4a4edfee2db08c input=af71c040b951c467]*/ +/*[clinic end generated code: output=ad4a4edfee2db08c input=18924dfac25ab7f1]*/ { int erg; erg = is_linetouched(self->win, line); @@ -2388,7 +2386,6 @@ _curses_window_is_linetouched_impl(PyCursesWindowObject *self, int line) #ifdef py_is_pad /*[clinic input] -@permit_long_docstring_body _curses.window.noutrefresh [ @@ -2403,9 +2400,9 @@ _curses.window.noutrefresh Mark for refresh but wait. -This function updates the data structure representing the desired state of the -window, but does not force an update of the physical screen. To accomplish -that, call doupdate(). +This function updates the data structure representing the desired +state of the window, but does not force an update of the physical +screen. To accomplish that, call doupdate(). [clinic start generated code]*/ static PyObject * @@ -2413,22 +2410,21 @@ _curses_window_noutrefresh_impl(PyCursesWindowObject *self, int group_right_1, int pminrow, int pmincol, int sminrow, int smincol, int smaxrow, int smaxcol) -/*[clinic end generated code: output=809a1f3c6a03e23e input=b39fe8fc79b9980b]*/ +/*[clinic end generated code: output=809a1f3c6a03e23e input=8b4c74bf55008803]*/ #else /*[clinic input] -@permit_long_docstring_body _curses.window.noutrefresh Mark for refresh but wait. -This function updates the data structure representing the desired state of the -window, but does not force an update of the physical screen. To accomplish -that, call doupdate(). +This function updates the data structure representing the desired +state of the window, but does not force an update of the physical +screen. To accomplish that, call doupdate(). [clinic start generated code]*/ static PyObject * _curses_window_noutrefresh_impl(PyCursesWindowObject *self) -/*[clinic end generated code: output=6ef6dec666643fee input=6a9f59ae5e4c139e]*/ +/*[clinic end generated code: output=6ef6dec666643fee input=a7c6306f8af9d0dd]*/ #endif { int rtn; @@ -2461,7 +2457,6 @@ _curses_window_noutrefresh_impl(PyCursesWindowObject *self) } /*[clinic input] -@permit_long_docstring_body _curses.window.overlay destwin: object(type="PyCursesWindowObject *", subclass_of="clinic_state()->window_type") @@ -2478,14 +2473,15 @@ _curses.window.overlay Overlay the window on top of destwin. -The windows need not be the same size, only the overlapping region is copied. -This copy is non-destructive, which means that the current background -character does not overwrite the old contents of destwin. +The windows need not be the same size, only the overlapping region +is copied. This copy is non-destructive, which means that the +current background character does not overwrite the old contents of +destwin. -To get fine-grained control over the copied region, the second form of -overlay() can be used. sminrow and smincol are the upper-left coordinates -of the source window, and the other variables mark a rectangle in the -destination window. +To get fine-grained control over the copied region, the second form +of overlay() can be used. sminrow and smincol are the upper-left +coordinates of the source window, and the other variables mark +a rectangle in the destination window. [clinic start generated code]*/ static PyObject * @@ -2493,7 +2489,7 @@ _curses_window_overlay_impl(PyCursesWindowObject *self, PyCursesWindowObject *destwin, int group_right_1, int sminrow, int smincol, int dminrow, int dmincol, int dmaxrow, int dmaxcol) -/*[clinic end generated code: output=82bb2c4cb443ca58 input=dd6af34deb892a65]*/ +/*[clinic end generated code: output=82bb2c4cb443ca58 input=da0cec7f7bda1b3f]*/ { int rtn; @@ -2509,7 +2505,6 @@ _curses_window_overlay_impl(PyCursesWindowObject *self, } /*[clinic input] -@permit_long_docstring_body _curses.window.overwrite destwin: object(type="PyCursesWindowObject *", subclass_of="clinic_state()->window_type") @@ -2526,14 +2521,15 @@ _curses.window.overwrite Overwrite the window on top of destwin. -The windows need not be the same size, in which case only the overlapping -region is copied. This copy is destructive, which means that the current -background character overwrites the old contents of destwin. +The windows need not be the same size, in which case only the +overlapping region is copied. This copy is destructive, which means +that the current background character overwrites the old contents of +destwin. -To get fine-grained control over the copied region, the second form of -overwrite() can be used. sminrow and smincol are the upper-left coordinates -of the source window, the other variables mark a rectangle in the destination -window. +To get fine-grained control over the copied region, the second form +of overwrite() can be used. sminrow and smincol are the upper-left +coordinates of the source window, the other variables mark +a rectangle in the destination window. [clinic start generated code]*/ static PyObject * @@ -2542,7 +2538,7 @@ _curses_window_overwrite_impl(PyCursesWindowObject *self, int group_right_1, int sminrow, int smincol, int dminrow, int dmincol, int dmaxrow, int dmaxcol) -/*[clinic end generated code: output=12ae007d1681be28 input=e84d8ebdf1c09596]*/ +/*[clinic end generated code: output=12ae007d1681be28 input=4244ab8a97087898]*/ { int rtn; @@ -2558,6 +2554,7 @@ _curses_window_overwrite_impl(PyCursesWindowObject *self, } /*[clinic input] +@permit_long_summary _curses.window.putwin file: object @@ -2570,7 +2567,7 @@ This information can be later retrieved using the getwin() function. static PyObject * _curses_window_putwin_impl(PyCursesWindowObject *self, PyObject *file) -/*[clinic end generated code: output=fdae68ac59b0281b input=0608648e09c8ea0a]*/ +/*[clinic end generated code: output=fdae68ac59b0281b input=959fc85a9e4a31c2]*/ { /* We have to simulate this by writing to a temporary FILE*, then reading back, then writing to the argument file. */ @@ -2626,7 +2623,6 @@ _curses_window_redrawln_impl(PyCursesWindowObject *self, int beg, int num) } /*[clinic input] -@permit_long_docstring_body _curses.window.refresh [ @@ -2642,23 +2638,24 @@ _curses.window.refresh Update the display immediately. Synchronize actual screen with previous drawing/deleting methods. -The 6 optional arguments can only be specified when the window is a pad -created with newpad(). The additional parameters are needed to indicate -what part of the pad and screen are involved. pminrow and pmincol specify -the upper left-hand corner of the rectangle to be displayed in the pad. -sminrow, smincol, smaxrow, and smaxcol specify the edges of the rectangle to -be displayed on the screen. The lower right-hand corner of the rectangle to -be displayed in the pad is calculated from the screen coordinates, since the -rectangles must be the same size. Both rectangles must be entirely contained -within their respective structures. Negative values of pminrow, pmincol, -sminrow, or smincol are treated as if they were zero. +The 6 optional arguments can only be specified when the window is +a pad created with newpad(). The additional parameters are needed +to indicate what part of the pad and screen are involved. pminrow +and pmincol specify the upper left-hand corner of the rectangle to +be displayed in the pad. sminrow, smincol, smaxrow, and smaxcol +specify the edges of the rectangle to be displayed on the screen. +The lower right-hand corner of the rectangle to be displayed in the +pad is calculated from the screen coordinates, since the rectangles +must be the same size. Both rectangles must be entirely contained +within their respective structures. Negative values of pminrow, +pmincol, sminrow, or smincol are treated as if they were zero. [clinic start generated code]*/ static PyObject * _curses_window_refresh_impl(PyCursesWindowObject *self, int group_right_1, int pminrow, int pmincol, int sminrow, int smincol, int smaxrow, int smaxcol) -/*[clinic end generated code: output=42199543115e6e63 input=65405c03290496a6]*/ +/*[clinic end generated code: output=42199543115e6e63 input=ff2e900c6b2696b1]*/ { int rtn; @@ -2711,7 +2708,6 @@ _curses_window_setscrreg_impl(PyCursesWindowObject *self, int top, } /*[clinic input] -@permit_long_docstring_body _curses.window.subwin [ @@ -2728,14 +2724,14 @@ _curses.window.subwin Create a sub-window (screen-relative coordinates). -By default, the sub-window will extend from the specified position to the -lower right corner of the window. +By default, the sub-window will extend from the specified position +to the lower right corner of the window. [clinic start generated code]*/ static PyObject * _curses_window_subwin_impl(PyCursesWindowObject *self, int group_left_1, int nlines, int ncols, int begin_y, int begin_x) -/*[clinic end generated code: output=93e898afc348f59a input=5292cf610e2f3585]*/ +/*[clinic end generated code: output=93e898afc348f59a input=07b5058cb8820595]*/ { WINDOW *win; const char *funcname; @@ -2763,7 +2759,6 @@ _curses_window_subwin_impl(PyCursesWindowObject *self, int group_left_1, } /*[clinic input] -@permit_long_docstring_body _curses.window.scroll [ @@ -2774,13 +2769,14 @@ _curses.window.scroll Scroll the screen or scrolling region. -Scroll upward if the argument is positive and downward if it is negative. +Scroll upward if the argument is positive and downward if it is +negative. [clinic start generated code]*/ static PyObject * _curses_window_scroll_impl(PyCursesWindowObject *self, int group_right_1, int lines) -/*[clinic end generated code: output=4541a8a11852d360 input=386456524c550113]*/ +/*[clinic end generated code: output=4541a8a11852d360 input=d8d81a5b52b9b40f]*/ { int rtn; const char *funcname; @@ -2796,7 +2792,6 @@ _curses_window_scroll_impl(PyCursesWindowObject *self, int group_right_1, } /*[clinic input] -@permit_long_docstring_body _curses.window.touchline start: int @@ -2808,14 +2803,15 @@ _curses.window.touchline Pretend count lines have been changed, starting with line start. -If changed is supplied, it specifies whether the affected lines are marked -as having been changed (changed=True) or unchanged (changed=False). +If changed is supplied, it specifies whether the affected lines are +marked as having been changed (changed=True) or unchanged +(changed=False). [clinic start generated code]*/ static PyObject * _curses_window_touchline_impl(PyCursesWindowObject *self, int start, int count, int group_right_1, int changed) -/*[clinic end generated code: output=65d05b3f7438c61d input=36e13b6f5eb591f5]*/ +/*[clinic end generated code: output=65d05b3f7438c61d input=e0dc62f90d9dea55]*/ { int rtn; const char *funcname; @@ -3182,20 +3178,20 @@ _curses.cbreak Enter cbreak mode. -In cbreak mode (sometimes called "rare" mode) normal tty line buffering is -turned off and characters are available to be read one by one. However, -unlike raw mode, special characters (interrupt, quit, suspend, and flow -control) retain their effects on the tty driver and calling program. -Calling first raw() then cbreak() leaves the terminal in cbreak mode. +In cbreak mode (sometimes called "rare" mode) normal tty line buffering +is turned off and characters are available to be read one by one. +However, unlike raw mode, special characters (interrupt, quit, suspend, +and flow control) retain their effects on the tty driver and calling +program. Calling first raw() then cbreak() leaves the terminal in +cbreak mode. [clinic start generated code]*/ static PyObject * _curses_cbreak_impl(PyObject *module, int flag) -/*[clinic end generated code: output=9f9dee9664769751 input=c7d0bddda93016c1]*/ +/*[clinic end generated code: output=9f9dee9664769751 input=42d81687f11ddbf3]*/ NoArgOrFlagNoReturnFunctionBody(cbreak, flag) /*[clinic input] -@permit_long_docstring_body _curses.color_content color_number: color @@ -3204,13 +3200,14 @@ _curses.color_content Return the red, green, and blue (RGB) components of the specified color. -A 3-tuple is returned, containing the R, G, B values for the given color, -which will be between 0 (no component) and 1000 (maximum amount of component). +A 3-tuple is returned, containing the R, G, B values for the given +color, which will be between 0 (no component) and 1000 (maximum amount +of component). [clinic start generated code]*/ static PyObject * _curses_color_content_impl(PyObject *module, int color_number) -/*[clinic end generated code: output=17b466df7054e0de input=baffe25b351eb916]*/ +/*[clinic end generated code: output=17b466df7054e0de input=c95fb50093fa0be0]*/ { _CURSES_COLOR_VAL_TYPE r,g,b; @@ -3236,12 +3233,13 @@ _curses.color_pair Return the attribute value for displaying text in the specified color. This attribute value can be combined with A_STANDOUT, A_REVERSE, and the -other A_* attributes. pair_number() is the counterpart to this function. +other A_* attributes. pair_number() is the counterpart to this +function. [clinic start generated code]*/ static PyObject * _curses_color_pair_impl(PyObject *module, int pair_number) -/*[clinic end generated code: output=60718abb10ce9feb input=6034e9146f343802]*/ +/*[clinic end generated code: output=60718abb10ce9feb input=cf74bb81d3cc3370]*/ { PyCursesStatefulInitialised(module); PyCursesStatefulInitialisedColor(module); @@ -3259,14 +3257,14 @@ _curses.curs_set Set the cursor state. If the terminal supports the visibility requested, the previous cursor -state is returned; otherwise, an exception is raised. On many terminals, -the "visible" mode is an underline cursor and the "very visible" mode is -a block cursor. +state is returned; otherwise, an exception is raised. On many +terminals, the "visible" mode is an underline cursor and the "very +visible" mode is a block cursor. [clinic start generated code]*/ static PyObject * _curses_curs_set_impl(PyObject *module, int visibility) -/*[clinic end generated code: output=ee8e62483b1d6cd4 input=81a7924a65d29504]*/ +/*[clinic end generated code: output=ee8e62483b1d6cd4 input=e010767a328f322b]*/ { int erg; @@ -3301,14 +3299,15 @@ _curses.def_shell_mode Save the current terminal mode as the "shell" mode. -The "shell" mode is the mode when the running program is not using curses. +The "shell" mode is the mode when the running program is not using +curses. Subsequent calls to reset_shell_mode() will restore this mode. [clinic start generated code]*/ static PyObject * _curses_def_shell_mode_impl(PyObject *module) -/*[clinic end generated code: output=d6e42f5c768f860f input=5ead21f6f0baa894]*/ +/*[clinic end generated code: output=d6e42f5c768f860f input=3809f85615c0b693]*/ NoArgNoReturnFunctionBody(def_shell_mode) /*[clinic input] @@ -3350,12 +3349,13 @@ _curses.echo Enter echo mode. -In echo mode, each character input is echoed to the screen as it is entered. +In echo mode, each character input is echoed to the screen as it is +entered. [clinic start generated code]*/ static PyObject * _curses_echo_impl(PyObject *module, int flag) -/*[clinic end generated code: output=03acb2ddfa6c8729 input=86cd4d5bb1d569c0]*/ +/*[clinic end generated code: output=03acb2ddfa6c8729 input=b4e9064326da9da4]*/ NoArgOrFlagNoReturnFunctionBody(echo, flag) /*[clinic input] @@ -3389,17 +3389,17 @@ _curses_erasechar_impl(PyObject *module) } /*[clinic input] -@permit_long_docstring_body _curses.flash Flash the screen. -That is, change it to reverse-video and then change it back in a short interval. +That is, change it to reverse-video and then change it back in a short +interval. [clinic start generated code]*/ static PyObject * _curses_flash_impl(PyObject *module) -/*[clinic end generated code: output=488b8a0ebd9ea9b8 input=dd33d718e6edf436]*/ +/*[clinic end generated code: output=488b8a0ebd9ea9b8 input=90878e305432add9]*/ NoArgNoReturnFunctionBody(flash) /*[clinic input] @@ -3407,13 +3407,13 @@ _curses.flushinp Flush all input buffers. -This throws away any typeahead that has been typed by the user and has not -yet been processed by the program. +This throws away any typeahead that has been typed by the user and has +not yet been processed by the program. [clinic start generated code]*/ static PyObject * _curses_flushinp_impl(PyObject *module) -/*[clinic end generated code: output=7e7a1fc1473960f5 input=59d042e705cef5ec]*/ +/*[clinic end generated code: output=7e7a1fc1473960f5 input=3a63c7213be8043c]*/ NoArgNoReturnVoidFunctionBody(flushinp) #ifdef getsyx @@ -3599,6 +3599,7 @@ _curses_has_colors_impl(PyObject *module) NoArgTrueFalseFunctionBody(has_colors) /*[clinic input] +@permit_long_summary _curses.has_ic Return True if the terminal has insert- and delete-character capabilities. @@ -3606,7 +3607,7 @@ Return True if the terminal has insert- and delete-character capabilities. static PyObject * _curses_has_ic_impl(PyObject *module) -/*[clinic end generated code: output=6be24da9cb1268fe input=9bc2d3a797cc7324]*/ +/*[clinic end generated code: output=6be24da9cb1268fe input=e37fa080d879f7a9]*/ NoArgTrueFalseFunctionBody(has_ic) /*[clinic input] @@ -3622,6 +3623,7 @@ NoArgTrueFalseFunctionBody(has_il) #ifdef HAVE_CURSES_HAS_KEY /*[clinic input] +@permit_long_summary _curses.has_key key: int @@ -3633,7 +3635,7 @@ Return True if the current terminal type recognizes a key with that value. static PyObject * _curses_has_key_impl(PyObject *module, int key) -/*[clinic end generated code: output=19ad48319414d0b1 input=78bd44acf1a4997c]*/ +/*[clinic end generated code: output=19ad48319414d0b1 input=046ac6c72bbc9587]*/ { PyCursesStatefulInitialised(module); @@ -3688,13 +3690,14 @@ _curses.init_pair Change the definition of a color-pair. -If the color-pair was previously initialized, the screen is refreshed and -all occurrences of that color-pair are changed to the new definition. +If the color-pair was previously initialized, the screen is refreshed +and all occurrences of that color-pair are changed to the new +definition. [clinic start generated code]*/ static PyObject * _curses_init_pair_impl(PyObject *module, int pair_number, int fg, int bg) -/*[clinic end generated code: output=a0bba03d2bbc3ee6 input=54b421b44c12c389]*/ +/*[clinic end generated code: output=a0bba03d2bbc3ee6 input=5486c3a105130dae]*/ { PyCursesStatefulInitialised(module); PyCursesStatefulInitialisedColor(module); @@ -3914,14 +3917,14 @@ _curses.get_escdelay Gets the curses ESCDELAY setting. -Gets the number of milliseconds to wait after reading an escape character, -to distinguish between an individual escape character entered on the -keyboard from escape sequences sent by cursor and function keys. +Gets the number of milliseconds to wait after reading an escape +character, to distinguish between an individual escape character entered +on the keyboard from escape sequences sent by cursor and function keys. [clinic start generated code]*/ static PyObject * _curses_get_escdelay_impl(PyObject *module) -/*[clinic end generated code: output=222fa1a822555d60 input=be2d5b3dd974d0a4]*/ +/*[clinic end generated code: output=222fa1a822555d60 input=b39eeae4b8f169ab]*/ { return PyLong_FromLong(ESCDELAY); } @@ -3933,14 +3936,14 @@ _curses.set_escdelay Sets the curses ESCDELAY setting. -Sets the number of milliseconds to wait after reading an escape character, -to distinguish between an individual escape character entered on the -keyboard from escape sequences sent by cursor and function keys. +Sets the number of milliseconds to wait after reading an escape +character, to distinguish between an individual escape character entered +on the keyboard from escape sequences sent by cursor and function keys. [clinic start generated code]*/ static PyObject * _curses_set_escdelay_impl(PyObject *module, int ms) -/*[clinic end generated code: output=43818efbf7980ac4 input=7796fe19f111e250]*/ +/*[clinic end generated code: output=43818efbf7980ac4 input=cc2529bcdda3b06c]*/ { if (ms <= 0) { PyErr_SetString(PyExc_ValueError, "ms must be > 0"); @@ -3955,13 +3958,13 @@ _curses.get_tabsize Gets the curses TABSIZE setting. -Gets the number of columns used by the curses library when converting a tab -character to spaces as it adds the tab to a window. +Gets the number of columns used by the curses library when converting +a tab character to spaces as it adds the tab to a window. [clinic start generated code]*/ static PyObject * _curses_get_tabsize_impl(PyObject *module) -/*[clinic end generated code: output=7e9e51fb6126fbdf input=74af86bf6c9f5d7e]*/ +/*[clinic end generated code: output=7e9e51fb6126fbdf input=58bdaacb337c103b]*/ { return PyLong_FromLong(TABSIZE); } @@ -3973,13 +3976,13 @@ _curses.set_tabsize Sets the curses TABSIZE setting. -Sets the number of columns used by the curses library when converting a tab -character to spaces as it adds the tab to a window. +Sets the number of columns used by the curses library when converting +a tab character to spaces as it adds the tab to a window. [clinic start generated code]*/ static PyObject * _curses_set_tabsize_impl(PyObject *module, int size) -/*[clinic end generated code: output=c1de5a76c0daab1e input=78cba6a3021ad061]*/ +/*[clinic end generated code: output=c1de5a76c0daab1e input=34c1be9a78cd28a2]*/ { if (size <= 0) { PyErr_SetString(PyExc_ValueError, "size must be > 0"); @@ -4087,18 +4090,17 @@ _curses_killchar_impl(PyObject *module) } /*[clinic input] -@permit_long_docstring_body _curses.longname Return the terminfo long name field describing the current terminal. -The maximum length of a verbose description is 128 characters. It is defined -only after the call to initscr(). +The maximum length of a verbose description is 128 characters. It is +defined only after the call to initscr(). [clinic start generated code]*/ static PyObject * _curses_longname_impl(PyObject *module) -/*[clinic end generated code: output=fdf30433727ef568 input=5de06852f2230ddb]*/ +/*[clinic end generated code: output=fdf30433727ef568 input=a924fabba0de78a6]*/ NoArgReturnStringFunctionBody(longname) /*[clinic input] @@ -4133,13 +4135,13 @@ _curses.mouseinterval Set and retrieve the maximum time between press and release in a click. Set the maximum time that can elapse between press and release events in -order for them to be recognized as a click, and return the previous interval -value. +order for them to be recognized as a click, and return the previous +interval value. [clinic start generated code]*/ static PyObject * _curses_mouseinterval_impl(PyObject *module, int interval) -/*[clinic end generated code: output=c4f5ff04354634c5 input=75aaa3f0db10ac4e]*/ +/*[clinic end generated code: output=c4f5ff04354634c5 input=b90249254389c080]*/ { PyCursesStatefulInitialised(module); int value = mouseinterval(interval); @@ -4160,14 +4162,15 @@ _curses.mousemask Set the mouse events to be reported, and return a tuple (availmask, oldmask). Return a tuple (availmask, oldmask). availmask indicates which of the -specified mouse events can be reported; on complete failure it returns 0. -oldmask is the previous value of the given window's mouse event mask. -If this function is never called, no mouse events are ever reported. +specified mouse events can be reported; on complete failure it returns +0. oldmask is the previous value of the given window's mouse event +mask. If this function is never called, no mouse events are ever +reported. [clinic start generated code]*/ static PyObject * _curses_mousemask_impl(PyObject *module, unsigned long newmask) -/*[clinic end generated code: output=9406cf1b8a36e485 input=b92ff4fbe5ce61b1]*/ +/*[clinic end generated code: output=9406cf1b8a36e485 input=78990ec6c52aa888]*/ { mmask_t oldmask, availmask; @@ -4249,14 +4252,14 @@ _curses.newwin Return a new window. -By default, the window will extend from the specified position to the lower -right corner of the screen. +By default, the window will extend from the specified position to the +lower right corner of the screen. [clinic start generated code]*/ static PyObject * _curses_newwin_impl(PyObject *module, int nlines, int ncols, int group_right_1, int begin_y, int begin_x) -/*[clinic end generated code: output=c1e0a8dc8ac2826c input=29312c15a72a003d]*/ +/*[clinic end generated code: output=c1e0a8dc8ac2826c input=a1517cbfea4ab24b]*/ { WINDOW *win; @@ -4281,13 +4284,14 @@ _curses.nl Enter newline mode. -This mode translates the return key into newline on input, and translates -newline into return and line-feed on output. Newline mode is initially on. +This mode translates the return key into newline on input, and +translates newline into return and line-feed on output. Newline mode +is initially on. [clinic start generated code]*/ static PyObject * _curses_nl_impl(PyObject *module, int flag) -/*[clinic end generated code: output=b39cc0ffc9015003 input=18e3e9c6e8cfcf6f]*/ +/*[clinic end generated code: output=b39cc0ffc9015003 input=3fb21dcf55521ee4]*/ NoArgOrFlagNoReturnFunctionBody(nl, flag) /*[clinic input] @@ -4321,13 +4325,13 @@ _curses.nonl Leave newline mode. -Disable translation of return into newline on input, and disable low-level -translation of newline into newline/return on output. +Disable translation of return into newline on input, and disable +low-level translation of newline into newline/return on output. [clinic start generated code]*/ static PyObject * _curses_nonl_impl(PyObject *module) -/*[clinic end generated code: output=99e917e9715770c6 input=9d37dd122d3022fc]*/ +/*[clinic end generated code: output=99e917e9715770c6 input=75cce08e4b6b3ef1]*/ NoArgNoReturnFunctionBody(nonl) /*[clinic input] @@ -4358,6 +4362,7 @@ _curses_noraw_impl(PyObject *module) NoArgNoReturnFunctionBody(noraw) /*[clinic input] +@permit_long_summary _curses.pair_content pair_number: pair @@ -4369,7 +4374,7 @@ Return a tuple (fg, bg) containing the colors for the requested color pair. static PyObject * _curses_pair_content_impl(PyObject *module, int pair_number) -/*[clinic end generated code: output=4a726dd0e6885f3f input=03970f840fc7b739]*/ +/*[clinic end generated code: output=4a726dd0e6885f3f input=faede9e26f1f2ca4]*/ { _CURSES_COLOR_NUM_TYPE f, b; @@ -4393,6 +4398,7 @@ _curses_pair_content_impl(PyObject *module, int pair_number) } /*[clinic input] +@permit_long_summary _curses.pair_number attr: int @@ -4405,7 +4411,7 @@ color_pair() is the counterpart to this function. static PyObject * _curses_pair_number_impl(PyObject *module, int attr) -/*[clinic end generated code: output=85bce7d65c0aa3f4 input=d478548e33f5e61a]*/ +/*[clinic end generated code: output=85bce7d65c0aa3f4 input=b11152a78c2f9abf]*/ { PyCursesStatefulInitialised(module); PyCursesStatefulInitialisedColor(module); @@ -4414,6 +4420,7 @@ _curses_pair_number_impl(PyObject *module, int attr) } /*[clinic input] +@permit_long_summary _curses.putp string: str(accept={robuffer}) @@ -4426,7 +4433,7 @@ Note that the output of putp() always goes to standard output. static PyObject * _curses_putp_impl(PyObject *module, const char *string) -/*[clinic end generated code: output=e98081d1b8eb5816 input=1601faa828b44cb3]*/ +/*[clinic end generated code: output=e98081d1b8eb5816 input=2f3b9e0f22829ee7]*/ { return curses_check_err(module, putp(string), "putp", NULL); } @@ -4539,13 +4546,13 @@ _curses.raw Enter raw mode. In raw mode, normal line buffering and processing of interrupt, quit, -suspend, and flow control keys are turned off; characters are presented to -curses input functions one by one. +suspend, and flow control keys are turned off; characters are presented +to curses input functions one by one. [clinic start generated code]*/ static PyObject * _curses_raw_impl(PyObject *module, int flag) -/*[clinic end generated code: output=a750e4b342be015b input=4b447701389fb4df]*/ +/*[clinic end generated code: output=a750e4b342be015b input=18a7de7eef16987a]*/ NoArgOrFlagNoReturnFunctionBody(raw, flag) /*[clinic input] @@ -4595,13 +4602,13 @@ _curses.resizeterm Resize the standard and current windows to the specified dimensions. -Adjusts other bookkeeping data used by the curses library that record the -window dimensions (in particular the SIGWINCH handler). +Adjusts other bookkeeping data used by the curses library that record +the window dimensions (in particular the SIGWINCH handler). [clinic start generated code]*/ static PyObject * _curses_resizeterm_impl(PyObject *module, short nlines, short ncols) -/*[clinic end generated code: output=4de3abab50c67f02 input=414e92a63e3e9899]*/ +/*[clinic end generated code: output=4de3abab50c67f02 input=7f0f077df2da1cf5]*/ { PyObject *result; int code; @@ -4623,7 +4630,6 @@ _curses_resizeterm_impl(PyObject *module, short nlines, short ncols) #ifdef HAVE_CURSES_RESIZE_TERM /*[clinic input] -@permit_long_docstring_body _curses.resize_term nlines: short @@ -4635,15 +4641,16 @@ _curses.resize_term Backend function used by resizeterm(), performing most of the work. When resizing the windows, resize_term() blank-fills the areas that are -extended. The calling application should fill in these areas with appropriate -data. The resize_term() function attempts to resize all windows. However, -due to the calling convention of pads, it is not possible to resize these -without additional interaction with the application. +extended. The calling application should fill in these areas with +appropriate data. The resize_term() function attempts to resize all +windows. However, due to the calling convention of pads, it is not +possible to resize these without additional interaction with the +application. [clinic start generated code]*/ static PyObject * _curses_resize_term_impl(PyObject *module, short nlines, short ncols) -/*[clinic end generated code: output=46c6d749fa291dbd input=ebfa840f6b5f03fa]*/ +/*[clinic end generated code: output=46c6d749fa291dbd input=ff4baaf2320c8ac9]*/ { PyObject *result; int code; @@ -4701,21 +4708,22 @@ _curses_setsyx_impl(PyObject *module, int y, int x) #endif /*[clinic input] +@permit_long_summary _curses.start_color Initializes eight basic colors and global variables COLORS and COLOR_PAIRS. -Must be called if the programmer wants to use colors, and before any other -color manipulation routine is called. It is good practice to call this -routine right after initscr(). +Must be called if the programmer wants to use colors, and before any +other color manipulation routine is called. It is good practice to call +this routine right after initscr(). -It also restores the colors on the terminal to the values they had when the -terminal was just turned on. +It also restores the colors on the terminal to the values they had when +the terminal was just turned on. [clinic start generated code]*/ static PyObject * _curses_start_color_impl(PyObject *module) -/*[clinic end generated code: output=8b772b41d8090ede input=0ca0ecb2b77e1a12]*/ +/*[clinic end generated code: output=8b772b41d8090ede input=7daacc6b6baba643]*/ { PyCursesStatefulInitialised(module); @@ -4804,13 +4812,13 @@ _curses.tigetnum Return the value of the numeric capability. -The value -2 is returned if capname is not a numeric capability, or -1 if -it is canceled or absent from the terminal description. +The value -2 is returned if capname is not a numeric capability, or -1 +if it is canceled or absent from the terminal description. [clinic start generated code]*/ static PyObject * _curses_tigetnum_impl(PyObject *module, const char *capname) -/*[clinic end generated code: output=46f8b0a1b5dff42f input=5cdf2f410b109720]*/ +/*[clinic end generated code: output=46f8b0a1b5dff42f input=87a64beec16ae077]*/ { PyCursesStatefulSetupTermCalled(module); @@ -4826,13 +4834,13 @@ _curses.tigetstr Return the value of the string capability. -None is returned if capname is not a string capability, or is canceled or -absent from the terminal description. +None is returned if capname is not a string capability, or is canceled +or absent from the terminal description. [clinic start generated code]*/ static PyObject * _curses_tigetstr_impl(PyObject *module, const char *capname) -/*[clinic end generated code: output=f22b576ad60248f3 input=36644df25c73c0a7]*/ +/*[clinic end generated code: output=f22b576ad60248f3 input=00bf0feda2207724]*/ { PyCursesStatefulSetupTermCalled(module); @@ -5030,7 +5038,6 @@ _curses_unget_wch(PyObject *module, PyObject *ch) #ifdef HAVE_CURSES_USE_ENV /*[clinic input] -@permit_long_docstring_body _curses.use_env flag: bool @@ -5038,19 +5045,19 @@ _curses.use_env Use environment variables LINES and COLUMNS. -If used, this function should be called before initscr() or newterm() are -called. +If used, this function should be called before initscr() or newterm() +are called. -When flag is False, the values of lines and columns specified in the terminfo -database will be used, even if environment variables LINES and COLUMNS (used -by default) are set, or if curses is running in a window (in which case -default behavior would be to use the window size if LINES and COLUMNS are -not set). +When flag is False, the values of lines and columns specified in the +terminfo database will be used, even if environment variables LINES and +COLUMNS (used by default) are set, or if curses is running in a window +(in which case default behavior would be to use the window size if LINES +and COLUMNS are not set). [clinic start generated code]*/ static PyObject * _curses_use_env_impl(PyObject *module, int flag) -/*[clinic end generated code: output=b2c445e435c0b164 input=eaa9047ec73c27d3]*/ +/*[clinic end generated code: output=b2c445e435c0b164 input=8e8feed746cf7fc1]*/ { use_env(flag); Py_RETURN_NONE; @@ -5078,6 +5085,7 @@ _curses_use_default_colors_impl(PyObject *module) } /*[clinic input] +@permit_long_summary _curses.assume_default_colors fg: int bg: int @@ -5093,7 +5101,7 @@ Use this to support transparency in your application. static PyObject * _curses_assume_default_colors_impl(PyObject *module, int fg, int bg) -/*[clinic end generated code: output=54985397a7d2b3a5 input=7fe301712ef3e9fb]*/ +/*[clinic end generated code: output=54985397a7d2b3a5 input=8945333c09893cf2]*/ { int code; @@ -5162,6 +5170,7 @@ make_ncurses_version(PyTypeObject *type) #endif /* NCURSES_VERSION */ /*[clinic input] +@permit_long_summary _curses.has_extended_color_support Return True if the module supports extended colors; otherwise, return False. @@ -5172,7 +5181,7 @@ that support more than 16 colors (e.g. xterm-256color). static PyObject * _curses_has_extended_color_support_impl(PyObject *module) -/*[clinic end generated code: output=68f1be2b57d92e22 input=4b905f046e35ee9f]*/ +/*[clinic end generated code: output=68f1be2b57d92e22 input=40d673471c5056f0]*/ { return PyBool_FromLong(_NCURSES_EXTENDED_COLOR_FUNCS); } diff --git a/Modules/clinic/_curses_panel.c.h b/Modules/clinic/_curses_panel.c.h index 75cf067c8aa822..d8b2cba7fd3f89 100644 --- a/Modules/clinic/_curses_panel.c.h +++ b/Modules/clinic/_curses_panel.c.h @@ -28,7 +28,8 @@ PyDoc_STRVAR(_curses_panel_panel_hide__doc__, "\n" "Hide the panel.\n" "\n" -"This does not delete the object, it just makes the window on screen invisible."); +"This does not delete the object, it just makes the window on screen\n" +"invisible."); #define _CURSES_PANEL_PANEL_HIDE_METHODDEF \ {"hide", (PyCFunction)_curses_panel_panel_hide, METH_NOARGS, _curses_panel_panel_hide__doc__}, @@ -328,7 +329,8 @@ PyDoc_STRVAR(_curses_panel_update_panels__doc__, "\n" "Updates the virtual screen after changes in the panel stack.\n" "\n" -"This does not call curses.doupdate(), so you\'ll have to do this yourself."); +"This does not call curses.doupdate(), so you\'ll have to do this\n" +"yourself."); #define _CURSES_PANEL_UPDATE_PANELS_METHODDEF \ {"update_panels", (PyCFunction)_curses_panel_update_panels, METH_NOARGS, _curses_panel_update_panels__doc__}, @@ -341,4 +343,4 @@ _curses_panel_update_panels(PyObject *module, PyObject *Py_UNUSED(ignored)) { return _curses_panel_update_panels_impl(module); } -/*[clinic end generated code: output=db2fe491582784aa input=a9049054013a1b77]*/ +/*[clinic end generated code: output=62f20ef03eefdf44 input=a9049054013a1b77]*/ diff --git a/Modules/clinic/_cursesmodule.c.h b/Modules/clinic/_cursesmodule.c.h index e6f9798cdf1249..eec9e82739b778 100644 --- a/Modules/clinic/_cursesmodule.c.h +++ b/Modules/clinic/_cursesmodule.c.h @@ -422,10 +422,10 @@ PyDoc_STRVAR(_curses_window_border__doc__, " br\n" " Bottom-right corner.\n" "\n" -"Each parameter specifies the character to use for a specific part of the\n" -"border. The characters can be specified as integers or as one-character\n" -"strings. A 0 value for any parameter will cause the default character to be\n" -"used for that parameter."); +"Each parameter specifies the character to use for a specific part of\n" +"the border. The characters can be specified as integers or as\n" +"one-character strings. A 0 value for any parameter will cause the\n" +"default character to be used for that parameter."); #define _CURSES_WINDOW_BORDER_METHODDEF \ {"border", _PyCFunction_CAST(_curses_window_border), METH_FASTCALL, _curses_window_border__doc__}, @@ -500,8 +500,9 @@ PyDoc_STRVAR(_curses_window_box__doc__, " horch\n" " Top and bottom side.\n" "\n" -"Similar to border(), but both ls and rs are verch and both ts and bs are\n" -"horch. The default corner characters are always used by this function."); +"Similar to border(), but both ls and rs are verch and both ts and bs\n" +"are horch. The default corner characters are always used by this\n" +"function."); #define _CURSES_WINDOW_BOX_METHODDEF \ {"box", (PyCFunction)_curses_window_box, METH_VARARGS, _curses_window_box__doc__}, @@ -593,9 +594,9 @@ PyDoc_STRVAR(_curses_window_derwin__doc__, " begin_x\n" " Left side x-coordinate.\n" "\n" -"derwin() is the same as calling subwin(), except that begin_y and begin_x\n" -"are relative to the origin of the window, rather than relative to the entire\n" -"screen."); +"derwin() is the same as calling subwin(), except that begin_y and\n" +"begin_x are relative to the origin of the window, rather than\n" +"relative to the entire screen."); #define _CURSES_WINDOW_DERWIN_METHODDEF \ {"derwin", (PyCFunction)_curses_window_derwin, METH_VARARGS, _curses_window_derwin__doc__}, @@ -751,9 +752,10 @@ PyDoc_STRVAR(_curses_window_getch__doc__, " x\n" " X-coordinate.\n" "\n" -"The integer returned does not have to be in ASCII range: function keys,\n" -"keypad keys and so on return numbers higher than 256. In no-delay mode, -1\n" -"is returned if there is no input, else getch() waits until a key is pressed."); +"The integer returned does not have to be in ASCII range: function\n" +"keys, keypad keys and so on return numbers higher than 256. In\n" +"no-delay mode, -1 is returned if there is no input, else getch()\n" +"waits until a key is pressed."); #define _CURSES_WINDOW_GETCH_METHODDEF \ {"getch", (PyCFunction)_curses_window_getch, METH_VARARGS, _curses_window_getch__doc__}, @@ -798,9 +800,10 @@ PyDoc_STRVAR(_curses_window_getkey__doc__, " x\n" " X-coordinate.\n" "\n" -"Returning a string instead of an integer, as getch() does. Function keys,\n" -"keypad keys and other special keys return a multibyte string containing the\n" -"key name. In no-delay mode, an exception is raised if there is no input."); +"Returning a string instead of an integer, as getch() does. Function\n" +"keys, keypad keys and other special keys return a multibyte string\n" +"containing the key name. In no-delay mode, an exception is raised\n" +"if there is no input."); #define _CURSES_WINDOW_GETKEY_METHODDEF \ {"getkey", (PyCFunction)_curses_window_getkey, METH_VARARGS, _curses_window_getkey__doc__}, @@ -969,8 +972,8 @@ PyDoc_STRVAR(_curses_window_insch__doc__, " attr\n" " Attributes for the character.\n" "\n" -"All characters to the right of the cursor are shifted one position right, with\n" -"the rightmost characters on the line being lost."); +"All characters to the right of the cursor are shifted one position\n" +"right, with the rightmost characters on the line being lost."); #define _CURSES_WINDOW_INSCH_METHODDEF \ {"insch", (PyCFunction)_curses_window_insch, METH_VARARGS, _curses_window_insch__doc__}, @@ -1035,7 +1038,8 @@ PyDoc_STRVAR(_curses_window_inch__doc__, " x\n" " X-coordinate.\n" "\n" -"The bottom 8 bits are the character proper, and upper bits are the attributes."); +"The bottom 8 bits are the character proper, and upper bits are the\n" +"attributes."); #define _CURSES_WINDOW_INCH_METHODDEF \ {"inch", (PyCFunction)_curses_window_inch, METH_VARARGS, _curses_window_inch__doc__}, @@ -1084,11 +1088,11 @@ PyDoc_STRVAR(_curses_window_insstr__doc__, " attr\n" " Attributes for characters.\n" "\n" -"Insert a character string (as many characters as will fit on the line)\n" -"before the character under the cursor. All characters to the right of\n" -"the cursor are shifted right, with the rightmost characters on the line\n" -"being lost. The cursor position does not change (after moving to y, x,\n" -"if specified)."); +"Insert a character string (as many characters as will fit on the\n" +"line) before the character under the cursor. All characters to the\n" +"right of the cursor are shifted right, with the rightmost characters\n" +"on the line being lost. The cursor position does not change (after\n" +"moving to y, x, if specified)."); #define _CURSES_WINDOW_INSSTR_METHODDEF \ {"insstr", (PyCFunction)_curses_window_insstr, METH_VARARGS, _curses_window_insstr__doc__}, @@ -1159,12 +1163,12 @@ PyDoc_STRVAR(_curses_window_insnstr__doc__, " attr\n" " Attributes for characters.\n" "\n" -"Insert a character string (as many characters as will fit on the line)\n" -"before the character under the cursor, up to n characters. If n is zero\n" -"or negative, the entire string is inserted. All characters to the right\n" -"of the cursor are shifted right, with the rightmost characters on the line\n" -"being lost. The cursor position does not change (after moving to y, x, if\n" -"specified)."); +"Insert a character string (as many characters as will fit on the\n" +"line) before the character under the cursor, up to n characters. If\n" +"n is zero or negative, the entire string is inserted. All\n" +"characters to the right of the cursor are shifted right, with the\n" +"rightmost characters on the line being lost. The cursor position\n" +"does not change (after moving to y, x, if specified)."); #define _CURSES_WINDOW_INSNSTR_METHODDEF \ {"insnstr", (PyCFunction)_curses_window_insnstr, METH_VARARGS, _curses_window_insnstr__doc__}, @@ -1230,7 +1234,8 @@ PyDoc_STRVAR(_curses_window_is_linetouched__doc__, " line\n" " Line number.\n" "\n" -"Raise a curses.error exception if line is not valid for the given window."); +"Raise a curses.error exception if line is not valid for the given\n" +"window."); #define _CURSES_WINDOW_IS_LINETOUCHED_METHODDEF \ {"is_linetouched", (PyCFunction)_curses_window_is_linetouched, METH_O, _curses_window_is_linetouched__doc__}, @@ -1260,9 +1265,9 @@ PyDoc_STRVAR(_curses_window_noutrefresh__doc__, "noutrefresh([pminrow, pmincol, sminrow, smincol, smaxrow, smaxcol])\n" "Mark for refresh but wait.\n" "\n" -"This function updates the data structure representing the desired state of the\n" -"window, but does not force an update of the physical screen. To accomplish\n" -"that, call doupdate()."); +"This function updates the data structure representing the desired\n" +"state of the window, but does not force an update of the physical\n" +"screen. To accomplish that, call doupdate()."); #define _CURSES_WINDOW_NOUTREFRESH_METHODDEF \ {"noutrefresh", (PyCFunction)_curses_window_noutrefresh, METH_VARARGS, _curses_window_noutrefresh__doc__}, @@ -1314,9 +1319,9 @@ PyDoc_STRVAR(_curses_window_noutrefresh__doc__, "\n" "Mark for refresh but wait.\n" "\n" -"This function updates the data structure representing the desired state of the\n" -"window, but does not force an update of the physical screen. To accomplish\n" -"that, call doupdate()."); +"This function updates the data structure representing the desired\n" +"state of the window, but does not force an update of the physical\n" +"screen. To accomplish that, call doupdate()."); #define _CURSES_WINDOW_NOUTREFRESH_METHODDEF \ {"noutrefresh", (PyCFunction)_curses_window_noutrefresh, METH_NOARGS, _curses_window_noutrefresh__doc__}, @@ -1336,14 +1341,15 @@ PyDoc_STRVAR(_curses_window_overlay__doc__, "overlay(destwin, [sminrow, smincol, dminrow, dmincol, dmaxrow, dmaxcol])\n" "Overlay the window on top of destwin.\n" "\n" -"The windows need not be the same size, only the overlapping region is copied.\n" -"This copy is non-destructive, which means that the current background\n" -"character does not overwrite the old contents of destwin.\n" +"The windows need not be the same size, only the overlapping region\n" +"is copied. This copy is non-destructive, which means that the\n" +"current background character does not overwrite the old contents of\n" +"destwin.\n" "\n" -"To get fine-grained control over the copied region, the second form of\n" -"overlay() can be used. sminrow and smincol are the upper-left coordinates\n" -"of the source window, and the other variables mark a rectangle in the\n" -"destination window."); +"To get fine-grained control over the copied region, the second form\n" +"of overlay() can be used. sminrow and smincol are the upper-left\n" +"coordinates of the source window, and the other variables mark\n" +"a rectangle in the destination window."); #define _CURSES_WINDOW_OVERLAY_METHODDEF \ {"overlay", (PyCFunction)_curses_window_overlay, METH_VARARGS, _curses_window_overlay__doc__}, @@ -1394,14 +1400,15 @@ PyDoc_STRVAR(_curses_window_overwrite__doc__, " dmaxcol])\n" "Overwrite the window on top of destwin.\n" "\n" -"The windows need not be the same size, in which case only the overlapping\n" -"region is copied. This copy is destructive, which means that the current\n" -"background character overwrites the old contents of destwin.\n" +"The windows need not be the same size, in which case only the\n" +"overlapping region is copied. This copy is destructive, which means\n" +"that the current background character overwrites the old contents of\n" +"destwin.\n" "\n" -"To get fine-grained control over the copied region, the second form of\n" -"overwrite() can be used. sminrow and smincol are the upper-left coordinates\n" -"of the source window, the other variables mark a rectangle in the destination\n" -"window."); +"To get fine-grained control over the copied region, the second form\n" +"of overwrite() can be used. sminrow and smincol are the upper-left\n" +"coordinates of the source window, the other variables mark\n" +"a rectangle in the destination window."); #define _CURSES_WINDOW_OVERWRITE_METHODDEF \ {"overwrite", (PyCFunction)_curses_window_overwrite, METH_VARARGS, _curses_window_overwrite__doc__}, @@ -1520,16 +1527,17 @@ PyDoc_STRVAR(_curses_window_refresh__doc__, "Update the display immediately.\n" "\n" "Synchronize actual screen with previous drawing/deleting methods.\n" -"The 6 optional arguments can only be specified when the window is a pad\n" -"created with newpad(). The additional parameters are needed to indicate\n" -"what part of the pad and screen are involved. pminrow and pmincol specify\n" -"the upper left-hand corner of the rectangle to be displayed in the pad.\n" -"sminrow, smincol, smaxrow, and smaxcol specify the edges of the rectangle to\n" -"be displayed on the screen. The lower right-hand corner of the rectangle to\n" -"be displayed in the pad is calculated from the screen coordinates, since the\n" -"rectangles must be the same size. Both rectangles must be entirely contained\n" -"within their respective structures. Negative values of pminrow, pmincol,\n" -"sminrow, or smincol are treated as if they were zero."); +"The 6 optional arguments can only be specified when the window is\n" +"a pad created with newpad(). The additional parameters are needed\n" +"to indicate what part of the pad and screen are involved. pminrow\n" +"and pmincol specify the upper left-hand corner of the rectangle to\n" +"be displayed in the pad. sminrow, smincol, smaxrow, and smaxcol\n" +"specify the edges of the rectangle to be displayed on the screen.\n" +"The lower right-hand corner of the rectangle to be displayed in the\n" +"pad is calculated from the screen coordinates, since the rectangles\n" +"must be the same size. Both rectangles must be entirely contained\n" +"within their respective structures. Negative values of pminrow,\n" +"pmincol, sminrow, or smincol are treated as if they were zero."); #define _CURSES_WINDOW_REFRESH_METHODDEF \ {"refresh", (PyCFunction)_curses_window_refresh, METH_VARARGS, _curses_window_refresh__doc__}, @@ -1627,8 +1635,8 @@ PyDoc_STRVAR(_curses_window_subwin__doc__, " begin_x\n" " Left side x-coordinate.\n" "\n" -"By default, the sub-window will extend from the specified position to the\n" -"lower right corner of the window."); +"By default, the sub-window will extend from the specified position\n" +"to the lower right corner of the window."); #define _CURSES_WINDOW_SUBWIN_METHODDEF \ {"subwin", (PyCFunction)_curses_window_subwin, METH_VARARGS, _curses_window_subwin__doc__}, @@ -1676,7 +1684,8 @@ PyDoc_STRVAR(_curses_window_scroll__doc__, " lines\n" " Number of lines to scroll.\n" "\n" -"Scroll upward if the argument is positive and downward if it is negative."); +"Scroll upward if the argument is positive and downward if it is\n" +"negative."); #define _CURSES_WINDOW_SCROLL_METHODDEF \ {"scroll", (PyCFunction)_curses_window_scroll, METH_VARARGS, _curses_window_scroll__doc__}, @@ -1715,8 +1724,9 @@ PyDoc_STRVAR(_curses_window_touchline__doc__, "touchline(start, count, [changed=True])\n" "Pretend count lines have been changed, starting with line start.\n" "\n" -"If changed is supplied, it specifies whether the affected lines are marked\n" -"as having been changed (changed=True) or unchanged (changed=False)."); +"If changed is supplied, it specifies whether the affected lines are\n" +"marked as having been changed (changed=True) or unchanged\n" +"(changed=False)."); #define _CURSES_WINDOW_TOUCHLINE_METHODDEF \ {"touchline", (PyCFunction)_curses_window_touchline, METH_VARARGS, _curses_window_touchline__doc__}, @@ -1910,11 +1920,12 @@ PyDoc_STRVAR(_curses_cbreak__doc__, " flag\n" " If false, the effect is the same as calling nocbreak().\n" "\n" -"In cbreak mode (sometimes called \"rare\" mode) normal tty line buffering is\n" -"turned off and characters are available to be read one by one. However,\n" -"unlike raw mode, special characters (interrupt, quit, suspend, and flow\n" -"control) retain their effects on the tty driver and calling program.\n" -"Calling first raw() then cbreak() leaves the terminal in cbreak mode."); +"In cbreak mode (sometimes called \"rare\" mode) normal tty line buffering\n" +"is turned off and characters are available to be read one by one.\n" +"However, unlike raw mode, special characters (interrupt, quit, suspend,\n" +"and flow control) retain their effects on the tty driver and calling\n" +"program. Calling first raw() then cbreak() leaves the terminal in\n" +"cbreak mode."); #define _CURSES_CBREAK_METHODDEF \ {"cbreak", _PyCFunction_CAST(_curses_cbreak), METH_FASTCALL, _curses_cbreak__doc__}, @@ -1954,8 +1965,9 @@ PyDoc_STRVAR(_curses_color_content__doc__, " color_number\n" " The number of the color (0 - (COLORS-1)).\n" "\n" -"A 3-tuple is returned, containing the R, G, B values for the given color,\n" -"which will be between 0 (no component) and 1000 (maximum amount of component)."); +"A 3-tuple is returned, containing the R, G, B values for the given\n" +"color, which will be between 0 (no component) and 1000 (maximum amount\n" +"of component)."); #define _CURSES_COLOR_CONTENT_METHODDEF \ {"color_content", (PyCFunction)_curses_color_content, METH_O, _curses_color_content__doc__}, @@ -1988,7 +2000,8 @@ PyDoc_STRVAR(_curses_color_pair__doc__, " The number of the color pair.\n" "\n" "This attribute value can be combined with A_STANDOUT, A_REVERSE, and the\n" -"other A_* attributes. pair_number() is the counterpart to this function."); +"other A_* attributes. pair_number() is the counterpart to this\n" +"function."); #define _CURSES_COLOR_PAIR_METHODDEF \ {"color_pair", (PyCFunction)_curses_color_pair, METH_O, _curses_color_pair__doc__}, @@ -2022,9 +2035,9 @@ PyDoc_STRVAR(_curses_curs_set__doc__, " 0 for invisible, 1 for normal visible, or 2 for very visible.\n" "\n" "If the terminal supports the visibility requested, the previous cursor\n" -"state is returned; otherwise, an exception is raised. On many terminals,\n" -"the \"visible\" mode is an underline cursor and the \"very visible\" mode is\n" -"a block cursor."); +"state is returned; otherwise, an exception is raised. On many\n" +"terminals, the \"visible\" mode is an underline cursor and the \"very\n" +"visible\" mode is a block cursor."); #define _CURSES_CURS_SET_METHODDEF \ {"curs_set", (PyCFunction)_curses_curs_set, METH_O, _curses_curs_set__doc__}, @@ -2076,7 +2089,8 @@ PyDoc_STRVAR(_curses_def_shell_mode__doc__, "\n" "Save the current terminal mode as the \"shell\" mode.\n" "\n" -"The \"shell\" mode is the mode when the running program is not using curses.\n" +"The \"shell\" mode is the mode when the running program is not using\n" +"curses.\n" "\n" "Subsequent calls to reset_shell_mode() will restore this mode."); @@ -2150,7 +2164,8 @@ PyDoc_STRVAR(_curses_echo__doc__, " flag\n" " If false, the effect is the same as calling noecho().\n" "\n" -"In echo mode, each character input is echoed to the screen as it is entered."); +"In echo mode, each character input is echoed to the screen as it is\n" +"entered."); #define _CURSES_ECHO_METHODDEF \ {"echo", _PyCFunction_CAST(_curses_echo), METH_FASTCALL, _curses_echo__doc__}, @@ -2223,7 +2238,8 @@ PyDoc_STRVAR(_curses_flash__doc__, "\n" "Flash the screen.\n" "\n" -"That is, change it to reverse-video and then change it back in a short interval."); +"That is, change it to reverse-video and then change it back in a short\n" +"interval."); #define _CURSES_FLASH_METHODDEF \ {"flash", (PyCFunction)_curses_flash, METH_NOARGS, _curses_flash__doc__}, @@ -2243,8 +2259,8 @@ PyDoc_STRVAR(_curses_flushinp__doc__, "\n" "Flush all input buffers.\n" "\n" -"This throws away any typeahead that has been typed by the user and has not\n" -"yet been processed by the program."); +"This throws away any typeahead that has been typed by the user and has\n" +"not yet been processed by the program."); #define _CURSES_FLUSHINP_METHODDEF \ {"flushinp", (PyCFunction)_curses_flushinp, METH_NOARGS, _curses_flushinp__doc__}, @@ -2614,8 +2630,9 @@ PyDoc_STRVAR(_curses_init_pair__doc__, " bg\n" " Background color number (-1 - (COLORS-1)).\n" "\n" -"If the color-pair was previously initialized, the screen is refreshed and\n" -"all occurrences of that color-pair are changed to the new definition."); +"If the color-pair was previously initialized, the screen is refreshed\n" +"and all occurrences of that color-pair are changed to the new\n" +"definition."); #define _CURSES_INIT_PAIR_METHODDEF \ {"init_pair", _PyCFunction_CAST(_curses_init_pair), METH_FASTCALL, _curses_init_pair__doc__}, @@ -2774,9 +2791,9 @@ PyDoc_STRVAR(_curses_get_escdelay__doc__, "\n" "Gets the curses ESCDELAY setting.\n" "\n" -"Gets the number of milliseconds to wait after reading an escape character,\n" -"to distinguish between an individual escape character entered on the\n" -"keyboard from escape sequences sent by cursor and function keys."); +"Gets the number of milliseconds to wait after reading an escape\n" +"character, to distinguish between an individual escape character entered\n" +"on the keyboard from escape sequences sent by cursor and function keys."); #define _CURSES_GET_ESCDELAY_METHODDEF \ {"get_escdelay", (PyCFunction)_curses_get_escdelay, METH_NOARGS, _curses_get_escdelay__doc__}, @@ -2803,9 +2820,9 @@ PyDoc_STRVAR(_curses_set_escdelay__doc__, " ms\n" " length of the delay in milliseconds.\n" "\n" -"Sets the number of milliseconds to wait after reading an escape character,\n" -"to distinguish between an individual escape character entered on the\n" -"keyboard from escape sequences sent by cursor and function keys."); +"Sets the number of milliseconds to wait after reading an escape\n" +"character, to distinguish between an individual escape character entered\n" +"on the keyboard from escape sequences sent by cursor and function keys."); #define _CURSES_SET_ESCDELAY_METHODDEF \ {"set_escdelay", (PyCFunction)_curses_set_escdelay, METH_O, _curses_set_escdelay__doc__}, @@ -2839,8 +2856,8 @@ PyDoc_STRVAR(_curses_get_tabsize__doc__, "\n" "Gets the curses TABSIZE setting.\n" "\n" -"Gets the number of columns used by the curses library when converting a tab\n" -"character to spaces as it adds the tab to a window."); +"Gets the number of columns used by the curses library when converting\n" +"a tab character to spaces as it adds the tab to a window."); #define _CURSES_GET_TABSIZE_METHODDEF \ {"get_tabsize", (PyCFunction)_curses_get_tabsize, METH_NOARGS, _curses_get_tabsize__doc__}, @@ -2867,8 +2884,8 @@ PyDoc_STRVAR(_curses_set_tabsize__doc__, " size\n" " rendered cell width of a tab character.\n" "\n" -"Sets the number of columns used by the curses library when converting a tab\n" -"character to spaces as it adds the tab to a window."); +"Sets the number of columns used by the curses library when converting\n" +"a tab character to spaces as it adds the tab to a window."); #define _CURSES_SET_TABSIZE_METHODDEF \ {"set_tabsize", (PyCFunction)_curses_set_tabsize, METH_O, _curses_set_tabsize__doc__}, @@ -3039,8 +3056,8 @@ PyDoc_STRVAR(_curses_longname__doc__, "\n" "Return the terminfo long name field describing the current terminal.\n" "\n" -"The maximum length of a verbose description is 128 characters. It is defined\n" -"only after the call to initscr()."); +"The maximum length of a verbose description is 128 characters. It is\n" +"defined only after the call to initscr()."); #define _CURSES_LONGNAME_METHODDEF \ {"longname", (PyCFunction)_curses_longname, METH_NOARGS, _curses_longname__doc__}, @@ -3097,8 +3114,8 @@ PyDoc_STRVAR(_curses_mouseinterval__doc__, " Time in milliseconds.\n" "\n" "Set the maximum time that can elapse between press and release events in\n" -"order for them to be recognized as a click, and return the previous interval\n" -"value."); +"order for them to be recognized as a click, and return the previous\n" +"interval value."); #define _CURSES_MOUSEINTERVAL_METHODDEF \ {"mouseinterval", (PyCFunction)_curses_mouseinterval, METH_O, _curses_mouseinterval__doc__}, @@ -3133,9 +3150,10 @@ PyDoc_STRVAR(_curses_mousemask__doc__, "Set the mouse events to be reported, and return a tuple (availmask, oldmask).\n" "\n" "Return a tuple (availmask, oldmask). availmask indicates which of the\n" -"specified mouse events can be reported; on complete failure it returns 0.\n" -"oldmask is the previous value of the given window\'s mouse event mask.\n" -"If this function is never called, no mouse events are ever reported."); +"specified mouse events can be reported; on complete failure it returns\n" +"0. oldmask is the previous value of the given window\'s mouse event\n" +"mask. If this function is never called, no mouse events are ever\n" +"reported."); #define _CURSES_MOUSEMASK_METHODDEF \ {"mousemask", (PyCFunction)_curses_mousemask, METH_O, _curses_mousemask__doc__}, @@ -3267,8 +3285,8 @@ PyDoc_STRVAR(_curses_newwin__doc__, " begin_x\n" " Left side x-coordinate.\n" "\n" -"By default, the window will extend from the specified position to the lower\n" -"right corner of the screen."); +"By default, the window will extend from the specified position to the\n" +"lower right corner of the screen."); #define _CURSES_NEWWIN_METHODDEF \ {"newwin", (PyCFunction)_curses_newwin, METH_VARARGS, _curses_newwin__doc__}, @@ -3318,8 +3336,9 @@ PyDoc_STRVAR(_curses_nl__doc__, " flag\n" " If false, the effect is the same as calling nonl().\n" "\n" -"This mode translates the return key into newline on input, and translates\n" -"newline into return and line-feed on output. Newline mode is initially on."); +"This mode translates the return key into newline on input, and\n" +"translates newline into return and line-feed on output. Newline mode\n" +"is initially on."); #define _CURSES_NL_METHODDEF \ {"nl", _PyCFunction_CAST(_curses_nl), METH_FASTCALL, _curses_nl__doc__}, @@ -3396,8 +3415,8 @@ PyDoc_STRVAR(_curses_nonl__doc__, "\n" "Leave newline mode.\n" "\n" -"Disable translation of return into newline on input, and disable low-level\n" -"translation of newline into newline/return on output."); +"Disable translation of return into newline on input, and disable\n" +"low-level translation of newline into newline/return on output."); #define _CURSES_NONL_METHODDEF \ {"nonl", (PyCFunction)_curses_nonl, METH_NOARGS, _curses_nonl__doc__}, @@ -3613,8 +3632,8 @@ PyDoc_STRVAR(_curses_raw__doc__, " If false, the effect is the same as calling noraw().\n" "\n" "In raw mode, normal line buffering and processing of interrupt, quit,\n" -"suspend, and flow control keys are turned off; characters are presented to\n" -"curses input functions one by one."); +"suspend, and flow control keys are turned off; characters are presented\n" +"to curses input functions one by one."); #define _CURSES_RAW_METHODDEF \ {"raw", _PyCFunction_CAST(_curses_raw), METH_FASTCALL, _curses_raw__doc__}, @@ -3712,8 +3731,8 @@ PyDoc_STRVAR(_curses_resizeterm__doc__, " ncols\n" " Width.\n" "\n" -"Adjusts other bookkeeping data used by the curses library that record the\n" -"window dimensions (in particular the SIGWINCH handler)."); +"Adjusts other bookkeeping data used by the curses library that record\n" +"the window dimensions (in particular the SIGWINCH handler)."); #define _CURSES_RESIZETERM_METHODDEF \ {"resizeterm", _PyCFunction_CAST(_curses_resizeterm), METH_FASTCALL, _curses_resizeterm__doc__}, @@ -3791,10 +3810,11 @@ PyDoc_STRVAR(_curses_resize_term__doc__, " Width.\n" "\n" "When resizing the windows, resize_term() blank-fills the areas that are\n" -"extended. The calling application should fill in these areas with appropriate\n" -"data. The resize_term() function attempts to resize all windows. However,\n" -"due to the calling convention of pads, it is not possible to resize these\n" -"without additional interaction with the application."); +"extended. The calling application should fill in these areas with\n" +"appropriate data. The resize_term() function attempts to resize all\n" +"windows. However, due to the calling convention of pads, it is not\n" +"possible to resize these without additional interaction with the\n" +"application."); #define _CURSES_RESIZE_TERM_METHODDEF \ {"resize_term", _PyCFunction_CAST(_curses_resize_term), METH_FASTCALL, _curses_resize_term__doc__}, @@ -3929,12 +3949,12 @@ PyDoc_STRVAR(_curses_start_color__doc__, "\n" "Initializes eight basic colors and global variables COLORS and COLOR_PAIRS.\n" "\n" -"Must be called if the programmer wants to use colors, and before any other\n" -"color manipulation routine is called. It is good practice to call this\n" -"routine right after initscr().\n" +"Must be called if the programmer wants to use colors, and before any\n" +"other color manipulation routine is called. It is good practice to call\n" +"this routine right after initscr().\n" "\n" -"It also restores the colors on the terminal to the values they had when the\n" -"terminal was just turned on."); +"It also restores the colors on the terminal to the values they had when\n" +"the terminal was just turned on."); #define _CURSES_START_COLOR_METHODDEF \ {"start_color", (PyCFunction)_curses_start_color, METH_NOARGS, _curses_start_color__doc__}, @@ -4036,8 +4056,8 @@ PyDoc_STRVAR(_curses_tigetnum__doc__, " capname\n" " The terminfo capability name.\n" "\n" -"The value -2 is returned if capname is not a numeric capability, or -1 if\n" -"it is canceled or absent from the terminal description."); +"The value -2 is returned if capname is not a numeric capability, or -1\n" +"if it is canceled or absent from the terminal description."); #define _CURSES_TIGETNUM_METHODDEF \ {"tigetnum", (PyCFunction)_curses_tigetnum, METH_O, _curses_tigetnum__doc__}, @@ -4079,8 +4099,8 @@ PyDoc_STRVAR(_curses_tigetstr__doc__, " capname\n" " The terminfo capability name.\n" "\n" -"None is returned if capname is not a string capability, or is canceled or\n" -"absent from the terminal description."); +"None is returned if capname is not a string capability, or is canceled\n" +"or absent from the terminal description."); #define _CURSES_TIGETSTR_METHODDEF \ {"tigetstr", (PyCFunction)_curses_tigetstr, METH_O, _curses_tigetstr__doc__}, @@ -4234,14 +4254,14 @@ PyDoc_STRVAR(_curses_use_env__doc__, "\n" "Use environment variables LINES and COLUMNS.\n" "\n" -"If used, this function should be called before initscr() or newterm() are\n" -"called.\n" +"If used, this function should be called before initscr() or newterm()\n" +"are called.\n" "\n" -"When flag is False, the values of lines and columns specified in the terminfo\n" -"database will be used, even if environment variables LINES and COLUMNS (used\n" -"by default) are set, or if curses is running in a window (in which case\n" -"default behavior would be to use the window size if LINES and COLUMNS are\n" -"not set)."); +"When flag is False, the values of lines and columns specified in the\n" +"terminfo database will be used, even if environment variables LINES and\n" +"COLUMNS (used by default) are set, or if curses is running in a window\n" +"(in which case default behavior would be to use the window size if LINES\n" +"and COLUMNS are not set)."); #define _CURSES_USE_ENV_METHODDEF \ {"use_env", (PyCFunction)_curses_use_env, METH_O, _curses_use_env__doc__}, @@ -4450,4 +4470,4 @@ _curses_has_extended_color_support(PyObject *module, PyObject *Py_UNUSED(ignored #ifndef _CURSES_ASSUME_DEFAULT_COLORS_METHODDEF #define _CURSES_ASSUME_DEFAULT_COLORS_METHODDEF #endif /* !defined(_CURSES_ASSUME_DEFAULT_COLORS_METHODDEF) */ -/*[clinic end generated code: output=135246e29163510c input=a9049054013a1b77]*/ +/*[clinic end generated code: output=e7c7932f4a4e9bce input=a9049054013a1b77]*/ From cfb2e431cd367ec49098b62048dfd719de38c6fb Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 24 May 2026 15:23:45 +0200 Subject: [PATCH 127/818] [3.15] gh-150285: Fix too long docstrings in the io module (GH-150287) (GH-150332) (cherry picked from commit 160dc74122ed4e31540b2ef2c77bda122b02c94a) Co-authored-by: Serhiy Storchaka --- Lib/_pyio.py | 130 +++++++++++++++------------- Modules/_io/_iomodule.c | 89 ++++++++++--------- Modules/_io/bytesio.c | 12 +-- Modules/_io/clinic/_iomodule.c.h | 85 +++++++++--------- Modules/_io/clinic/bytesio.c.h | 10 +-- Modules/_io/clinic/fileio.c.h | 66 +++++++------- Modules/_io/clinic/iobase.c.h | 16 ++-- Modules/_io/clinic/stringio.c.h | 5 +- Modules/_io/clinic/textio.c.h | 13 +-- Modules/_io/clinic/winconsoleio.c.h | 8 +- Modules/_io/fileio.c | 82 +++++++++--------- Modules/_io/iobase.c | 19 ++-- Modules/_io/stringio.c | 5 +- Modules/_io/textio.c | 18 ++-- Modules/_io/winconsoleio.c | 8 +- 15 files changed, 296 insertions(+), 270 deletions(-) diff --git a/Lib/_pyio.py b/Lib/_pyio.py index 3306c8a274760b..9739b6d37fb21b 100644 --- a/Lib/_pyio.py +++ b/Lib/_pyio.py @@ -83,27 +83,28 @@ def open(file, mode="r", buffering=-1, encoding=None, errors=None, wrapped. (If a file descriptor is given, it is closed when the returned I/O object is closed, unless closefd is set to False.) - mode is an optional string that specifies the mode in which the file is - opened. It defaults to 'r' which means open for reading in text mode. Other - common values are 'w' for writing (truncating the file if it already - exists), 'x' for exclusive creation of a new file, and 'a' for appending - (which on some Unix systems, means that all writes append to the end of the - file regardless of the current seek position). In text mode, if encoding is - not specified the encoding used is platform dependent. (For reading and - writing raw bytes use binary mode and leave encoding unspecified.) The - available modes are: - - ========= =============================================================== + mode is an optional string that specifies the mode in which the file + is opened. It defaults to 'r' which means open for reading in text + mode. Other common values are 'w' for writing (truncating the file if + it already exists), 'x' for exclusive creation of a new file, and + 'a' for appending (which on some Unix systems, means that all writes + append to the end of the file regardless of the current seek position). + In text mode, if encoding is not specified the encoding used is platform + dependent. (For reading and writing raw bytes use binary mode and leave + encoding unspecified.) The available modes are: + + ========= ========================================================== Character Meaning - --------- --------------------------------------------------------------- + --------- ---------------------------------------------------------- 'r' open for reading (default) 'w' open for writing, truncating the file first 'x' create a new file and open it for writing - 'a' open for writing, appending to the end of the file if it exists + 'a' open for writing, appending to the end of the file if it + exists 'b' binary mode 't' text mode (default) '+' open a disk file for updating (reading and writing) - ========= =============================================================== + ========= ========================================================== The default mode is 'rt' (open for reading text). For binary random access, the mode 'w+b' opens and truncates the file to 0 bytes, while @@ -111,23 +112,23 @@ def open(file, mode="r", buffering=-1, encoding=None, errors=None, raises an `FileExistsError` if the file already exists. Python distinguishes between files opened in binary and text modes, - even when the underlying operating system doesn't. Files opened in + even when the underlying operating system doesn't. Files opened in binary mode (appending 'b' to the mode argument) return contents as - bytes objects without any decoding. In text mode (the default, or when + bytes objects without any decoding. In text mode (the default, or when 't' is appended to the mode argument), the contents of the file are returned as strings, the bytes having been first decoded using a platform-dependent encoding or using the specified encoding if given. buffering is an optional integer used to set the buffering policy. - Pass 0 to switch buffering off (only allowed in binary mode), 1 to select - line buffering (only usable in text mode), and an integer > 1 to indicate - the size of a fixed-size chunk buffer. When no buffering argument is - given, the default buffering policy works as follows: + Pass 0 to switch buffering off (only allowed in binary mode), 1 to + select line buffering (only usable in text mode), and an integer > 1 to + indicate the size of a fixed-size chunk buffer. When no buffering + argument is given, the default buffering policy works as follows: - * Binary files are buffered in fixed-size chunks; the size of the buffer - is max(min(blocksize, 8 MiB), DEFAULT_BUFFER_SIZE) - when the device block size is available. - On most systems, the buffer will typically be 128 kilobytes long. + * Binary files are buffered in fixed-size chunks; the size of the buffer + is max(min(blocksize, 8 MiB), DEFAULT_BUFFER_SIZE) when the device + block size is available. + On most systems, the buffer will typically be 128 kilobytes long. * "Interactive" text files (files for which isatty() returns True) use line buffering. Other text files use the policy described above @@ -147,8 +148,8 @@ def open(file, mode="r", buffering=-1, encoding=None, errors=None, encoding error strings. newline is a string controlling how universal newlines works (it only - applies to text mode). It can be None, '', '\n', '\r', and '\r\n'. It works - as follows: + applies to text mode). It can be None, '', '\n', '\r', and '\r\n'. It + works as follows: * On input, if newline is None, universal newlines mode is enabled. Lines in the input can end in '\n', '\r', or '\r\n', and @@ -164,17 +165,17 @@ def open(file, mode="r", buffering=-1, encoding=None, errors=None, other legal values, any '\n' characters written are translated to the given string. - closedfd is a bool. If closefd is False, the underlying file descriptor will - be kept open when the file is closed. This does not work when a file name is - given and must be True in that case. + closedfd is a bool. If closefd is False, the underlying file descriptor + will be kept open when the file is closed. This does not work when + a file name is given and must be True in that case. The newly created file is non-inheritable. A custom opener can be used by passing a callable as *opener*. The - underlying file descriptor for the file object is then obtained by calling - *opener* with (*file*, *flags*). *opener* must return an open file - descriptor (passing os.open as *opener* results in functionality similar to - passing None). + underlying file descriptor for the file object is then obtained by + calling *opener* with (*file*, *flags*). *opener* must return an open + file descriptor (passing os.open as *opener* results in functionality + similar to passing None). open() returns a file object whose type depends on the mode, and through which the standard file operations such as reading and writing @@ -351,10 +352,12 @@ def seek(self, pos, whence=0): interpreted relative to the position indicated by whence. Values for whence are ints: - * 0 -- start of stream (the default); offset should be zero or positive + * 0 -- start of stream (the default); offset should be zero or + positive * 1 -- current stream position; offset may be negative * 2 -- end of stream; offset is usually negative - Some operating systems / file systems could provide additional values. + Some operating systems / file systems could provide additional + values. Return an int indicating the new absolute position. """ @@ -367,8 +370,8 @@ def tell(self): def truncate(self, pos=None): """Truncate file to size bytes. - Size defaults to the current IO position as reported by tell(). Return - the new size. + Size defaults to the current IO position as reported by tell(). + Return the new size. """ self._unsupported("truncate") @@ -492,7 +495,8 @@ def __exit__(self, *args): def fileno(self): """Returns underlying file descriptor (an int) if one exists. - An OSError is raised if the IO object does not use a file descriptor. + An OSError is raised if the IO object does not use a file + descriptor. """ self._unsupported("fileno") @@ -1505,17 +1509,22 @@ class FileIO(RawIOBase): _closefd = True def __init__(self, file, mode='r', closefd=True, opener=None): - """Open a file. The mode can be 'r' (default), 'w', 'x' or 'a' for reading, - writing, exclusive creation or appending. The file will be created if it - doesn't exist when opened for writing or appending; it will be truncated - when opened for writing. A FileExistsError will be raised if it already - exists when opened for creating. Opening a file for creating implies - writing so this mode behaves in a similar way to 'w'. Add a '+' to the mode - to allow simultaneous reading and writing. A custom opener can be used by - passing a callable as *opener*. The underlying file descriptor for the file - object is then obtained by calling opener with (*name*, *flags*). - *opener* must return an open file descriptor (passing os.open as *opener* - results in functionality similar to passing None). + """Open a file. + + The mode can be 'r' (default), 'w', 'x' or 'a' for reading, + writing, exclusive creation or appending. The file will be created + if it doesn't exist when opened for writing or appending; it will be + truncated when opened for writing. A FileExistsError will be raised + if it already exists when opened for creating. Opening a file for + creating implies writing so this mode behaves in a similar way to + 'w'. Add a '+' to the mode to allow simultaneous reading and + writing. + + A custom opener can be used by passing a callable as *opener*. + The underlying file descriptor for the file object is then obtained + by calling opener with (*name*, *flags*). *opener* must return + an open file descriptor (passing os.open as *opener* results in + functionality similar to passing None). """ if self._fd >= 0: # Have to close the existing file first. @@ -1754,8 +1763,8 @@ def write(self, b): """Write bytes b to file, return number written. Only makes one system call, so not all of the data may be written. - The number of bytes actually written is returned. In non-blocking mode, - returns None if the write would block. + The number of bytes actually written is returned. In non-blocking + mode, returns None if the write would block. """ self._checkClosed() self._checkWritable() @@ -1767,11 +1776,12 @@ def write(self, b): def seek(self, pos, whence=SEEK_SET): """Move to new file position. - Argument offset is a byte count. Optional argument whence defaults to - SEEK_SET or 0 (offset from start of file, offset should be >= 0); other values - are SEEK_CUR or 1 (move relative to current position, positive or negative), - and SEEK_END or 2 (move relative to end of file, usually negative, although - many platforms allow seeking beyond the end of a file). + Argument offset is a byte count. Optional argument whence defaults + to SEEK_SET or 0 (offset from start of file, offset should be >= 0); + other values are SEEK_CUR or 1 (move relative to current position, + positive or negative), and SEEK_END or 2 (move relative to end of + file, usually negative, although many platforms allow seeking beyond + the end of a file). Note that not all file objects are seekable. """ @@ -1804,8 +1814,8 @@ def truncate(self, size=None): def close(self): """Close the file. - A closed file cannot be used for further I/O operations. close() may be - called more than once without error. + A closed file cannot be used for further I/O operations. + close() may be called more than once without error. """ if not self.closed: self._stat_atopen = None @@ -1903,8 +1913,8 @@ class TextIOBase(IOBase): def read(self, size=-1): """Read at most size characters from stream, where size is an int. - Read from underlying buffer until we have size characters or we hit EOF. - If size is negative or omitted, read until EOF. + Read from underlying buffer until we have size characters or we hit + EOF. If size is negative or omitted, read until EOF. Returns a string. """ diff --git a/Modules/_io/_iomodule.c b/Modules/_io/_iomodule.c index 32c55f8e225ed9..03e6fbe08889d4 100644 --- a/Modules/_io/_iomodule.c +++ b/Modules/_io/_iomodule.c @@ -70,7 +70,6 @@ PyDoc_STRVAR(module_doc, /*[clinic input] module _io -@permit_long_docstring_body _io.open file: object mode: str = "r" @@ -86,112 +85,113 @@ Open file and return a stream. Raise OSError upon failure. file is either a text or byte string giving the name (and the path if the file isn't in the current working directory) of the file to be opened or an integer file descriptor of the file to be -wrapped. (If a file descriptor is given, it is closed when the +wrapped. (If a file descriptor is given, it is closed when the returned I/O object is closed, unless closefd is set to False.) mode is an optional string that specifies the mode in which the file -is opened. It defaults to 'r' which means open for reading in text +is opened. It defaults to 'r' which means open for reading in text mode. Other common values are 'w' for writing (truncating the file if it already exists), 'x' for creating and writing to a new file, and 'a' for appending (which on some Unix systems, means that all writes append to the end of the file regardless of the current seek position). In text mode, if encoding is not specified the encoding used is platform -dependent: locale.getencoding() is called to get the current locale encoding. -(For reading and writing raw bytes use binary mode and leave encoding -unspecified.) The available modes are: +dependent: locale.getencoding() is called to get the current locale +encoding. (For reading and writing raw bytes use binary mode and leave +encoding unspecified.) The available modes are: -========= =============================================================== +========= ========================================================== Character Meaning ---------- --------------------------------------------------------------- +--------- ---------------------------------------------------------- 'r' open for reading (default) 'w' open for writing, truncating the file first 'x' create a new file and open it for writing -'a' open for writing, appending to the end of the file if it exists +'a' open for writing, appending to the end of the file if it + exists 'b' binary mode 't' text mode (default) '+' open a disk file for updating (reading and writing) -========= =============================================================== +========= ========================================================== -The default mode is 'rt' (open for reading text). For binary random +The default mode is 'rt' (open for reading text). For binary random access, the mode 'w+b' opens and truncates the file to 0 bytes, while -'r+b' opens the file without truncation. The 'x' mode implies 'w' and +'r+b' opens the file without truncation. The 'x' mode implies 'w' and raises an `FileExistsError` if the file already exists. Python distinguishes between files opened in binary and text modes, -even when the underlying operating system doesn't. Files opened in +even when the underlying operating system doesn't. Files opened in binary mode (appending 'b' to the mode argument) return contents as -bytes objects without any decoding. In text mode (the default, or when +bytes objects without any decoding. In text mode (the default, or when 't' is appended to the mode argument), the contents of the file are returned as strings, the bytes having been first decoded using a platform-dependent encoding or using the specified encoding if given. buffering is an optional integer used to set the buffering policy. -Pass 0 to switch buffering off (only allowed in binary mode), 1 to select -line buffering (only usable in text mode), and an integer > 1 to indicate -the size of a fixed-size chunk buffer. When no buffering argument is -given, the default buffering policy works as follows: +Pass 0 to switch buffering off (only allowed in binary mode), 1 to +select line buffering (only usable in text mode), and an integer > 1 to +indicate the size of a fixed-size chunk buffer. When no buffering +argument is given, the default buffering policy works as follows: * Binary files are buffered in fixed-size chunks; the size of the buffer - is max(min(blocksize, 8 MiB), DEFAULT_BUFFER_SIZE) - when the device block size is available. - On most systems, the buffer will typically be 128 kilobytes long. + is max(min(blocksize, 8 MiB), DEFAULT_BUFFER_SIZE) when the device + block size is available. + On most systems, the buffer will typically be 128 kilobytes long. * "Interactive" text files (files for which isatty() returns True) use line buffering. Other text files use the policy described above for binary files. encoding is the name of the encoding used to decode or encode the -file. This should only be used in text mode. The default encoding is +file. This should only be used in text mode. The default encoding is platform dependent, but any encoding supported by Python can be passed. See the codecs module for the list of supported encodings. errors is an optional string that specifies how encoding errors are to -be handled---this argument should not be used in binary mode. Pass +be handled---this argument should not be used in binary mode. Pass 'strict' to raise a ValueError exception if there is an encoding error (the default of None has the same effect), or pass 'ignore' to ignore -errors. (Note that ignoring encoding errors can lead to data loss.) +errors. (Note that ignoring encoding errors can lead to data loss.) See the documentation for codecs.register or run 'help(codecs.Codec)' for a list of the permitted encoding error strings. newline controls how universal newlines works (it only applies to text -mode). It can be None, '', '\n', '\r', and '\r\n'. It works as +mode). It can be None, '', '\n', '\r', and '\r\n'. It works as follows: -* On input, if newline is None, universal newlines mode is - enabled. Lines in the input can end in '\n', '\r', or '\r\n', and - these are translated into '\n' before being returned to the - caller. If it is '', universal newline mode is enabled, but line - endings are returned to the caller untranslated. If it has any of - the other legal values, input lines are only terminated by the given - string, and the line ending is returned to the caller untranslated. +* On input, if newline is None, universal newlines mode is enabled. + Lines in the input can end in '\n', '\r', or '\r\n', and these are + translated into '\n' before being returned to the caller. If it is + '', universal newline mode is enabled, but line endings are returned + to the caller untranslated. If it has any of the other legal values, + input lines are only terminated by the given string, and the line + ending is returned to the caller untranslated. * On output, if newline is None, any '\n' characters written are - translated to the system default line separator, os.linesep. If - newline is '' or '\n', no translation takes place. If newline is any + translated to the system default line separator, os.linesep. If + newline is '' or '\n', no translation takes place. If newline is any of the other legal values, any '\n' characters written are translated to the given string. If closefd is False, the underlying file descriptor will be kept open -when the file is closed. This does not work when a file name is given +when the file is closed. This does not work when a file name is given and must be True in that case. -A custom opener can be used by passing a callable as *opener*. The +A custom opener can be used by passing a callable as *opener*. The underlying file descriptor for the file object is then obtained by -calling *opener* with (*file*, *flags*). *opener* must return an open +calling *opener* with (*file*, *flags*). *opener* must return an open file descriptor (passing os.open as *opener* results in functionality similar to passing None). open() returns a file object whose type depends on the mode, and through which the standard file operations such as reading and writing -are performed. When open() is used to open a file in a text mode ('w', -'r', 'wt', 'rt', etc.), it returns a TextIOWrapper. When used to open +are performed. When open() is used to open a file in a text mode ('w', +'r', 'wt', 'rt', etc.), it returns a TextIOWrapper. When used to open a file in a binary mode, the returned class varies: in read binary mode, it returns a BufferedReader; in write binary and append binary modes, it returns a BufferedWriter, and in read/write mode, it returns a BufferedRandom. It is also possible to use a string or bytearray as a file for both -reading and writing. For strings StringIO can be used like a file +reading and writing. For strings StringIO can be used like a file opened in a text mode, and for bytes a BytesIO can be used like a file opened in a binary mode. [clinic start generated code]*/ @@ -200,7 +200,7 @@ static PyObject * _io_open_impl(PyObject *module, PyObject *file, const char *mode, int buffering, const char *encoding, const char *errors, const char *newline, int closefd, PyObject *opener) -/*[clinic end generated code: output=aefafc4ce2b46dc0 input=8629579a442a99e3]*/ +/*[clinic end generated code: output=aefafc4ce2b46dc0 input=b3cefa70bef404b3]*/ { size_t i; @@ -499,21 +499,20 @@ _io_text_encoding_impl(PyObject *module, PyObject *encoding, int stacklevel) /*[clinic input] -@permit_long_docstring_body _io.open_code path : unicode Opens the provided file with the intent to import the contents. -This may perform extra validation beyond open(), but is otherwise interchangeable -with calling open(path, 'rb'). +This may perform extra validation beyond open(), but is otherwise +interchangeable with calling open(path, 'rb'). [clinic start generated code]*/ static PyObject * _io_open_code_impl(PyObject *module, PyObject *path) -/*[clinic end generated code: output=2fe4ecbd6f3d6844 input=53d38a37d780d034]*/ +/*[clinic end generated code: output=2fe4ecbd6f3d6844 input=2803c35aeb63c719]*/ { return PyFile_OpenCodeObject(path); } diff --git a/Modules/_io/bytesio.c b/Modules/_io/bytesio.c index d088bb0efac797..8cdcbd0d89c718 100644 --- a/Modules/_io/bytesio.c +++ b/Modules/_io/bytesio.c @@ -488,13 +488,13 @@ _io.BytesIO.read1 Read at most size bytes, returned as a bytes object. -If the size argument is negative or omitted, read until EOF is reached. -Return an empty bytes object at EOF. +If the size argument is negative or omitted, read until EOF is +reached. Return an empty bytes object at EOF. [clinic start generated code]*/ static PyObject * _io_BytesIO_read1_impl(bytesio *self, Py_ssize_t size) -/*[clinic end generated code: output=d0f843285aa95f1c input=a08fc9e507ab380c]*/ +/*[clinic end generated code: output=d0f843285aa95f1c input=796ff4e0efccc4d9]*/ { return _io_BytesIO_read_impl(self, size); } @@ -792,13 +792,13 @@ _io.BytesIO.writelines Write lines to the file. Note that newlines are not added. lines can be any iterable object -producing bytes-like objects. This is equivalent to calling write() for -each element. +producing bytes-like objects. This is equivalent to calling write() +for each element. [clinic start generated code]*/ static PyObject * _io_BytesIO_writelines_impl(bytesio *self, PyObject *lines) -/*[clinic end generated code: output=03a43a75773bc397 input=5d6a616ae39dc9ca]*/ +/*[clinic end generated code: output=03a43a75773bc397 input=d265f76533b058e7]*/ { PyObject *it, *item; diff --git a/Modules/_io/clinic/_iomodule.c.h b/Modules/_io/clinic/_iomodule.c.h index 90b80af3018fb0..f03638064385e2 100644 --- a/Modules/_io/clinic/_iomodule.c.h +++ b/Modules/_io/clinic/_iomodule.c.h @@ -18,112 +18,113 @@ PyDoc_STRVAR(_io_open__doc__, "file is either a text or byte string giving the name (and the path\n" "if the file isn\'t in the current working directory) of the file to\n" "be opened or an integer file descriptor of the file to be\n" -"wrapped. (If a file descriptor is given, it is closed when the\n" +"wrapped. (If a file descriptor is given, it is closed when the\n" "returned I/O object is closed, unless closefd is set to False.)\n" "\n" "mode is an optional string that specifies the mode in which the file\n" -"is opened. It defaults to \'r\' which means open for reading in text\n" +"is opened. It defaults to \'r\' which means open for reading in text\n" "mode. Other common values are \'w\' for writing (truncating the file if\n" "it already exists), \'x\' for creating and writing to a new file, and\n" "\'a\' for appending (which on some Unix systems, means that all writes\n" "append to the end of the file regardless of the current seek position).\n" "In text mode, if encoding is not specified the encoding used is platform\n" -"dependent: locale.getencoding() is called to get the current locale encoding.\n" -"(For reading and writing raw bytes use binary mode and leave encoding\n" -"unspecified.) The available modes are:\n" +"dependent: locale.getencoding() is called to get the current locale\n" +"encoding. (For reading and writing raw bytes use binary mode and leave\n" +"encoding unspecified.) The available modes are:\n" "\n" -"========= ===============================================================\n" +"========= ==========================================================\n" "Character Meaning\n" -"--------- ---------------------------------------------------------------\n" +"--------- ----------------------------------------------------------\n" "\'r\' open for reading (default)\n" "\'w\' open for writing, truncating the file first\n" "\'x\' create a new file and open it for writing\n" -"\'a\' open for writing, appending to the end of the file if it exists\n" +"\'a\' open for writing, appending to the end of the file if it\n" +" exists\n" "\'b\' binary mode\n" "\'t\' text mode (default)\n" "\'+\' open a disk file for updating (reading and writing)\n" -"========= ===============================================================\n" +"========= ==========================================================\n" "\n" -"The default mode is \'rt\' (open for reading text). For binary random\n" +"The default mode is \'rt\' (open for reading text). For binary random\n" "access, the mode \'w+b\' opens and truncates the file to 0 bytes, while\n" -"\'r+b\' opens the file without truncation. The \'x\' mode implies \'w\' and\n" +"\'r+b\' opens the file without truncation. The \'x\' mode implies \'w\' and\n" "raises an `FileExistsError` if the file already exists.\n" "\n" "Python distinguishes between files opened in binary and text modes,\n" -"even when the underlying operating system doesn\'t. Files opened in\n" +"even when the underlying operating system doesn\'t. Files opened in\n" "binary mode (appending \'b\' to the mode argument) return contents as\n" -"bytes objects without any decoding. In text mode (the default, or when\n" +"bytes objects without any decoding. In text mode (the default, or when\n" "\'t\' is appended to the mode argument), the contents of the file are\n" "returned as strings, the bytes having been first decoded using a\n" "platform-dependent encoding or using the specified encoding if given.\n" "\n" "buffering is an optional integer used to set the buffering policy.\n" -"Pass 0 to switch buffering off (only allowed in binary mode), 1 to select\n" -"line buffering (only usable in text mode), and an integer > 1 to indicate\n" -"the size of a fixed-size chunk buffer. When no buffering argument is\n" -"given, the default buffering policy works as follows:\n" +"Pass 0 to switch buffering off (only allowed in binary mode), 1 to\n" +"select line buffering (only usable in text mode), and an integer > 1 to\n" +"indicate the size of a fixed-size chunk buffer. When no buffering\n" +"argument is given, the default buffering policy works as follows:\n" "\n" "* Binary files are buffered in fixed-size chunks; the size of the buffer\n" -" is max(min(blocksize, 8 MiB), DEFAULT_BUFFER_SIZE)\n" -" when the device block size is available.\n" -" On most systems, the buffer will typically be 128 kilobytes long.\n" +" is max(min(blocksize, 8 MiB), DEFAULT_BUFFER_SIZE) when the device\n" +" block size is available.\n" +" On most systems, the buffer will typically be 128 kilobytes long.\n" "\n" "* \"Interactive\" text files (files for which isatty() returns True)\n" " use line buffering. Other text files use the policy described above\n" " for binary files.\n" "\n" "encoding is the name of the encoding used to decode or encode the\n" -"file. This should only be used in text mode. The default encoding is\n" +"file. This should only be used in text mode. The default encoding is\n" "platform dependent, but any encoding supported by Python can be\n" "passed. See the codecs module for the list of supported encodings.\n" "\n" "errors is an optional string that specifies how encoding errors are to\n" -"be handled---this argument should not be used in binary mode. Pass\n" +"be handled---this argument should not be used in binary mode. Pass\n" "\'strict\' to raise a ValueError exception if there is an encoding error\n" "(the default of None has the same effect), or pass \'ignore\' to ignore\n" -"errors. (Note that ignoring encoding errors can lead to data loss.)\n" +"errors. (Note that ignoring encoding errors can lead to data loss.)\n" "See the documentation for codecs.register or run \'help(codecs.Codec)\'\n" "for a list of the permitted encoding error strings.\n" "\n" "newline controls how universal newlines works (it only applies to text\n" -"mode). It can be None, \'\', \'\\n\', \'\\r\', and \'\\r\\n\'. It works as\n" +"mode). It can be None, \'\', \'\\n\', \'\\r\', and \'\\r\\n\'. It works as\n" "follows:\n" "\n" -"* On input, if newline is None, universal newlines mode is\n" -" enabled. Lines in the input can end in \'\\n\', \'\\r\', or \'\\r\\n\', and\n" -" these are translated into \'\\n\' before being returned to the\n" -" caller. If it is \'\', universal newline mode is enabled, but line\n" -" endings are returned to the caller untranslated. If it has any of\n" -" the other legal values, input lines are only terminated by the given\n" -" string, and the line ending is returned to the caller untranslated.\n" +"* On input, if newline is None, universal newlines mode is enabled.\n" +" Lines in the input can end in \'\\n\', \'\\r\', or \'\\r\\n\', and these are\n" +" translated into \'\\n\' before being returned to the caller. If it is\n" +" \'\', universal newline mode is enabled, but line endings are returned\n" +" to the caller untranslated. If it has any of the other legal values,\n" +" input lines are only terminated by the given string, and the line\n" +" ending is returned to the caller untranslated.\n" "\n" "* On output, if newline is None, any \'\\n\' characters written are\n" -" translated to the system default line separator, os.linesep. If\n" -" newline is \'\' or \'\\n\', no translation takes place. If newline is any\n" +" translated to the system default line separator, os.linesep. If\n" +" newline is \'\' or \'\\n\', no translation takes place. If newline is any\n" " of the other legal values, any \'\\n\' characters written are translated\n" " to the given string.\n" "\n" "If closefd is False, the underlying file descriptor will be kept open\n" -"when the file is closed. This does not work when a file name is given\n" +"when the file is closed. This does not work when a file name is given\n" "and must be True in that case.\n" "\n" -"A custom opener can be used by passing a callable as *opener*. The\n" +"A custom opener can be used by passing a callable as *opener*. The\n" "underlying file descriptor for the file object is then obtained by\n" -"calling *opener* with (*file*, *flags*). *opener* must return an open\n" +"calling *opener* with (*file*, *flags*). *opener* must return an open\n" "file descriptor (passing os.open as *opener* results in functionality\n" "similar to passing None).\n" "\n" "open() returns a file object whose type depends on the mode, and\n" "through which the standard file operations such as reading and writing\n" -"are performed. When open() is used to open a file in a text mode (\'w\',\n" -"\'r\', \'wt\', \'rt\', etc.), it returns a TextIOWrapper. When used to open\n" +"are performed. When open() is used to open a file in a text mode (\'w\',\n" +"\'r\', \'wt\', \'rt\', etc.), it returns a TextIOWrapper. When used to open\n" "a file in a binary mode, the returned class varies: in read binary\n" "mode, it returns a BufferedReader; in write binary and append binary\n" "modes, it returns a BufferedWriter, and in read/write mode, it returns\n" "a BufferedRandom.\n" "\n" "It is also possible to use a string or bytearray as a file for both\n" -"reading and writing. For strings StringIO can be used like a file\n" +"reading and writing. For strings StringIO can be used like a file\n" "opened in a text mode, and for bytes a BytesIO can be used like a file\n" "opened in a binary mode."); @@ -352,8 +353,8 @@ PyDoc_STRVAR(_io_open_code__doc__, "\n" "Opens the provided file with the intent to import the contents.\n" "\n" -"This may perform extra validation beyond open(), but is otherwise interchangeable\n" -"with calling open(path, \'rb\')."); +"This may perform extra validation beyond open(), but is otherwise\n" +"interchangeable with calling open(path, \'rb\')."); #define _IO_OPEN_CODE_METHODDEF \ {"open_code", _PyCFunction_CAST(_io_open_code), METH_FASTCALL|METH_KEYWORDS, _io_open_code__doc__}, @@ -410,4 +411,4 @@ _io_open_code(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObjec exit: return return_value; } -/*[clinic end generated code: output=7a8e032c0424bce2 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=5190d11f0803bfe8 input=a9049054013a1b77]*/ diff --git a/Modules/_io/clinic/bytesio.c.h b/Modules/_io/clinic/bytesio.c.h index 6595dc937bbcf0..fad11ea6c9f6cf 100644 --- a/Modules/_io/clinic/bytesio.c.h +++ b/Modules/_io/clinic/bytesio.c.h @@ -254,8 +254,8 @@ PyDoc_STRVAR(_io_BytesIO_read1__doc__, "\n" "Read at most size bytes, returned as a bytes object.\n" "\n" -"If the size argument is negative or omitted, read until EOF is reached.\n" -"Return an empty bytes object at EOF."); +"If the size argument is negative or omitted, read until EOF is\n" +"reached. Return an empty bytes object at EOF."); #define _IO_BYTESIO_READ1_METHODDEF \ {"read1", _PyCFunction_CAST(_io_BytesIO_read1), METH_FASTCALL, _io_BytesIO_read1__doc__}, @@ -529,8 +529,8 @@ PyDoc_STRVAR(_io_BytesIO_writelines__doc__, "Write lines to the file.\n" "\n" "Note that newlines are not added. lines can be any iterable object\n" -"producing bytes-like objects. This is equivalent to calling write() for\n" -"each element."); +"producing bytes-like objects. This is equivalent to calling write()\n" +"for each element."); #define _IO_BYTESIO_WRITELINES_METHODDEF \ {"writelines", (PyCFunction)_io_BytesIO_writelines, METH_O, _io_BytesIO_writelines__doc__}, @@ -637,4 +637,4 @@ _io_BytesIO___init__(PyObject *self, PyObject *args, PyObject *kwargs) exit: return return_value; } -/*[clinic end generated code: output=daa81dfdae5ccc57 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=eac3911e207aaf45 input=a9049054013a1b77]*/ diff --git a/Modules/_io/clinic/fileio.c.h b/Modules/_io/clinic/fileio.c.h index 96c31ce8d6f415..890b6bc3fac9d5 100644 --- a/Modules/_io/clinic/fileio.c.h +++ b/Modules/_io/clinic/fileio.c.h @@ -15,8 +15,8 @@ PyDoc_STRVAR(_io_FileIO_close__doc__, "\n" "Close the file.\n" "\n" -"A closed file cannot be used for further I/O operations. close() may be\n" -"called more than once without error."); +"A closed file cannot be used for further I/O operations. close()\n" +"may be called more than once without error."); #define _IO_FILEIO_CLOSE_METHODDEF \ {"close", _PyCFunction_CAST(_io_FileIO_close), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _io_FileIO_close__doc__}, @@ -41,16 +41,19 @@ PyDoc_STRVAR(_io_FileIO___init____doc__, "Open a file.\n" "\n" "The mode can be \'r\' (default), \'w\', \'x\' or \'a\' for reading,\n" -"writing, exclusive creation or appending. The file will be created if it\n" -"doesn\'t exist when opened for writing or appending; it will be truncated\n" -"when opened for writing. A FileExistsError will be raised if it already\n" -"exists when opened for creating. Opening a file for creating implies\n" -"writing so this mode behaves in a similar way to \'w\'.Add a \'+\' to the mode\n" -"to allow simultaneous reading and writing. A custom opener can be used by\n" -"passing a callable as *opener*. The underlying file descriptor for the file\n" -"object is then obtained by calling opener with (*name*, *flags*).\n" -"*opener* must return an open file descriptor (passing os.open as *opener*\n" -"results in functionality similar to passing None)."); +"writing, exclusive creation or appending. The file will be created\n" +"if it doesn\'t exist when opened for writing or appending; it will be\n" +"truncated when opened for writing. A FileExistsError will be raised\n" +"if it already exists when opened for creating. Opening a file for\n" +"creating implies writing so this mode behaves in a similar way to\n" +"\'w\'. Add a \'+\' to the mode to allow simultaneous reading and\n" +"writing.\n" +"\n" +"A custom opener can be used by passing a callable as *opener*.\n" +"The underlying file descriptor for the file object is then obtained\n" +"by calling opener with (*name*, *flags*). *opener* must return\n" +"an open file descriptor (passing os.open as *opener* results in\n" +"functionality similar to passing None)."); static int _io_FileIO___init___impl(fileio *self, PyObject *nameobj, const char *mode, @@ -270,11 +273,13 @@ PyDoc_STRVAR(_io_FileIO_readall__doc__, "\n" "Read all data from the file, returned as bytes.\n" "\n" -"Reads until either there is an error or read() returns size 0 (indicates EOF).\n" -"If the file is already at EOF, returns an empty bytes object.\n" +"Reads until either there is an error or read() returns size 0\n" +"(indicates EOF). If the file is already at EOF, returns an empty\n" +"bytes object.\n" "\n" -"In non-blocking mode, returns as much data as could be read before EAGAIN. If no\n" -"data is available (EAGAIN is returned before bytes are read) returns None."); +"In non-blocking mode, returns as much data as could be read before\n" +"EAGAIN. If no data is available (EAGAIN is returned before bytes\n" +"are read) returns None."); #define _IO_FILEIO_READALL_METHODDEF \ {"readall", _PyCFunction_CAST(_io_FileIO_readall), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _io_FileIO_readall__doc__}, @@ -298,14 +303,14 @@ PyDoc_STRVAR(_io_FileIO_read__doc__, "\n" "Read at most size bytes, returned as bytes.\n" "\n" -"If size is less than 0, read all bytes in the file making multiple read calls.\n" -"See ``FileIO.readall``.\n" +"If size is less than 0, read all bytes in the file making multiple\n" +"read calls. See ``FileIO.readall``.\n" "\n" -"Attempts to make only one system call, retrying only per PEP 475 (EINTR). This\n" -"means less data may be returned than requested.\n" +"Attempts to make only one system call, retrying only per PEP 475\n" +"(EINTR). This means less data may be returned than requested.\n" "\n" -"In non-blocking mode, returns None if no data is available. Return an empty\n" -"bytes object at EOF."); +"In non-blocking mode, returns None if no data is available. Return\n" +"an empty bytes object at EOF."); #define _IO_FILEIO_READ_METHODDEF \ {"read", _PyCFunction_CAST(_io_FileIO_read), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _io_FileIO_read__doc__}, @@ -358,8 +363,8 @@ PyDoc_STRVAR(_io_FileIO_write__doc__, "Write buffer b to file, return number of bytes written.\n" "\n" "Only makes one system call, so not all of the data may be written.\n" -"The number of bytes actually written is returned. In non-blocking mode,\n" -"returns None if the write would block."); +"The number of bytes actually written is returned. In non-blocking\n" +"mode, returns None if the write would block."); #define _IO_FILEIO_WRITE_METHODDEF \ {"write", _PyCFunction_CAST(_io_FileIO_write), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _io_FileIO_write__doc__}, @@ -412,11 +417,12 @@ PyDoc_STRVAR(_io_FileIO_seek__doc__, "\n" "Move to new file position and return the file position.\n" "\n" -"Argument offset is a byte count. Optional argument whence defaults to\n" -"SEEK_SET or 0 (offset from start of file, offset should be >= 0); other values\n" -"are SEEK_CUR or 1 (move relative to current position, positive or negative),\n" -"and SEEK_END or 2 (move relative to end of file, usually negative, although\n" -"many platforms allow seeking beyond the end of a file).\n" +"Argument offset is a byte count. Optional argument whence defaults\n" +"to SEEK_SET or 0 (offset from start of file, offset should be >= 0);\n" +"other values are SEEK_CUR or 1 (move relative to current position,\n" +"positive or negative), and SEEK_END or 2 (move relative to end of\n" +"file, usually negative, although many platforms allow seeking beyond\n" +"the end of a file).\n" "\n" "Note that not all file objects are seekable."); @@ -547,4 +553,4 @@ _io_FileIO_isatty(PyObject *self, PyObject *Py_UNUSED(ignored)) #ifndef _IO_FILEIO_TRUNCATE_METHODDEF #define _IO_FILEIO_TRUNCATE_METHODDEF #endif /* !defined(_IO_FILEIO_TRUNCATE_METHODDEF) */ -/*[clinic end generated code: output=2e48f3df2f189170 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=453d584e2e72f986 input=a9049054013a1b77]*/ diff --git a/Modules/_io/clinic/iobase.c.h b/Modules/_io/clinic/iobase.c.h index 402448545dfc51..e4438c26431aa8 100644 --- a/Modules/_io/clinic/iobase.c.h +++ b/Modules/_io/clinic/iobase.c.h @@ -19,11 +19,13 @@ PyDoc_STRVAR(_io__IOBase_seek__doc__, " whence\n" " The relative position to seek from.\n" "\n" -"The offset is interpreted relative to the position indicated by whence.\n" -"Values for whence are:\n" +"The offset is interpreted relative to the position indicated by\n" +"whence. Values for whence are:\n" "\n" -"* os.SEEK_SET or 0 -- start of stream (the default); offset should be zero or positive\n" -"* os.SEEK_CUR or 1 -- current stream position; offset may be negative\n" +"* os.SEEK_SET or 0 -- start of stream (the default); offset should\n" +" be zero or positive\n" +"* os.SEEK_CUR or 1 -- current stream position; offset may be\n" +" negative\n" "* os.SEEK_END or 2 -- end of stream; offset is usually negative\n" "\n" "Return the new absolute position."); @@ -103,8 +105,8 @@ PyDoc_STRVAR(_io__IOBase_truncate__doc__, "\n" "Truncate file to size bytes.\n" "\n" -"File pointer is left unchanged. Size defaults to the current IO position\n" -"as reported by tell(). Return the new size."); +"File pointer is left unchanged. Size defaults to the current IO\n" +"position as reported by tell(). Return the new size."); #define _IO__IOBASE_TRUNCATE_METHODDEF \ {"truncate", _PyCFunction_CAST(_io__IOBase_truncate), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _io__IOBase_truncate__doc__}, @@ -443,4 +445,4 @@ _io__RawIOBase_readall(PyObject *self, PyObject *Py_UNUSED(ignored)) { return _io__RawIOBase_readall_impl(self); } -/*[clinic end generated code: output=9359e74d95534bef input=a9049054013a1b77]*/ +/*[clinic end generated code: output=28c06bb6db32c096 input=a9049054013a1b77]*/ diff --git a/Modules/_io/clinic/stringio.c.h b/Modules/_io/clinic/stringio.c.h index 83165e5f7ad08b..d6d4afb9b63c62 100644 --- a/Modules/_io/clinic/stringio.c.h +++ b/Modules/_io/clinic/stringio.c.h @@ -179,7 +179,8 @@ PyDoc_STRVAR(_io_StringIO_seek__doc__, "\n" "Change stream position.\n" "\n" -"Seek to character offset pos relative to position indicated by whence:\n" +"Seek to character offset pos relative to position indicated by\n" +"whence:\n" " 0 Start of stream (the default). pos should be >= 0;\n" " 1 Current position - pos must be 0;\n" " 2 End of stream - pos must be 0.\n" @@ -550,4 +551,4 @@ _io_StringIO_newlines_get(PyObject *self, void *Py_UNUSED(context)) return return_value; } -/*[clinic end generated code: output=bccc25ef8e6ce9ef input=a9049054013a1b77]*/ +/*[clinic end generated code: output=730c34b2a6c0500b input=a9049054013a1b77]*/ diff --git a/Modules/_io/clinic/textio.c.h b/Modules/_io/clinic/textio.c.h index 3898a9c2982436..9407076b850cee 100644 --- a/Modules/_io/clinic/textio.c.h +++ b/Modules/_io/clinic/textio.c.h @@ -16,7 +16,8 @@ PyDoc_STRVAR(_io__TextIOBase_detach__doc__, "\n" "Separate the underlying buffer from the TextIOBase and return it.\n" "\n" -"After the underlying buffer has been detached, the TextIO is in an unusable state."); +"After the underlying buffer has been detached, the TextIO is in\n" +"an unusable state."); #define _IO__TEXTIOBASE_DETACH_METHODDEF \ {"detach", _PyCFunction_CAST(_io__TextIOBase_detach), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _io__TextIOBase_detach__doc__}, @@ -40,8 +41,8 @@ PyDoc_STRVAR(_io__TextIOBase_read__doc__, "\n" "Read at most size characters from stream.\n" "\n" -"Read from underlying buffer until we have size characters or we hit EOF.\n" -"If size is negative or omitted, read until EOF."); +"Read from underlying buffer until we have size characters or we hit\n" +"EOF. If size is negative or omitted, read until EOF."); #define _IO__TEXTIOBASE_READ_METHODDEF \ {"read", _PyCFunction_CAST(_io__TextIOBase_read), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _io__TextIOBase_read__doc__}, @@ -964,8 +965,8 @@ PyDoc_STRVAR(_io_TextIOWrapper_tell__doc__, "\n" "Return the stream position as an opaque number.\n" "\n" -"The return value of tell() can be given as input to seek(), to restore a\n" -"previous stream position."); +"The return value of tell() can be given as input to seek(), to\n" +"restore a previous stream position."); #define _IO_TEXTIOWRAPPER_TELL_METHODDEF \ {"tell", (PyCFunction)_io_TextIOWrapper_tell, METH_NOARGS, _io_TextIOWrapper_tell__doc__}, @@ -1328,4 +1329,4 @@ _io_TextIOWrapper__CHUNK_SIZE_set(PyObject *self, PyObject *value, void *Py_UNUS return return_value; } -/*[clinic end generated code: output=c38e6cd5ff4b7eea input=a9049054013a1b77]*/ +/*[clinic end generated code: output=f900b42090c9781c input=a9049054013a1b77]*/ diff --git a/Modules/_io/clinic/winconsoleio.c.h b/Modules/_io/clinic/winconsoleio.c.h index 7af5923b6c1747..bd8073cd0af3f6 100644 --- a/Modules/_io/clinic/winconsoleio.c.h +++ b/Modules/_io/clinic/winconsoleio.c.h @@ -46,9 +46,9 @@ PyDoc_STRVAR(_io__WindowsConsoleIO___init____doc__, "\n" "Open a console buffer by file descriptor.\n" "\n" -"The mode can be \'rb\' (default), or \'wb\' for reading or writing bytes. All\n" -"other mode characters will be ignored. Mode \'b\' will be assumed if it is\n" -"omitted. The *opener* parameter is always ignored."); +"The mode can be \'rb\' (default), or \'wb\' for reading or writing\n" +"bytes. All other mode characters will be ignored. Mode \'b\' will be\n" +"assumed if it is omitted. The *opener* parameter is always ignored."); static int _io__WindowsConsoleIO___init___impl(winconsoleio *self, PyObject *nameobj, @@ -463,4 +463,4 @@ _io__WindowsConsoleIO_isatty(PyObject *self, PyObject *Py_UNUSED(ignored)) #ifndef _IO__WINDOWSCONSOLEIO_ISATTY_METHODDEF #define _IO__WINDOWSCONSOLEIO_ISATTY_METHODDEF #endif /* !defined(_IO__WINDOWSCONSOLEIO_ISATTY_METHODDEF) */ -/*[clinic end generated code: output=ce50bcd905f1f213 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=dfe49dd71f4f4b1d input=a9049054013a1b77]*/ diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c index 5d7741fdd830a5..3aeb30dfe24a35 100644 --- a/Modules/_io/fileio.c +++ b/Modules/_io/fileio.c @@ -153,13 +153,13 @@ _io.FileIO.close Close the file. -A closed file cannot be used for further I/O operations. close() may be -called more than once without error. +A closed file cannot be used for further I/O operations. close() +may be called more than once without error. [clinic start generated code]*/ static PyObject * _io_FileIO_close_impl(fileio *self, PyTypeObject *cls) -/*[clinic end generated code: output=c30cbe9d1f23ca58 input=70da49e63db7c64d]*/ +/*[clinic end generated code: output=c30cbe9d1f23ca58 input=b405751dc4163da3]*/ { PyObject *res; int rc; @@ -231,22 +231,25 @@ _io.FileIO.__init__ Open a file. The mode can be 'r' (default), 'w', 'x' or 'a' for reading, -writing, exclusive creation or appending. The file will be created if it -doesn't exist when opened for writing or appending; it will be truncated -when opened for writing. A FileExistsError will be raised if it already -exists when opened for creating. Opening a file for creating implies -writing so this mode behaves in a similar way to 'w'.Add a '+' to the mode -to allow simultaneous reading and writing. A custom opener can be used by -passing a callable as *opener*. The underlying file descriptor for the file -object is then obtained by calling opener with (*name*, *flags*). -*opener* must return an open file descriptor (passing os.open as *opener* -results in functionality similar to passing None). +writing, exclusive creation or appending. The file will be created +if it doesn't exist when opened for writing or appending; it will be +truncated when opened for writing. A FileExistsError will be raised +if it already exists when opened for creating. Opening a file for +creating implies writing so this mode behaves in a similar way to +'w'. Add a '+' to the mode to allow simultaneous reading and +writing. + +A custom opener can be used by passing a callable as *opener*. +The underlying file descriptor for the file object is then obtained +by calling opener with (*name*, *flags*). *opener* must return +an open file descriptor (passing os.open as *opener* results in +functionality similar to passing None). [clinic start generated code]*/ static int _io_FileIO___init___impl(fileio *self, PyObject *nameobj, const char *mode, int closefd, PyObject *opener) -/*[clinic end generated code: output=23413f68e6484bbd input=588aac967e0ba74b]*/ +/*[clinic end generated code: output=23413f68e6484bbd input=bac4efcd8f930bf3]*/ { #ifdef MS_WINDOWS wchar_t *widename = NULL; @@ -725,7 +728,6 @@ new_buffersize(fileio *self, size_t currentsize) } /*[clinic input] -@permit_long_docstring_body _io.FileIO.readall cls: defining_class @@ -733,16 +735,18 @@ _io.FileIO.readall Read all data from the file, returned as bytes. -Reads until either there is an error or read() returns size 0 (indicates EOF). -If the file is already at EOF, returns an empty bytes object. +Reads until either there is an error or read() returns size 0 +(indicates EOF). If the file is already at EOF, returns an empty +bytes object. -In non-blocking mode, returns as much data as could be read before EAGAIN. If no -data is available (EAGAIN is returned before bytes are read) returns None. +In non-blocking mode, returns as much data as could be read before +EAGAIN. If no data is available (EAGAIN is returned before bytes +are read) returns None. [clinic start generated code]*/ static PyObject * _io_FileIO_readall_impl(fileio *self, PyTypeObject *cls) -/*[clinic end generated code: output=d546737ec895c462 input=cecda40bf9961299]*/ +/*[clinic end generated code: output=d546737ec895c462 input=65d05bd0169f2df5]*/ { Py_off_t pos, end; PyBytesWriter *writer; @@ -850,7 +854,6 @@ _io_FileIO_readall_impl(fileio *self, PyTypeObject *cls) } /*[clinic input] -@permit_long_docstring_body _io.FileIO.read cls: defining_class size: Py_ssize_t(accept={int, NoneType}) = -1 @@ -858,19 +861,19 @@ _io.FileIO.read Read at most size bytes, returned as bytes. -If size is less than 0, read all bytes in the file making multiple read calls. -See ``FileIO.readall``. +If size is less than 0, read all bytes in the file making multiple +read calls. See ``FileIO.readall``. -Attempts to make only one system call, retrying only per PEP 475 (EINTR). This -means less data may be returned than requested. +Attempts to make only one system call, retrying only per PEP 475 +(EINTR). This means less data may be returned than requested. -In non-blocking mode, returns None if no data is available. Return an empty -bytes object at EOF. +In non-blocking mode, returns None if no data is available. Return +an empty bytes object at EOF. [clinic start generated code]*/ static PyObject * _io_FileIO_read_impl(fileio *self, PyTypeObject *cls, Py_ssize_t size) -/*[clinic end generated code: output=bbd749c7c224143e input=752d1ad3db8564a5]*/ +/*[clinic end generated code: output=bbd749c7c224143e input=c7baa3b440af9337]*/ { if (self->fd < 0) return err_closed(); @@ -916,13 +919,13 @@ _io.FileIO.write Write buffer b to file, return number of bytes written. Only makes one system call, so not all of the data may be written. -The number of bytes actually written is returned. In non-blocking mode, -returns None if the write would block. +The number of bytes actually written is returned. In non-blocking +mode, returns None if the write would block. [clinic start generated code]*/ static PyObject * _io_FileIO_write_impl(fileio *self, PyTypeObject *cls, Py_buffer *b) -/*[clinic end generated code: output=927e25be80f3b77b input=2776314f043088f5]*/ +/*[clinic end generated code: output=927e25be80f3b77b input=233f1f70f9e8b09e]*/ { Py_ssize_t n; int err; @@ -1016,7 +1019,6 @@ portable_lseek(fileio *self, PyObject *posobj, int whence, bool suppress_pipe_er } /*[clinic input] -@permit_long_docstring_body _io.FileIO.seek pos: object whence: int = 0 @@ -1024,18 +1026,19 @@ _io.FileIO.seek Move to new file position and return the file position. -Argument offset is a byte count. Optional argument whence defaults to -SEEK_SET or 0 (offset from start of file, offset should be >= 0); other values -are SEEK_CUR or 1 (move relative to current position, positive or negative), -and SEEK_END or 2 (move relative to end of file, usually negative, although -many platforms allow seeking beyond the end of a file). +Argument offset is a byte count. Optional argument whence defaults +to SEEK_SET or 0 (offset from start of file, offset should be >= 0); +other values are SEEK_CUR or 1 (move relative to current position, +positive or negative), and SEEK_END or 2 (move relative to end of +file, usually negative, although many platforms allow seeking beyond +the end of a file). Note that not all file objects are seekable. [clinic start generated code]*/ static PyObject * _io_FileIO_seek_impl(fileio *self, PyObject *pos, int whence) -/*[clinic end generated code: output=c976acdf054e6655 input=f077c492a84c9e62]*/ +/*[clinic end generated code: output=c976acdf054e6655 input=f165a1b4f5d494ad]*/ { if (self->fd < 0) return err_closed(); @@ -1063,6 +1066,7 @@ _io_FileIO_tell_impl(fileio *self) #ifdef HAVE_FTRUNCATE /*[clinic input] +@permit_long_summary _io.FileIO.truncate cls: defining_class size as posobj: object = None @@ -1076,7 +1080,7 @@ The current file position is changed to the value of size. static PyObject * _io_FileIO_truncate_impl(fileio *self, PyTypeObject *cls, PyObject *posobj) -/*[clinic end generated code: output=d936732a49e8d5a2 input=c367fb45d6bb2c18]*/ +/*[clinic end generated code: output=d936732a49e8d5a2 input=8f22152bcf900ed2]*/ { Py_off_t pos; int ret; diff --git a/Modules/_io/iobase.c b/Modules/_io/iobase.c index f036ea503b11e8..1253f124108bdb 100644 --- a/Modules/_io/iobase.c +++ b/Modules/_io/iobase.c @@ -93,7 +93,6 @@ iobase_unsupported(_PyIO_State *state, const char *message) /* Positioning */ /*[clinic input] -@permit_long_docstring_body _io._IOBase.seek cls: defining_class offset: int(unused=True) @@ -104,11 +103,13 @@ _io._IOBase.seek Change the stream position to the given byte offset. -The offset is interpreted relative to the position indicated by whence. -Values for whence are: +The offset is interpreted relative to the position indicated by +whence. Values for whence are: -* os.SEEK_SET or 0 -- start of stream (the default); offset should be zero or positive -* os.SEEK_CUR or 1 -- current stream position; offset may be negative +* os.SEEK_SET or 0 -- start of stream (the default); offset should + be zero or positive +* os.SEEK_CUR or 1 -- current stream position; offset may be + negative * os.SEEK_END or 2 -- end of stream; offset is usually negative Return the new absolute position. @@ -117,7 +118,7 @@ Return the new absolute position. static PyObject * _io__IOBase_seek_impl(PyObject *self, PyTypeObject *cls, int Py_UNUSED(offset), int Py_UNUSED(whence)) -/*[clinic end generated code: output=8bd74ea6538ded53 input=a21b5aad416ff6a9]*/ +/*[clinic end generated code: output=8bd74ea6538ded53 input=22eaf07a7a0ee289]*/ { _PyIO_State *state = get_io_state_by_cls(cls); return iobase_unsupported(state, "seek"); @@ -144,14 +145,14 @@ _io._IOBase.truncate Truncate file to size bytes. -File pointer is left unchanged. Size defaults to the current IO position -as reported by tell(). Return the new size. +File pointer is left unchanged. Size defaults to the current IO +position as reported by tell(). Return the new size. [clinic start generated code]*/ static PyObject * _io__IOBase_truncate_impl(PyObject *self, PyTypeObject *cls, PyObject *Py_UNUSED(size)) -/*[clinic end generated code: output=2013179bff1fe8ef input=660ac20936612c27]*/ +/*[clinic end generated code: output=2013179bff1fe8ef input=5b3b6ab3c7abd806]*/ { _PyIO_State *state = get_io_state_by_cls(cls); return iobase_unsupported(state, "truncate"); diff --git a/Modules/_io/stringio.c b/Modules/_io/stringio.c index 5debae5b42480b..0d9196f3647dde 100644 --- a/Modules/_io/stringio.c +++ b/Modules/_io/stringio.c @@ -497,7 +497,8 @@ _io.StringIO.seek Change stream position. -Seek to character offset pos relative to position indicated by whence: +Seek to character offset pos relative to position indicated by +whence: 0 Start of stream (the default). pos should be >= 0; 1 Current position - pos must be 0; 2 End of stream - pos must be 0. @@ -506,7 +507,7 @@ Returns the new absolute position. static PyObject * _io_StringIO_seek_impl(stringio *self, Py_ssize_t pos, int whence) -/*[clinic end generated code: output=e9e0ac9a8ae71c25 input=c75ced09343a00d7]*/ +/*[clinic end generated code: output=e9e0ac9a8ae71c25 input=ffef24668fd71a5d]*/ { CHECK_INITIALIZED(self); CHECK_CLOSED(self); diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c index 347bfe976619e8..e80b75066c59a6 100644 --- a/Modules/_io/textio.c +++ b/Modules/_io/textio.c @@ -53,19 +53,19 @@ _unsupported(_PyIO_State *state, const char *message) } /*[clinic input] -@permit_long_docstring_body _io._TextIOBase.detach cls: defining_class / Separate the underlying buffer from the TextIOBase and return it. -After the underlying buffer has been detached, the TextIO is in an unusable state. +After the underlying buffer has been detached, the TextIO is in +an unusable state. [clinic start generated code]*/ static PyObject * _io__TextIOBase_detach_impl(PyObject *self, PyTypeObject *cls) -/*[clinic end generated code: output=50915f40c609eaa4 input=8cd0652c17d7f015]*/ +/*[clinic end generated code: output=50915f40c609eaa4 input=8099c088abcb87d8]*/ { _PyIO_State *state = get_io_state_by_cls(cls); return _unsupported(state, "detach"); @@ -79,14 +79,14 @@ _io._TextIOBase.read Read at most size characters from stream. -Read from underlying buffer until we have size characters or we hit EOF. -If size is negative or omitted, read until EOF. +Read from underlying buffer until we have size characters or we hit +EOF. If size is negative or omitted, read until EOF. [clinic start generated code]*/ static PyObject * _io__TextIOBase_read_impl(PyObject *self, PyTypeObject *cls, int Py_UNUSED(size)) -/*[clinic end generated code: output=51a5178a309ce647 input=f5e37720f9fc563f]*/ +/*[clinic end generated code: output=51a5178a309ce647 input=c9fd4cc1cf1b4614]*/ { _PyIO_State *state = get_io_state_by_cls(cls); return _unsupported(state, "read"); @@ -2727,13 +2727,13 @@ _io.TextIOWrapper.tell Return the stream position as an opaque number. -The return value of tell() can be given as input to seek(), to restore a -previous stream position. +The return value of tell() can be given as input to seek(), to +restore a previous stream position. [clinic start generated code]*/ static PyObject * _io_TextIOWrapper_tell_impl(textio *self) -/*[clinic end generated code: output=4f168c08bf34ad5f input=415d6b4e4f8e6e8c]*/ +/*[clinic end generated code: output=4f168c08bf34ad5f input=aeece020f747fd92]*/ { PyObject *res; PyObject *posobj = NULL; diff --git a/Modules/_io/winconsoleio.c b/Modules/_io/winconsoleio.c index 4a3fc586fa3a14..4cd71094e8f459 100644 --- a/Modules/_io/winconsoleio.c +++ b/Modules/_io/winconsoleio.c @@ -315,16 +315,16 @@ _io._WindowsConsoleIO.__init__ Open a console buffer by file descriptor. -The mode can be 'rb' (default), or 'wb' for reading or writing bytes. All -other mode characters will be ignored. Mode 'b' will be assumed if it is -omitted. The *opener* parameter is always ignored. +The mode can be 'rb' (default), or 'wb' for reading or writing +bytes. All other mode characters will be ignored. Mode 'b' will be +assumed if it is omitted. The *opener* parameter is always ignored. [clinic start generated code]*/ static int _io__WindowsConsoleIO___init___impl(winconsoleio *self, PyObject *nameobj, const char *mode, int closefd, PyObject *opener) -/*[clinic end generated code: output=3fd9cbcdd8d95429 input=7a3eed6bbe998fd9]*/ +/*[clinic end generated code: output=3fd9cbcdd8d95429 input=f31100e2cd724617]*/ { const char *s; wchar_t *name = NULL; From e8f534d1af4ff925d7f1d90c63f2faf34198d597 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 24 May 2026 15:24:08 +0200 Subject: [PATCH 128/818] [3.15] gh-150285: Fix too long docstrings in the decimal module (GH-150288) (GH-150333) (cherry picked from commit 6bed57a3b659a34c4a7d75e76f4fe840f762bf7f) Co-authored-by: Serhiy Storchaka --- Lib/_pydecimal.py | 107 ++++++++-------- Modules/_decimal/_decimal.c | 175 ++++++++++++++------------- Modules/_decimal/clinic/_decimal.c.h | 122 ++++++++++--------- 3 files changed, 213 insertions(+), 191 deletions(-) diff --git a/Lib/_pydecimal.py b/Lib/_pydecimal.py index ef889ea0cc834c..8c0afd14d616e8 100644 --- a/Lib/_pydecimal.py +++ b/Lib/_pydecimal.py @@ -107,8 +107,8 @@ class DecimalException(ArithmeticError): anything, though. handle -- Called when context._raise_error is called and the - trap_enabler is not set. First argument is self, second is the - context. More arguments can be given, those being after + trap_enabler is not set. First argument is self, second is + the context. More arguments can be given, those being after the explanation in _raise_error (For example, context._raise_error(NewError, '(-x)!', self._sign) would call NewError().handle(context, self._sign).) @@ -225,11 +225,12 @@ class InvalidContext(InvalidOperation): """Invalid context. Unknown rounding, for example. This occurs and signals invalid-operation if an invalid context was - detected during an operation. This can occur if contexts are not checked - on creation and either the precision exceeds the capability of the - underlying concrete representation or an unknown or unsupported rounding - was specified. These aspects of the context need only be checked when - the values are required to be used. The result is [0,qNaN]. + detected during an operation. This can occur if contexts are not + checked on creation and either the precision exceeds the capability of + the underlying concrete representation or an unknown or unsupported + rounding was specified. These aspects of the context need only be + checked when the values are required to be used. The result is + [0,qNaN]. """ def handle(self, context, *args): @@ -322,8 +323,9 @@ class FloatOperation(DecimalException, TypeError): Decimal.from_float() or context.create_decimal_from_float() do not set the flag. - Otherwise (the signal is trapped), only equality comparisons and explicit - conversions are silent. All other mixed operations raise FloatOperation. + Otherwise (the signal is trapped), only equality comparisons and + explicit conversions are silent. All other mixed operations raise + FloatOperation. """ # List of public traps and flags @@ -2901,8 +2903,8 @@ def compare_total(self, other, context=None): """Compares self to other using the abstract representations. This is not like the standard compare, which use their numerical - value. Note that a total ordering is defined for all possible abstract - representations. + value. Note that a total ordering is defined for all possible + abstract representations. """ other = _convert_other(other, raiseit=True) @@ -2973,7 +2975,8 @@ def compare_total(self, other, context=None): def compare_total_mag(self, other, context=None): """Compares self to other using abstract repr., ignoring sign. - Like compare_total, but with operand's sign ignored and assumed to be 0. + Like compare_total, but with operand's sign ignored and assumed to + be 0. """ other = _convert_other(other, raiseit=True) @@ -4110,9 +4113,9 @@ def create_decimal_from_float(self, f): def abs(self, a): """Returns the absolute value of the operand. - If the operand is negative, the result is the same as using the minus - operation on the operand. Otherwise, the result is the same as using - the plus operation on the operand. + If the operand is negative, the result is the same as using the + minus operation on the operand. Otherwise, the result is the same + as using the plus operation on the operand. >>> ExtendedContext.abs(Decimal('2.1')) Decimal('2.1') @@ -4168,16 +4171,17 @@ def canonical(self, a): def compare(self, a, b): """Compares values numerically. - If the signs of the operands differ, a value representing each operand - ('-1' if the operand is less than zero, '0' if the operand is zero or - negative zero, or '1' if the operand is greater than zero) is used in - place of that operand for the comparison instead of the actual - operand. + If the signs of the operands differ, a value representing each + operand ('-1' if the operand is less than zero, '0' if the operand + is zero or negative zero, or '1' if the operand is greater than + zero) is used in place of that operand for the comparison instead of + the actual operand. - The comparison is then effected by subtracting the second operand from - the first and then returning a value according to the result of the - subtraction: '-1' if the result is less than zero, '0' if the result is - zero or negative zero, or '1' if the result is greater than zero. + The comparison is then effected by subtracting the second operand + from the first and then returning a value according to the result of + the subtraction: '-1' if the result is less than zero, '0' if the + result is zero or negative zero, or '1' if the result is greater + than zero. >>> ExtendedContext.compare(Decimal('2.1'), Decimal('3')) Decimal('-1') @@ -4240,8 +4244,8 @@ def compare_total(self, a, b): """Compares two operands using their abstract representation. This is not like the standard compare, which use their numerical - value. Note that a total ordering is defined for all possible abstract - representations. + value. Note that a total ordering is defined for all possible + abstract representations. >>> ExtendedContext.compare_total(Decimal('12.73'), Decimal('127.9')) Decimal('-1') @@ -4268,7 +4272,8 @@ def compare_total(self, a, b): def compare_total_mag(self, a, b): """Compares two operands using their abstract representation ignoring sign. - Like compare_total, but with operand's sign ignored and assumed to be 0. + Like compare_total, but with operand's sign ignored and assumed to + be 0. """ a = _convert_other(a, raiseit=True) return a.compare_total_mag(b) @@ -4926,8 +4931,8 @@ def multiply(self, a, b): If either operand is a special value then the general rules apply. Otherwise, the operands are multiplied together - ('long multiplication'), resulting in a number which may be as long as - the sum of the lengths of the two operands. + ('long multiplication'), resulting in a number which may be as long + as the sum of the lengths of the two operands. >>> ExtendedContext.multiply(Decimal('1.20'), Decimal('3')) Decimal('3.60') @@ -5203,19 +5208,19 @@ def quantize(self, a, b): """Returns a value equal to 'a' (rounded), having the exponent of 'b'. The coefficient of the result is derived from that of the left-hand - operand. It may be rounded using the current rounding setting (if the - exponent is being increased), multiplied by a positive power of ten (if - the exponent is being decreased), or is unchanged (if the exponent is - already equal to that of the right-hand operand). + operand. It may be rounded using the current rounding setting (if + the exponent is being increased), multiplied by a positive power of + ten (if the exponent is being decreased), or is unchanged (if the + exponent is already equal to that of the right-hand operand). Unlike other operations, if the length of the coefficient after the quantize operation would be greater than precision then an Invalid - operation condition is raised. This guarantees that, unless there is - an error condition, the exponent of the result of a quantize is always - equal to that of the right-hand operand. + operation condition is raised. This guarantees that, unless there + is an error condition, the exponent of the result of a quantize is + always equal to that of the right-hand operand. - Also unlike other operations, quantize will never raise Underflow, even - if the result is subnormal and inexact. + Also unlike other operations, quantize will never raise Underflow, + even if the result is subnormal and inexact. >>> ExtendedContext.quantize(Decimal('2.17'), Decimal('0.001')) Decimal('2.170') @@ -5269,13 +5274,13 @@ def remainder(self, a, b): """Returns the remainder from integer division. The result is the residue of the dividend after the operation of - calculating integer division as described for divide-integer, rounded - to precision digits if necessary. The sign of the result, if - non-zero, is the same as that of the original dividend. + calculating integer division as described for divide-integer, + rounded to precision digits if necessary. The sign of the result, + if non-zero, is the same as that of the original dividend. - This operation will fail under the same conditions as integer division - (that is, if integer division on the same two operands would fail, the - remainder cannot be calculated). + This operation will fail under the same conditions as integer + division (that is, if integer division on the same two operands + would fail, the remainder cannot be calculated). >>> ExtendedContext.remainder(Decimal('2.1'), Decimal('3')) Decimal('2.1') @@ -5309,9 +5314,9 @@ def remainder_near(self, a, b): is chosen). If the result is equal to 0 then its sign will be the sign of a. - This operation will fail under the same conditions as integer division - (that is, if integer division on the same two operands would fail, the - remainder cannot be calculated). + This operation will fail under the same conditions as integer + division (that is, if integer division on the same two operands + would fail, the remainder cannot be calculated). >>> ExtendedContext.remainder_near(Decimal('2.1'), Decimal('3')) Decimal('-0.9') @@ -5369,8 +5374,8 @@ def rotate(self, a, b): def same_quantum(self, a, b): """Returns True if the two operands have the same exponent. - The result is never affected by either the sign or the coefficient of - either operand. + The result is never affected by either the sign or the coefficient + of either operand. >>> ExtendedContext.same_quantum(Decimal('2.17'), Decimal('0.001')) False @@ -5442,8 +5447,8 @@ def shift(self, a, b): def sqrt(self, a): """Square root of a non-negative number to context precision. - If the result must be inexact, it is rounded using the round-half-even - algorithm. + If the result must be inexact, it is rounded using the + round-half-even algorithm. >>> ExtendedContext.sqrt(Decimal('0')) Decimal('0') diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index 0a8308d9ebce7a..2760792a3fe18e 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -939,13 +939,13 @@ _decimal.Context.Etop Return a value equal to Emax - prec + 1. -This is the maximum exponent if the _clamp field of the context is set -to 1 (IEEE clamp mode). Etop() must not be negative. +This is the maximum exponent if the _clamp field of the context is +set to 1 (IEEE clamp mode). Etop() must not be negative. [clinic start generated code]*/ static PyObject * _decimal_Context_Etop_impl(PyObject *self) -/*[clinic end generated code: output=f0a3f6e1b829074e input=838a4409316ec728]*/ +/*[clinic end generated code: output=f0a3f6e1b829074e input=35b9defc69d5e5d1]*/ { return PyLong_FromSsize_t(mpd_etop(CTX(self))); } @@ -2997,6 +2997,7 @@ PyDecType_FromSequenceExact(PyTypeObject *type, PyObject *v, PyDecType_FromSequenceExact((st)->PyDec_Type, sequence, context) /*[clinic input] +@permit_long_docstring_body @classmethod _decimal.Decimal.from_float @@ -3022,7 +3023,7 @@ Decimal.from_float(0.1) is not the same as Decimal('0.1'). static PyObject * _decimal_Decimal_from_float_impl(PyTypeObject *type, PyTypeObject *cls, PyObject *pyfloat) -/*[clinic end generated code: output=fcb7d55d2f9dc790 input=03bc8dbe963e52ca]*/ +/*[clinic end generated code: output=fcb7d55d2f9dc790 input=29abf05dd8fe79e4]*/ { PyObject *context; PyObject *result; @@ -3068,6 +3069,8 @@ PyDecType_FromNumberExact(PyTypeObject *type, PyTypeObject *cls, } /*[clinic input] +@permit_long_summary +@permit_long_docstring_body @classmethod _decimal.Decimal.from_number @@ -3088,7 +3091,7 @@ Class method that converts a real number to a decimal number, exactly. static PyObject * _decimal_Decimal_from_number_impl(PyTypeObject *type, PyTypeObject *cls, PyObject *number) -/*[clinic end generated code: output=4d3ec722b7acfd8b input=271cb4feb3148804]*/ +/*[clinic end generated code: output=4d3ec722b7acfd8b input=34ff3696955d3def]*/ { PyObject *context; PyObject *result; @@ -3959,6 +3962,7 @@ dec_as_long(PyObject *dec, PyObject *context, int round) } /*[clinic input] +@permit_long_summary _decimal.Decimal.as_integer_ratio cls: defining_class @@ -3971,7 +3975,7 @@ Raise OverflowError on infinities and a ValueError on NaNs. static PyObject * _decimal_Decimal_as_integer_ratio_impl(PyObject *self, PyTypeObject *cls) -/*[clinic end generated code: output=eb49c512701f844b input=07e33d8852184761]*/ +/*[clinic end generated code: output=eb49c512701f844b input=136f1dc585ca8d80]*/ { PyObject *numerator = NULL; PyObject *denominator = NULL; @@ -4146,17 +4150,17 @@ _decimal.Decimal.to_integral_exact = _decimal.Decimal.to_integral_value Round to the nearest integer. -Decimal.to_integral_exact() signals Inexact or Rounded as appropriate -if rounding occurs. The rounding mode is determined by the rounding -parameter if given, else by the given context. If neither parameter is -given, then the rounding mode of the current default context is used. +This method signals Inexact or Rounded as appropriate if rounding +occurs. The rounding mode is determined by the rounding parameter +if given, else by the given context. If neither parameter is given, +then the rounding mode of the current default context is used. [clinic start generated code]*/ static PyObject * _decimal_Decimal_to_integral_exact_impl(PyObject *self, PyTypeObject *cls, PyObject *rounding, PyObject *context) -/*[clinic end generated code: output=543a39a02eea9917 input=fabce7a744b8087c]*/ +/*[clinic end generated code: output=543a39a02eea9917 input=d4d8abe543393de1]*/ { PyObject *result; uint32_t status = 0; @@ -4791,13 +4795,14 @@ _decimal.Decimal.sqrt = _decimal.Decimal.exp Return the square root of the argument to full precision. -The result is correctly rounded using the ROUND_HALF_EVEN rounding mode. +The result is correctly rounded using the ROUND_HALF_EVEN rounding +mode. [clinic start generated code]*/ static PyObject * _decimal_Decimal_sqrt_impl(PyObject *self, PyTypeObject *cls, PyObject *context) -/*[clinic end generated code: output=deb1280077b5e586 input=3a76afbd39dc20b9]*/ +/*[clinic end generated code: output=deb1280077b5e586 input=c565a7216e9605e7]*/ Dec_UnaryFuncVA(mpd_qsqrt) /* Binary arithmetic functions, optional context arg */ @@ -4853,6 +4858,7 @@ _decimal_Decimal_max_impl(PyObject *self, PyTypeObject *cls, PyObject *other, Dec_BinaryFuncVA(mpd_qmax) /*[clinic input] +@permit_long_summary _decimal.Decimal.max_mag = _decimal.Decimal.compare As the max() method, but compares the absolute values of the operands. @@ -4861,7 +4867,7 @@ As the max() method, but compares the absolute values of the operands. static PyObject * _decimal_Decimal_max_mag_impl(PyObject *self, PyTypeObject *cls, PyObject *other, PyObject *context) -/*[clinic end generated code: output=f71f2c27d9bc7cac input=88b105e66cf138c5]*/ +/*[clinic end generated code: output=f71f2c27d9bc7cac input=5f81b9da49b45e5d]*/ Dec_BinaryFuncVA(mpd_qmax_mag) /*[clinic input] @@ -4880,6 +4886,7 @@ _decimal_Decimal_min_impl(PyObject *self, PyTypeObject *cls, PyObject *other, Dec_BinaryFuncVA(mpd_qmin) /*[clinic input] +@permit_long_summary _decimal.Decimal.min_mag = _decimal.Decimal.compare As the min() method, but compares the absolute values of the operands. @@ -4888,7 +4895,7 @@ As the min() method, but compares the absolute values of the operands. static PyObject * _decimal_Decimal_min_mag_impl(PyObject *self, PyTypeObject *cls, PyObject *other, PyObject *context) -/*[clinic end generated code: output=018562ad1c22aae3 input=351fa3c0e592746a]*/ +/*[clinic end generated code: output=018562ad1c22aae3 input=94c29817c7f16db7]*/ Dec_BinaryFuncVA(mpd_qmin_mag) /*[clinic input] @@ -4896,16 +4903,16 @@ _decimal.Decimal.next_toward = _decimal.Decimal.compare Returns the number closest to self, in the direction towards other. -If the two operands are unequal, return the number closest to the first -operand in the direction of the second operand. If both operands are -numerically equal, return a copy of the first operand with the sign set -to be the same as the sign of the second operand. +If the two operands are unequal, return the number closest to the +first operand in the direction of the second operand. If both +operands are numerically equal, return a copy of the first operand +with the sign set to be the same as the sign of the second operand. [clinic start generated code]*/ static PyObject * _decimal_Decimal_next_toward_impl(PyObject *self, PyTypeObject *cls, PyObject *other, PyObject *context) -/*[clinic end generated code: output=71d879bca8bc1019 input=fdf0091ea6e9e416]*/ +/*[clinic end generated code: output=71d879bca8bc1019 input=adc5d453fc140341]*/ Dec_BinaryFuncVA(mpd_qnext_toward) /*[clinic input] @@ -4914,10 +4921,10 @@ _decimal.Decimal.remainder_near = _decimal.Decimal.compare Return the remainder from dividing self by other. This differs from self % other in that the sign of the remainder is -chosen so as to minimize its absolute value. More precisely, the return -value is self - n * other where n is the integer nearest to the exact -value of self / other, and if two integers are equally near then the -even one is chosen. +chosen so as to minimize its absolute value. More precisely, the +return value is self - n * other where n is the integer nearest to +the exact value of self / other, and if two integers are equally +near then the even one is chosen. If the result is zero then its sign will be the sign of self. [clinic start generated code]*/ @@ -4925,7 +4932,7 @@ If the result is zero then its sign will be the sign of self. static PyObject * _decimal_Decimal_remainder_near_impl(PyObject *self, PyTypeObject *cls, PyObject *other, PyObject *context) -/*[clinic end generated code: output=d3fbb4985f2077fa input=eb5a8dfe3470b794]*/ +/*[clinic end generated code: output=d3fbb4985f2077fa input=dcb66d4afa0c77c3]*/ Dec_BinaryFuncVA(mpd_qrem_near) /* Ternary arithmetic functions, optional context arg */ @@ -4992,6 +4999,7 @@ _decimal_Decimal_is_infinite_impl(PyObject *self) Dec_BoolFunc(mpd_isinfinite) /*[clinic input] +@permit_long_summary _decimal.Decimal.is_nan Return True if the argument is a (quiet or signaling) NaN, else False. @@ -4999,7 +5007,7 @@ Return True if the argument is a (quiet or signaling) NaN, else False. static PyObject * _decimal_Decimal_is_nan_impl(PyObject *self) -/*[clinic end generated code: output=b704e8b49a164388 input=795e5dac85976994]*/ +/*[clinic end generated code: output=b704e8b49a164388 input=b7d8f0d59fe2332a]*/ Dec_BoolFunc(mpd_isnan) /*[clinic input] @@ -5153,13 +5161,13 @@ _decimal.Decimal.radix Return Decimal(10). -This is the radix (base) in which the Decimal class does -all its arithmetic. Included for compatibility with the specification. +This is the radix (base) in which the Decimal class does all its +arithmetic. Included for compatibility with the specification. [clinic start generated code]*/ static PyObject * _decimal_Decimal_radix_impl(PyObject *self, PyTypeObject *cls) -/*[clinic end generated code: output=40a3bc7ec3d99228 input=b0d4cb9f870bbac1]*/ +/*[clinic end generated code: output=40a3bc7ec3d99228 input=d1cdbdbbbdefdec2]*/ { decimal_state *state = PyType_GetModuleState(cls); return _dec_mpd_radix(state); @@ -5250,15 +5258,15 @@ _decimal.Decimal.logb = _decimal.Decimal.exp Return the adjusted exponent of the operand as a Decimal instance. -If the operand is a zero, then Decimal('-Infinity') is returned and the -DivisionByZero condition is raised. If the operand is an infinity then -Decimal('Infinity') is returned. +If the operand is a zero, then Decimal('-Infinity') is returned and +the DivisionByZero condition is raised. If the operand is an +infinity then Decimal('Infinity') is returned. [clinic start generated code]*/ static PyObject * _decimal_Decimal_logb_impl(PyObject *self, PyTypeObject *cls, PyObject *context) -/*[clinic end generated code: output=36b0bda09e934245 input=a8df027d1b8a2b17]*/ +/*[clinic end generated code: output=36b0bda09e934245 input=eeafa6bbf8d8a013]*/ Dec_UnaryFuncVA(mpd_qlogb) /*[clinic input] @@ -5280,14 +5288,15 @@ The returned value is one of the following ten strings: * '+Normal', indicating that the operand is a positive normal number. * '+Infinity', indicating that the operand is positive infinity. - * 'NaN', indicating that the operand is a quiet NaN (Not a Number). + * 'NaN', indicating that the operand is a quiet NaN (Not a + Number). * 'sNaN', indicating that the operand is a signaling NaN. [clinic start generated code]*/ static PyObject * _decimal_Decimal_number_class_impl(PyObject *self, PyTypeObject *cls, PyObject *context) -/*[clinic end generated code: output=1ac82412e0849c52 input=447095d2677fa0ca]*/ +/*[clinic end generated code: output=1ac82412e0849c52 input=0b59852b43c521aa]*/ { const char *cp; @@ -5303,19 +5312,19 @@ _decimal.Decimal.to_eng_string = _decimal.Decimal.exp Convert to an engineering-type string. -Engineering notation has an exponent which is a multiple of 3, so there -are up to 3 digits left of the decimal place. For example, +Engineering notation has an exponent which is a multiple of 3, so +there are up to 3 digits left of the decimal place. For example, Decimal('123E+1') is converted to Decimal('1.23E+3'). -The value of context.capitals determines whether the exponent sign is -lower or upper case. Otherwise, the context does not affect the +The value of context.capitals determines whether the exponent sign +is lower or upper case. Otherwise, the context does not affect the operation. [clinic start generated code]*/ static PyObject * _decimal_Decimal_to_eng_string_impl(PyObject *self, PyTypeObject *cls, PyObject *context) -/*[clinic end generated code: output=901f128d437ae5c0 input=b2cb7e01e268e45d]*/ +/*[clinic end generated code: output=901f128d437ae5c0 input=111db4de6561f211]*/ { PyObject *result; mpd_ssize_t size; @@ -5343,31 +5352,31 @@ _decimal.Decimal.compare_total = _decimal.Decimal.compare Compare two operands using their abstract representation. -Similar to the compare() method, but the result -gives a total ordering on Decimal instances. Two Decimal instances with -the same numeric value but different representations compare unequal -in this ordering: +Similar to the compare() method, but the result gives a total +ordering on Decimal instances. Two Decimal instances with the same +numeric value but different representations compare unequal in this +ordering: >>> Decimal('12.0').compare_total(Decimal('12')) Decimal('-1') -Quiet and signaling NaNs are also included in the total ordering. The -result of this function is Decimal('0') if both operands have the same -representation, Decimal('-1') if the first operand is lower in the -total order than the second, and Decimal('1') if the first operand is -higher in the total order than the second operand. See the -specification for details of the total order. +Quiet and signaling NaNs are also included in the total ordering. +The result of this function is Decimal('0') if both operands have +the same representation, Decimal('-1') if the first operand is lower +in the total order than the second, and Decimal('1') if the first +operand is higher in the total order than the second operand. See +the specification for details of the total order. This operation is unaffected by context and is quiet: no flags are -changed and no rounding is performed. As an exception, the C version -may raise InvalidOperation if the second operand cannot be converted -exactly. +changed and no rounding is performed. As an exception, the C +version may raise InvalidOperation if the second operand cannot be +converted exactly. [clinic start generated code]*/ static PyObject * _decimal_Decimal_compare_total_impl(PyObject *self, PyTypeObject *cls, PyObject *other, PyObject *context) -/*[clinic end generated code: output=83649010bad7815f input=6f3111ec5fdbf3c1]*/ +/*[clinic end generated code: output=83649010bad7815f input=d795bf204b9ff2a8]*/ Dec_BinaryFuncVA_NO_CTX(mpd_compare_total) /*[clinic input] @@ -5516,18 +5525,19 @@ _decimal.Decimal.rotate = _decimal.Decimal.compare Returns a rotated copy of self's digits, value-of-other times. -The second operand must be an integer in the range -precision through -precision. The absolute value of the second operand gives the number of -places to rotate. If the second operand is positive then rotation is to -the left; otherwise rotation is to the right. The coefficient of the -first operand is padded on the left with zeros to length precision if -necessary. The sign and exponent of the first operand are unchanged. +The second operand must be an integer in the range -precision +through precision. The absolute value of the second operand gives +the number of places to rotate. If the second operand is positive +then rotation is to the left; otherwise rotation is to the right. +The coefficient of the first operand is padded on the left with +zeros to length precision if necessary. The sign and exponent of +the first operand are unchanged. [clinic start generated code]*/ static PyObject * _decimal_Decimal_rotate_impl(PyObject *self, PyTypeObject *cls, PyObject *other, PyObject *context) -/*[clinic end generated code: output=09f2737082882b83 input=cde7b032eac43f0b]*/ +/*[clinic end generated code: output=09f2737082882b83 input=4bc840d51842934c]*/ Dec_BinaryFuncVA(mpd_qrotate) /*[clinic input] @@ -5550,18 +5560,18 @@ _decimal.Decimal.shift = _decimal.Decimal.compare Returns a shifted copy of self's digits, value-of-other times. -The second operand must be an integer in the range -precision through -precision. The absolute value of the second operand gives the number -of places to shift. If the second operand is positive, then the shift -is to the left; otherwise the shift is to the right. Digits shifted -into the coefficient are zeros. The sign and exponent of the first -operand are unchanged. +The second operand must be an integer in the range -precision +through precision. The absolute value of the second operand gives +the number of places to shift. If the second operand is positive, +then the shift is to the left; otherwise the shift is to the right. +Digits shifted into the coefficient are zeros. The sign and +exponent of the first operand are unchanged. [clinic start generated code]*/ static PyObject * _decimal_Decimal_shift_impl(PyObject *self, PyTypeObject *cls, PyObject *other, PyObject *context) -/*[clinic end generated code: output=82e061a0d9ecc4f5 input=501759c2522cb78e]*/ +/*[clinic end generated code: output=82e061a0d9ecc4f5 input=c05f3fd69fc1f9f9]*/ Dec_BinaryFuncVA(mpd_qshift) /*[clinic input] @@ -5589,18 +5599,18 @@ that of the right-hand operand. Also unlike other operations, quantize never signals Underflow, even if the result is subnormal and inexact. -If the exponent of the second operand is larger than that of the first, -then rounding may be necessary. In this case, the rounding mode is -determined by the rounding argument if given, else by the given context -argument; if neither argument is given, the rounding mode of the -current thread's context is used. +If the exponent of the second operand is larger than that of the +first, then rounding may be necessary. In this case, the rounding +mode is determined by the rounding argument if given, else by the +given context argument; if neither argument is given, the rounding +mode of the current thread's context is used. [clinic start generated code]*/ static PyObject * _decimal_Decimal_quantize_impl(PyObject *self, PyTypeObject *cls, PyObject *w, PyObject *rounding, PyObject *context) -/*[clinic end generated code: output=fc51edf458559913 input=1166e6311e047b74]*/ +/*[clinic end generated code: output=fc51edf458559913 input=7838b0a5f684adb8]*/ { PyObject *a, *b; PyObject *result; @@ -6629,14 +6639,14 @@ _decimal.Context.remainder_near = _decimal.Context.add Return x - y * n. -Here n is the integer nearest the exact value of x / y (if the result -is 0 then its sign will be the sign of x). +Here n is the integer nearest the exact value of x / y (if the +result is 0 then its sign will be the sign of x). [clinic start generated code]*/ static PyObject * _decimal_Context_remainder_near_impl(PyObject *context, PyTypeObject *cls, PyObject *x, PyObject *y) -/*[clinic end generated code: output=7f18c535a12cf8ac input=bafb6327bb314c5c]*/ +/*[clinic end generated code: output=7f18c535a12cf8ac input=60342558000d4be6]*/ DecCtx_BinaryFunc(mpd_qrem_near) /*[clinic input] @@ -6723,13 +6733,14 @@ restrictions hold: * all three arguments must be integral * 'b' must be nonnegative * at least one of 'a' or 'b' must be nonzero - * modulo must be nonzero and less than 10**prec in absolute value + * modulo must be nonzero and less than 10**prec in absolute + value [clinic start generated code]*/ static PyObject * _decimal_Context_power_impl(PyObject *context, PyTypeObject *cls, PyObject *base, PyObject *exp, PyObject *mod) -/*[clinic end generated code: output=d06d40c37cdd69dc input=2a70edd03317c666]*/ +/*[clinic end generated code: output=d06d40c37cdd69dc input=178a254468ec189b]*/ { PyObject *a, *b, *c = NULL; PyObject *result; @@ -7276,6 +7287,7 @@ _decimal_Context_copy_sign_impl(PyObject *context, PyTypeObject *cls, } /*[clinic input] +@permit_long_docstring_body _decimal.Context.logical_and = _decimal.Context.add Applies the logical operation 'and' between each operand's digits. @@ -7305,7 +7317,7 @@ The operands must be both logical numbers. static PyObject * _decimal_Context_logical_and_impl(PyObject *context, PyTypeObject *cls, PyObject *x, PyObject *y) -/*[clinic end generated code: output=009dfa08ecaa2ac8 input=bcb7d3d6ab7530de]*/ +/*[clinic end generated code: output=009dfa08ecaa2ac8 input=9f8a93a31b9d7088]*/ DecCtx_BinaryFunc(mpd_qand) /*[clinic input] @@ -7342,6 +7354,7 @@ _decimal_Context_logical_or_impl(PyObject *context, PyTypeObject *cls, DecCtx_BinaryFunc(mpd_qor) /*[clinic input] +@permit_long_docstring_body _decimal.Context.logical_xor = _decimal.Context.add Applies the logical operation 'xor' between each operand's digits. @@ -7371,7 +7384,7 @@ The operands must be both logical numbers. static PyObject * _decimal_Context_logical_xor_impl(PyObject *context, PyTypeObject *cls, PyObject *x, PyObject *y) -/*[clinic end generated code: output=23cd81fdcd865d5a input=fcaaf828c1d2d089]*/ +/*[clinic end generated code: output=23cd81fdcd865d5a input=119412854ae58440]*/ DecCtx_BinaryFunc(mpd_qxor) /*[clinic input] diff --git a/Modules/_decimal/clinic/_decimal.c.h b/Modules/_decimal/clinic/_decimal.c.h index b09200845d12e9..c803006ad44382 100644 --- a/Modules/_decimal/clinic/_decimal.c.h +++ b/Modules/_decimal/clinic/_decimal.c.h @@ -36,8 +36,8 @@ PyDoc_STRVAR(_decimal_Context_Etop__doc__, "\n" "Return a value equal to Emax - prec + 1.\n" "\n" -"This is the maximum exponent if the _clamp field of the context is set\n" -"to 1 (IEEE clamp mode). Etop() must not be negative."); +"This is the maximum exponent if the _clamp field of the context is\n" +"set to 1 (IEEE clamp mode). Etop() must not be negative."); #define _DECIMAL_CONTEXT_ETOP_METHODDEF \ {"Etop", (PyCFunction)_decimal_Context_Etop, METH_NOARGS, _decimal_Context_Etop__doc__}, @@ -1092,10 +1092,10 @@ PyDoc_STRVAR(_decimal_Decimal_to_integral_exact__doc__, "\n" "Round to the nearest integer.\n" "\n" -"Decimal.to_integral_exact() signals Inexact or Rounded as appropriate\n" -"if rounding occurs. The rounding mode is determined by the rounding\n" -"parameter if given, else by the given context. If neither parameter is\n" -"given, then the rounding mode of the current default context is used."); +"This method signals Inexact or Rounded as appropriate if rounding\n" +"occurs. The rounding mode is determined by the rounding parameter\n" +"if given, else by the given context. If neither parameter is given,\n" +"then the rounding mode of the current default context is used."); #define _DECIMAL_DECIMAL_TO_INTEGRAL_EXACT_METHODDEF \ {"to_integral_exact", _PyCFunction_CAST(_decimal_Decimal_to_integral_exact), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_to_integral_exact__doc__}, @@ -1638,7 +1638,8 @@ PyDoc_STRVAR(_decimal_Decimal_sqrt__doc__, "\n" "Return the square root of the argument to full precision.\n" "\n" -"The result is correctly rounded using the ROUND_HALF_EVEN rounding mode."); +"The result is correctly rounded using the ROUND_HALF_EVEN rounding\n" +"mode."); #define _DECIMAL_DECIMAL_SQRT_METHODDEF \ {"sqrt", _PyCFunction_CAST(_decimal_Decimal_sqrt), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_sqrt__doc__}, @@ -2113,10 +2114,10 @@ PyDoc_STRVAR(_decimal_Decimal_next_toward__doc__, "\n" "Returns the number closest to self, in the direction towards other.\n" "\n" -"If the two operands are unequal, return the number closest to the first\n" -"operand in the direction of the second operand. If both operands are\n" -"numerically equal, return a copy of the first operand with the sign set\n" -"to be the same as the sign of the second operand."); +"If the two operands are unequal, return the number closest to the\n" +"first operand in the direction of the second operand. If both\n" +"operands are numerically equal, return a copy of the first operand\n" +"with the sign set to be the same as the sign of the second operand."); #define _DECIMAL_DECIMAL_NEXT_TOWARD_METHODDEF \ {"next_toward", _PyCFunction_CAST(_decimal_Decimal_next_toward), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_next_toward__doc__}, @@ -2185,10 +2186,10 @@ PyDoc_STRVAR(_decimal_Decimal_remainder_near__doc__, "Return the remainder from dividing self by other.\n" "\n" "This differs from self % other in that the sign of the remainder is\n" -"chosen so as to minimize its absolute value. More precisely, the return\n" -"value is self - n * other where n is the integer nearest to the exact\n" -"value of self / other, and if two integers are equally near then the\n" -"even one is chosen.\n" +"chosen so as to minimize its absolute value. More precisely, the\n" +"return value is self - n * other where n is the integer nearest to\n" +"the exact value of self / other, and if two integers are equally\n" +"near then the even one is chosen.\n" "\n" "If the result is zero then its sign will be the sign of self."); @@ -2671,8 +2672,8 @@ PyDoc_STRVAR(_decimal_Decimal_radix__doc__, "\n" "Return Decimal(10).\n" "\n" -"This is the radix (base) in which the Decimal class does\n" -"all its arithmetic. Included for compatibility with the specification."); +"This is the radix (base) in which the Decimal class does all its\n" +"arithmetic. Included for compatibility with the specification."); #define _DECIMAL_DECIMAL_RADIX_METHODDEF \ {"radix", _PyCFunction_CAST(_decimal_Decimal_radix), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_radix__doc__}, @@ -2812,9 +2813,9 @@ PyDoc_STRVAR(_decimal_Decimal_logb__doc__, "\n" "Return the adjusted exponent of the operand as a Decimal instance.\n" "\n" -"If the operand is a zero, then Decimal(\'-Infinity\') is returned and the\n" -"DivisionByZero condition is raised. If the operand is an infinity then\n" -"Decimal(\'Infinity\') is returned."); +"If the operand is a zero, then Decimal(\'-Infinity\') is returned and\n" +"the DivisionByZero condition is raised. If the operand is an\n" +"infinity then Decimal(\'Infinity\') is returned."); #define _DECIMAL_DECIMAL_LOGB_METHODDEF \ {"logb", _PyCFunction_CAST(_decimal_Decimal_logb), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_logb__doc__}, @@ -2894,7 +2895,8 @@ PyDoc_STRVAR(_decimal_Decimal_number_class__doc__, " * \'+Normal\', indicating that the operand is a positive normal\n" " number.\n" " * \'+Infinity\', indicating that the operand is positive infinity.\n" -" * \'NaN\', indicating that the operand is a quiet NaN (Not a Number).\n" +" * \'NaN\', indicating that the operand is a quiet NaN (Not a\n" +" Number).\n" " * \'sNaN\', indicating that the operand is a signaling NaN."); #define _DECIMAL_DECIMAL_NUMBER_CLASS_METHODDEF \ @@ -2961,12 +2963,12 @@ PyDoc_STRVAR(_decimal_Decimal_to_eng_string__doc__, "\n" "Convert to an engineering-type string.\n" "\n" -"Engineering notation has an exponent which is a multiple of 3, so there\n" -"are up to 3 digits left of the decimal place. For example,\n" +"Engineering notation has an exponent which is a multiple of 3, so\n" +"there are up to 3 digits left of the decimal place. For example,\n" "Decimal(\'123E+1\') is converted to Decimal(\'1.23E+3\').\n" "\n" -"The value of context.capitals determines whether the exponent sign is\n" -"lower or upper case. Otherwise, the context does not affect the\n" +"The value of context.capitals determines whether the exponent sign\n" +"is lower or upper case. Otherwise, the context does not affect the\n" "operation."); #define _DECIMAL_DECIMAL_TO_ENG_STRING_METHODDEF \ @@ -3033,25 +3035,25 @@ PyDoc_STRVAR(_decimal_Decimal_compare_total__doc__, "\n" "Compare two operands using their abstract representation.\n" "\n" -"Similar to the compare() method, but the result\n" -"gives a total ordering on Decimal instances. Two Decimal instances with\n" -"the same numeric value but different representations compare unequal\n" -"in this ordering:\n" +"Similar to the compare() method, but the result gives a total\n" +"ordering on Decimal instances. Two Decimal instances with the same\n" +"numeric value but different representations compare unequal in this\n" +"ordering:\n" "\n" " >>> Decimal(\'12.0\').compare_total(Decimal(\'12\'))\n" " Decimal(\'-1\')\n" "\n" -"Quiet and signaling NaNs are also included in the total ordering. The\n" -"result of this function is Decimal(\'0\') if both operands have the same\n" -"representation, Decimal(\'-1\') if the first operand is lower in the\n" -"total order than the second, and Decimal(\'1\') if the first operand is\n" -"higher in the total order than the second operand. See the\n" -"specification for details of the total order.\n" +"Quiet and signaling NaNs are also included in the total ordering.\n" +"The result of this function is Decimal(\'0\') if both operands have\n" +"the same representation, Decimal(\'-1\') if the first operand is lower\n" +"in the total order than the second, and Decimal(\'1\') if the first\n" +"operand is higher in the total order than the second operand. See\n" +"the specification for details of the total order.\n" "\n" "This operation is unaffected by context and is quiet: no flags are\n" -"changed and no rounding is performed. As an exception, the C version\n" -"may raise InvalidOperation if the second operand cannot be converted\n" -"exactly."); +"changed and no rounding is performed. As an exception, the C\n" +"version may raise InvalidOperation if the second operand cannot be\n" +"converted exactly."); #define _DECIMAL_DECIMAL_COMPARE_TOTAL_METHODDEF \ {"compare_total", _PyCFunction_CAST(_decimal_Decimal_compare_total), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_compare_total__doc__}, @@ -3544,12 +3546,13 @@ PyDoc_STRVAR(_decimal_Decimal_rotate__doc__, "\n" "Returns a rotated copy of self\'s digits, value-of-other times.\n" "\n" -"The second operand must be an integer in the range -precision through\n" -"precision. The absolute value of the second operand gives the number of\n" -"places to rotate. If the second operand is positive then rotation is to\n" -"the left; otherwise rotation is to the right. The coefficient of the\n" -"first operand is padded on the left with zeros to length precision if\n" -"necessary. The sign and exponent of the first operand are unchanged."); +"The second operand must be an integer in the range -precision\n" +"through precision. The absolute value of the second operand gives\n" +"the number of places to rotate. If the second operand is positive\n" +"then rotation is to the left; otherwise rotation is to the right.\n" +"The coefficient of the first operand is padded on the left with\n" +"zeros to length precision if necessary. The sign and exponent of\n" +"the first operand are unchanged."); #define _DECIMAL_DECIMAL_ROTATE_METHODDEF \ {"rotate", _PyCFunction_CAST(_decimal_Decimal_rotate), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_rotate__doc__}, @@ -3686,12 +3689,12 @@ PyDoc_STRVAR(_decimal_Decimal_shift__doc__, "\n" "Returns a shifted copy of self\'s digits, value-of-other times.\n" "\n" -"The second operand must be an integer in the range -precision through\n" -"precision. The absolute value of the second operand gives the number\n" -"of places to shift. If the second operand is positive, then the shift\n" -"is to the left; otherwise the shift is to the right. Digits shifted\n" -"into the coefficient are zeros. The sign and exponent of the first\n" -"operand are unchanged."); +"The second operand must be an integer in the range -precision\n" +"through precision. The absolute value of the second operand gives\n" +"the number of places to shift. If the second operand is positive,\n" +"then the shift is to the left; otherwise the shift is to the right.\n" +"Digits shifted into the coefficient are zeros. The sign and\n" +"exponent of the first operand are unchanged."); #define _DECIMAL_DECIMAL_SHIFT_METHODDEF \ {"shift", _PyCFunction_CAST(_decimal_Decimal_shift), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_shift__doc__}, @@ -3774,11 +3777,11 @@ PyDoc_STRVAR(_decimal_Decimal_quantize__doc__, "Also unlike other operations, quantize never signals Underflow, even\n" "if the result is subnormal and inexact.\n" "\n" -"If the exponent of the second operand is larger than that of the first,\n" -"then rounding may be necessary. In this case, the rounding mode is\n" -"determined by the rounding argument if given, else by the given context\n" -"argument; if neither argument is given, the rounding mode of the\n" -"current thread\'s context is used."); +"If the exponent of the second operand is larger than that of the\n" +"first, then rounding may be necessary. In this case, the rounding\n" +"mode is determined by the rounding argument if given, else by the\n" +"given context argument; if neither argument is given, the rounding\n" +"mode of the current thread\'s context is used."); #define _DECIMAL_DECIMAL_QUANTIZE_METHODDEF \ {"quantize", _PyCFunction_CAST(_decimal_Decimal_quantize), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_quantize__doc__}, @@ -5197,8 +5200,8 @@ PyDoc_STRVAR(_decimal_Context_remainder_near__doc__, "\n" "Return x - y * n.\n" "\n" -"Here n is the integer nearest the exact value of x / y (if the result\n" -"is 0 then its sign will be the sign of x)."); +"Here n is the integer nearest the exact value of x / y (if the\n" +"result is 0 then its sign will be the sign of x)."); #define _DECIMAL_CONTEXT_REMAINDER_NEAR_METHODDEF \ {"remainder_near", _PyCFunction_CAST(_decimal_Context_remainder_near), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Context_remainder_near__doc__}, @@ -5336,7 +5339,8 @@ PyDoc_STRVAR(_decimal_Context_power__doc__, " * all three arguments must be integral\n" " * \'b\' must be nonnegative\n" " * at least one of \'a\' or \'b\' must be nonzero\n" -" * modulo must be nonzero and less than 10**prec in absolute value"); +" * modulo must be nonzero and less than 10**prec in absolute\n" +" value"); #define _DECIMAL_CONTEXT_POWER_METHODDEF \ {"power", _PyCFunction_CAST(_decimal_Context_power), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Context_power__doc__}, @@ -6980,4 +6984,4 @@ _decimal_Context_same_quantum(PyObject *context, PyTypeObject *cls, PyObject *co #ifndef _DECIMAL_CONTEXT_APPLY_METHODDEF #define _DECIMAL_CONTEXT_APPLY_METHODDEF #endif /* !defined(_DECIMAL_CONTEXT_APPLY_METHODDEF) */ -/*[clinic end generated code: output=b288181c82fdc9f1 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=0eb835634388294e input=a9049054013a1b77]*/ From d3e2a133d23d7ed3a4acc2ee71757281b1f282cd Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 24 May 2026 15:24:34 +0200 Subject: [PATCH 129/818] [3.15] gh-150285: Fix too long docstrings in the zstd module (GH-150291) (GH-150335) (cherry picked from commit 9fceb1c0c5c5ad527bc257b115bcf45995daf631) Co-authored-by: Serhiy Storchaka --- Lib/compression/zstd/__init__.py | 28 +++++++++--------- Lib/compression/zstd/_zstdfile.py | 39 ++++++++++++------------- Modules/_zstd/clinic/compressor.c.h | 31 ++++++++++---------- Modules/_zstd/clinic/decompressor.c.h | 30 +++++++++++--------- Modules/_zstd/clinic/zstddict.c.h | 30 +++++++++++--------- Modules/_zstd/compressor.c | 41 +++++++++++++-------------- Modules/_zstd/decompressor.c | 37 ++++++++++++------------ Modules/_zstd/zstddict.c | 40 +++++++++++++------------- 8 files changed, 140 insertions(+), 136 deletions(-) diff --git a/Lib/compression/zstd/__init__.py b/Lib/compression/zstd/__init__.py index 84b25914b0aa93..5326cf9b19cf88 100644 --- a/Lib/compression/zstd/__init__.py +++ b/Lib/compression/zstd/__init__.py @@ -61,8 +61,9 @@ def __setattr__(self, name, _): def get_frame_info(frame_buffer): """Get Zstandard frame information from a frame header. - *frame_buffer* is a bytes-like object. It should start from the beginning - of a frame, and needs to include at least the frame header (6 to 18 bytes). + *frame_buffer* is a bytes-like object. It should start from the + beginning of a frame, and needs to include at least the frame header + (6 to 18 bytes). The returned FrameInfo object has two attributes. 'decompressed_size' is the size in bytes of the data in the frame when @@ -103,16 +104,17 @@ def finalize_dict(zstd_dict, /, samples, dict_size, level): finalize *zstd_dict* by adding headers and statistics according to the Zstandard dictionary format. - You may compose an effective dictionary content by hand, which is used as - basis dictionary, and use some samples to finalize a dictionary. The basis - dictionary may be a "raw content" dictionary. See *is_raw* in ZstdDict. + You may compose an effective dictionary content by hand, which is used + as basis dictionary, and use some samples to finalize a dictionary. The + basis dictionary may be a "raw content" dictionary. See *is_raw* in + ZstdDict. - *samples* is an iterable of samples, where a sample is a bytes-like object - representing a file. + *samples* is an iterable of samples, where a sample is a bytes-like + object representing a file. *dict_size* is the dictionary's maximum size, in bytes. *level* is the expected compression level. The statistics for each - compression level differ, so tuning the dictionary to the compression level - can provide improvements. + compression level differ, so tuning the dictionary to the compression + level can provide improvements. """ if not isinstance(zstd_dict, ZstdDict): @@ -140,8 +142,8 @@ def compress(data, level=None, options=None, zstd_dict=None): COMPRESSION_LEVEL_DEFAULT ('3'). *options* is a dict object that contains advanced compression parameters. See CompressionParameter for more on options. - *zstd_dict* is a ZstdDict object, a pre-trained Zstandard dictionary. See - the function train_dict for how to train a ZstdDict on sample data. + *zstd_dict* is a ZstdDict object, a pre-trained Zstandard dictionary. + See the function train_dict for how to train a ZstdDict on sample data. For incremental compression, use a ZstdCompressor instead. """ @@ -152,8 +154,8 @@ def compress(data, level=None, options=None, zstd_dict=None): def decompress(data, zstd_dict=None, options=None): """Decompress one or more frames of Zstandard compressed *data*. - *zstd_dict* is a ZstdDict object, a pre-trained Zstandard dictionary. See - the function train_dict for how to train a ZstdDict on sample data. + *zstd_dict* is a ZstdDict object, a pre-trained Zstandard dictionary. + See the function train_dict for how to train a ZstdDict on sample data. *options* is a dict object that contains advanced compression parameters. See DecompressionParameter for more on options. diff --git a/Lib/compression/zstd/_zstdfile.py b/Lib/compression/zstd/_zstdfile.py index d709f5efc658fa..8d3358152e9a88 100644 --- a/Lib/compression/zstd/_zstdfile.py +++ b/Lib/compression/zstd/_zstdfile.py @@ -36,9 +36,9 @@ def __init__(self, file, /, mode='r', *, *file* can be either an file-like object, or a file name to open. - *mode* can be 'r' for reading (default), 'w' for (over)writing, 'x' for - creating exclusively, or 'a' for appending. These can equivalently be - given as 'rb', 'wb', 'xb' and 'ab' respectively. + *mode* can be 'r' for reading (default), 'w' for (over)writing, 'x' + for creating exclusively, or 'a' for appending. These can + equivalently be given as 'rb', 'wb', 'xb' and 'ab' respectively. *level* is an optional int specifying the compression level to use, or COMPRESSION_LEVEL_DEFAULT if not given. @@ -296,26 +296,27 @@ def open(file, /, mode='rb', *, level=None, options=None, zstd_dict=None, encoding=None, errors=None, newline=None): """Open a Zstandard compressed file in binary or text mode. - file can be either a file name (given as a str, bytes, or PathLike object), - in which case the named file is opened, or it can be an existing file object - to read from or write to. + file can be either a file name (given as a str, bytes, or PathLike + object), in which case the named file is opened, or it can be + an existing file object to read from or write to. - The mode parameter can be 'r', 'rb' (default), 'w', 'wb', 'x', 'xb', 'a', - 'ab' for binary mode, or 'rt', 'wt', 'xt', 'at' for text mode. + The mode parameter can be 'r', 'rb' (default), 'w', 'wb', 'x', 'xb', + 'a', 'ab' for binary mode, or 'rt', 'wt', 'xt', 'at' for text mode. - The level, options, and zstd_dict parameters specify the settings the same - as ZstdFile. + The level, options, and zstd_dict parameters specify the settings the + same as ZstdFile. When using read mode (decompression), the options parameter is a dict - representing advanced decompression options. The level parameter is not - supported in this case. When using write mode (compression), only one of - level, an int representing the compression level, or options, a dict - representing advanced compression options, may be passed. In both modes, - zstd_dict is a ZstdDict instance containing a trained Zstandard dictionary. - - For binary mode, this function is equivalent to the ZstdFile constructor: - ZstdFile(filename, mode, ...). In this case, the encoding, errors and - newline parameters must not be provided. + representing advanced decompression options. The level parameter is not + supported in this case. When using write mode (compression), only one + of level, an int representing the compression level, or options, a dict + representing advanced compression options, may be passed. In both + modes, zstd_dict is a ZstdDict instance containing a trained Zstandard + dictionary. + + For binary mode, this function is equivalent to the ZstdFile + constructor: ZstdFile(filename, mode, ...). In this case, the encoding, + errors and newline parameters must not be provided. For text mode, an ZstdFile object is created, and wrapped in an io.TextIOWrapper instance with the specified encoding, error handling diff --git a/Modules/_zstd/clinic/compressor.c.h b/Modules/_zstd/clinic/compressor.c.h index 4f8d93fd9e867c..6775ba4826a652 100644 --- a/Modules/_zstd/clinic/compressor.c.h +++ b/Modules/_zstd/clinic/compressor.c.h @@ -21,8 +21,8 @@ PyDoc_STRVAR(_zstd_ZstdCompressor_new__doc__, " zstd_dict\n" " A ZstdDict object, a pre-trained Zstandard dictionary.\n" "\n" -"Thread-safe at method level. For one-shot compression, use the compress()\n" -"function instead."); +"Thread-safe at method level. For one-shot compression, use the\n" +"compress() function instead."); static PyObject * _zstd_ZstdCompressor_new_impl(PyTypeObject *type, PyObject *level, @@ -105,9 +105,9 @@ PyDoc_STRVAR(_zstd_ZstdCompressor_compress__doc__, " Can be these 3 values ZstdCompressor.CONTINUE,\n" " ZstdCompressor.FLUSH_BLOCK, ZstdCompressor.FLUSH_FRAME\n" "\n" -"Return a chunk of compressed data if possible, or b\'\' otherwise. When you have\n" -"finished providing data to the compressor, call the flush() method to finish\n" -"the compression process."); +"Return a chunk of compressed data if possible, or b\'\' otherwise.\n" +"When you have finished providing data to the compressor, call the\n" +"flush() method to finish the compression process."); #define _ZSTD_ZSTDCOMPRESSOR_COMPRESS_METHODDEF \ {"compress", _PyCFunction_CAST(_zstd_ZstdCompressor_compress), METH_FASTCALL|METH_KEYWORDS, _zstd_ZstdCompressor_compress__doc__}, @@ -189,9 +189,9 @@ PyDoc_STRVAR(_zstd_ZstdCompressor_flush__doc__, " Can be these 2 values ZstdCompressor.FLUSH_FRAME,\n" " ZstdCompressor.FLUSH_BLOCK\n" "\n" -"Flush any remaining data left in internal buffers. Since Zstandard data\n" -"consists of one or more independent frames, the compressor object can still\n" -"be used after this method is called."); +"Flush any remaining data left in internal buffers. Since Zstandard\n" +"data consists of one or more independent frames, the compressor\n" +"object can still be used after this method is called."); #define _ZSTD_ZSTDCOMPRESSOR_FLUSH_METHODDEF \ {"flush", _PyCFunction_CAST(_zstd_ZstdCompressor_flush), METH_FASTCALL|METH_KEYWORDS, _zstd_ZstdCompressor_flush__doc__}, @@ -262,13 +262,14 @@ PyDoc_STRVAR(_zstd_ZstdCompressor_set_pledged_input_size__doc__, " size\n" " The size of the uncompressed data to be provided to the compressor.\n" "\n" -"This method can be used to ensure the header of the frame about to be written\n" -"includes the size of the data, unless the CompressionParameter.content_size_flag\n" -"is set to False. If last_mode != FLUSH_FRAME, then a RuntimeError is raised.\n" +"This method can be used to ensure the header of the frame about to\n" +"be written includes the size of the data, unless the\n" +"CompressionParameter.content_size_flag is set to False.\n" +"If last_mode != FLUSH_FRAME, then a RuntimeError is raised.\n" "\n" -"It is important to ensure that the pledged data size matches the actual data\n" -"size. If they do not match the compressed output data may be corrupted and the\n" -"final chunk written may be lost."); +"It is important to ensure that the pledged data size matches the\n" +"actual data size. If they do not match the compressed output data\n" +"may be corrupted and the final chunk written may be lost."); #define _ZSTD_ZSTDCOMPRESSOR_SET_PLEDGED_INPUT_SIZE_METHODDEF \ {"set_pledged_input_size", (PyCFunction)_zstd_ZstdCompressor_set_pledged_input_size, METH_O, _zstd_ZstdCompressor_set_pledged_input_size__doc__}, @@ -291,4 +292,4 @@ _zstd_ZstdCompressor_set_pledged_input_size(PyObject *self, PyObject *arg) exit: return return_value; } -/*[clinic end generated code: output=c1d5c2cf06a8becd input=a9049054013a1b77]*/ +/*[clinic end generated code: output=1a5e21476885866c input=a9049054013a1b77]*/ diff --git a/Modules/_zstd/clinic/decompressor.c.h b/Modules/_zstd/clinic/decompressor.c.h index c6fdae74ab0447..fe3b76b8bb369d 100644 --- a/Modules/_zstd/clinic/decompressor.c.h +++ b/Modules/_zstd/clinic/decompressor.c.h @@ -20,8 +20,8 @@ PyDoc_STRVAR(_zstd_ZstdDecompressor_new__doc__, " options\n" " A dict object that contains advanced decompression parameters.\n" "\n" -"Thread-safe at method level. For one-shot decompression, use the decompress()\n" -"function instead."); +"Thread-safe at method level. For one-shot decompression, use the\n" +"decompress() function instead."); static PyObject * _zstd_ZstdDecompressor_new_impl(PyTypeObject *type, PyObject *zstd_dict, @@ -91,7 +91,8 @@ PyDoc_STRVAR(_zstd_ZstdDecompressor_unused_data__doc__, "A bytes object of un-consumed input data.\n" "\n" "When ZstdDecompressor object stops after a frame is\n" -"decompressed, unused input data after the frame. Otherwise this will be b\'\'."); +"decompressed, unused input data after the frame. Otherwise this\n" +"will be b\'\'."); #if defined(_zstd_ZstdDecompressor_unused_data_DOCSTR) # undef _zstd_ZstdDecompressor_unused_data_DOCSTR #endif @@ -129,18 +130,19 @@ PyDoc_STRVAR(_zstd_ZstdDecompressor_decompress__doc__, " output buffer is unlimited. When it is nonnegative, returns at\n" " most max_length bytes of decompressed data.\n" "\n" -"If *max_length* is nonnegative, returns at most *max_length* bytes of\n" -"decompressed data. If this limit is reached and further output can be\n" -"produced, *self.needs_input* will be set to ``False``. In this case, the next\n" -"call to *decompress()* may provide *data* as b\'\' to obtain more of the output.\n" +"If *max_length* is nonnegative, returns at most *max_length* bytes\n" +"of decompressed data. If this limit is reached and further output\n" +"can be produced, *self.needs_input* will be set to ``False``. In\n" +"this case, the next call to *decompress()* may provide *data* as b\'\'\n" +"to obtain more of the output.\n" "\n" -"If all of the input data was decompressed and returned (either because this\n" -"was less than *max_length* bytes, or because *max_length* was negative),\n" -"*self.needs_input* will be set to True.\n" +"If all of the input data was decompressed and returned (either\n" +"because this was less than *max_length* bytes, or because\n" +"*max_length* was negative), *self.needs_input* will be set to True.\n" "\n" -"Attempting to decompress data after the end of a frame is reached raises an\n" -"EOFError. Any data found after the end of the frame is ignored and saved in\n" -"the self.unused_data attribute."); +"Attempting to decompress data after the end of a frame is reached\n" +"raises an EOFError. Any data found after the end of the frame is\n" +"ignored and saved in the self.unused_data attribute."); #define _ZSTD_ZSTDDECOMPRESSOR_DECOMPRESS_METHODDEF \ {"decompress", _PyCFunction_CAST(_zstd_ZstdDecompressor_decompress), METH_FASTCALL|METH_KEYWORDS, _zstd_ZstdDecompressor_decompress__doc__}, @@ -220,4 +222,4 @@ _zstd_ZstdDecompressor_decompress(PyObject *self, PyObject *const *args, Py_ssiz return return_value; } -/*[clinic end generated code: output=30c12ef047027ede input=a9049054013a1b77]*/ +/*[clinic end generated code: output=70bc308e86463751 input=a9049054013a1b77]*/ diff --git a/Modules/_zstd/clinic/zstddict.c.h b/Modules/_zstd/clinic/zstddict.c.h index 166d925a542352..18b049e3cbe37e 100644 --- a/Modules/_zstd/clinic/zstddict.c.h +++ b/Modules/_zstd/clinic/zstddict.c.h @@ -21,8 +21,8 @@ PyDoc_STRVAR(_zstd_ZstdDict_new__doc__, " advanced cases. Otherwise, check that the content represents\n" " a Zstandard dictionary created by the zstd library or CLI.\n" "\n" -"The dictionary can be used for compression or decompression, and can be shared\n" -"by multiple ZstdCompressor or ZstdDecompressor objects."); +"The dictionary can be used for compression or decompression, and can be\n" +"shared by multiple ZstdCompressor or ZstdDecompressor objects."); static PyObject * _zstd_ZstdDict_new_impl(PyTypeObject *type, Py_buffer *dict_content, @@ -125,11 +125,11 @@ PyDoc_STRVAR(_zstd_ZstdDict_as_digested_dict__doc__, "Pass this attribute as zstd_dict argument:\n" "compress(dat, zstd_dict=zd.as_digested_dict)\n" "\n" -"1. Some advanced compression parameters of compressor may be overridden\n" -" by parameters of digested dictionary.\n" -"2. ZstdDict has a digested dictionaries cache for each compression level.\n" -" It\'s faster when loading again a digested dictionary with the same\n" -" compression level.\n" +"1. Some advanced compression parameters of compressor may be\n" +" overridden by parameters of digested dictionary.\n" +"2. ZstdDict has a digested dictionaries cache for each compression\n" +" level. It\'s faster when loading again a digested dictionary with\n" +" the same compression level.\n" "3. No need to use this for decompression."); #if defined(_zstd_ZstdDict_as_digested_dict_DOCSTR) # undef _zstd_ZstdDict_as_digested_dict_DOCSTR @@ -161,9 +161,10 @@ PyDoc_STRVAR(_zstd_ZstdDict_as_undigested_dict__doc__, "Pass this attribute as zstd_dict argument:\n" "compress(dat, zstd_dict=zd.as_undigested_dict)\n" "\n" -"1. The advanced compression parameters of compressor will not be overridden.\n" -"2. Loading an undigested dictionary is costly. If load an undigested dictionary\n" -" multiple times, consider reusing a compressor object.\n" +"1. The advanced compression parameters of compressor will not be\n" +" overridden.\n" +"2. Loading an undigested dictionary is costly. If load an undigested\n" +" dictionary multiple times, consider reusing a compressor object.\n" "3. No need to use this for decompression."); #if defined(_zstd_ZstdDict_as_undigested_dict_DOCSTR) # undef _zstd_ZstdDict_as_undigested_dict_DOCSTR @@ -195,9 +196,10 @@ PyDoc_STRVAR(_zstd_ZstdDict_as_prefix__doc__, "Pass this attribute as zstd_dict argument:\n" "compress(dat, zstd_dict=zd.as_prefix)\n" "\n" -"1. Prefix is compatible with long distance matching, while dictionary is not.\n" -"2. It only works for the first frame, then the compressor/decompressor will\n" -" return to no prefix state.\n" +"1. Prefix is compatible with long distance matching, while\n" +" dictionary is not.\n" +"2. It only works for the first frame, then the\n" +" compressor/decompressor will return to no prefix state.\n" "3. When decompressing, must use the same prefix as when compressing."); #if defined(_zstd_ZstdDict_as_prefix_DOCSTR) # undef _zstd_ZstdDict_as_prefix_DOCSTR @@ -222,4 +224,4 @@ _zstd_ZstdDict_as_prefix_get(PyObject *self, void *Py_UNUSED(context)) { return _zstd_ZstdDict_as_prefix_get_impl((ZstdDict *)self); } -/*[clinic end generated code: output=f41d9e2e2cc2928f input=a9049054013a1b77]*/ +/*[clinic end generated code: output=49b66061b4fcdb5f input=a9049054013a1b77]*/ diff --git a/Modules/_zstd/compressor.c b/Modules/_zstd/compressor.c index 8a3cd182ab1516..b2eb22d9ec8add 100644 --- a/Modules/_zstd/compressor.c +++ b/Modules/_zstd/compressor.c @@ -332,14 +332,14 @@ _zstd.ZstdCompressor.__new__ as _zstd_ZstdCompressor_new Create a compressor object for compressing data incrementally. -Thread-safe at method level. For one-shot compression, use the compress() -function instead. +Thread-safe at method level. For one-shot compression, use the +compress() function instead. [clinic start generated code]*/ static PyObject * _zstd_ZstdCompressor_new_impl(PyTypeObject *type, PyObject *level, PyObject *options, PyObject *zstd_dict) -/*[clinic end generated code: output=cdef61eafecac3d7 input=92de0211ae20ffdc]*/ +/*[clinic end generated code: output=cdef61eafecac3d7 input=bbfeeaa06fd3bd4d]*/ { ZstdCompressor* self = PyObject_GC_New(ZstdCompressor, type); if (self == NULL) { @@ -583,7 +583,6 @@ compress_mt_continue_lock_held(ZstdCompressor *self, Py_buffer *data) } /*[clinic input] -@permit_long_docstring_body _zstd.ZstdCompressor.compress data: Py_buffer @@ -593,15 +592,15 @@ _zstd.ZstdCompressor.compress Provide data to the compressor object. -Return a chunk of compressed data if possible, or b'' otherwise. When you have -finished providing data to the compressor, call the flush() method to finish -the compression process. +Return a chunk of compressed data if possible, or b'' otherwise. +When you have finished providing data to the compressor, call the +flush() method to finish the compression process. [clinic start generated code]*/ static PyObject * _zstd_ZstdCompressor_compress_impl(ZstdCompressor *self, Py_buffer *data, int mode) -/*[clinic end generated code: output=ed7982d1cf7b4f98 input=6018ed6cc729cea6]*/ +/*[clinic end generated code: output=ed7982d1cf7b4f98 input=11726dff64d7b2f9]*/ { PyObject *ret; @@ -643,7 +642,6 @@ _zstd_ZstdCompressor_compress_impl(ZstdCompressor *self, Py_buffer *data, } /*[clinic input] -@permit_long_docstring_body _zstd.ZstdCompressor.flush mode: int(c_default="ZSTD_e_end") = ZstdCompressor.FLUSH_FRAME @@ -652,14 +650,14 @@ _zstd.ZstdCompressor.flush Finish the compression process. -Flush any remaining data left in internal buffers. Since Zstandard data -consists of one or more independent frames, the compressor object can still -be used after this method is called. +Flush any remaining data left in internal buffers. Since Zstandard +data consists of one or more independent frames, the compressor +object can still be used after this method is called. [clinic start generated code]*/ static PyObject * _zstd_ZstdCompressor_flush_impl(ZstdCompressor *self, int mode) -/*[clinic end generated code: output=b7cf2c8d64dcf2e3 input=a9871ec742d79003]*/ +/*[clinic end generated code: output=b7cf2c8d64dcf2e3 input=130e0b1eddf0f498]*/ { PyObject *ret; @@ -693,7 +691,7 @@ _zstd_ZstdCompressor_flush_impl(ZstdCompressor *self, int mode) /*[clinic input] -@permit_long_docstring_body +@permit_long_summary _zstd.ZstdCompressor.set_pledged_input_size size: zstd_contentsize @@ -702,19 +700,20 @@ _zstd.ZstdCompressor.set_pledged_input_size Set the uncompressed content size to be written into the frame header. -This method can be used to ensure the header of the frame about to be written -includes the size of the data, unless the CompressionParameter.content_size_flag -is set to False. If last_mode != FLUSH_FRAME, then a RuntimeError is raised. +This method can be used to ensure the header of the frame about to +be written includes the size of the data, unless the +CompressionParameter.content_size_flag is set to False. +If last_mode != FLUSH_FRAME, then a RuntimeError is raised. -It is important to ensure that the pledged data size matches the actual data -size. If they do not match the compressed output data may be corrupted and the -final chunk written may be lost. +It is important to ensure that the pledged data size matches the +actual data size. If they do not match the compressed output data +may be corrupted and the final chunk written may be lost. [clinic start generated code]*/ static PyObject * _zstd_ZstdCompressor_set_pledged_input_size_impl(ZstdCompressor *self, unsigned long long size) -/*[clinic end generated code: output=3a09e55cc0e3b4f9 input=b4c87bcbd5ce6111]*/ +/*[clinic end generated code: output=3a09e55cc0e3b4f9 input=714cd7a9aa10e2a8]*/ { // Error occurred while converting argument, should be unreachable assert(size != ZSTD_CONTENTSIZE_ERROR); diff --git a/Modules/_zstd/decompressor.c b/Modules/_zstd/decompressor.c index 46682b483ad06a..cb95ba89eb650a 100644 --- a/Modules/_zstd/decompressor.c +++ b/Modules/_zstd/decompressor.c @@ -469,7 +469,6 @@ stream_decompress_lock_held(ZstdDecompressor *self, Py_buffer *data, /*[clinic input] -@permit_long_docstring_body @classmethod _zstd.ZstdDecompressor.__new__ as _zstd_ZstdDecompressor_new zstd_dict: object = None @@ -479,14 +478,14 @@ _zstd.ZstdDecompressor.__new__ as _zstd_ZstdDecompressor_new Create a decompressor object for decompressing data incrementally. -Thread-safe at method level. For one-shot decompression, use the decompress() -function instead. +Thread-safe at method level. For one-shot decompression, use the +decompress() function instead. [clinic start generated code]*/ static PyObject * _zstd_ZstdDecompressor_new_impl(PyTypeObject *type, PyObject *zstd_dict, PyObject *options) -/*[clinic end generated code: output=590ca65c1102ff4a input=ed8891edfd14cdaa]*/ +/*[clinic end generated code: output=590ca65c1102ff4a input=73879de69bf89f59]*/ { ZstdDecompressor* self = PyObject_GC_New(ZstdDecompressor, type); if (self == NULL) { @@ -571,19 +570,19 @@ ZstdDecompressor_dealloc(PyObject *ob) } /*[clinic input] -@permit_long_docstring_body @getter _zstd.ZstdDecompressor.unused_data A bytes object of un-consumed input data. When ZstdDecompressor object stops after a frame is -decompressed, unused input data after the frame. Otherwise this will be b''. +decompressed, unused input data after the frame. Otherwise this +will be b''. [clinic start generated code]*/ static PyObject * _zstd_ZstdDecompressor_unused_data_get_impl(ZstdDecompressor *self) -/*[clinic end generated code: output=f3a20940f11b6b09 input=37c2c531ab56f914]*/ +/*[clinic end generated code: output=f3a20940f11b6b09 input=0462065c5e60ba01]*/ { PyObject *ret; @@ -613,7 +612,6 @@ _zstd_ZstdDecompressor_unused_data_get_impl(ZstdDecompressor *self) /*[clinic input] @permit_long_summary -@permit_long_docstring_body _zstd.ZstdDecompressor.decompress data: Py_buffer @@ -625,25 +623,26 @@ _zstd.ZstdDecompressor.decompress Decompress *data*, returning uncompressed bytes if possible, or b'' otherwise. -If *max_length* is nonnegative, returns at most *max_length* bytes of -decompressed data. If this limit is reached and further output can be -produced, *self.needs_input* will be set to ``False``. In this case, the next -call to *decompress()* may provide *data* as b'' to obtain more of the output. +If *max_length* is nonnegative, returns at most *max_length* bytes +of decompressed data. If this limit is reached and further output +can be produced, *self.needs_input* will be set to ``False``. In +this case, the next call to *decompress()* may provide *data* as b'' +to obtain more of the output. -If all of the input data was decompressed and returned (either because this -was less than *max_length* bytes, or because *max_length* was negative), -*self.needs_input* will be set to True. +If all of the input data was decompressed and returned (either +because this was less than *max_length* bytes, or because +*max_length* was negative), *self.needs_input* will be set to True. -Attempting to decompress data after the end of a frame is reached raises an -EOFError. Any data found after the end of the frame is ignored and saved in -the self.unused_data attribute. +Attempting to decompress data after the end of a frame is reached +raises an EOFError. Any data found after the end of the frame is +ignored and saved in the self.unused_data attribute. [clinic start generated code]*/ static PyObject * _zstd_ZstdDecompressor_decompress_impl(ZstdDecompressor *self, Py_buffer *data, Py_ssize_t max_length) -/*[clinic end generated code: output=a4302b3c940dbec6 input=e5c905a774df1553]*/ +/*[clinic end generated code: output=a4302b3c940dbec6 input=4ddda5a0bdd00673]*/ { PyObject *ret; /* Thread-safe code */ diff --git a/Modules/_zstd/zstddict.c b/Modules/_zstd/zstddict.c index b0bfbdc886e04f..e1b9d998e697fb 100644 --- a/Modules/_zstd/zstddict.c +++ b/Modules/_zstd/zstddict.c @@ -23,7 +23,6 @@ class _zstd.ZstdDict "ZstdDict *" "&zstd_dict_type_spec" #define ZstdDict_CAST(op) ((ZstdDict *)op) /*[clinic input] -@permit_long_docstring_body @classmethod _zstd.ZstdDict.__new__ as _zstd_ZstdDict_new dict_content: Py_buffer @@ -37,14 +36,14 @@ _zstd.ZstdDict.__new__ as _zstd_ZstdDict_new Represents a Zstandard dictionary. -The dictionary can be used for compression or decompression, and can be shared -by multiple ZstdCompressor or ZstdDecompressor objects. +The dictionary can be used for compression or decompression, and can be +shared by multiple ZstdCompressor or ZstdDecompressor objects. [clinic start generated code]*/ static PyObject * _zstd_ZstdDict_new_impl(PyTypeObject *type, Py_buffer *dict_content, int is_raw) -/*[clinic end generated code: output=685b7406a48b0949 input=b132ee40b784c293]*/ +/*[clinic end generated code: output=685b7406a48b0949 input=3bb66063c0240433]*/ { /* All dictionaries must be at least 8 bytes */ if (dict_content->len < 8) { @@ -154,7 +153,6 @@ _zstd_ZstdDict_dict_content_get_impl(ZstdDict *self) } /*[clinic input] -@permit_long_docstring_body @getter _zstd.ZstdDict.as_digested_dict @@ -163,23 +161,22 @@ Load as a digested dictionary to compressor. Pass this attribute as zstd_dict argument: compress(dat, zstd_dict=zd.as_digested_dict) -1. Some advanced compression parameters of compressor may be overridden - by parameters of digested dictionary. -2. ZstdDict has a digested dictionaries cache for each compression level. - It's faster when loading again a digested dictionary with the same - compression level. +1. Some advanced compression parameters of compressor may be + overridden by parameters of digested dictionary. +2. ZstdDict has a digested dictionaries cache for each compression + level. It's faster when loading again a digested dictionary with + the same compression level. 3. No need to use this for decompression. [clinic start generated code]*/ static PyObject * _zstd_ZstdDict_as_digested_dict_get_impl(ZstdDict *self) -/*[clinic end generated code: output=09b086e7a7320dbb input=8d01ff0b8b043f2e]*/ +/*[clinic end generated code: output=09b086e7a7320dbb input=a9417d40f1d7fedd]*/ { return Py_BuildValue("Oi", self, DICT_TYPE_DIGESTED); } /*[clinic input] -@permit_long_docstring_body @getter _zstd.ZstdDict.as_undigested_dict @@ -188,21 +185,21 @@ Load as an undigested dictionary to compressor. Pass this attribute as zstd_dict argument: compress(dat, zstd_dict=zd.as_undigested_dict) -1. The advanced compression parameters of compressor will not be overridden. -2. Loading an undigested dictionary is costly. If load an undigested dictionary - multiple times, consider reusing a compressor object. +1. The advanced compression parameters of compressor will not be + overridden. +2. Loading an undigested dictionary is costly. If load an undigested + dictionary multiple times, consider reusing a compressor object. 3. No need to use this for decompression. [clinic start generated code]*/ static PyObject * _zstd_ZstdDict_as_undigested_dict_get_impl(ZstdDict *self) -/*[clinic end generated code: output=43c7a989e6d4253a input=b1bdb306c3798ad4]*/ +/*[clinic end generated code: output=43c7a989e6d4253a input=56443c9c4e589cd5]*/ { return Py_BuildValue("Oi", self, DICT_TYPE_UNDIGESTED); } /*[clinic input] -@permit_long_docstring_body @getter _zstd.ZstdDict.as_prefix @@ -211,15 +208,16 @@ Load as a prefix to compressor/decompressor. Pass this attribute as zstd_dict argument: compress(dat, zstd_dict=zd.as_prefix) -1. Prefix is compatible with long distance matching, while dictionary is not. -2. It only works for the first frame, then the compressor/decompressor will - return to no prefix state. +1. Prefix is compatible with long distance matching, while + dictionary is not. +2. It only works for the first frame, then the + compressor/decompressor will return to no prefix state. 3. When decompressing, must use the same prefix as when compressing. [clinic start generated code]*/ static PyObject * _zstd_ZstdDict_as_prefix_get_impl(ZstdDict *self) -/*[clinic end generated code: output=6f7130c356595a16 input=77966c012d15e6ab]*/ +/*[clinic end generated code: output=6f7130c356595a16 input=192681a899c6fad0]*/ { return Py_BuildValue("Oi", self, DICT_TYPE_PREFIX); } From ef89cf56cc1150b2078ab4467813a378e31b9743 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 24 May 2026 15:24:57 +0200 Subject: [PATCH 130/818] [3.15] gh-150285: Fix too long docstrings in builtins (GH-150293) (GH-150336) (cherry picked from commit e1e06be11908ddb6935e8df35f972879dd1bc3d8) Co-authored-by: Serhiy Storchaka --- Objects/bytearrayobject.c | 98 ++++++------ Objects/bytes_methods.c | 4 +- Objects/bytesobject.c | 105 +++++++------ Objects/clinic/bytearrayobject.c.h | 73 +++++---- Objects/clinic/bytesobject.c.h | 75 ++++----- Objects/clinic/codeobject.c.h | 5 +- Objects/clinic/floatobject.c.h | 6 +- Objects/clinic/listobject.c.h | 10 +- Objects/clinic/longobject.c.h | 45 +++--- Objects/clinic/memoryobject.c.h | 17 +- Objects/clinic/odictobject.c.h | 5 +- Objects/clinic/unicodeobject.c.h | 162 +++++++++---------- Objects/codeobject.c | 5 +- Objects/dictobject.c | 3 +- Objects/floatobject.c | 7 +- Objects/frameobject.c | 3 +- Objects/listobject.c | 11 +- Objects/longobject.c | 53 ++++--- Objects/memoryobject.c | 20 +-- Objects/odictobject.c | 5 +- Objects/setobject.c | 6 +- Objects/sliceobject.c | 4 +- Objects/typeobject.c | 3 +- Objects/unicodeobject.c | 239 ++++++++++++++--------------- Python/bltinmodule.c | 139 +++++++++-------- Python/clinic/bltinmodule.c.h | 63 ++++---- 26 files changed, 613 insertions(+), 553 deletions(-) diff --git a/Objects/bytearrayobject.c b/Objects/bytearrayobject.c index c583193b5a252c..ca7956579e80bb 100644 --- a/Objects/bytearrayobject.c +++ b/Objects/bytearrayobject.c @@ -1620,6 +1620,7 @@ bytearray_take_bytes_impl(PyByteArrayObject *self, PyObject *n) /*[clinic input] +@permit_long_summary @critical_section bytearray.translate @@ -1630,14 +1631,15 @@ bytearray.translate Return a copy with each character mapped by the given translation table. -All characters occurring in the optional argument delete are removed. -The remaining characters are mapped through the given translation table. +All characters occurring in the optional argument delete are +removed. The remaining characters are mapped through the given +translation table. [clinic start generated code]*/ static PyObject * bytearray_translate_impl(PyByteArrayObject *self, PyObject *table, PyObject *deletechars) -/*[clinic end generated code: output=b6a8f01c2a74e446 input=cd6fa93ca04e05bc]*/ +/*[clinic end generated code: output=b6a8f01c2a74e446 input=e30d2ae004365ed9]*/ { char *input, *output; const char *table_chars; @@ -1727,7 +1729,6 @@ bytearray_translate_impl(PyByteArrayObject *self, PyObject *table, /*[clinic input] @permit_long_summary -@permit_long_docstring_body @staticmethod bytearray.maketrans @@ -1737,15 +1738,15 @@ bytearray.maketrans Return a translation table usable for the bytes or bytearray translate method. -The returned table will be one where each byte in frm is mapped to the byte at -the same position in to. +The returned table will be one where each byte in frm is mapped to +the byte at the same position in to. The bytes objects frm and to must be of the same length. [clinic start generated code]*/ static PyObject * bytearray_maketrans_impl(Py_buffer *frm, Py_buffer *to) -/*[clinic end generated code: output=1df267d99f56b15e input=1146b43a592eca13]*/ +/*[clinic end generated code: output=1df267d99f56b15e input=c2f5f6e7e6b0221d]*/ { return _Py_bytes_maketrans(frm, to); } @@ -1785,8 +1786,8 @@ bytearray.split sep: object = None The delimiter according which to split the bytearray. - None (the default value) means split on ASCII whitespace characters - (space, tab, return, newline, formfeed, vertical tab). + None (the default value) means split on ASCII whitespace + characters (space, tab, return, newline, formfeed, vertical tab). maxsplit: Py_ssize_t = -1 Maximum number of splits to do. -1 (the default value) means no limit. @@ -1797,7 +1798,7 @@ Return a list of the sections in the bytearray, using sep as the delimiter. static PyObject * bytearray_split_impl(PyByteArrayObject *self, PyObject *sep, Py_ssize_t maxsplit) -/*[clinic end generated code: output=833e2cf385d9a04d input=dd9f6e2910cc3a34]*/ +/*[clinic end generated code: output=833e2cf385d9a04d input=45605178023b52ac]*/ { PyObject *list = NULL; @@ -1829,7 +1830,6 @@ bytearray_split_impl(PyByteArrayObject *self, PyObject *sep, } /*[clinic input] -@permit_long_docstring_body @critical_section bytearray.partition @@ -1838,17 +1838,18 @@ bytearray.partition Partition the bytearray into three parts using the given separator. -This will search for the separator sep in the bytearray. If the separator is -found, returns a 3-tuple containing the part before the separator, the -separator itself, and the part after it as new bytearray objects. +This will search for the separator sep in the bytearray. If the +separator is found, returns a 3-tuple containing the part before the +separator, the separator itself, and the part after it as new +bytearray objects. -If the separator is not found, returns a 3-tuple containing the copy of the -original bytearray object and two empty bytearray objects. +If the separator is not found, returns a 3-tuple containing the copy +of the original bytearray object and two empty bytearray objects. [clinic start generated code]*/ static PyObject * bytearray_partition_impl(PyByteArrayObject *self, PyObject *sep) -/*[clinic end generated code: output=b5fa1e03f10cfccb input=b87276af883f39d9]*/ +/*[clinic end generated code: output=b5fa1e03f10cfccb input=d76673ed03acf5dd]*/ { PyObject *bytesep, *result; @@ -1868,7 +1869,6 @@ bytearray_partition_impl(PyByteArrayObject *self, PyObject *sep) } /*[clinic input] -@permit_long_docstring_body @critical_section bytearray.rpartition @@ -1877,18 +1877,19 @@ bytearray.rpartition Partition the bytearray into three parts using the given separator. -This will search for the separator sep in the bytearray, starting at the end. -If the separator is found, returns a 3-tuple containing the part before the -separator, the separator itself, and the part after it as new bytearray -objects. +This will search for the separator sep in the bytearray, starting at +the end. If the separator is found, returns a 3-tuple containing +the part before the separator, the separator itself, and the part +after it as new bytearray objects. -If the separator is not found, returns a 3-tuple containing two empty bytearray -objects and the copy of the original bytearray object. +If the separator is not found, returns a 3-tuple containing two +empty bytearray objects and the copy of the original bytearray +object. [clinic start generated code]*/ static PyObject * bytearray_rpartition_impl(PyByteArrayObject *self, PyObject *sep) -/*[clinic end generated code: output=0186ce7b1ef61289 input=5bdcfc4c333bcfab]*/ +/*[clinic end generated code: output=0186ce7b1ef61289 input=b9216a2074174a36]*/ { PyObject *bytesep, *result; @@ -1909,19 +1910,19 @@ bytearray_rpartition_impl(PyByteArrayObject *self, PyObject *sep) /*[clinic input] @permit_long_summary -@permit_long_docstring_body @critical_section bytearray.rsplit = bytearray.split Return a list of the sections in the bytearray, using sep as the delimiter. -Splitting is done starting at the end of the bytearray and working to the front. +Splitting is done starting at the end of the bytearray and working +to the front. [clinic start generated code]*/ static PyObject * bytearray_rsplit_impl(PyByteArrayObject *self, PyObject *sep, Py_ssize_t maxsplit) -/*[clinic end generated code: output=a55e0b5a03cb6190 input=60e9abf305128ff4]*/ +/*[clinic end generated code: output=a55e0b5a03cb6190 input=e201671c9a0c19ee]*/ { PyObject *list = NULL; @@ -2392,7 +2393,6 @@ bytearray_strip_impl_helper(PyByteArrayObject* self, PyObject* bytes, int stript } /*[clinic input] -@permit_long_docstring_body @critical_section bytearray.strip @@ -2401,12 +2401,13 @@ bytearray.strip Strip leading and trailing bytes contained in the argument. -If the argument is omitted or None, strip leading and trailing ASCII whitespace. +If the argument is omitted or None, strip leading and trailing ASCII +whitespace. [clinic start generated code]*/ static PyObject * bytearray_strip_impl(PyByteArrayObject *self, PyObject *bytes) -/*[clinic end generated code: output=760412661a34ad5a input=6acaf88b2ec9daa7]*/ +/*[clinic end generated code: output=760412661a34ad5a input=f4ec5fa609df7d14]*/ { return bytearray_strip_impl_helper(self, bytes, BOTHSTRIP); } @@ -2506,11 +2507,11 @@ bytearray.decode encoding: str(c_default="NULL") = 'utf-8' The encoding with which to decode the bytearray. errors: str(c_default="NULL") = 'strict' - The error handling scheme to use for the handling of decoding errors. - The default is 'strict' meaning that decoding errors raise a - UnicodeDecodeError. Other possible values are 'ignore' and 'replace' - as well as any other name registered with codecs.register_error that - can handle UnicodeDecodeErrors. + The error handling scheme to use for the handling of decoding + errors. The default is 'strict' meaning that decoding errors + raise a UnicodeDecodeError. Other possible values are 'ignore' + and 'replace' as well as any other name registered with + codecs.register_error that can handle UnicodeDecodeErrors. Decode the bytearray using the codec registered for encoding. [clinic start generated code]*/ @@ -2518,7 +2519,7 @@ Decode the bytearray using the codec registered for encoding. static PyObject * bytearray_decode_impl(PyByteArrayObject *self, const char *encoding, const char *errors) -/*[clinic end generated code: output=f57d43f4a00b42c5 input=86c303ee376b8453]*/ +/*[clinic end generated code: output=f57d43f4a00b42c5 input=e51ce9b82b51e2ca]*/ { if (encoding == NULL) encoding = PyUnicode_GetDefaultEncoding(); @@ -2550,14 +2551,15 @@ bytearray.join Concatenate any number of bytes/bytearray objects. -The bytearray whose method is called is inserted in between each pair. +The bytearray whose method is called is inserted in between each +pair. The result is returned as a new bytearray object. [clinic start generated code]*/ static PyObject * bytearray_join_impl(PyByteArrayObject *self, PyObject *iterable_of_bytes) -/*[clinic end generated code: output=0ced382b5846a7ee input=49627e07ca31ca26]*/ +/*[clinic end generated code: output=0ced382b5846a7ee input=0a31db349efcd7fa]*/ { PyObject *ret; self->ob_exports++; // this protects `self` from being cleared/resized if `iterable_of_bytes` is a custom iterator @@ -2588,7 +2590,6 @@ bytearray_rjust(PyObject *self, PyObject *const *args, Py_ssize_t nargs) /*[clinic input] @permit_long_summary -@permit_long_docstring_body @critical_section bytearray.splitlines @@ -2596,13 +2597,13 @@ bytearray.splitlines Return a list of the lines in the bytearray, breaking at line boundaries. -Line breaks are not included in the resulting list unless keepends is given and -true. +Line breaks are not included in the resulting list unless keepends +is given and true. [clinic start generated code]*/ static PyObject * bytearray_splitlines_impl(PyByteArrayObject *self, int keepends) -/*[clinic end generated code: output=4223c94b895f6ad9 input=21bc3f02bf1be832]*/ +/*[clinic end generated code: output=4223c94b895f6ad9 input=cc2bb740eed19f27]*/ { return stringlib_splitlines( (PyObject*) self, PyByteArray_AS_STRING(self), @@ -2620,12 +2621,13 @@ bytearray.fromhex Create a bytearray object from a string of hexadecimal numbers. Spaces between two numbers are accepted. -Example: bytearray.fromhex('B9 01EF') -> bytearray(b'\\xb9\\x01\\xef') +Example: + bytearray.fromhex('B9 01EF') -> bytearray(b'\\xb9\\x01\\xef') [clinic start generated code]*/ static PyObject * bytearray_fromhex_impl(PyTypeObject *type, PyObject *string) -/*[clinic end generated code: output=8f0f0b6d30fb3ba0 input=7e314e5b2d7ab484]*/ +/*[clinic end generated code: output=8f0f0b6d30fb3ba0 input=2243a8b0b9e66cd5]*/ { PyObject *result = _PyBytes_FromHex(string, type == &PyByteArray_Type); if (type != &PyByteArray_Type && result != NULL) { @@ -2641,8 +2643,8 @@ bytearray.hex sep: object = NULL An optional single character or byte to separate hex bytes. bytes_per_sep: Py_ssize_t = 1 - How many bytes between separators. Positive values count from the - right, negative values count from the left. + How many bytes between separators. Positive values count from + the right, negative values count from the left. Create a string of hexadecimal numbers from a bytearray object. @@ -2661,7 +2663,7 @@ Create a string of hexadecimal numbers from a bytearray object. static PyObject * bytearray_hex_impl(PyByteArrayObject *self, PyObject *sep, Py_ssize_t bytes_per_sep) -/*[clinic end generated code: output=c9563921aff1262b input=d2b23ef057cfcad5]*/ +/*[clinic end generated code: output=c9563921aff1262b input=9ed746203691e894]*/ { char* argbuf = PyByteArray_AS_STRING(self); Py_ssize_t arglen = PyByteArray_GET_SIZE(self); diff --git a/Objects/bytes_methods.c b/Objects/bytes_methods.c index 56a461d0dd08a7..414afeb7bb003c 100644 --- a/Objects/bytes_methods.c +++ b/Objects/bytes_methods.c @@ -277,8 +277,8 @@ _Py_bytes_upper(char *result, const char *cptr, Py_ssize_t len) PyDoc_STRVAR_shared(_Py_title__doc__, "B.title() -> copy of B\n\ \n\ -Return a titlecased version of B, i.e. ASCII words start with uppercase\n\ -characters, all remaining cased characters have lowercase."); +Return a titlecased version of B, i.e. ASCII words start with\n\ +uppercase characters, all remaining cased characters have lowercase."); void _Py_bytes_title(char *result, const char *s, Py_ssize_t len) diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c index 2d694922557429..1135770549c017 100644 --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -1849,12 +1849,13 @@ bytes___bytes___impl(PyBytesObject *self) #define BOTHSTRIP 2 /*[clinic input] +@permit_long_summary bytes.split sep: object = None The delimiter according which to split the bytes. - None (the default value) means split on ASCII whitespace characters - (space, tab, return, newline, formfeed, vertical tab). + None (the default value) means split on ASCII whitespace + characters (space, tab, return, newline, formfeed, vertical tab). maxsplit: Py_ssize_t = -1 Maximum number of splits to do. -1 (the default value) means no limit. @@ -1864,7 +1865,7 @@ Return a list of the sections in the bytes, using sep as the delimiter. static PyObject * bytes_split_impl(PyBytesObject *self, PyObject *sep, Py_ssize_t maxsplit) -/*[clinic end generated code: output=52126b5844c1d8ef input=8b809b39074abbfa]*/ +/*[clinic end generated code: output=52126b5844c1d8ef input=330ff95d92544b05]*/ { Py_ssize_t len = PyBytes_GET_SIZE(self), n; const char *s = PyBytes_AS_STRING(self), *sub; @@ -1886,7 +1887,6 @@ bytes_split_impl(PyBytesObject *self, PyObject *sep, Py_ssize_t maxsplit) } /*[clinic input] -@permit_long_docstring_body bytes.partition sep: Py_buffer @@ -1894,17 +1894,17 @@ bytes.partition Partition the bytes into three parts using the given separator. -This will search for the separator sep in the bytes. If the separator is found, -returns a 3-tuple containing the part before the separator, the separator -itself, and the part after it. +This will search for the separator sep in the bytes. If the +separator is found, returns a 3-tuple containing the part before the +separator, the separator itself, and the part after it. -If the separator is not found, returns a 3-tuple containing the original bytes -object and two empty bytes objects. +If the separator is not found, returns a 3-tuple containing the +original bytes object and two empty bytes objects. [clinic start generated code]*/ static PyObject * bytes_partition_impl(PyBytesObject *self, Py_buffer *sep) -/*[clinic end generated code: output=f532b392a17ff695 input=31c55a0cebaf7722]*/ +/*[clinic end generated code: output=f532b392a17ff695 input=2e6e551ea4f8b95a]*/ { return stringlib_partition( (PyObject*) self, @@ -1914,7 +1914,6 @@ bytes_partition_impl(PyBytesObject *self, Py_buffer *sep) } /*[clinic input] -@permit_long_docstring_body bytes.rpartition sep: Py_buffer @@ -1922,17 +1921,18 @@ bytes.rpartition Partition the bytes into three parts using the given separator. -This will search for the separator sep in the bytes, starting at the end. If -the separator is found, returns a 3-tuple containing the part before the -separator, the separator itself, and the part after it. +This will search for the separator sep in the bytes, starting at the +end. If the separator is found, returns a 3-tuple containing the +part before the separator, the separator itself, and the part after +it. -If the separator is not found, returns a 3-tuple containing two empty bytes -objects and the original bytes object. +If the separator is not found, returns a 3-tuple containing two +empty bytes objects and the original bytes object. [clinic start generated code]*/ static PyObject * bytes_rpartition_impl(PyBytesObject *self, Py_buffer *sep) -/*[clinic end generated code: output=191b114cbb028e50 input=9ea5a3ab0b02bf52]*/ +/*[clinic end generated code: output=191b114cbb028e50 input=f7d24f722a5470a4]*/ { return stringlib_rpartition( (PyObject*) self, @@ -1942,17 +1942,18 @@ bytes_rpartition_impl(PyBytesObject *self, Py_buffer *sep) } /*[clinic input] -@permit_long_docstring_body +@permit_long_summary bytes.rsplit = bytes.split Return a list of the sections in the bytes, using sep as the delimiter. -Splitting is done starting at the end of the bytes and working to the front. +Splitting is done starting at the end of the bytes and working to +the front. [clinic start generated code]*/ static PyObject * bytes_rsplit_impl(PyBytesObject *self, PyObject *sep, Py_ssize_t maxsplit) -/*[clinic end generated code: output=ba698d9ea01e1c8f input=55b6eaea1f3d7046]*/ +/*[clinic end generated code: output=ba698d9ea01e1c8f input=ba9bee56285f43e4]*/ { Py_ssize_t len = PyBytes_GET_SIZE(self), n; const char *s = PyBytes_AS_STRING(self), *sub; @@ -2172,7 +2173,6 @@ do_argstrip(PyBytesObject *self, int striptype, PyObject *bytes) } /*[clinic input] -@permit_long_docstring_body bytes.strip bytes: object = None @@ -2180,12 +2180,13 @@ bytes.strip Strip leading and trailing bytes contained in the argument. -If the argument is omitted or None, strip leading and trailing ASCII whitespace. +If the argument is omitted or None, strip leading and trailing ASCII +whitespace. [clinic start generated code]*/ static PyObject * bytes_strip_impl(PyBytesObject *self, PyObject *bytes) -/*[clinic end generated code: output=c7c228d3bd104a1b input=71904cd278c0ee03]*/ +/*[clinic end generated code: output=c7c228d3bd104a1b input=9ffea5f752032bd0]*/ { return do_argstrip(self, BOTHSTRIP, bytes); } @@ -2245,6 +2246,7 @@ bytes_count_impl(PyBytesObject *self, PyObject *sub, Py_ssize_t start, /*[clinic input] +@permit_long_summary bytes.translate table: object @@ -2254,14 +2256,15 @@ bytes.translate Return a copy with each character mapped by the given translation table. -All characters occurring in the optional argument delete are removed. -The remaining characters are mapped through the given translation table. +All characters occurring in the optional argument delete are +removed. The remaining characters are mapped through the given +translation table. [clinic start generated code]*/ static PyObject * bytes_translate_impl(PyBytesObject *self, PyObject *table, PyObject *deletechars) -/*[clinic end generated code: output=43be3437f1956211 input=0ecdf159f654233c]*/ +/*[clinic end generated code: output=43be3437f1956211 input=bddcdef0a87895d2]*/ { const char *input; char *output; @@ -2379,7 +2382,6 @@ bytes_translate_impl(PyBytesObject *self, PyObject *table, /*[clinic input] @permit_long_summary -@permit_long_docstring_body @staticmethod bytes.maketrans @@ -2389,15 +2391,15 @@ bytes.maketrans Return a translation table usable for the bytes or bytearray translate method. -The returned table will be one where each byte in frm is mapped to the byte at -the same position in to. +The returned table will be one where each byte in frm is mapped to +the byte at the same position in to. The bytes objects frm and to must be of the same length. [clinic start generated code]*/ static PyObject * bytes_maketrans_impl(Py_buffer *frm, Py_buffer *to) -/*[clinic end generated code: output=a36f6399d4b77f6f input=a06b75f44d933fb3]*/ +/*[clinic end generated code: output=a36f6399d4b77f6f input=3a577e5badfea8f7]*/ { return _Py_bytes_maketrans(frm, to); } @@ -2432,6 +2434,7 @@ bytes_replace_impl(PyBytesObject *self, Py_buffer *old, Py_buffer *new, /** End DALKE **/ /*[clinic input] +@permit_long_summary bytes.removeprefix as bytes_removeprefix prefix: Py_buffer @@ -2439,13 +2442,14 @@ bytes.removeprefix as bytes_removeprefix Return a bytes object with the given prefix string removed if present. -If the bytes starts with the prefix string, return bytes[len(prefix):]. -Otherwise, return a copy of the original bytes. +If the bytes starts with the prefix string, return +bytes[len(prefix):]. Otherwise, return a copy of the original +bytes. [clinic start generated code]*/ static PyObject * bytes_removeprefix_impl(PyBytesObject *self, Py_buffer *prefix) -/*[clinic end generated code: output=f006865331a06ab6 input=0c93bac817a8502c]*/ +/*[clinic end generated code: output=f006865331a06ab6 input=3a2672bcee61d7a7]*/ { const char *self_start = PyBytes_AS_STRING(self); Py_ssize_t self_len = PyBytes_GET_SIZE(self); @@ -2468,6 +2472,7 @@ bytes_removeprefix_impl(PyBytesObject *self, Py_buffer *prefix) } /*[clinic input] +@permit_long_summary bytes.removesuffix as bytes_removesuffix suffix: Py_buffer @@ -2475,14 +2480,14 @@ bytes.removesuffix as bytes_removesuffix Return a bytes object with the given suffix string removed if present. -If the bytes ends with the suffix string and that suffix is not empty, -return bytes[:-len(prefix)]. Otherwise, return a copy of the original -bytes. +If the bytes ends with the suffix string and that suffix is not +empty, return bytes[:-len(prefix)]. Otherwise, return a copy of the +original bytes. [clinic start generated code]*/ static PyObject * bytes_removesuffix_impl(PyBytesObject *self, Py_buffer *suffix) -/*[clinic end generated code: output=d887d308e3242eeb input=9f4e1da8c637bbf1]*/ +/*[clinic end generated code: output=d887d308e3242eeb input=04df5f18a36f69d7]*/ { const char *self_start = PyBytes_AS_STRING(self); Py_ssize_t self_len = PyBytes_GET_SIZE(self); @@ -2562,11 +2567,11 @@ bytes.decode encoding: str(c_default="NULL") = 'utf-8' The encoding with which to decode the bytes. errors: str(c_default="NULL") = 'strict' - The error handling scheme to use for the handling of decoding errors. - The default is 'strict' meaning that decoding errors raise a - UnicodeDecodeError. Other possible values are 'ignore' and 'replace' - as well as any other name registered with codecs.register_error that - can handle UnicodeDecodeErrors. + The error handling scheme to use for the handling of decoding + errors. The default is 'strict' meaning that decoding errors + raise a UnicodeDecodeError. Other possible values are 'ignore' + and 'replace' as well as any other name registered with + codecs.register_error that can handle UnicodeDecodeErrors. Decode the bytes using the codec registered for encoding. [clinic start generated code]*/ @@ -2574,27 +2579,27 @@ Decode the bytes using the codec registered for encoding. static PyObject * bytes_decode_impl(PyBytesObject *self, const char *encoding, const char *errors) -/*[clinic end generated code: output=5649a53dde27b314 input=958174769d2a40ca]*/ +/*[clinic end generated code: output=5649a53dde27b314 input=94e9b8524f1d7f37]*/ { return PyUnicode_FromEncodedObject((PyObject*)self, encoding, errors); } /*[clinic input] -@permit_long_docstring_body +@permit_long_summary bytes.splitlines keepends: bool = False Return a list of the lines in the bytes, breaking at line boundaries. -Line breaks are not included in the resulting list unless keepends is given and -true. +Line breaks are not included in the resulting list unless keepends +is given and true. [clinic start generated code]*/ static PyObject * bytes_splitlines_impl(PyBytesObject *self, int keepends) -/*[clinic end generated code: output=3484149a5d880ffb input=d17968d2a355fe55]*/ +/*[clinic end generated code: output=3484149a5d880ffb input=8734672f34430514]*/ { return stringlib_splitlines( (PyObject*) self, PyBytes_AS_STRING(self), @@ -2745,8 +2750,8 @@ bytes.hex sep: object = NULL An optional single character or byte to separate hex bytes. bytes_per_sep: Py_ssize_t = 1 - How many bytes between separators. Positive values count from the - right, negative values count from the left. + How many bytes between separators. Positive values count from + the right, negative values count from the left. Create a string of hexadecimal numbers from a bytes object. @@ -2764,7 +2769,7 @@ Create a string of hexadecimal numbers from a bytes object. static PyObject * bytes_hex_impl(PyBytesObject *self, PyObject *sep, Py_ssize_t bytes_per_sep) -/*[clinic end generated code: output=588821f02cb9d8f5 input=bd8eceb755d8230f]*/ +/*[clinic end generated code: output=588821f02cb9d8f5 input=b8d40cf203d172dc]*/ { const char *argbuf = PyBytes_AS_STRING(self); Py_ssize_t arglen = PyBytes_GET_SIZE(self); diff --git a/Objects/clinic/bytearrayobject.c.h b/Objects/clinic/bytearrayobject.c.h index 64603adcc1124b..41ce82c05c57d9 100644 --- a/Objects/clinic/bytearrayobject.c.h +++ b/Objects/clinic/bytearrayobject.c.h @@ -679,8 +679,9 @@ PyDoc_STRVAR(bytearray_translate__doc__, " table\n" " Translation table, which must be a bytes object of length 256.\n" "\n" -"All characters occurring in the optional argument delete are removed.\n" -"The remaining characters are mapped through the given translation table."); +"All characters occurring in the optional argument delete are\n" +"removed. The remaining characters are mapped through the given\n" +"translation table."); #define BYTEARRAY_TRANSLATE_METHODDEF \ {"translate", _PyCFunction_CAST(bytearray_translate), METH_FASTCALL|METH_KEYWORDS, bytearray_translate__doc__}, @@ -750,8 +751,8 @@ PyDoc_STRVAR(bytearray_maketrans__doc__, "\n" "Return a translation table usable for the bytes or bytearray translate method.\n" "\n" -"The returned table will be one where each byte in frm is mapped to the byte at\n" -"the same position in to.\n" +"The returned table will be one where each byte in frm is mapped to\n" +"the byte at the same position in to.\n" "\n" "The bytes objects frm and to must be of the same length."); @@ -901,8 +902,8 @@ PyDoc_STRVAR(bytearray_split__doc__, "\n" " sep\n" " The delimiter according which to split the bytearray.\n" -" None (the default value) means split on ASCII whitespace characters\n" -" (space, tab, return, newline, formfeed, vertical tab).\n" +" None (the default value) means split on ASCII whitespace\n" +" characters (space, tab, return, newline, formfeed, vertical tab).\n" " maxsplit\n" " Maximum number of splits to do.\n" " -1 (the default value) means no limit."); @@ -991,12 +992,13 @@ PyDoc_STRVAR(bytearray_partition__doc__, "\n" "Partition the bytearray into three parts using the given separator.\n" "\n" -"This will search for the separator sep in the bytearray. If the separator is\n" -"found, returns a 3-tuple containing the part before the separator, the\n" -"separator itself, and the part after it as new bytearray objects.\n" +"This will search for the separator sep in the bytearray. If the\n" +"separator is found, returns a 3-tuple containing the part before the\n" +"separator, the separator itself, and the part after it as new\n" +"bytearray objects.\n" "\n" -"If the separator is not found, returns a 3-tuple containing the copy of the\n" -"original bytearray object and two empty bytearray objects."); +"If the separator is not found, returns a 3-tuple containing the copy\n" +"of the original bytearray object and two empty bytearray objects."); #define BYTEARRAY_PARTITION_METHODDEF \ {"partition", (PyCFunction)bytearray_partition, METH_O, bytearray_partition__doc__}, @@ -1022,13 +1024,14 @@ PyDoc_STRVAR(bytearray_rpartition__doc__, "\n" "Partition the bytearray into three parts using the given separator.\n" "\n" -"This will search for the separator sep in the bytearray, starting at the end.\n" -"If the separator is found, returns a 3-tuple containing the part before the\n" -"separator, the separator itself, and the part after it as new bytearray\n" -"objects.\n" +"This will search for the separator sep in the bytearray, starting at\n" +"the end. If the separator is found, returns a 3-tuple containing\n" +"the part before the separator, the separator itself, and the part\n" +"after it as new bytearray objects.\n" "\n" -"If the separator is not found, returns a 3-tuple containing two empty bytearray\n" -"objects and the copy of the original bytearray object."); +"If the separator is not found, returns a 3-tuple containing two\n" +"empty bytearray objects and the copy of the original bytearray\n" +"object."); #define BYTEARRAY_RPARTITION_METHODDEF \ {"rpartition", (PyCFunction)bytearray_rpartition, METH_O, bytearray_rpartition__doc__}, @@ -1056,13 +1059,14 @@ PyDoc_STRVAR(bytearray_rsplit__doc__, "\n" " sep\n" " The delimiter according which to split the bytearray.\n" -" None (the default value) means split on ASCII whitespace characters\n" -" (space, tab, return, newline, formfeed, vertical tab).\n" +" None (the default value) means split on ASCII whitespace\n" +" characters (space, tab, return, newline, formfeed, vertical tab).\n" " maxsplit\n" " Maximum number of splits to do.\n" " -1 (the default value) means no limit.\n" "\n" -"Splitting is done starting at the end of the bytearray and working to the front."); +"Splitting is done starting at the end of the bytearray and working\n" +"to the front."); #define BYTEARRAY_RSPLIT_METHODDEF \ {"rsplit", _PyCFunction_CAST(bytearray_rsplit), METH_FASTCALL|METH_KEYWORDS, bytearray_rsplit__doc__}, @@ -1364,7 +1368,8 @@ PyDoc_STRVAR(bytearray_strip__doc__, "\n" "Strip leading and trailing bytes contained in the argument.\n" "\n" -"If the argument is omitted or None, strip leading and trailing ASCII whitespace."); +"If the argument is omitted or None, strip leading and trailing ASCII\n" +"whitespace."); #define BYTEARRAY_STRIP_METHODDEF \ {"strip", _PyCFunction_CAST(bytearray_strip), METH_FASTCALL, bytearray_strip__doc__}, @@ -1475,11 +1480,11 @@ PyDoc_STRVAR(bytearray_decode__doc__, " encoding\n" " The encoding with which to decode the bytearray.\n" " errors\n" -" The error handling scheme to use for the handling of decoding errors.\n" -" The default is \'strict\' meaning that decoding errors raise a\n" -" UnicodeDecodeError. Other possible values are \'ignore\' and \'replace\'\n" -" as well as any other name registered with codecs.register_error that\n" -" can handle UnicodeDecodeErrors."); +" The error handling scheme to use for the handling of decoding\n" +" errors. The default is \'strict\' meaning that decoding errors\n" +" raise a UnicodeDecodeError. Other possible values are \'ignore\'\n" +" and \'replace\' as well as any other name registered with\n" +" codecs.register_error that can handle UnicodeDecodeErrors."); #define BYTEARRAY_DECODE_METHODDEF \ {"decode", _PyCFunction_CAST(bytearray_decode), METH_FASTCALL|METH_KEYWORDS, bytearray_decode__doc__}, @@ -1578,7 +1583,8 @@ PyDoc_STRVAR(bytearray_join__doc__, "\n" "Concatenate any number of bytes/bytearray objects.\n" "\n" -"The bytearray whose method is called is inserted in between each pair.\n" +"The bytearray whose method is called is inserted in between each\n" +"pair.\n" "\n" "The result is returned as a new bytearray object."); @@ -1606,8 +1612,8 @@ PyDoc_STRVAR(bytearray_splitlines__doc__, "\n" "Return a list of the lines in the bytearray, breaking at line boundaries.\n" "\n" -"Line breaks are not included in the resulting list unless keepends is given and\n" -"true."); +"Line breaks are not included in the resulting list unless keepends\n" +"is given and true."); #define BYTEARRAY_SPLITLINES_METHODDEF \ {"splitlines", _PyCFunction_CAST(bytearray_splitlines), METH_FASTCALL|METH_KEYWORDS, bytearray_splitlines__doc__}, @@ -1678,7 +1684,8 @@ PyDoc_STRVAR(bytearray_fromhex__doc__, "Create a bytearray object from a string of hexadecimal numbers.\n" "\n" "Spaces between two numbers are accepted.\n" -"Example: bytearray.fromhex(\'B9 01EF\') -> bytearray(b\'\\\\xb9\\\\x01\\\\xef\')"); +"Example:\n" +" bytearray.fromhex(\'B9 01EF\') -> bytearray(b\'\\\\xb9\\\\x01\\\\xef\')"); #define BYTEARRAY_FROMHEX_METHODDEF \ {"fromhex", (PyCFunction)bytearray_fromhex, METH_O|METH_CLASS, bytearray_fromhex__doc__}, @@ -1705,8 +1712,8 @@ PyDoc_STRVAR(bytearray_hex__doc__, " sep\n" " An optional single character or byte to separate hex bytes.\n" " bytes_per_sep\n" -" How many bytes between separators. Positive values count from the\n" -" right, negative values count from the left.\n" +" How many bytes between separators. Positive values count from\n" +" the right, negative values count from the left.\n" "\n" "Example:\n" ">>> value = bytearray([0xb9, 0x01, 0xef])\n" @@ -1875,4 +1882,4 @@ bytearray_sizeof(PyObject *self, PyObject *Py_UNUSED(ignored)) { return bytearray_sizeof_impl((PyByteArrayObject *)self); } -/*[clinic end generated code: output=2cacb323147202b9 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=6dc315d35de3e670 input=a9049054013a1b77]*/ diff --git a/Objects/clinic/bytesobject.c.h b/Objects/clinic/bytesobject.c.h index 4ff696be91b12d..ee2b737f9e63f9 100644 --- a/Objects/clinic/bytesobject.c.h +++ b/Objects/clinic/bytesobject.c.h @@ -35,8 +35,8 @@ PyDoc_STRVAR(bytes_split__doc__, "\n" " sep\n" " The delimiter according which to split the bytes.\n" -" None (the default value) means split on ASCII whitespace characters\n" -" (space, tab, return, newline, formfeed, vertical tab).\n" +" None (the default value) means split on ASCII whitespace\n" +" characters (space, tab, return, newline, formfeed, vertical tab).\n" " maxsplit\n" " Maximum number of splits to do.\n" " -1 (the default value) means no limit."); @@ -122,12 +122,12 @@ PyDoc_STRVAR(bytes_partition__doc__, "\n" "Partition the bytes into three parts using the given separator.\n" "\n" -"This will search for the separator sep in the bytes. If the separator is found,\n" -"returns a 3-tuple containing the part before the separator, the separator\n" -"itself, and the part after it.\n" +"This will search for the separator sep in the bytes. If the\n" +"separator is found, returns a 3-tuple containing the part before the\n" +"separator, the separator itself, and the part after it.\n" "\n" -"If the separator is not found, returns a 3-tuple containing the original bytes\n" -"object and two empty bytes objects."); +"If the separator is not found, returns a 3-tuple containing the\n" +"original bytes object and two empty bytes objects."); #define BYTES_PARTITION_METHODDEF \ {"partition", (PyCFunction)bytes_partition, METH_O, bytes_partition__doc__}, @@ -161,12 +161,13 @@ PyDoc_STRVAR(bytes_rpartition__doc__, "\n" "Partition the bytes into three parts using the given separator.\n" "\n" -"This will search for the separator sep in the bytes, starting at the end. If\n" -"the separator is found, returns a 3-tuple containing the part before the\n" -"separator, the separator itself, and the part after it.\n" +"This will search for the separator sep in the bytes, starting at the\n" +"end. If the separator is found, returns a 3-tuple containing the\n" +"part before the separator, the separator itself, and the part after\n" +"it.\n" "\n" -"If the separator is not found, returns a 3-tuple containing two empty bytes\n" -"objects and the original bytes object."); +"If the separator is not found, returns a 3-tuple containing two\n" +"empty bytes objects and the original bytes object."); #define BYTES_RPARTITION_METHODDEF \ {"rpartition", (PyCFunction)bytes_rpartition, METH_O, bytes_rpartition__doc__}, @@ -202,13 +203,14 @@ PyDoc_STRVAR(bytes_rsplit__doc__, "\n" " sep\n" " The delimiter according which to split the bytes.\n" -" None (the default value) means split on ASCII whitespace characters\n" -" (space, tab, return, newline, formfeed, vertical tab).\n" +" None (the default value) means split on ASCII whitespace\n" +" characters (space, tab, return, newline, formfeed, vertical tab).\n" " maxsplit\n" " Maximum number of splits to do.\n" " -1 (the default value) means no limit.\n" "\n" -"Splitting is done starting at the end of the bytes and working to the front."); +"Splitting is done starting at the end of the bytes and working to\n" +"the front."); #define BYTES_RSPLIT_METHODDEF \ {"rsplit", _PyCFunction_CAST(bytes_rsplit), METH_FASTCALL|METH_KEYWORDS, bytes_rsplit__doc__}, @@ -523,7 +525,8 @@ PyDoc_STRVAR(bytes_strip__doc__, "\n" "Strip leading and trailing bytes contained in the argument.\n" "\n" -"If the argument is omitted or None, strip leading and trailing ASCII whitespace."); +"If the argument is omitted or None, strip leading and trailing ASCII\n" +"whitespace."); #define BYTES_STRIP_METHODDEF \ {"strip", _PyCFunction_CAST(bytes_strip), METH_FASTCALL, bytes_strip__doc__}, @@ -677,8 +680,9 @@ PyDoc_STRVAR(bytes_translate__doc__, " table\n" " Translation table, which must be a bytes object of length 256.\n" "\n" -"All characters occurring in the optional argument delete are removed.\n" -"The remaining characters are mapped through the given translation table."); +"All characters occurring in the optional argument delete are\n" +"removed. The remaining characters are mapped through the given\n" +"translation table."); #define BYTES_TRANSLATE_METHODDEF \ {"translate", _PyCFunction_CAST(bytes_translate), METH_FASTCALL|METH_KEYWORDS, bytes_translate__doc__}, @@ -746,8 +750,8 @@ PyDoc_STRVAR(bytes_maketrans__doc__, "\n" "Return a translation table usable for the bytes or bytearray translate method.\n" "\n" -"The returned table will be one where each byte in frm is mapped to the byte at\n" -"the same position in to.\n" +"The returned table will be one where each byte in frm is mapped to\n" +"the byte at the same position in to.\n" "\n" "The bytes objects frm and to must be of the same length."); @@ -893,8 +897,9 @@ PyDoc_STRVAR(bytes_removeprefix__doc__, "\n" "Return a bytes object with the given prefix string removed if present.\n" "\n" -"If the bytes starts with the prefix string, return bytes[len(prefix):].\n" -"Otherwise, return a copy of the original bytes."); +"If the bytes starts with the prefix string, return\n" +"bytes[len(prefix):]. Otherwise, return a copy of the original\n" +"bytes."); #define BYTES_REMOVEPREFIX_METHODDEF \ {"removeprefix", (PyCFunction)bytes_removeprefix, METH_O, bytes_removeprefix__doc__}, @@ -928,9 +933,9 @@ PyDoc_STRVAR(bytes_removesuffix__doc__, "\n" "Return a bytes object with the given suffix string removed if present.\n" "\n" -"If the bytes ends with the suffix string and that suffix is not empty,\n" -"return bytes[:-len(prefix)]. Otherwise, return a copy of the original\n" -"bytes."); +"If the bytes ends with the suffix string and that suffix is not\n" +"empty, return bytes[:-len(prefix)]. Otherwise, return a copy of the\n" +"original bytes."); #define BYTES_REMOVESUFFIX_METHODDEF \ {"removesuffix", (PyCFunction)bytes_removesuffix, METH_O, bytes_removesuffix__doc__}, @@ -1069,11 +1074,11 @@ PyDoc_STRVAR(bytes_decode__doc__, " encoding\n" " The encoding with which to decode the bytes.\n" " errors\n" -" The error handling scheme to use for the handling of decoding errors.\n" -" The default is \'strict\' meaning that decoding errors raise a\n" -" UnicodeDecodeError. Other possible values are \'ignore\' and \'replace\'\n" -" as well as any other name registered with codecs.register_error that\n" -" can handle UnicodeDecodeErrors."); +" The error handling scheme to use for the handling of decoding\n" +" errors. The default is \'strict\' meaning that decoding errors\n" +" raise a UnicodeDecodeError. Other possible values are \'ignore\'\n" +" and \'replace\' as well as any other name registered with\n" +" codecs.register_error that can handle UnicodeDecodeErrors."); #define BYTES_DECODE_METHODDEF \ {"decode", _PyCFunction_CAST(bytes_decode), METH_FASTCALL|METH_KEYWORDS, bytes_decode__doc__}, @@ -1170,8 +1175,8 @@ PyDoc_STRVAR(bytes_splitlines__doc__, "\n" "Return a list of the lines in the bytes, breaking at line boundaries.\n" "\n" -"Line breaks are not included in the resulting list unless keepends is given and\n" -"true."); +"Line breaks are not included in the resulting list unless keepends\n" +"is given and true."); #define BYTES_SPLITLINES_METHODDEF \ {"splitlines", _PyCFunction_CAST(bytes_splitlines), METH_FASTCALL|METH_KEYWORDS, bytes_splitlines__doc__}, @@ -1267,8 +1272,8 @@ PyDoc_STRVAR(bytes_hex__doc__, " sep\n" " An optional single character or byte to separate hex bytes.\n" " bytes_per_sep\n" -" How many bytes between separators. Positive values count from the\n" -" right, negative values count from the left.\n" +" How many bytes between separators. Positive values count from\n" +" the right, negative values count from the left.\n" "\n" "Example:\n" ">>> value = b\'\\xb9\\x01\\xef\'\n" @@ -1450,4 +1455,4 @@ bytes_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) exit: return return_value; } -/*[clinic end generated code: output=b252801ff04a89b3 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=c20458db7a2123db input=a9049054013a1b77]*/ diff --git a/Objects/clinic/codeobject.c.h b/Objects/clinic/codeobject.c.h index 0cd6e0b56620e8..88333e9d3363eb 100644 --- a/Objects/clinic/codeobject.c.h +++ b/Objects/clinic/codeobject.c.h @@ -414,7 +414,8 @@ PyDoc_STRVAR(code__varname_from_oparg__doc__, "\n" "(internal-only) Return the local variable name for the given oparg.\n" "\n" -"WARNING: this method is for internal use only and may change or go away."); +"WARNING: this method is for internal use only and may change or go\n" +"away."); #define CODE__VARNAME_FROM_OPARG_METHODDEF \ {"_varname_from_oparg", _PyCFunction_CAST(code__varname_from_oparg), METH_FASTCALL|METH_KEYWORDS, code__varname_from_oparg__doc__}, @@ -470,4 +471,4 @@ code__varname_from_oparg(PyObject *self, PyObject *const *args, Py_ssize_t nargs exit: return return_value; } -/*[clinic end generated code: output=c5c6e40fc357defe input=a9049054013a1b77]*/ +/*[clinic end generated code: output=5c22e29e430401b4 input=a9049054013a1b77]*/ diff --git a/Objects/clinic/floatobject.c.h b/Objects/clinic/floatobject.c.h index c0ae9d3ff9b8d3..8768555c909257 100644 --- a/Objects/clinic/floatobject.c.h +++ b/Objects/clinic/floatobject.c.h @@ -291,8 +291,8 @@ PyDoc_STRVAR(float___getformat____doc__, "It exists mainly to be used in Python\'s test suite.\n" "\n" "This function returns whichever of \'IEEE, big-endian\' or \'IEEE,\n" -"little-endian\' best describes the format of floating-point numbers used by the\n" -"C type named by typestr."); +"little-endian\' best describes the format of floating-point numbers\n" +"used by the C type named by typestr."); #define FLOAT___GETFORMAT___METHODDEF \ {"__getformat__", (PyCFunction)float___getformat__, METH_O|METH_CLASS, float___getformat____doc__}, @@ -353,4 +353,4 @@ float___format__(PyObject *self, PyObject *arg) exit: return return_value; } -/*[clinic end generated code: output=f0b2af257213c8b0 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=5d7b0bf9e47ff997 input=a9049054013a1b77]*/ diff --git a/Objects/clinic/listobject.c.h b/Objects/clinic/listobject.c.h index 26ba5b954336da..f3821ef5f70c21 100644 --- a/Objects/clinic/listobject.c.h +++ b/Objects/clinic/listobject.c.h @@ -200,11 +200,11 @@ PyDoc_STRVAR(list_sort__doc__, "\n" "Sort the list in ascending order and return None.\n" "\n" -"The sort is in-place (i.e. the list itself is modified) and stable (i.e. the\n" -"order of two equal elements is maintained).\n" +"The sort is in-place (i.e. the list itself is modified) and stable\n" +"(i.e. the order of two equal elements is maintained).\n" "\n" -"If a key function is given, apply it once to each list item and sort them,\n" -"ascending or descending, according to their function values.\n" +"If a key function is given, apply it once to each list item and sort\n" +"them, ascending or descending, according to their function values.\n" "\n" "The reverse flag can be set to sort in descending order."); @@ -468,4 +468,4 @@ list___reversed__(PyObject *self, PyObject *Py_UNUSED(ignored)) { return list___reversed___impl((PyListObject *)self); } -/*[clinic end generated code: output=ae13fc2b56dc27c2 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=06c21b0bffbe8d84 input=a9049054013a1b77]*/ diff --git a/Objects/clinic/longobject.c.h b/Objects/clinic/longobject.c.h index c88772030ec283..52ecaffa1f4cf3 100644 --- a/Objects/clinic/longobject.c.h +++ b/Objects/clinic/longobject.c.h @@ -262,19 +262,20 @@ PyDoc_STRVAR(int_to_bytes__doc__, "Return an array of bytes representing an integer.\n" "\n" " length\n" -" Length of bytes object to use. An OverflowError is raised if the\n" -" integer is not representable with the given number of bytes. Default\n" -" is length 1.\n" +" Length of bytes object to use. An OverflowError is raised if\n" +" the integer is not representable with the given number of bytes.\n" +" Default is length 1.\n" " byteorder\n" -" The byte order used to represent the integer. If byteorder is \'big\',\n" -" the most significant byte is at the beginning of the byte array. If\n" -" byteorder is \'little\', the most significant byte is at the end of the\n" -" byte array. To request the native byte order of the host system, use\n" -" sys.byteorder as the byte order value. Default is to use \'big\'.\n" +" The byte order used to represent the integer. If byteorder is\n" +" \'big\', the most significant byte is at the beginning of the byte\n" +" array. If byteorder is \'little\', the most significant byte is at\n" +" the end of the byte array. To request the native byte order of\n" +" the host system, use sys.byteorder as the byte order value.\n" +" Default is to use \'big\'.\n" " signed\n" -" Determines whether two\'s complement is used to represent the integer.\n" -" If signed is False and a negative integer is given, an OverflowError\n" -" is raised."); +" Determines whether two\'s complement is used to represent the\n" +" integer. If signed is False and a negative integer is given,\n" +" an OverflowError is raised."); #define INT_TO_BYTES_METHODDEF \ {"to_bytes", _PyCFunction_CAST(int_to_bytes), METH_FASTCALL|METH_KEYWORDS, int_to_bytes__doc__}, @@ -383,17 +384,19 @@ PyDoc_STRVAR(int_from_bytes__doc__, "\n" " bytes\n" " Holds the array of bytes to convert. The argument must either\n" -" support the buffer protocol or be an iterable object producing bytes.\n" -" Bytes and bytearray are examples of built-in objects that support the\n" -" buffer protocol.\n" +" support the buffer protocol or be an iterable object producing\n" +" bytes. Bytes and bytearray are examples of built-in objects that\n" +" support the buffer protocol.\n" " byteorder\n" -" The byte order used to represent the integer. If byteorder is \'big\',\n" -" the most significant byte is at the beginning of the byte array. If\n" -" byteorder is \'little\', the most significant byte is at the end of the\n" -" byte array. To request the native byte order of the host system, use\n" -" sys.byteorder as the byte order value. Default is to use \'big\'.\n" +" The byte order used to represent the integer. If byteorder is\n" +" \'big\', the most significant byte is at the beginning of the byte\n" +" array. If byteorder is \'little\', the most significant byte is at\n" +" the end of the byte array. To request the native byte order of\n" +" the host system, use sys.byteorder as the byte order value.\n" +" Default is to use \'big\'.\n" " signed\n" -" Indicates whether two\'s complement is used to represent the integer."); +" Indicates whether two\'s complement is used to represent the\n" +" integer."); #define INT_FROM_BYTES_METHODDEF \ {"from_bytes", _PyCFunction_CAST(int_from_bytes), METH_FASTCALL|METH_KEYWORDS|METH_CLASS, int_from_bytes__doc__}, @@ -490,4 +493,4 @@ int_is_integer(PyObject *self, PyObject *Py_UNUSED(ignored)) { return int_is_integer_impl(self); } -/*[clinic end generated code: output=e68f4e23ead3f649 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=d95766fb7ff46963 input=a9049054013a1b77]*/ diff --git a/Objects/clinic/memoryobject.c.h b/Objects/clinic/memoryobject.c.h index d97c626532c803..a0cf3243edc08a 100644 --- a/Objects/clinic/memoryobject.c.h +++ b/Objects/clinic/memoryobject.c.h @@ -259,11 +259,12 @@ PyDoc_STRVAR(memoryview_tobytes__doc__, "\n" "Return the data in the buffer as a byte string.\n" "\n" -"Order can be {\'C\', \'F\', \'A\'}. When order is \'C\' or \'F\', the data of the\n" -"original array is converted to C or Fortran order. For contiguous views,\n" -"\'A\' returns an exact copy of the physical memory. In particular, in-memory\n" -"Fortran order is preserved. For non-contiguous views, the data is converted\n" -"to C first. order=None is the same as order=\'C\'."); +"Order can be {\'C\', \'F\', \'A\'}. When order is \'C\' or \'F\', the data of\n" +"the original array is converted to C or Fortran order. For\n" +"contiguous views, \'A\' returns an exact copy of the physical memory.\n" +"In particular, in-memory Fortran order is preserved. For\n" +"non-contiguous views, the data is converted to C first. order=None\n" +"is the same as order=\'C\'."); #define MEMORYVIEW_TOBYTES_METHODDEF \ {"tobytes", _PyCFunction_CAST(memoryview_tobytes), METH_FASTCALL|METH_KEYWORDS, memoryview_tobytes__doc__}, @@ -348,8 +349,8 @@ PyDoc_STRVAR(memoryview_hex__doc__, " sep\n" " An optional single character or byte to separate hex bytes.\n" " bytes_per_sep\n" -" How many bytes between separators. Positive values count from the\n" -" right, negative values count from the left.\n" +" How many bytes between separators. Positive values count from\n" +" the right, negative values count from the left.\n" "\n" "Example:\n" ">>> value = memoryview(b\'\\xb9\\x01\\xef\')\n" @@ -505,4 +506,4 @@ memoryview_index(PyObject *self, PyObject *const *args, Py_ssize_t nargs) exit: return return_value; } -/*[clinic end generated code: output=348b6ddb98a1f412 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=3abf9c80cd49229a input=a9049054013a1b77]*/ diff --git a/Objects/clinic/odictobject.c.h b/Objects/clinic/odictobject.c.h index 894e9be91bbdce..92129e6444810f 100644 --- a/Objects/clinic/odictobject.c.h +++ b/Objects/clinic/odictobject.c.h @@ -268,7 +268,8 @@ PyDoc_STRVAR(OrderedDict_popitem__doc__, "\n" "Remove and return a (key, value) pair from the dictionary.\n" "\n" -"Pairs are returned in LIFO order if last is true or FIFO order if false."); +"Pairs are returned in LIFO order if last is true or FIFO order if\n" +"false."); #define ORDEREDDICT_POPITEM_METHODDEF \ {"popitem", _PyCFunction_CAST(OrderedDict_popitem), METH_FASTCALL|METH_KEYWORDS, OrderedDict_popitem__doc__}, @@ -451,4 +452,4 @@ OrderedDict_move_to_end(PyObject *self, PyObject *const *args, Py_ssize_t nargs, exit: return return_value; } -/*[clinic end generated code: output=7bc997ca7900f06f input=a9049054013a1b77]*/ +/*[clinic end generated code: output=89f7e92de998f9a4 input=a9049054013a1b77]*/ diff --git a/Objects/clinic/unicodeobject.c.h b/Objects/clinic/unicodeobject.c.h index 4b53e24fb7d649..d0753b38843fcc 100644 --- a/Objects/clinic/unicodeobject.c.h +++ b/Objects/clinic/unicodeobject.c.h @@ -33,8 +33,8 @@ PyDoc_STRVAR(unicode_title__doc__, "\n" "Return a version of the string where each word is titlecased.\n" "\n" -"More specifically, words start with uppercased characters and all remaining\n" -"cased characters have lower case."); +"More specifically, words start with uppercased characters and all\n" +"remaining cased characters have lower case."); #define UNICODE_TITLE_METHODDEF \ {"title", (PyCFunction)unicode_title, METH_NOARGS, unicode_title__doc__}, @@ -54,8 +54,8 @@ PyDoc_STRVAR(unicode_capitalize__doc__, "\n" "Return a capitalized version of the string.\n" "\n" -"More specifically, make the first character have upper case and the rest lower\n" -"case."); +"More specifically, make the first character have upper case and the\n" +"rest lower case."); #define UNICODE_CAPITALIZE_METHODDEF \ {"capitalize", (PyCFunction)unicode_capitalize, METH_NOARGS, unicode_capitalize__doc__}, @@ -93,7 +93,8 @@ PyDoc_STRVAR(unicode_center__doc__, "\n" "Return a centered string of length width.\n" "\n" -"Padding is done using the specified fill character (default is a space)."); +"Padding is done using the specified fill character (default is\n" +"a space)."); #define UNICODE_CENTER_METHODDEF \ {"center", _PyCFunction_CAST(unicode_center), METH_FASTCALL, unicode_center__doc__}, @@ -142,7 +143,8 @@ PyDoc_STRVAR(unicode_count__doc__, "\n" "Return the number of non-overlapping occurrences of substring sub in string S[start:end].\n" "\n" -"Optional arguments start and end are interpreted as in slice notation."); +"Optional arguments start and end are interpreted as in slice\n" +"notation."); #define UNICODE_COUNT_METHODDEF \ {"count", _PyCFunction_CAST(unicode_count), METH_FASTCALL, unicode_count__doc__}, @@ -202,8 +204,8 @@ PyDoc_STRVAR(unicode_encode__doc__, " errors\n" " The error handling scheme to use for encoding errors.\n" " The default is \'strict\' meaning that encoding errors raise a\n" -" UnicodeEncodeError. Other possible values are \'ignore\', \'replace\' and\n" -" \'xmlcharrefreplace\' as well as any other name registered with\n" +" UnicodeEncodeError. Other possible values are \'ignore\', \'replace\'\n" +" and \'xmlcharrefreplace\' as well as any other name registered with\n" " codecs.register_error that can handle UnicodeEncodeErrors."); #define UNICODE_ENCODE_METHODDEF \ @@ -368,8 +370,8 @@ PyDoc_STRVAR(unicode_find__doc__, "\n" "Return the lowest index in S where substring sub is found, such that sub is contained within S[start:end].\n" "\n" -"Optional arguments start and end are interpreted as in slice notation.\n" -"Return -1 on failure."); +"Optional arguments start and end are interpreted as in slice\n" +"notation. Return -1 on failure."); #define UNICODE_FIND_METHODDEF \ {"find", _PyCFunction_CAST(unicode_find), METH_FASTCALL, unicode_find__doc__}, @@ -424,8 +426,8 @@ PyDoc_STRVAR(unicode_index__doc__, "\n" "Return the lowest index in S where substring sub is found, such that sub is contained within S[start:end].\n" "\n" -"Optional arguments start and end are interpreted as in slice notation.\n" -"Raises ValueError when the substring is not found."); +"Optional arguments start and end are interpreted as in slice\n" +"notation. Raises ValueError when the substring is not found."); #define UNICODE_INDEX_METHODDEF \ {"index", _PyCFunction_CAST(unicode_index), METH_FASTCALL, unicode_index__doc__}, @@ -501,8 +503,8 @@ PyDoc_STRVAR(unicode_islower__doc__, "\n" "Return True if the string is a lowercase string, False otherwise.\n" "\n" -"A string is lowercase if all cased characters in the string are lowercase and\n" -"there is at least one cased character in the string."); +"A string is lowercase if all cased characters in the string are\n" +"lowercase and there is at least one cased character in the string."); #define UNICODE_ISLOWER_METHODDEF \ {"islower", (PyCFunction)unicode_islower, METH_NOARGS, unicode_islower__doc__}, @@ -522,8 +524,8 @@ PyDoc_STRVAR(unicode_isupper__doc__, "\n" "Return True if the string is an uppercase string, False otherwise.\n" "\n" -"A string is uppercase if all cased characters in the string are uppercase and\n" -"there is at least one cased character in the string."); +"A string is uppercase if all cased characters in the string are\n" +"uppercase and there is at least one cased character in the string."); #define UNICODE_ISUPPER_METHODDEF \ {"isupper", (PyCFunction)unicode_isupper, METH_NOARGS, unicode_isupper__doc__}, @@ -564,8 +566,8 @@ PyDoc_STRVAR(unicode_isspace__doc__, "\n" "Return True if the string is a whitespace string, False otherwise.\n" "\n" -"A string is whitespace if all characters in the string are whitespace and there\n" -"is at least one character in the string."); +"A string is whitespace if all characters in the string are\n" +"whitespace and there is at least one character in the string."); #define UNICODE_ISSPACE_METHODDEF \ {"isspace", (PyCFunction)unicode_isspace, METH_NOARGS, unicode_isspace__doc__}, @@ -585,8 +587,8 @@ PyDoc_STRVAR(unicode_isalpha__doc__, "\n" "Return True if the string is an alphabetic string, False otherwise.\n" "\n" -"A string is alphabetic if all characters in the string are alphabetic and there\n" -"is at least one character in the string."); +"A string is alphabetic if all characters in the string are\n" +"alphabetic and there is at least one character in the string."); #define UNICODE_ISALPHA_METHODDEF \ {"isalpha", (PyCFunction)unicode_isalpha, METH_NOARGS, unicode_isalpha__doc__}, @@ -606,8 +608,8 @@ PyDoc_STRVAR(unicode_isalnum__doc__, "\n" "Return True if the string is an alpha-numeric string, False otherwise.\n" "\n" -"A string is alpha-numeric if all characters in the string are alpha-numeric and\n" -"there is at least one character in the string."); +"A string is alpha-numeric if all characters in the string are\n" +"alpha-numeric and there is at least one character in the string."); #define UNICODE_ISALNUM_METHODDEF \ {"isalnum", (PyCFunction)unicode_isalnum, METH_NOARGS, unicode_isalnum__doc__}, @@ -627,8 +629,8 @@ PyDoc_STRVAR(unicode_isdecimal__doc__, "\n" "Return True if the string is a decimal string, False otherwise.\n" "\n" -"A string is a decimal string if all characters in the string are decimal and\n" -"there is at least one character in the string."); +"A string is a decimal string if all characters in the string are\n" +"decimal and there is at least one character in the string."); #define UNICODE_ISDECIMAL_METHODDEF \ {"isdecimal", (PyCFunction)unicode_isdecimal, METH_NOARGS, unicode_isdecimal__doc__}, @@ -648,8 +650,8 @@ PyDoc_STRVAR(unicode_isdigit__doc__, "\n" "Return True if the string is a digit string, False otherwise.\n" "\n" -"A string is a digit string if all characters in the string are digits and there\n" -"is at least one character in the string."); +"A string is a digit string if all characters in the string are\n" +"digits and there is at least one character in the string."); #define UNICODE_ISDIGIT_METHODDEF \ {"isdigit", (PyCFunction)unicode_isdigit, METH_NOARGS, unicode_isdigit__doc__}, @@ -669,8 +671,8 @@ PyDoc_STRVAR(unicode_isnumeric__doc__, "\n" "Return True if the string is a numeric string, False otherwise.\n" "\n" -"A string is numeric if all characters in the string are numeric and there is at\n" -"least one character in the string."); +"A string is numeric if all characters in the string are numeric and\n" +"there is at least one character in the string."); #define UNICODE_ISNUMERIC_METHODDEF \ {"isnumeric", (PyCFunction)unicode_isnumeric, METH_NOARGS, unicode_isnumeric__doc__}, @@ -690,8 +692,8 @@ PyDoc_STRVAR(unicode_isidentifier__doc__, "\n" "Return True if the string is a valid Python identifier, False otherwise.\n" "\n" -"Call keyword.iskeyword(s) to test whether string s is a reserved identifier,\n" -"such as \"def\" or \"class\"."); +"Call keyword.iskeyword(s) to test whether string s is a reserved\n" +"identifier, such as \"def\" or \"class\"."); #define UNICODE_ISIDENTIFIER_METHODDEF \ {"isidentifier", (PyCFunction)unicode_isidentifier, METH_NOARGS, unicode_isidentifier__doc__}, @@ -731,8 +733,8 @@ PyDoc_STRVAR(unicode_join__doc__, "\n" "Concatenate any number of strings.\n" "\n" -"The string whose method is called is inserted in between each given string.\n" -"The result is returned as a new string.\n" +"The string whose method is called is inserted in between each given\n" +"string. The result is returned as a new string.\n" "\n" "Example: \'.\'.join([\'ab\', \'pq\', \'rs\']) -> \'ab.pq.rs\'"); @@ -745,7 +747,8 @@ PyDoc_STRVAR(unicode_ljust__doc__, "\n" "Return a left-justified string of length width.\n" "\n" -"Padding is done using the specified fill character (default is a space)."); +"Padding is done using the specified fill character (default is\n" +"a space)."); #define UNICODE_LJUST_METHODDEF \ {"ljust", _PyCFunction_CAST(unicode_ljust), METH_FASTCALL, unicode_ljust__doc__}, @@ -1008,8 +1011,9 @@ PyDoc_STRVAR(unicode_removeprefix__doc__, "\n" "Return a str with the given prefix string removed if present.\n" "\n" -"If the string starts with the prefix string, return string[len(prefix):].\n" -"Otherwise, return a copy of the original string."); +"If the string starts with the prefix string, return\n" +"string[len(prefix):]. Otherwise, return a copy of the original\n" +"string."); #define UNICODE_REMOVEPREFIX_METHODDEF \ {"removeprefix", (PyCFunction)unicode_removeprefix, METH_O, unicode_removeprefix__doc__}, @@ -1040,9 +1044,9 @@ PyDoc_STRVAR(unicode_removesuffix__doc__, "\n" "Return a str with the given suffix string removed if present.\n" "\n" -"If the string ends with the suffix string and that suffix is not empty,\n" -"return string[:-len(suffix)]. Otherwise, return a copy of the original\n" -"string."); +"If the string ends with the suffix string and that suffix is not\n" +"empty, return string[:-len(suffix)]. Otherwise, return a copy of\n" +"the original string."); #define UNICODE_REMOVESUFFIX_METHODDEF \ {"removesuffix", (PyCFunction)unicode_removesuffix, METH_O, unicode_removesuffix__doc__}, @@ -1073,8 +1077,8 @@ PyDoc_STRVAR(unicode_rfind__doc__, "\n" "Return the highest index in S where substring sub is found, such that sub is contained within S[start:end].\n" "\n" -"Optional arguments start and end are interpreted as in slice notation.\n" -"Return -1 on failure."); +"Optional arguments start and end are interpreted as in slice\n" +"notation. Return -1 on failure."); #define UNICODE_RFIND_METHODDEF \ {"rfind", _PyCFunction_CAST(unicode_rfind), METH_FASTCALL, unicode_rfind__doc__}, @@ -1129,8 +1133,8 @@ PyDoc_STRVAR(unicode_rindex__doc__, "\n" "Return the highest index in S where substring sub is found, such that sub is contained within S[start:end].\n" "\n" -"Optional arguments start and end are interpreted as in slice notation.\n" -"Raises ValueError when the substring is not found."); +"Optional arguments start and end are interpreted as in slice\n" +"notation. Raises ValueError when the substring is not found."); #define UNICODE_RINDEX_METHODDEF \ {"rindex", _PyCFunction_CAST(unicode_rindex), METH_FASTCALL, unicode_rindex__doc__}, @@ -1185,7 +1189,8 @@ PyDoc_STRVAR(unicode_rjust__doc__, "\n" "Return a right-justified string of length width.\n" "\n" -"Padding is done using the specified fill character (default is a space)."); +"Padding is done using the specified fill character (default is\n" +"a space)."); #define UNICODE_RJUST_METHODDEF \ {"rjust", _PyCFunction_CAST(unicode_rjust), METH_FASTCALL, unicode_rjust__doc__}, @@ -1237,18 +1242,18 @@ PyDoc_STRVAR(unicode_split__doc__, " sep\n" " The separator used to split the string.\n" "\n" -" When set to None (the default value), will split on any whitespace\n" -" character (including \\n \\r \\t \\f and spaces) and will discard\n" -" empty strings from the result.\n" +" When set to None (the default value), will split on any\n" +" whitespace character (including \\n \\r \\t \\f and spaces) and\n" +" will discard empty strings from the result.\n" " maxsplit\n" " Maximum number of splits.\n" " -1 (the default value) means no limit.\n" "\n" "Splitting starts at the front of the string and works to the end.\n" "\n" -"Note, str.split() is mainly useful for data that has been intentionally\n" -"delimited. With natural text that includes punctuation, consider using\n" -"the regular expression module."); +"Note, str.split() is mainly useful for data that has been\n" +"intentionally delimited. With natural text that includes\n" +"punctuation, consider using the regular expression module."); #define UNICODE_SPLIT_METHODDEF \ {"split", _PyCFunction_CAST(unicode_split), METH_FASTCALL|METH_KEYWORDS, unicode_split__doc__}, @@ -1331,12 +1336,12 @@ PyDoc_STRVAR(unicode_partition__doc__, "\n" "Partition the string into three parts using the given separator.\n" "\n" -"This will search for the separator in the string. If the separator is found,\n" -"returns a 3-tuple containing the part before the separator, the separator\n" -"itself, and the part after it.\n" +"This will search for the separator in the string. If the separator\n" +"is found, returns a 3-tuple containing the part before the\n" +"separator, the separator itself, and the part after it.\n" "\n" -"If the separator is not found, returns a 3-tuple containing the original string\n" -"and two empty strings."); +"If the separator is not found, returns a 3-tuple containing\n" +"the original string and two empty strings."); #define UNICODE_PARTITION_METHODDEF \ {"partition", (PyCFunction)unicode_partition, METH_O, unicode_partition__doc__}, @@ -1347,12 +1352,13 @@ PyDoc_STRVAR(unicode_rpartition__doc__, "\n" "Partition the string into three parts using the given separator.\n" "\n" -"This will search for the separator in the string, starting at the end. If\n" -"the separator is found, returns a 3-tuple containing the part before the\n" -"separator, the separator itself, and the part after it.\n" +"This will search for the separator in the string, starting at the\n" +"end. If the separator is found, returns a 3-tuple containing the\n" +"part before the separator, the separator itself, and the part after\n" +"it.\n" "\n" -"If the separator is not found, returns a 3-tuple containing two empty strings\n" -"and the original string."); +"If the separator is not found, returns a 3-tuple containing two\n" +"empty strings and the original string."); #define UNICODE_RPARTITION_METHODDEF \ {"rpartition", (PyCFunction)unicode_rpartition, METH_O, unicode_rpartition__doc__}, @@ -1366,9 +1372,9 @@ PyDoc_STRVAR(unicode_rsplit__doc__, " sep\n" " The separator used to split the string.\n" "\n" -" When set to None (the default value), will split on any whitespace\n" -" character (including \\n \\r \\t \\f and spaces) and will discard\n" -" empty strings from the result.\n" +" When set to None (the default value), will split on any\n" +" whitespace character (including \\n \\r \\t \\f and spaces) and\n" +" will discard empty strings from the result.\n" " maxsplit\n" " Maximum number of splits.\n" " -1 (the default value) means no limit.\n" @@ -1456,8 +1462,8 @@ PyDoc_STRVAR(unicode_splitlines__doc__, "\n" "Return a list of the lines in the string, breaking at line boundaries.\n" "\n" -"Line breaks are not included in the resulting list unless keepends is given and\n" -"true."); +"Line breaks are not included in the resulting list unless keepends\n" +"is given and true."); #define UNICODE_SPLITLINES_METHODDEF \ {"splitlines", _PyCFunction_CAST(unicode_splitlines), METH_FASTCALL|METH_KEYWORDS, unicode_splitlines__doc__}, @@ -1543,13 +1549,14 @@ PyDoc_STRVAR(unicode_maketrans__doc__, "\n" "Return a translation table usable for str.translate().\n" "\n" -"If there is only one argument, it must be a dictionary mapping Unicode\n" -"ordinals (integers) or characters to Unicode ordinals, strings or None.\n" -"Character keys will be then converted to ordinals.\n" -"If there are two arguments, they must be strings of equal length, and\n" -"in the resulting dictionary, each character in x will be mapped to the\n" -"character at the same position in y. If there is a third argument, it\n" -"must be a string, whose characters will be mapped to None in the result."); +"If there is only one argument, it must be a dictionary mapping\n" +"Unicode ordinals (integers) or characters to Unicode ordinals,\n" +"strings or None. Character keys will be then converted to ordinals.\n" +"If there are two arguments, they must be strings of equal length,\n" +"and in the resulting dictionary, each character in x will be mapped\n" +"to the character at the same position in y. If there is a third\n" +"argument, it must be a string, whose characters will be mapped to\n" +"None in the result."); #define UNICODE_MAKETRANS_METHODDEF \ {"maketrans", _PyCFunction_CAST(unicode_maketrans), METH_FASTCALL|METH_STATIC, unicode_maketrans__doc__}, @@ -1599,12 +1606,13 @@ PyDoc_STRVAR(unicode_translate__doc__, "Replace each character in the string using the given translation table.\n" "\n" " table\n" -" Translation table, which must be a mapping of Unicode ordinals to\n" -" Unicode ordinals, strings, or None.\n" +" Translation table, which must be a mapping of Unicode ordinals\n" +" to Unicode ordinals, strings, or None.\n" "\n" -"The table must implement lookup/indexing via __getitem__, for instance a\n" -"dictionary or list. If this operation raises LookupError, the character is\n" -"left untouched. Characters mapped to None are deleted."); +"The table must implement lookup/indexing via __getitem__, for\n" +"instance a dictionary or list. If this operation raises\n" +"LookupError, the character is left untouched. Characters mapped to\n" +"None are deleted."); #define UNICODE_TRANSLATE_METHODDEF \ {"translate", (PyCFunction)unicode_translate, METH_O, unicode_translate__doc__}, @@ -1908,4 +1916,4 @@ unicode_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) exit: return return_value; } -/*[clinic end generated code: output=13eaf65699ea9fc9 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=9d243c63e951e31d input=a9049054013a1b77]*/ diff --git a/Objects/codeobject.c b/Objects/codeobject.c index 8be85b1accbdca..4ede8de6e8adc5 100644 --- a/Objects/codeobject.c +++ b/Objects/codeobject.c @@ -2840,12 +2840,13 @@ code._varname_from_oparg (internal-only) Return the local variable name for the given oparg. -WARNING: this method is for internal use only and may change or go away. +WARNING: this method is for internal use only and may change or go +away. [clinic start generated code]*/ static PyObject * code__varname_from_oparg_impl(PyCodeObject *self, int oparg) -/*[clinic end generated code: output=1fd1130413184206 input=c5fa3ee9bac7d4ca]*/ +/*[clinic end generated code: output=1fd1130413184206 input=6ba7d6df0d566463]*/ { PyObject *name = PyTuple_GetItem(self->co_localsplusnames, oparg); if (name == NULL) { diff --git a/Objects/dictobject.c b/Objects/dictobject.c index 3830fedd42bd27..66546b72130dd0 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -3892,6 +3892,7 @@ PyDict_Items(PyObject *dict) } /*[clinic input] +@permit_long_summary @classmethod dict.fromkeys iterable: object @@ -3903,7 +3904,7 @@ Create a new dictionary with keys from iterable and values set to value. static PyObject * dict_fromkeys_impl(PyTypeObject *type, PyObject *iterable, PyObject *value) -/*[clinic end generated code: output=8fb98e4b10384999 input=382ba4855d0f74c3]*/ +/*[clinic end generated code: output=8fb98e4b10384999 input=3903715eb48b287e]*/ { return _PyDict_FromKeys((PyObject *)type, iterable, value); } diff --git a/Objects/floatobject.c b/Objects/floatobject.c index d91468dddded9b..17e6a729dcd83f 100644 --- a/Objects/floatobject.c +++ b/Objects/floatobject.c @@ -1670,7 +1670,6 @@ float___getnewargs___impl(PyObject *self) /*[clinic input] -@permit_long_docstring_body @classmethod float.__getformat__ @@ -1683,13 +1682,13 @@ You probably don't want to use this function. It exists mainly to be used in Python's test suite. This function returns whichever of 'IEEE, big-endian' or 'IEEE, -little-endian' best describes the format of floating-point numbers used by the -C type named by typestr. +little-endian' best describes the format of floating-point numbers +used by the C type named by typestr. [clinic start generated code]*/ static PyObject * float___getformat___impl(PyTypeObject *type, const char *typestr) -/*[clinic end generated code: output=2bfb987228cc9628 input=0ae1ba35d192f704]*/ +/*[clinic end generated code: output=2bfb987228cc9628 input=eb1cf45e9bddab72]*/ { if (strcmp(typestr, "double") != 0 && strcmp(typestr, "float") != 0) { PyErr_SetString(PyExc_ValueError, diff --git a/Objects/frameobject.c b/Objects/frameobject.c index 5ae85c5bca61b9..f60cdb2dd1bf20 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -1890,6 +1890,7 @@ frame_trace_set_impl(PyFrameObject *self, PyObject *value) } /*[clinic input] +@permit_long_summary @critical_section @getter frame.f_generator as frame_generator @@ -1899,7 +1900,7 @@ Return the generator or coroutine associated with this frame, or None. static PyObject * frame_generator_get_impl(PyFrameObject *self) -/*[clinic end generated code: output=97aeb2392562e55b input=00a2bd008b239ab0]*/ +/*[clinic end generated code: output=97aeb2392562e55b input=3ffba57ba10f84be]*/ { if (self->f_frame->owner == FRAME_OWNED_BY_GENERATOR) { PyObject *gen = (PyObject *)_PyGen_GetGeneratorFromFrame(self->f_frame); diff --git a/Objects/listobject.c b/Objects/listobject.c index c76721c5d2ac9e..38dc38dd277b97 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -2922,7 +2922,6 @@ unsafe_tuple_compare(PyObject *v, PyObject *w, MergeState *ms) * duplicated). */ /*[clinic input] -@permit_long_docstring_body @critical_section list.sort @@ -2932,18 +2931,18 @@ list.sort Sort the list in ascending order and return None. -The sort is in-place (i.e. the list itself is modified) and stable (i.e. the -order of two equal elements is maintained). +The sort is in-place (i.e. the list itself is modified) and stable +(i.e. the order of two equal elements is maintained). -If a key function is given, apply it once to each list item and sort them, -ascending or descending, according to their function values. +If a key function is given, apply it once to each list item and sort +them, ascending or descending, according to their function values. The reverse flag can be set to sort in descending order. [clinic start generated code]*/ static PyObject * list_sort_impl(PyListObject *self, PyObject *keyfunc, int reverse) -/*[clinic end generated code: output=57b9f9c5e23fbe42 input=e4f6b6069181ad7d]*/ +/*[clinic end generated code: output=57b9f9c5e23fbe42 input=c145526281e1fb9f]*/ { MergeState ms; Py_ssize_t nremaining; diff --git a/Objects/longobject.c b/Objects/longobject.c index 549cf0b8f12b4e..6e6011cb19aab5 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -6367,20 +6367,21 @@ int_as_integer_ratio_impl(PyObject *self) int.to_bytes length: Py_ssize_t(allow_negative=False) = 1 - Length of bytes object to use. An OverflowError is raised if the - integer is not representable with the given number of bytes. Default - is length 1. + Length of bytes object to use. An OverflowError is raised if + the integer is not representable with the given number of bytes. + Default is length 1. byteorder: unicode(c_default="NULL") = "big" - The byte order used to represent the integer. If byteorder is 'big', - the most significant byte is at the beginning of the byte array. If - byteorder is 'little', the most significant byte is at the end of the - byte array. To request the native byte order of the host system, use - sys.byteorder as the byte order value. Default is to use 'big'. + The byte order used to represent the integer. If byteorder is + 'big', the most significant byte is at the beginning of the byte + array. If byteorder is 'little', the most significant byte is at + the end of the byte array. To request the native byte order of + the host system, use sys.byteorder as the byte order value. + Default is to use 'big'. * signed as is_signed: bool = False - Determines whether two's complement is used to represent the integer. - If signed is False and a negative integer is given, an OverflowError - is raised. + Determines whether two's complement is used to represent the + integer. If signed is False and a negative integer is given, + an OverflowError is raised. Return an array of bytes representing an integer. [clinic start generated code]*/ @@ -6388,7 +6389,7 @@ Return an array of bytes representing an integer. static PyObject * int_to_bytes_impl(PyObject *self, Py_ssize_t length, PyObject *byteorder, int is_signed) -/*[clinic end generated code: output=89c801df114050a3 input=66f9d0c20529b44f]*/ +/*[clinic end generated code: output=89c801df114050a3 input=c74a93c07b2f6526]*/ { int little_endian; if (byteorder == NULL) @@ -6424,18 +6425,20 @@ int.from_bytes bytes as bytes_obj: object Holds the array of bytes to convert. The argument must either - support the buffer protocol or be an iterable object producing bytes. - Bytes and bytearray are examples of built-in objects that support the - buffer protocol. + support the buffer protocol or be an iterable object producing + bytes. Bytes and bytearray are examples of built-in objects that + support the buffer protocol. byteorder: unicode(c_default="NULL") = "big" - The byte order used to represent the integer. If byteorder is 'big', - the most significant byte is at the beginning of the byte array. If - byteorder is 'little', the most significant byte is at the end of the - byte array. To request the native byte order of the host system, use - sys.byteorder as the byte order value. Default is to use 'big'. + The byte order used to represent the integer. If byteorder is + 'big', the most significant byte is at the beginning of the byte + array. If byteorder is 'little', the most significant byte is at + the end of the byte array. To request the native byte order of + the host system, use sys.byteorder as the byte order value. + Default is to use 'big'. * signed as is_signed: bool = False - Indicates whether two's complement is used to represent the integer. + Indicates whether two's complement is used to represent the + integer. Return the integer represented by the given array of bytes. [clinic start generated code]*/ @@ -6443,7 +6446,7 @@ Return the integer represented by the given array of bytes. static PyObject * int_from_bytes_impl(PyTypeObject *type, PyObject *bytes_obj, PyObject *byteorder, int is_signed) -/*[clinic end generated code: output=efc5d68e31f9314f input=2ff527997fe7b0c5]*/ +/*[clinic end generated code: output=efc5d68e31f9314f input=95801e50b942e164]*/ { int little_endian; PyObject *long_obj, *bytes; @@ -6508,6 +6511,7 @@ long_long_getter(PyObject *self, void *Py_UNUSED(ignored)) } /*[clinic input] +@permit_long_summary int.is_integer Returns True. Exists for duck type compatibility with float.is_integer. @@ -6515,7 +6519,7 @@ Returns True. Exists for duck type compatibility with float.is_integer. static PyObject * int_is_integer_impl(PyObject *self) -/*[clinic end generated code: output=90f8e794ce5430ef input=7e41c4d4416e05f2]*/ +/*[clinic end generated code: output=90f8e794ce5430ef input=aacf01a2c81c0244]*/ { Py_RETURN_TRUE; } @@ -6597,7 +6601,8 @@ If x is not a number or if base is given, then x must be a string,\n\ bytes, or bytearray instance representing an integer literal in the\n\ given base. The literal can be preceded by '+' or '-' and be surrounded\n\ by whitespace. The base defaults to 10. Valid bases are 0 and 2-36.\n\ -Base 0 means to interpret the base from the string as an integer literal.\n\ +Base 0 means to interpret the base from the string as an integer\n\ +iteral.\n\ >>> int('0b100', base=0)\n\ 4"); diff --git a/Objects/memoryobject.c b/Objects/memoryobject.c index 9d1ca633780f92..3cfee04d80bb74 100644 --- a/Objects/memoryobject.c +++ b/Objects/memoryobject.c @@ -2339,23 +2339,23 @@ memoryview_tolist_impl(PyMemoryViewObject *self) } /*[clinic input] -@permit_long_docstring_body memoryview.tobytes order: str(accept={str, NoneType}, c_default="NULL") = 'C' Return the data in the buffer as a byte string. -Order can be {'C', 'F', 'A'}. When order is 'C' or 'F', the data of the -original array is converted to C or Fortran order. For contiguous views, -'A' returns an exact copy of the physical memory. In particular, in-memory -Fortran order is preserved. For non-contiguous views, the data is converted -to C first. order=None is the same as order='C'. +Order can be {'C', 'F', 'A'}. When order is 'C' or 'F', the data of +the original array is converted to C or Fortran order. For +contiguous views, 'A' returns an exact copy of the physical memory. +In particular, in-memory Fortran order is preserved. For +non-contiguous views, the data is converted to C first. order=None +is the same as order='C'. [clinic start generated code]*/ static PyObject * memoryview_tobytes_impl(PyMemoryViewObject *self, const char *order) -/*[clinic end generated code: output=1288b62560a32a23 input=23c9faf372cfdbcc]*/ +/*[clinic end generated code: output=1288b62560a32a23 input=119c70aa91791dc8]*/ { Py_buffer *src = VIEW_ADDR(self); char ord = 'C'; @@ -2396,8 +2396,8 @@ memoryview.hex sep: object = NULL An optional single character or byte to separate hex bytes. bytes_per_sep: Py_ssize_t = 1 - How many bytes between separators. Positive values count from the - right, negative values count from the left. + How many bytes between separators. Positive values count from + the right, negative values count from the left. Return the data in the buffer as a str of hexadecimal numbers. @@ -2416,7 +2416,7 @@ Return the data in the buffer as a str of hexadecimal numbers. static PyObject * memoryview_hex_impl(PyMemoryViewObject *self, PyObject *sep, Py_ssize_t bytes_per_sep) -/*[clinic end generated code: output=c9bb00c7a8e86056 input=dc48a56ed3b058ae]*/ +/*[clinic end generated code: output=c9bb00c7a8e86056 input=3f1c5d08906e3b70]*/ { Py_buffer *src = VIEW_ADDR(self); diff --git a/Objects/odictobject.c b/Objects/odictobject.c index b391283e83795d..6f05395b18d781 100644 --- a/Objects/odictobject.c +++ b/Objects/odictobject.c @@ -1149,12 +1149,13 @@ OrderedDict.popitem Remove and return a (key, value) pair from the dictionary. -Pairs are returned in LIFO order if last is true or FIFO order if false. +Pairs are returned in LIFO order if last is true or FIFO order if +false. [clinic start generated code]*/ static PyObject * OrderedDict_popitem_impl(PyODictObject *self, int last) -/*[clinic end generated code: output=98e7d986690d49eb input=8aafc7433e0a40e7]*/ +/*[clinic end generated code: output=98e7d986690d49eb input=ebf1cc91579c9e54]*/ { PyObject *key, *value; _ODictNode *node; diff --git a/Objects/setobject.c b/Objects/setobject.c index 1e630563604552..642baef3544d36 100644 --- a/Objects/setobject.c +++ b/Objects/setobject.c @@ -2111,6 +2111,7 @@ set_difference(PySetObject *so, PyObject *other) } /*[clinic input] +@permit_long_summary set.difference as set_difference_multi so: setobject *others: array @@ -2121,7 +2122,7 @@ Return a new set with elements in the set that are not in the others. static PyObject * set_difference_multi_impl(PySetObject *so, PyObject * const *others, Py_ssize_t others_length) -/*[clinic end generated code: output=b0d33fb05d5477a7 input=c1eb448d483416ad]*/ +/*[clinic end generated code: output=b0d33fb05d5477a7 input=e0fbedbf79d91d4e]*/ { Py_ssize_t i; PyObject *result, *other; @@ -2293,6 +2294,7 @@ set_symmetric_difference_update_impl(PySetObject *so, PyObject *other) } /*[clinic input] +@permit_long_summary @critical_section so other set.symmetric_difference so: setobject @@ -2304,7 +2306,7 @@ Return a new set with elements in either the set or other but not both. static PyObject * set_symmetric_difference_impl(PySetObject *so, PyObject *other) -/*[clinic end generated code: output=270ee0b5d42b0797 input=624f6e7bbdf70db1]*/ +/*[clinic end generated code: output=270ee0b5d42b0797 input=8c29b0be90d47feb]*/ { PySetObject *result = (PySetObject *)make_new_set_basetype(Py_TYPE(so), NULL); if (result == NULL) { diff --git a/Objects/sliceobject.c b/Objects/sliceobject.c index 95f10815687757..dbb509b06ecbba 100644 --- a/Objects/sliceobject.c +++ b/Objects/sliceobject.c @@ -342,7 +342,9 @@ PyDoc_STRVAR(slice_doc, "slice(stop)\n\ slice(start, stop[, step])\n\ \n\ -Create a slice object. This is used for extended slicing (e.g. a[0:10:2])."); +Create a slice object.\n\ +\n\ +This is used for extended slicing (e.g. a[0:10:2])."); static void slice_dealloc(PyObject *op) diff --git a/Objects/typeobject.c b/Objects/typeobject.c index fc679ef747e856..e0464fe6475cfd 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -12941,7 +12941,8 @@ PyDoc_STRVAR(super_doc, "super() -> same as super(__class__, )\n" "super(type) -> unbound super object\n" "super(type, obj) -> bound super object; requires isinstance(obj, type)\n" -"super(type, type2) -> bound super object; requires issubclass(type2, type)\n" +"super(type, type2) -> bound super object; requires\n" +" issubclass(type2, type)\n" "Typical use to call a cooperative superclass method:\n" "class C(B):\n" " def meth(self, arg):\n" diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 9aee7120c811de..74d6ba4db9f2b8 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -10794,35 +10794,33 @@ replace(PyObject *self, PyObject *str1, /* --- Unicode Object Methods --------------------------------------------- */ /*[clinic input] -@permit_long_docstring_body str.title as unicode_title Return a version of the string where each word is titlecased. -More specifically, words start with uppercased characters and all remaining -cased characters have lower case. +More specifically, words start with uppercased characters and all +remaining cased characters have lower case. [clinic start generated code]*/ static PyObject * unicode_title_impl(PyObject *self) -/*[clinic end generated code: output=c75ae03809574902 input=533ce0eb6a7f5d1b]*/ +/*[clinic end generated code: output=c75ae03809574902 input=2a07e2c7df94627a]*/ { return case_operation(self, do_title); } /*[clinic input] -@permit_long_docstring_body str.capitalize as unicode_capitalize Return a capitalized version of the string. -More specifically, make the first character have upper case and the rest lower -case. +More specifically, make the first character have upper case and the +rest lower case. [clinic start generated code]*/ static PyObject * unicode_capitalize_impl(PyObject *self) -/*[clinic end generated code: output=e49a4c333cdb7667 input=a4a15ade41f6f9e9]*/ +/*[clinic end generated code: output=e49a4c333cdb7667 input=e50e50ed45a654cf]*/ { if (PyUnicode_GET_LENGTH(self) == 0) return unicode_result_unchanged(self); @@ -10876,12 +10874,13 @@ str.center as unicode_center Return a centered string of length width. -Padding is done using the specified fill character (default is a space). +Padding is done using the specified fill character (default is +a space). [clinic start generated code]*/ static PyObject * unicode_center_impl(PyObject *self, Py_ssize_t width, Py_UCS4 fillchar) -/*[clinic end generated code: output=420c8859effc7c0c input=b42b247eb26e6519]*/ +/*[clinic end generated code: output=420c8859effc7c0c input=df91017dfd186a78]*/ { Py_ssize_t marg, left; @@ -11441,13 +11440,14 @@ str.count as unicode_count -> Py_ssize_t Return the number of non-overlapping occurrences of substring sub in string S[start:end]. -Optional arguments start and end are interpreted as in slice notation. +Optional arguments start and end are interpreted as in slice +notation. [clinic start generated code]*/ static Py_ssize_t unicode_count_impl(PyObject *str, PyObject *substr, Py_ssize_t start, Py_ssize_t end) -/*[clinic end generated code: output=8fcc3aef0b18edbf input=8590716ee228b935]*/ +/*[clinic end generated code: output=8fcc3aef0b18edbf input=c9209e05438cc352]*/ { assert(PyUnicode_Check(str)); assert(PyUnicode_Check(substr)); @@ -11520,8 +11520,8 @@ str.encode as unicode_encode errors: str(c_default="NULL") = 'strict' The error handling scheme to use for encoding errors. The default is 'strict' meaning that encoding errors raise a - UnicodeEncodeError. Other possible values are 'ignore', 'replace' and - 'xmlcharrefreplace' as well as any other name registered with + UnicodeEncodeError. Other possible values are 'ignore', 'replace' + and 'xmlcharrefreplace' as well as any other name registered with codecs.register_error that can handle UnicodeEncodeErrors. Encode the string using the codec registered for encoding. @@ -11529,7 +11529,7 @@ Encode the string using the codec registered for encoding. static PyObject * unicode_encode_impl(PyObject *self, const char *encoding, const char *errors) -/*[clinic end generated code: output=bf78b6e2a9470e3c input=f0a9eb293d08fe02]*/ +/*[clinic end generated code: output=bf78b6e2a9470e3c input=b85a9645cb33b729]*/ { return PyUnicode_AsEncodedString(self, encoding, errors); } @@ -11626,14 +11626,14 @@ str.find as unicode_find = str.count Return the lowest index in S where substring sub is found, such that sub is contained within S[start:end]. -Optional arguments start and end are interpreted as in slice notation. -Return -1 on failure. +Optional arguments start and end are interpreted as in slice +notation. Return -1 on failure. [clinic start generated code]*/ static Py_ssize_t unicode_find_impl(PyObject *str, PyObject *substr, Py_ssize_t start, Py_ssize_t end) -/*[clinic end generated code: output=51dbe6255712e278 input=3a9d650fe4c24695]*/ +/*[clinic end generated code: output=51dbe6255712e278 input=f57e93c59d1ee927]*/ { Py_ssize_t result = any_find_slice(str, substr, start, end, 1); if (result < 0) { @@ -11690,14 +11690,14 @@ str.index as unicode_index = str.count Return the lowest index in S where substring sub is found, such that sub is contained within S[start:end]. -Optional arguments start and end are interpreted as in slice notation. -Raises ValueError when the substring is not found. +Optional arguments start and end are interpreted as in slice +notation. Raises ValueError when the substring is not found. [clinic start generated code]*/ static Py_ssize_t unicode_index_impl(PyObject *str, PyObject *substr, Py_ssize_t start, Py_ssize_t end) -/*[clinic end generated code: output=77558288837cdf40 input=ae5e48f69ed75b06]*/ +/*[clinic end generated code: output=77558288837cdf40 input=5900ab84de55e628]*/ { Py_ssize_t result = any_find_slice(str, substr, start, end, 1); if (result == -1) { @@ -11710,6 +11710,7 @@ unicode_index_impl(PyObject *str, PyObject *substr, Py_ssize_t start, } /*[clinic input] +@permit_long_summary str.isascii as unicode_isascii Return True if all characters in the string are ASCII, False otherwise. @@ -11720,24 +11721,23 @@ Empty string is ASCII too. static PyObject * unicode_isascii_impl(PyObject *self) -/*[clinic end generated code: output=c5910d64b5a8003f input=5a43cbc6399621d5]*/ +/*[clinic end generated code: output=c5910d64b5a8003f input=dc74e1ced821159f]*/ { return PyBool_FromLong(PyUnicode_IS_ASCII(self)); } /*[clinic input] -@permit_long_docstring_body str.islower as unicode_islower Return True if the string is a lowercase string, False otherwise. -A string is lowercase if all cased characters in the string are lowercase and -there is at least one cased character in the string. +A string is lowercase if all cased characters in the string are +lowercase and there is at least one cased character in the string. [clinic start generated code]*/ static PyObject * unicode_islower_impl(PyObject *self) -/*[clinic end generated code: output=dbd41995bd005b81 input=c6fc0295241a1aaa]*/ +/*[clinic end generated code: output=dbd41995bd005b81 input=1879b48dfc628366]*/ { Py_ssize_t i, length; int kind; @@ -11770,18 +11770,17 @@ unicode_islower_impl(PyObject *self) } /*[clinic input] -@permit_long_docstring_body str.isupper as unicode_isupper Return True if the string is an uppercase string, False otherwise. -A string is uppercase if all cased characters in the string are uppercase and -there is at least one cased character in the string. +A string is uppercase if all cased characters in the string are +uppercase and there is at least one cased character in the string. [clinic start generated code]*/ static PyObject * unicode_isupper_impl(PyObject *self) -/*[clinic end generated code: output=049209c8e7f15f59 input=8d5cb33e67efde72]*/ +/*[clinic end generated code: output=049209c8e7f15f59 input=77d29904aef0e3a0]*/ { Py_ssize_t i, length; int kind; @@ -11870,18 +11869,17 @@ unicode_istitle_impl(PyObject *self) } /*[clinic input] -@permit_long_docstring_body str.isspace as unicode_isspace Return True if the string is a whitespace string, False otherwise. -A string is whitespace if all characters in the string are whitespace and there -is at least one character in the string. +A string is whitespace if all characters in the string are +whitespace and there is at least one character in the string. [clinic start generated code]*/ static PyObject * unicode_isspace_impl(PyObject *self) -/*[clinic end generated code: output=163a63bfa08ac2b9 input=44fe05e248c6e159]*/ +/*[clinic end generated code: output=163a63bfa08ac2b9 input=29e09560fc23fbeb]*/ { Py_ssize_t i, length; int kind; @@ -11909,18 +11907,17 @@ unicode_isspace_impl(PyObject *self) } /*[clinic input] -@permit_long_docstring_body str.isalpha as unicode_isalpha Return True if the string is an alphabetic string, False otherwise. -A string is alphabetic if all characters in the string are alphabetic and there -is at least one character in the string. +A string is alphabetic if all characters in the string are +alphabetic and there is at least one character in the string. [clinic start generated code]*/ static PyObject * unicode_isalpha_impl(PyObject *self) -/*[clinic end generated code: output=cc81b9ac3883ec4f input=c233000624a56e0d]*/ +/*[clinic end generated code: output=cc81b9ac3883ec4f input=9906a07f3e04892e]*/ { Py_ssize_t i, length; int kind; @@ -11947,18 +11944,18 @@ unicode_isalpha_impl(PyObject *self) } /*[clinic input] -@permit_long_docstring_body +@permit_long_summary str.isalnum as unicode_isalnum Return True if the string is an alpha-numeric string, False otherwise. -A string is alpha-numeric if all characters in the string are alpha-numeric and -there is at least one character in the string. +A string is alpha-numeric if all characters in the string are +alpha-numeric and there is at least one character in the string. [clinic start generated code]*/ static PyObject * unicode_isalnum_impl(PyObject *self) -/*[clinic end generated code: output=a5a23490ffc3660c input=5d63ba9c9bafdb6b]*/ +/*[clinic end generated code: output=a5a23490ffc3660c input=892f64ebc171fd4f]*/ { int kind; const void *data; @@ -11987,18 +11984,17 @@ unicode_isalnum_impl(PyObject *self) } /*[clinic input] -@permit_long_docstring_body str.isdecimal as unicode_isdecimal Return True if the string is a decimal string, False otherwise. -A string is a decimal string if all characters in the string are decimal and -there is at least one character in the string. +A string is a decimal string if all characters in the string are +decimal and there is at least one character in the string. [clinic start generated code]*/ static PyObject * unicode_isdecimal_impl(PyObject *self) -/*[clinic end generated code: output=fb2dcdb62d3fc548 input=8e84a58b414935a3]*/ +/*[clinic end generated code: output=fb2dcdb62d3fc548 input=63b0453c48cad0af]*/ { Py_ssize_t i, length; int kind; @@ -12025,18 +12021,17 @@ unicode_isdecimal_impl(PyObject *self) } /*[clinic input] -@permit_long_docstring_body str.isdigit as unicode_isdigit Return True if the string is a digit string, False otherwise. -A string is a digit string if all characters in the string are digits and there -is at least one character in the string. +A string is a digit string if all characters in the string are +digits and there is at least one character in the string. [clinic start generated code]*/ static PyObject * unicode_isdigit_impl(PyObject *self) -/*[clinic end generated code: output=10a6985311da6858 input=99e284affb54d4a0]*/ +/*[clinic end generated code: output=10a6985311da6858 input=353b03747b062e4b]*/ { Py_ssize_t i, length; int kind; @@ -12064,18 +12059,17 @@ unicode_isdigit_impl(PyObject *self) } /*[clinic input] -@permit_long_docstring_body str.isnumeric as unicode_isnumeric Return True if the string is a numeric string, False otherwise. -A string is numeric if all characters in the string are numeric and there is at -least one character in the string. +A string is numeric if all characters in the string are numeric and +there is at least one character in the string. [clinic start generated code]*/ static PyObject * unicode_isnumeric_impl(PyObject *self) -/*[clinic end generated code: output=9172a32d9013051a input=e9f5b6b8b29b0ee6]*/ +/*[clinic end generated code: output=9172a32d9013051a input=83b2a072ed7aff48]*/ { Py_ssize_t i, length; int kind; @@ -12145,18 +12139,18 @@ PyUnicode_IsIdentifier(PyObject *self) } /*[clinic input] -@permit_long_docstring_body +@permit_long_summary str.isidentifier as unicode_isidentifier Return True if the string is a valid Python identifier, False otherwise. -Call keyword.iskeyword(s) to test whether string s is a reserved identifier, -such as "def" or "class". +Call keyword.iskeyword(s) to test whether string s is a reserved +identifier, such as "def" or "class". [clinic start generated code]*/ static PyObject * unicode_isidentifier_impl(PyObject *self) -/*[clinic end generated code: output=fe585a9666572905 input=86315dd889d7bd04]*/ +/*[clinic end generated code: output=fe585a9666572905 input=cabde62c20a3be6b]*/ { return PyBool_FromLong(PyUnicode_IsIdentifier(self)); } @@ -12196,7 +12190,6 @@ unicode_isprintable_impl(PyObject *self) } /*[clinic input] -@permit_long_docstring_body str.join as unicode_join iterable: object @@ -12204,15 +12197,15 @@ str.join as unicode_join Concatenate any number of strings. -The string whose method is called is inserted in between each given string. -The result is returned as a new string. +The string whose method is called is inserted in between each given +string. The result is returned as a new string. Example: '.'.join(['ab', 'pq', 'rs']) -> 'ab.pq.rs' [clinic start generated code]*/ static PyObject * unicode_join(PyObject *self, PyObject *iterable) -/*[clinic end generated code: output=6857e7cecfe7bf98 input=bac724ed412ef3f8]*/ +/*[clinic end generated code: output=6857e7cecfe7bf98 input=fd330a11ee845fb2]*/ { return PyUnicode_Join(self, iterable); } @@ -12232,12 +12225,13 @@ str.ljust as unicode_ljust Return a left-justified string of length width. -Padding is done using the specified fill character (default is a space). +Padding is done using the specified fill character (default is +a space). [clinic start generated code]*/ static PyObject * unicode_ljust_impl(PyObject *self, Py_ssize_t width, Py_UCS4 fillchar) -/*[clinic end generated code: output=1cce0e0e0a0b84b3 input=3ab599e335e60a32]*/ +/*[clinic end generated code: output=1cce0e0e0a0b84b3 input=8a55f06694c20ed6]*/ { if (PyUnicode_GET_LENGTH(self) >= width) return unicode_result_unchanged(self); @@ -12593,7 +12587,6 @@ unicode_replace_impl(PyObject *self, PyObject *old, PyObject *new, } /*[clinic input] -@permit_long_docstring_body str.removeprefix as unicode_removeprefix prefix: unicode @@ -12601,13 +12594,14 @@ str.removeprefix as unicode_removeprefix Return a str with the given prefix string removed if present. -If the string starts with the prefix string, return string[len(prefix):]. -Otherwise, return a copy of the original string. +If the string starts with the prefix string, return +string[len(prefix):]. Otherwise, return a copy of the original +string. [clinic start generated code]*/ static PyObject * unicode_removeprefix_impl(PyObject *self, PyObject *prefix) -/*[clinic end generated code: output=f1e5945e9763bcb9 input=1989a856dbb813f1]*/ +/*[clinic end generated code: output=f1e5945e9763bcb9 input=90d162724944bfa7]*/ { int match = tailmatch(self, prefix, 0, PY_SSIZE_T_MAX, -1); if (match == -1) { @@ -12628,14 +12622,14 @@ str.removesuffix as unicode_removesuffix Return a str with the given suffix string removed if present. -If the string ends with the suffix string and that suffix is not empty, -return string[:-len(suffix)]. Otherwise, return a copy of the original -string. +If the string ends with the suffix string and that suffix is not +empty, return string[:-len(suffix)]. Otherwise, return a copy of +the original string. [clinic start generated code]*/ static PyObject * unicode_removesuffix_impl(PyObject *self, PyObject *suffix) -/*[clinic end generated code: output=d36629e227636822 input=12cc32561e769be4]*/ +/*[clinic end generated code: output=d36629e227636822 input=6efc96152d4bfcd5]*/ { int match = tailmatch(self, suffix, 0, PY_SSIZE_T_MAX, +1); if (match == -1) { @@ -12745,14 +12739,14 @@ str.rfind as unicode_rfind = str.count Return the highest index in S where substring sub is found, such that sub is contained within S[start:end]. -Optional arguments start and end are interpreted as in slice notation. -Return -1 on failure. +Optional arguments start and end are interpreted as in slice +notation. Return -1 on failure. [clinic start generated code]*/ static Py_ssize_t unicode_rfind_impl(PyObject *str, PyObject *substr, Py_ssize_t start, Py_ssize_t end) -/*[clinic end generated code: output=880b29f01dd014c8 input=7f7e97d5cd3299a2]*/ +/*[clinic end generated code: output=880b29f01dd014c8 input=2e67789533baf2f5]*/ { Py_ssize_t result = any_find_slice(str, substr, start, end, -1); if (result < 0) { @@ -12767,14 +12761,14 @@ str.rindex as unicode_rindex = str.count Return the highest index in S where substring sub is found, such that sub is contained within S[start:end]. -Optional arguments start and end are interpreted as in slice notation. -Raises ValueError when the substring is not found. +Optional arguments start and end are interpreted as in slice +notation. Raises ValueError when the substring is not found. [clinic start generated code]*/ static Py_ssize_t unicode_rindex_impl(PyObject *str, PyObject *substr, Py_ssize_t start, Py_ssize_t end) -/*[clinic end generated code: output=5f3aef124c867fe1 input=0363a324740b3e62]*/ +/*[clinic end generated code: output=5f3aef124c867fe1 input=e29d446c8234c9d9]*/ { Py_ssize_t result = any_find_slice(str, substr, start, end, -1); if (result == -1) { @@ -12795,12 +12789,13 @@ str.rjust as unicode_rjust Return a right-justified string of length width. -Padding is done using the specified fill character (default is a space). +Padding is done using the specified fill character (default is +a space). [clinic start generated code]*/ static PyObject * unicode_rjust_impl(PyObject *self, Py_ssize_t width, Py_UCS4 fillchar) -/*[clinic end generated code: output=804a1a57fbe8d5cf input=d05f550b5beb1f72]*/ +/*[clinic end generated code: output=804a1a57fbe8d5cf input=1256a8d659589907]*/ { if (PyUnicode_GET_LENGTH(self) >= width) return unicode_result_unchanged(self); @@ -12824,9 +12819,9 @@ str.split as unicode_split sep: object = None The separator used to split the string. - When set to None (the default value), will split on any whitespace - character (including \n \r \t \f and spaces) and will discard - empty strings from the result. + When set to None (the default value), will split on any + whitespace character (including \n \r \t \f and spaces) and + will discard empty strings from the result. maxsplit: Py_ssize_t = -1 Maximum number of splits. -1 (the default value) means no limit. @@ -12835,15 +12830,15 @@ Return a list of the substrings in the string, using sep as the separator string Splitting starts at the front of the string and works to the end. -Note, str.split() is mainly useful for data that has been intentionally -delimited. With natural text that includes punctuation, consider using -the regular expression module. +Note, str.split() is mainly useful for data that has been +intentionally delimited. With natural text that includes +punctuation, consider using the regular expression module. [clinic start generated code]*/ static PyObject * unicode_split_impl(PyObject *self, PyObject *sep, Py_ssize_t maxsplit) -/*[clinic end generated code: output=3a65b1db356948dc input=2c1fd08a78e038b8]*/ +/*[clinic end generated code: output=3a65b1db356948dc input=288cfd6bc8828f5a]*/ { if (sep == Py_None) return split(self, NULL, maxsplit); @@ -12960,7 +12955,6 @@ PyUnicode_RPartition(PyObject *str_obj, PyObject *sep_obj) } /*[clinic input] -@permit_long_docstring_body str.partition as unicode_partition sep: object @@ -12968,38 +12962,38 @@ str.partition as unicode_partition Partition the string into three parts using the given separator. -This will search for the separator in the string. If the separator is found, -returns a 3-tuple containing the part before the separator, the separator -itself, and the part after it. +This will search for the separator in the string. If the separator +is found, returns a 3-tuple containing the part before the +separator, the separator itself, and the part after it. -If the separator is not found, returns a 3-tuple containing the original string -and two empty strings. +If the separator is not found, returns a 3-tuple containing +the original string and two empty strings. [clinic start generated code]*/ static PyObject * unicode_partition(PyObject *self, PyObject *sep) -/*[clinic end generated code: output=e4ced7bd253ca3c4 input=4d854b520d7b0e97]*/ +/*[clinic end generated code: output=e4ced7bd253ca3c4 input=e45faa8c26270cb1]*/ { return PyUnicode_Partition(self, sep); } /*[clinic input] -@permit_long_docstring_body str.rpartition as unicode_rpartition = str.partition Partition the string into three parts using the given separator. -This will search for the separator in the string, starting at the end. If -the separator is found, returns a 3-tuple containing the part before the -separator, the separator itself, and the part after it. +This will search for the separator in the string, starting at the +end. If the separator is found, returns a 3-tuple containing the +part before the separator, the separator itself, and the part after +it. -If the separator is not found, returns a 3-tuple containing two empty strings -and the original string. +If the separator is not found, returns a 3-tuple containing two +empty strings and the original string. [clinic start generated code]*/ static PyObject * unicode_rpartition(PyObject *self, PyObject *sep) -/*[clinic end generated code: output=1aa13cf1156572aa input=a6adabe91e75b486]*/ +/*[clinic end generated code: output=1aa13cf1156572aa input=53a7f8cb19975b7c]*/ { return PyUnicode_RPartition(self, sep); } @@ -13038,20 +13032,20 @@ unicode_rsplit_impl(PyObject *self, PyObject *sep, Py_ssize_t maxsplit) } /*[clinic input] -@permit_long_docstring_body +@permit_long_summary str.splitlines as unicode_splitlines keepends: bool = False Return a list of the lines in the string, breaking at line boundaries. -Line breaks are not included in the resulting list unless keepends is given and -true. +Line breaks are not included in the resulting list unless keepends +is given and true. [clinic start generated code]*/ static PyObject * unicode_splitlines_impl(PyObject *self, int keepends) -/*[clinic end generated code: output=f664dcdad153ec40 input=39eeafbfef61c827]*/ +/*[clinic end generated code: output=f664dcdad153ec40 input=b45ea0f87645a06d]*/ { return PyUnicode_Splitlines(self, keepends); } @@ -13130,18 +13124,19 @@ str.maketrans as unicode_maketrans Return a translation table usable for str.translate(). -If there is only one argument, it must be a dictionary mapping Unicode -ordinals (integers) or characters to Unicode ordinals, strings or None. -Character keys will be then converted to ordinals. -If there are two arguments, they must be strings of equal length, and -in the resulting dictionary, each character in x will be mapped to the -character at the same position in y. If there is a third argument, it -must be a string, whose characters will be mapped to None in the result. +If there is only one argument, it must be a dictionary mapping +Unicode ordinals (integers) or characters to Unicode ordinals, +strings or None. Character keys will be then converted to ordinals. +If there are two arguments, they must be strings of equal length, +and in the resulting dictionary, each character in x will be mapped +to the character at the same position in y. If there is a third +argument, it must be a string, whose characters will be mapped to +None in the result. [clinic start generated code]*/ static PyObject * unicode_maketrans_impl(PyObject *x, PyObject *y, PyObject *z) -/*[clinic end generated code: output=a925c89452bd5881 input=7bfbf529a293c6c5]*/ +/*[clinic end generated code: output=a925c89452bd5881 input=66bc00a1b4258a6e]*/ { PyObject *new = NULL, *key, *value; Py_ssize_t i = 0; @@ -13221,24 +13216,25 @@ unicode_maketrans_impl(PyObject *x, PyObject *y, PyObject *z) } /*[clinic input] -@permit_long_docstring_body +@permit_long_summary str.translate as unicode_translate table: object - Translation table, which must be a mapping of Unicode ordinals to - Unicode ordinals, strings, or None. + Translation table, which must be a mapping of Unicode ordinals + to Unicode ordinals, strings, or None. / Replace each character in the string using the given translation table. -The table must implement lookup/indexing via __getitem__, for instance a -dictionary or list. If this operation raises LookupError, the character is -left untouched. Characters mapped to None are deleted. +The table must implement lookup/indexing via __getitem__, for +instance a dictionary or list. If this operation raises +LookupError, the character is left untouched. Characters mapped to +None are deleted. [clinic start generated code]*/ static PyObject * unicode_translate(PyObject *self, PyObject *table) -/*[clinic end generated code: output=3cb448ff2fd96bf3 input=699e5fa0ebf9f5e9]*/ +/*[clinic end generated code: output=3cb448ff2fd96bf3 input=48cf0efe06bc1b75]*/ { return _PyUnicode_TranslateCharmap(self, table, "ignore"); } @@ -13434,6 +13430,7 @@ Return a formatted version of the string, using substitutions from mapping.\n\ The substitutions are identified by braces ('{' and '}')."); /*[clinic input] +@permit_long_summary str.__format__ as unicode___format__ format_spec: unicode @@ -13444,7 +13441,7 @@ Return a formatted version of the string as described by format_spec. static PyObject * unicode___format___impl(PyObject *self, PyObject *format_spec) -/*[clinic end generated code: output=45fceaca6d2ba4c8 input=5e135645d167a214]*/ +/*[clinic end generated code: output=45fceaca6d2ba4c8 input=77a2a19f3f7969f2]*/ { _PyUnicodeWriter writer; int ret; diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c index 35b30a243318cc..d5129bf6a5a6bc 100644 --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -252,7 +252,6 @@ PyDoc_STRVAR(build_class_doc, Internal helper function used by the class statement."); /*[clinic input] -@permit_long_docstring_body __import__ as builtin___import__ name: object @@ -273,15 +272,16 @@ should be a list of names to emulate ``from name import ...``, or an empty list to emulate ``import name``. When importing a module from a package, note that __import__('A.B', ...) returns package A when fromlist is empty, but its submodule B when -fromlist is not empty. The level argument is used to determine whether to -perform absolute or relative imports: 0 is absolute, while a positive number -is the number of parent directories to search relative to the current module. +fromlist is not empty. The level argument is used to determine whether +to perform absolute or relative imports: 0 is absolute, while a positive +number is the number of parent directories to search relative to the +current module. [clinic start generated code]*/ static PyObject * builtin___import___impl(PyObject *module, PyObject *name, PyObject *globals, PyObject *locals, PyObject *fromlist, int level) -/*[clinic end generated code: output=4febeda88a0cd245 input=01a3283590eae93a]*/ +/*[clinic end generated code: output=4febeda88a0cd245 input=e3096a230383f72d]*/ { return PyImport_ImportModuleLevelObject(name, globals, locals, fromlist, level); @@ -299,15 +299,15 @@ __lazy_import__ as builtin___lazy_import__ Lazily imports a module. -Returns either the module to be imported or a imp.lazy_module object which -indicates the module to be lazily imported. +Returns either the module to be imported or a imp.lazy_module object +which indicates the module to be lazily imported. [clinic start generated code]*/ static PyObject * builtin___lazy_import___impl(PyObject *module, PyObject *name, PyObject *globals, PyObject *locals, PyObject *fromlist, int level) -/*[clinic end generated code: output=300f1771094b9e8c input=9394874f340b2948]*/ +/*[clinic end generated code: output=300f1771094b9e8c input=9c85cccd6a885b9b]*/ { PyObject *builtins; PyThreadState *tstate = PyThreadState_GET(); @@ -696,8 +696,9 @@ PyDoc_STRVAR(filter_doc, "filter(function, iterable, /)\n\ --\n\ \n\ -Return an iterator yielding those items of iterable for which function(item)\n\ -is true. If function is None, return the items that are true."); +Return an iterator yielding those items of iterable for which\n\ +function(item) is true. If function is None, return the items that\n\ +are true."); PyTypeObject PyFilter_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) @@ -770,6 +771,7 @@ builtin_format_impl(PyObject *module, PyObject *value, PyObject *format_spec) } /*[clinic input] +@permit_long_summary chr as builtin_chr i: object @@ -780,7 +782,7 @@ Return a Unicode string of one character with ordinal i; 0 <= i <= 0x10ffff. static PyObject * builtin_chr(PyObject *module, PyObject *i) -/*[clinic end generated code: output=d34f25b8035a9b10 input=f919867f0ba2f496]*/ +/*[clinic end generated code: output=d34f25b8035a9b10 input=a9b255f2d2e503f0]*/ { int overflow; long v = PyLong_AsLongAndOverflow(i, &overflow); @@ -804,6 +806,7 @@ builtin_chr(PyObject *module, PyObject *i) /*[clinic input] +@permit_long_summary compile as builtin_compile source: object @@ -818,23 +821,24 @@ compile as builtin_compile Compile source into a code object that can be executed by exec() or eval(). -The source code may represent a Python module, statement or expression. +The source code may represent a Python module, statement or +expression. The filename will be used for run-time error messages. The mode must be 'exec' to compile a module, 'single' to compile a single (interactive) statement, or 'eval' to compile an expression. -The flags argument, if present, controls which future statements influence -the compilation of the code. +The flags argument, if present, controls which future statements +influence the compilation of the code. The dont_inherit argument, if true, stops the compilation inheriting the effects of any future statements in effect in the code calling -compile; if absent or false these statements do influence the compilation, -in addition to any features explicitly specified. +compile; if absent or false these statements do influence the +compilation, in addition to any features explicitly specified. [clinic start generated code]*/ static PyObject * builtin_compile_impl(PyObject *module, PyObject *source, PyObject *filename, const char *mode, int flags, int dont_inherit, int optimize, PyObject *modname, int feature_version) -/*[clinic end generated code: output=9a0dce1945917a86 input=ddeae1e0253459dc]*/ +/*[clinic end generated code: output=9a0dce1945917a86 input=444c4fe466a97279]*/ { PyObject *source_copy; const char *str; @@ -982,10 +986,10 @@ PyDoc_STRVAR(dir_doc, "dir([object]) -> list of strings\n" "\n" "If called without an argument, return the names in the current scope.\n" -"Else, return an alphabetized list of names comprising (some of) the attributes\n" -"of the given object, and of attributes reachable from it.\n" -"If the object supplies a method named __dir__, it will be used; otherwise\n" -"the default dir() logic is used and returns:\n" +"Else, return an alphabetized list of names comprising (some of) the\n" +"attributes of the given object, and of attributes reachable from it.\n" +"If the object supplies a method named __dir__, it will be used;\n" +"otherwise the default dir() logic is used and returns:\n" " for a module object: the module's attributes.\n" " for a class object: its attributes, and recursively the attributes\n" " of its bases.\n" @@ -1326,9 +1330,11 @@ builtin_getattr(PyObject *self, PyObject *const *args, Py_ssize_t nargs) PyDoc_STRVAR(getattr_doc, "getattr(object, name[, default]) -> value\n\ \n\ -Get a named attribute from an object; getattr(x, 'y') is equivalent to x.y.\n\ -When a default argument is given, it is returned when the attribute doesn't\n\ -exist; without it, an exception is raised in that case."); +Get a named attribute from an object.\n\ +\n\ +getattr(x, 'y') is equivalent to x.y.\n\ +When a default argument is given, it is returned when the attribute\n\ +doesn't exist; without it, an exception is raised in that case."); /*[clinic input] @@ -1336,13 +1342,13 @@ globals as builtin_globals Return the dictionary containing the current scope's global variables. -NOTE: Updates to this dictionary *will* affect name lookups in the current -global scope and vice-versa. +NOTE: Updates to this dictionary *will* affect name lookups in the +current global scope and vice-versa. [clinic start generated code]*/ static PyObject * builtin_globals_impl(PyObject *module) -/*[clinic end generated code: output=e5dd1527067b94d2 input=9327576f92bb48ba]*/ +/*[clinic end generated code: output=e5dd1527067b94d2 input=6d725a9b48d1eaeb]*/ { PyObject *globals; if (_PyEval_GetFrame() != NULL) { @@ -1695,8 +1701,8 @@ PyDoc_STRVAR(map_doc, Make an iterator that computes the function using arguments from\n\ each of the iterables. Stops when the shortest iterable is exhausted.\n\ \n\ -If strict is true and one of the arguments is exhausted before the others,\n\ -raise a ValueError."); +If strict is true and one of the arguments is exhausted before the\n\ +others, raise a ValueError."); PyTypeObject PyMap_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) @@ -1783,8 +1789,8 @@ builtin_next(PyObject *self, PyObject *const *args, Py_ssize_t nargs) PyDoc_STRVAR(next_doc, "next(iterator[, default])\n\ \n\ -Return the next item from the iterator. If default is given and the iterator\n\ -is exhausted, it is returned instead of raising StopIteration."); +Return the next item from the iterator. If default is given and the\n\ +iterator is exhausted, it is returned instead of raising StopIteration."); /*[clinic input] @@ -1907,7 +1913,8 @@ iter(callable, sentinel) -> iterator\n\ \n\ Get an iterator from an object. In the first form, the argument must\n\ supply its own iterator, or be a sequence.\n\ -In the second form, the callable is called until it returns the sentinel."); +In the second form, the callable is called until it returns the\n\ +sentinel."); /*[clinic input] @@ -2001,14 +2008,15 @@ locals as builtin_locals Return a dictionary containing the current scope's local variables. -NOTE: Whether or not updates to this dictionary will affect name lookups in -the local scope and vice-versa is *implementation dependent* and not -covered by any backwards compatibility guarantees. +NOTE: Whether or not updates to this dictionary will affect name +lookups in the local scope and vice-versa is *implementation +dependent* and not covered by any backwards compatibility +guarantees. [clinic start generated code]*/ static PyObject * builtin_locals_impl(PyObject *module) -/*[clinic end generated code: output=b46c94015ce11448 input=7874018d478d5c4b]*/ +/*[clinic end generated code: output=b46c94015ce11448 input=989cc75c22167c42]*/ { PyObject *locals; if (_PyEval_GetFrame() != NULL) { @@ -2260,6 +2268,7 @@ builtin_ord(PyObject *module, PyObject *c) /*[clinic input] +@permit_long_summary pow as builtin_pow base: object @@ -2268,14 +2277,14 @@ pow as builtin_pow Equivalent to base**exp with 2 arguments or base**exp % mod with 3 arguments -Some types, such as ints, are able to use a more efficient algorithm when -invoked using the three argument form. +Some types, such as ints, are able to use a more efficient algorithm +when invoked using the three argument form. [clinic start generated code]*/ static PyObject * builtin_pow_impl(PyObject *module, PyObject *base, PyObject *exp, PyObject *mod) -/*[clinic end generated code: output=3ca1538221bbf15f input=435dbd48a12efb23]*/ +/*[clinic end generated code: output=3ca1538221bbf15f input=0cd5c3ecc8003aec]*/ { return PyNumber_Power(base, exp, mod); } @@ -2396,13 +2405,14 @@ Read a string from standard input. The trailing newline is stripped. The prompt string, if given, is printed to standard output without a trailing newline before reading input. -If the user hits EOF (*nix: Ctrl-D, Windows: Ctrl-Z+Return), raise EOFError. +If the user hits EOF (*nix: Ctrl-D, Windows: Ctrl-Z+Return), raise +EOFError. On *nix systems, readline is used if available. [clinic start generated code]*/ static PyObject * builtin_input_impl(PyObject *module, PyObject *prompt) -/*[clinic end generated code: output=83db5a191e7a0d60 input=159c46d4ae40977e]*/ +/*[clinic end generated code: output=83db5a191e7a0d60 input=ebb939c954639427]*/ { PyObject *fin = NULL; PyObject *fout = NULL; @@ -2670,13 +2680,14 @@ round as builtin_round Round a number to a given precision in decimal digits. -The return value is an integer if ndigits is omitted or None. Otherwise -the return value has the same type as the number. ndigits may be negative. +The return value is an integer if ndigits is omitted or None. +Otherwise the return value has the same type as the number. ndigits +may be negative. [clinic start generated code]*/ static PyObject * builtin_round_impl(PyObject *module, PyObject *number, PyObject *ndigits) -/*[clinic end generated code: output=ff0d9dd176c02ede input=275678471d7aca15]*/ +/*[clinic end generated code: output=ff0d9dd176c02ede input=bdcb7c67bf4a4320]*/ { PyObject *result; if (ndigits == Py_None) { @@ -2708,8 +2719,8 @@ sorted as builtin_sorted Return a new list containing all items from the iterable in ascending order. -A custom key function can be supplied to customize the sort order, and the -reverse flag can be set to request the result in descending order. +A custom key function can be supplied to customize the sort order, and +the reverse flag can be set to request the result in descending order. [end disabled clinic input]*/ PyDoc_STRVAR(builtin_sorted__doc__, @@ -2843,6 +2854,7 @@ cs_to_double(CompensatedSum total) } /*[clinic input] +@permit_long_summary sum as builtin_sum iterable: object @@ -2852,13 +2864,13 @@ sum as builtin_sum Return the sum of a 'start' value (default: 0) plus an iterable of numbers When the iterable is empty, return the start value. -This function is intended specifically for use with numeric values and may -reject non-numeric types. +This function is intended specifically for use with numeric values and +may reject non-numeric types. [clinic start generated code]*/ static PyObject * builtin_sum_impl(PyObject *module, PyObject *iterable, PyObject *start) -/*[clinic end generated code: output=df758cec7d1d302f input=162b50765250d222]*/ +/*[clinic end generated code: output=df758cec7d1d302f input=d464d57815196b73]*/ { PyObject *result = start; PyObject *temp, *item, *iter; @@ -3094,6 +3106,7 @@ builtin_sum_impl(PyObject *module, PyObject *iterable, PyObject *start) /*[clinic input] +@permit_long_summary isinstance as builtin_isinstance obj: object @@ -3102,15 +3115,15 @@ isinstance as builtin_isinstance Return whether an object is an instance of a class or of a subclass thereof. -A tuple, as in ``isinstance(x, (A, B, ...))``, may be given as the target to -check against. This is equivalent to ``isinstance(x, A) or isinstance(x, B) -or ...`` etc. +A tuple, as in ``isinstance(x, (A, B, ...))``, may be given as the +target to check against. This is equivalent to ``isinstance(x, A) or +isinstance(x, B) or ...`` etc. [clinic start generated code]*/ static PyObject * builtin_isinstance_impl(PyObject *module, PyObject *obj, PyObject *class_or_tuple) -/*[clinic end generated code: output=6faf01472c13b003 input=ffa743db1daf7549]*/ +/*[clinic end generated code: output=6faf01472c13b003 input=5d74d547df498f38]*/ { int retval; @@ -3130,15 +3143,15 @@ issubclass as builtin_issubclass Return whether 'cls' is derived from another class or is the same class. -A tuple, as in ``issubclass(x, (A, B, ...))``, may be given as the target to -check against. This is equivalent to ``issubclass(x, A) or issubclass(x, B) -or ...``. +A tuple, as in ``issubclass(x, (A, B, ...))``, may be given as the +target to check against. This is equivalent to ``issubclass(x, A) or +issubclass(x, B) or ...``. [clinic start generated code]*/ static PyObject * builtin_issubclass_impl(PyObject *module, PyObject *cls, PyObject *class_or_tuple) -/*[clinic end generated code: output=358412410cd7a250 input=a24b9f3d58c370d6]*/ +/*[clinic end generated code: output=358412410cd7a250 input=a91ce96345a6705d]*/ { int retval; @@ -3368,13 +3381,13 @@ PyDoc_STRVAR(zip_doc, "zip(*iterables, strict=False)\n\ --\n\ \n\ -The zip object yields n-length tuples, where n is the number of iterables\n\ -passed as positional arguments to zip(). The i-th element in every tuple\n\ -comes from the i-th iterable argument to zip(). This continues until the\n\ -shortest argument is exhausted.\n\ +The zip object yields n-length tuples, where n is the number of\n\ +iterables passed as positional arguments to zip(). The i-th element\n\ +in every tuple comes from the i-th iterable argument to zip(). This\n\ +continues until the shortest argument is exhausted.\n\ \n\ -If strict is true and one of the arguments is exhausted before the others,\n\ -raise a ValueError.\n\ +If strict is true and one of the arguments is exhausted before the\n\ +others, raise a ValueError.\n\ \n\ >>> list(zip('abcdefg', range(3), range(4)))\n\ [('a', 0, 0), ('b', 1, 1), ('c', 2, 2)]"); diff --git a/Python/clinic/bltinmodule.c.h b/Python/clinic/bltinmodule.c.h index e6b845cd375d73..4a38e0df61708c 100644 --- a/Python/clinic/bltinmodule.c.h +++ b/Python/clinic/bltinmodule.c.h @@ -25,9 +25,10 @@ PyDoc_STRVAR(builtin___import____doc__, "empty list to emulate ``import name``.\n" "When importing a module from a package, note that __import__(\'A.B\', ...)\n" "returns package A when fromlist is empty, but its submodule B when\n" -"fromlist is not empty. The level argument is used to determine whether to\n" -"perform absolute or relative imports: 0 is absolute, while a positive number\n" -"is the number of parent directories to search relative to the current module."); +"fromlist is not empty. The level argument is used to determine whether\n" +"to perform absolute or relative imports: 0 is absolute, while a positive\n" +"number is the number of parent directories to search relative to the\n" +"current module."); #define BUILTIN___IMPORT___METHODDEF \ {"__import__", _PyCFunction_CAST(builtin___import__), METH_FASTCALL|METH_KEYWORDS, builtin___import____doc__}, @@ -120,8 +121,8 @@ PyDoc_STRVAR(builtin___lazy_import____doc__, "\n" "Lazily imports a module.\n" "\n" -"Returns either the module to be imported or a imp.lazy_module object which\n" -"indicates the module to be lazily imported."); +"Returns either the module to be imported or a imp.lazy_module object\n" +"which indicates the module to be lazily imported."); #define BUILTIN___LAZY_IMPORT___METHODDEF \ {"__lazy_import__", _PyCFunction_CAST(builtin___lazy_import__), METH_FASTCALL|METH_KEYWORDS, builtin___lazy_import____doc__}, @@ -339,16 +340,17 @@ PyDoc_STRVAR(builtin_compile__doc__, "\n" "Compile source into a code object that can be executed by exec() or eval().\n" "\n" -"The source code may represent a Python module, statement or expression.\n" +"The source code may represent a Python module, statement or\n" +"expression.\n" "The filename will be used for run-time error messages.\n" "The mode must be \'exec\' to compile a module, \'single\' to compile a\n" "single (interactive) statement, or \'eval\' to compile an expression.\n" -"The flags argument, if present, controls which future statements influence\n" -"the compilation of the code.\n" +"The flags argument, if present, controls which future statements\n" +"influence the compilation of the code.\n" "The dont_inherit argument, if true, stops the compilation inheriting\n" "the effects of any future statements in effect in the code calling\n" -"compile; if absent or false these statements do influence the compilation,\n" -"in addition to any features explicitly specified."); +"compile; if absent or false these statements do influence the\n" +"compilation, in addition to any features explicitly specified."); #define BUILTIN_COMPILE_METHODDEF \ {"compile", _PyCFunction_CAST(builtin_compile), METH_FASTCALL|METH_KEYWORDS, builtin_compile__doc__}, @@ -683,8 +685,8 @@ PyDoc_STRVAR(builtin_globals__doc__, "\n" "Return the dictionary containing the current scope\'s global variables.\n" "\n" -"NOTE: Updates to this dictionary *will* affect name lookups in the current\n" -"global scope and vice-versa."); +"NOTE: Updates to this dictionary *will* affect name lookups in the\n" +"current global scope and vice-versa."); #define BUILTIN_GLOBALS_METHODDEF \ {"globals", (PyCFunction)builtin_globals, METH_NOARGS, builtin_globals__doc__}, @@ -910,9 +912,10 @@ PyDoc_STRVAR(builtin_locals__doc__, "\n" "Return a dictionary containing the current scope\'s local variables.\n" "\n" -"NOTE: Whether or not updates to this dictionary will affect name lookups in\n" -"the local scope and vice-versa is *implementation dependent* and not\n" -"covered by any backwards compatibility guarantees."); +"NOTE: Whether or not updates to this dictionary will affect name\n" +"lookups in the local scope and vice-versa is *implementation\n" +"dependent* and not covered by any backwards compatibility\n" +"guarantees."); #define BUILTIN_LOCALS_METHODDEF \ {"locals", (PyCFunction)builtin_locals, METH_NOARGS, builtin_locals__doc__}, @@ -959,8 +962,8 @@ PyDoc_STRVAR(builtin_pow__doc__, "\n" "Equivalent to base**exp with 2 arguments or base**exp % mod with 3 arguments\n" "\n" -"Some types, such as ints, are able to use a more efficient algorithm when\n" -"invoked using the three argument form."); +"Some types, such as ints, are able to use a more efficient algorithm\n" +"when invoked using the three argument form."); #define BUILTIN_POW_METHODDEF \ {"pow", _PyCFunction_CAST(builtin_pow), METH_FASTCALL|METH_KEYWORDS, builtin_pow__doc__}, @@ -1136,7 +1139,8 @@ PyDoc_STRVAR(builtin_input__doc__, "The prompt string, if given, is printed to standard output without a\n" "trailing newline before reading input.\n" "\n" -"If the user hits EOF (*nix: Ctrl-D, Windows: Ctrl-Z+Return), raise EOFError.\n" +"If the user hits EOF (*nix: Ctrl-D, Windows: Ctrl-Z+Return), raise\n" +"EOFError.\n" "On *nix systems, readline is used if available."); #define BUILTIN_INPUT_METHODDEF \ @@ -1182,8 +1186,9 @@ PyDoc_STRVAR(builtin_round__doc__, "\n" "Round a number to a given precision in decimal digits.\n" "\n" -"The return value is an integer if ndigits is omitted or None. Otherwise\n" -"the return value has the same type as the number. ndigits may be negative."); +"The return value is an integer if ndigits is omitted or None.\n" +"Otherwise the return value has the same type as the number. ndigits\n" +"may be negative."); #define BUILTIN_ROUND_METHODDEF \ {"round", _PyCFunction_CAST(builtin_round), METH_FASTCALL|METH_KEYWORDS, builtin_round__doc__}, @@ -1251,8 +1256,8 @@ PyDoc_STRVAR(builtin_sum__doc__, "Return the sum of a \'start\' value (default: 0) plus an iterable of numbers\n" "\n" "When the iterable is empty, return the start value.\n" -"This function is intended specifically for use with numeric values and may\n" -"reject non-numeric types."); +"This function is intended specifically for use with numeric values and\n" +"may reject non-numeric types."); #define BUILTIN_SUM_METHODDEF \ {"sum", _PyCFunction_CAST(builtin_sum), METH_FASTCALL|METH_KEYWORDS, builtin_sum__doc__}, @@ -1319,9 +1324,9 @@ PyDoc_STRVAR(builtin_isinstance__doc__, "\n" "Return whether an object is an instance of a class or of a subclass thereof.\n" "\n" -"A tuple, as in ``isinstance(x, (A, B, ...))``, may be given as the target to\n" -"check against. This is equivalent to ``isinstance(x, A) or isinstance(x, B)\n" -"or ...`` etc."); +"A tuple, as in ``isinstance(x, (A, B, ...))``, may be given as the\n" +"target to check against. This is equivalent to ``isinstance(x, A) or\n" +"isinstance(x, B) or ...`` etc."); #define BUILTIN_ISINSTANCE_METHODDEF \ {"isinstance", _PyCFunction_CAST(builtin_isinstance), METH_FASTCALL, builtin_isinstance__doc__}, @@ -1354,9 +1359,9 @@ PyDoc_STRVAR(builtin_issubclass__doc__, "\n" "Return whether \'cls\' is derived from another class or is the same class.\n" "\n" -"A tuple, as in ``issubclass(x, (A, B, ...))``, may be given as the target to\n" -"check against. This is equivalent to ``issubclass(x, A) or issubclass(x, B)\n" -"or ...``."); +"A tuple, as in ``issubclass(x, (A, B, ...))``, may be given as the\n" +"target to check against. This is equivalent to ``issubclass(x, A) or\n" +"issubclass(x, B) or ...``."); #define BUILTIN_ISSUBCLASS_METHODDEF \ {"issubclass", _PyCFunction_CAST(builtin_issubclass), METH_FASTCALL, builtin_issubclass__doc__}, @@ -1382,4 +1387,4 @@ builtin_issubclass(PyObject *module, PyObject *const *args, Py_ssize_t nargs) exit: return return_value; } -/*[clinic end generated code: output=f1fc836a63d89826 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=84efa9c5cc737ce5 input=a9049054013a1b77]*/ From 3573b3b1ecbd99030a0b18658e1bfece771b2566 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 24 May 2026 15:36:30 +0200 Subject: [PATCH 131/818] [3.15] gh-149018: Use `XML_SetHashSalt16Bytes` in `pyexpat`/`_elementtree` when possible (#149645) (cherry picked from commit 24b8f12544468e4cedf5bfbe25442fcd495391e4) Co-authored-by: Stan Ulbrych --- Include/internal/pycore_pyhash.h | 8 +++++--- Include/pyexpat.h | 3 +++ .../2026-04-26-19-30-45.gh-issue-149018.a9SqWb.rst | 3 +++ Modules/_elementtree.c | 8 ++++++-- Modules/pyexpat.c | 10 +++++++++- 5 files changed, 26 insertions(+), 6 deletions(-) create mode 100644 Misc/NEWS.d/next/Security/2026-04-26-19-30-45.gh-issue-149018.a9SqWb.rst diff --git a/Include/internal/pycore_pyhash.h b/Include/internal/pycore_pyhash.h index 84cb72fa6fd1b2..3056dc44cc0f1b 100644 --- a/Include/internal/pycore_pyhash.h +++ b/Include/internal/pycore_pyhash.h @@ -27,14 +27,14 @@ _Py_HashPointerRaw(const void *ptr) * pppppppp ssssssss ........ fnv -- two Py_hash_t * k0k0k0k0 k1k1k1k1 ........ siphash -- two uint64_t * ........ ........ ssssssss djbx33a -- 16 bytes padding + one Py_hash_t - * ........ ........ eeeeeeee pyexpat XML hash salt + * eeeeeeee eeeeeeee eeeeeeee pyexpat XML hash salt * * memory layout on 32 bit systems * cccccccc cccccccc cccccccc uc * ppppssss ........ ........ fnv -- two Py_hash_t * k0k0k0k0 k1k1k1k1 ........ siphash -- two uint64_t (*) * ........ ........ ssss.... djbx33a -- 16 bytes padding + one Py_hash_t - * ........ ........ eeee.... pyexpat XML hash salt + * eeeeeeee eeeeeeee eeee.... pyexpat XML hash salt * * (*) The siphash member may not be available on 32 bit platforms without * an unsigned int64 data type. @@ -58,7 +58,9 @@ typedef union { Py_hash_t suffix; } djbx33a; struct { - unsigned char padding[16]; + /* 16 bytes for XML_SetHashSalt16Bytes */ + uint8_t hashsalt16[16]; + /* 4/8 bytes for legacy XML_SetHashSalt */ Py_hash_t hashsalt; } expat; } _Py_HashSecret_t; diff --git a/Include/pyexpat.h b/Include/pyexpat.h index f523f8bb273983..a676e16a7a457e 100644 --- a/Include/pyexpat.h +++ b/Include/pyexpat.h @@ -62,6 +62,9 @@ struct PyExpat_CAPI XML_Parser parser, unsigned long long activationThresholdBytes); XML_Bool (*SetBillionLaughsAttackProtectionMaximumAmplification)( XML_Parser parser, float maxAmplificationFactor); + /* might be NULL for expat < 2.8.0 */ + XML_Bool (*SetHashSalt16Bytes)( + XML_Parser parser, const uint8_t entropy[16]); /* always add new stuff to the end! */ }; diff --git a/Misc/NEWS.d/next/Security/2026-04-26-19-30-45.gh-issue-149018.a9SqWb.rst b/Misc/NEWS.d/next/Security/2026-04-26-19-30-45.gh-issue-149018.a9SqWb.rst new file mode 100644 index 00000000000000..d1b5b368684e6a --- /dev/null +++ b/Misc/NEWS.d/next/Security/2026-04-26-19-30-45.gh-issue-149018.a9SqWb.rst @@ -0,0 +1,3 @@ +Improved protection against XML hash-flooding attacks in +:mod:`xml.parsers.expat` and :mod:`xml.etree.ElementTree` when Python is +compiled with libExpat 2.8.0 or later. diff --git a/Modules/_elementtree.c b/Modules/_elementtree.c index cbd1e026df2722..9e794be5c109ba 100644 --- a/Modules/_elementtree.c +++ b/Modules/_elementtree.c @@ -3735,8 +3735,12 @@ _elementtree_XMLParser___init___impl(XMLParserObject *self, PyObject *target, PyErr_NoMemory(); return -1; } - /* expat < 2.1.0 has no XML_SetHashSalt() */ - if (EXPAT(st, SetHashSalt) != NULL) { + // Prefer 16-byte entropy, only expat >= 2.8.0. See gh-149018 + if (EXPAT(st, SetHashSalt16Bytes) != NULL) { + EXPAT(st, SetHashSalt16Bytes)(self->parser, + _Py_HashSecret.expat.hashsalt16); + } + else if (EXPAT(st, SetHashSalt) != NULL) { EXPAT(st, SetHashSalt)(self->parser, (unsigned long)_Py_HashSecret.expat.hashsalt); } diff --git a/Modules/pyexpat.c b/Modules/pyexpat.c index c01f7babe74527..64314e5dff93a1 100644 --- a/Modules/pyexpat.c +++ b/Modules/pyexpat.c @@ -1533,7 +1533,10 @@ newxmlparseobject(pyexpat_state *state, const char *encoding, Py_DECREF(self); return NULL; } -#if XML_COMBINED_VERSION >= 20100 +#if XML_COMBINED_VERSION >= 20800 + /* This feature was added upstream in libexpat 2.8.0. */ + XML_SetHashSalt16Bytes(self->itself, _Py_HashSecret.expat.hashsalt16); +#elif XML_COMBINED_VERSION >= 20100 /* This feature was added upstream in libexpat 2.1.0. */ XML_SetHashSalt(self->itself, (unsigned long)_Py_HashSecret.expat.hashsalt); @@ -2427,6 +2430,11 @@ pyexpat_exec(PyObject *mod) #else capi->SetHashSalt = NULL; #endif +#if XML_COMBINED_VERSION >= 20800 + capi->SetHashSalt16Bytes = XML_SetHashSalt16Bytes; +#else + capi->SetHashSalt16Bytes = NULL; +#endif #if XML_COMBINED_VERSION >= 20600 capi->SetReparseDeferralEnabled = XML_SetReparseDeferralEnabled; #else From d52dad6989eb79fd01378654954cd79c363c1179 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 24 May 2026 15:39:29 +0200 Subject: [PATCH 132/818] [3.15] gh-149619: Fix `_remote_debugging` permissions error on Linux (GH-150012) (#150339) gh-149619: Fix `_remote_debugging` permissions error on Linux (GH-150012) When running profiling on Linux without sudo, attempts to read process memory would fail with the misleading error 'Failed to find the PyRuntime section in process on Linux platform'. The actual issue is a permissions error because profiling was not run with sudo. We were clearing the exception on Linux when trying to read memory, instead, we should bubble up the permissions error and show it properly. (cherry picked from commit 0563890872b3c63f94953e983fe396615b708540) Co-authored-by: ivonastojanovic <80911834+ivonastojanovic@users.noreply.github.com> --- Python/remote_debug.h | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/Python/remote_debug.h b/Python/remote_debug.h index 7b2c4f3bcb8077..53bbd571ad3cef 100644 --- a/Python/remote_debug.h +++ b/Python/remote_debug.h @@ -170,7 +170,9 @@ _Py_RemoteDebug_ValidatePyRuntimeCookie(proc_handle_t *handle, uintptr_t address } char buf[sizeof(_Py_Debug_Cookie) - 1]; if (_Py_RemoteDebug_ReadRemoteMemory(handle, address, sizeof(buf), buf) != 0) { - PyErr_Clear(); + if (!PyErr_ExceptionMatches(PyExc_PermissionError)) { + PyErr_Clear(); + } return 0; } return memcmp(buf, _Py_Debug_Cookie, sizeof(buf)) == 0; @@ -785,6 +787,10 @@ search_linux_map_for_section(proc_handle_t *handle, const char* secname, const c } if (strstr(filename, substr)) { + if (PyErr_ExceptionMatches(PyExc_PermissionError)) { + retval = 0; + break; + } PyErr_Clear(); retval = search_elf_file_for_section(handle, secname, start, path); if (retval @@ -960,12 +966,14 @@ _Py_RemoteDebug_GetPyRuntimeAddress(proc_handle_t* handle) address = search_linux_map_for_section(handle, "PyRuntime", "python", _Py_RemoteDebug_ValidatePyRuntimeCookie); if (address == 0) { - // Error out: 'python' substring covers both executable and DLL - PyObject *exc = PyErr_GetRaisedException(); - PyErr_Format(PyExc_RuntimeError, - "Failed to find the PyRuntime section in process %d on Linux platform", - handle->pid); - _PyErr_ChainExceptions1(exc); + if (!PyErr_ExceptionMatches(PyExc_PermissionError)) { + // Error out: 'python' substring covers both executable and DLL + PyObject *exc = PyErr_GetRaisedException(); + PyErr_Format(PyExc_RuntimeError, + "Failed to find the PyRuntime section in process %d on Linux platform", + handle->pid); + _PyErr_ChainExceptions1(exc); + } } #elif defined(__APPLE__) && defined(TARGET_OS_OSX) && TARGET_OS_OSX // On macOS, try libpython first, then fall back to python From baf22f34cab477faa007c4ebc04841db3a727af9 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 24 May 2026 15:41:40 +0200 Subject: [PATCH 133/818] [3.15] gh-150285: Fix too long docstrings in the pyexpat module (GH-150294) (GH-150337) (cherry picked from commit 9da7923835a4c72e738551bbd78b8179a81286ad) Co-authored-by: Serhiy Storchaka --- Modules/clinic/pyexpat.c.h | 73 +++++++++++++++++------------- Modules/pyexpat.c | 93 ++++++++++++++++++++------------------ 2 files changed, 90 insertions(+), 76 deletions(-) diff --git a/Modules/clinic/pyexpat.c.h b/Modules/clinic/pyexpat.c.h index ff2e28269dc927..1a07726d303eca 100644 --- a/Modules/clinic/pyexpat.c.h +++ b/Modules/clinic/pyexpat.c.h @@ -218,8 +218,9 @@ PyDoc_STRVAR(pyexpat_xmlparser_GetInputContext__doc__, "\n" "Return the untranslated text of the input that caused the current event.\n" "\n" -"If the event was generated by a large amount of text (such as a start tag\n" -"for an element with many attributes), not all of the text may be available."); +"If the event was generated by a large amount of text (such as\n" +"a start tag for an element with many attributes), not all of the\n" +"text may be available."); #define PYEXPAT_XMLPARSER_GETINPUTCONTEXT_METHODDEF \ {"GetInputContext", (PyCFunction)pyexpat_xmlparser_GetInputContext, METH_NOARGS, pyexpat_xmlparser_GetInputContext__doc__}, @@ -357,9 +358,10 @@ PyDoc_STRVAR(pyexpat_xmlparser_UseForeignDTD__doc__, "\n" "Allows the application to provide an artificial external subset if one is not specified as part of the document instance.\n" "\n" -"This readily allows the use of a \'default\' document type controlled by the\n" -"application, while still getting the advantage of providing document type\n" -"information to the parser. \'flag\' defaults to True if not provided."); +"This readily allows the use of a \'default\' document type controlled\n" +"by the application, while still getting the advantage of providing\n" +"document type information to the parser. \'flag\' defaults to True if\n" +"not provided."); #define PYEXPAT_XMLPARSER_USEFOREIGNDTD_METHODDEF \ {"UseForeignDTD", _PyCFunction_CAST(pyexpat_xmlparser_UseForeignDTD), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, pyexpat_xmlparser_UseForeignDTD__doc__}, @@ -417,14 +419,15 @@ PyDoc_STRVAR(pyexpat_xmlparser_SetBillionLaughsAttackProtectionActivationThresho "\n" "Sets the number of output bytes needed to activate protection against billion laughs attacks.\n" "\n" -"The number of output bytes includes amplification from entity expansion\n" -"and reading DTD files.\n" +"The number of output bytes includes amplification from entity\n" +"expansion and reading DTD files.\n" "\n" -"Parser objects usually have a protection activation threshold of 8 MiB,\n" -"but the actual default value depends on the underlying Expat library.\n" +"Parser objects usually have a protection activation threshold of\n" +"8 MiB, but the actual default value depends on the underlying Expat\n" +"library.\n" "\n" -"Activation thresholds below 4 MiB are known to break support for DITA 1.3\n" -"payload and are hence not recommended."); +"Activation thresholds below 4 MiB are known to break support for\n" +"DITA 1.3 payload and are hence not recommended."); #define PYEXPAT_XMLPARSER_SETBILLIONLAUGHSATTACKPROTECTIONACTIVATIONTHRESHOLD_METHODDEF \ {"SetBillionLaughsAttackProtectionActivationThreshold", _PyCFunction_CAST(pyexpat_xmlparser_SetBillionLaughsAttackProtectionActivationThreshold), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, pyexpat_xmlparser_SetBillionLaughsAttackProtectionActivationThreshold__doc__}, @@ -479,18 +482,21 @@ PyDoc_STRVAR(pyexpat_xmlparser_SetBillionLaughsAttackProtectionMaximumAmplificat "\n" "Sets the maximum tolerated amplification factor for protection against billion laughs attacks.\n" "\n" -"The amplification factor is calculated as \"(direct + indirect) / direct\"\n" -"while parsing, where \"direct\" is the number of bytes read from the primary\n" -"document in parsing and \"indirect\" is the number of bytes added by expanding\n" -"entities and reading external DTD files, combined.\n" +"The amplification factor is calculated as \"(direct + indirect) /\n" +"direct\" while parsing, where \"direct\" is the number of bytes read\n" +"from the primary document in parsing and \"indirect\" is the number of\n" +"bytes added by expanding entities and reading external DTD files,\n" +"combined.\n" "\n" -"The \'max_factor\' value must be a non-NaN floating point value greater than\n" -"or equal to 1.0. Amplification factors greater than 30,000 can be observed\n" -"in the middle of parsing even with benign files in practice. In particular,\n" -"the activation threshold should be carefully chosen to avoid false positives.\n" +"The \'max_factor\' value must be a non-NaN floating point value\n" +"greater than or equal to 1.0. Amplification factors greater than\n" +"30,000 can be observed in the middle of parsing even with benign\n" +"files in practice. In particular, the activation threshold should\n" +"be carefully chosen to avoid false positives.\n" "\n" "Parser objects usually have a maximum amplification factor of 100,\n" -"but the actual default value depends on the underlying Expat library."); +"but the actual default value depends on the underlying Expat\n" +"library."); #define PYEXPAT_XMLPARSER_SETBILLIONLAUGHSATTACKPROTECTIONMAXIMUMAMPLIFICATION_METHODDEF \ {"SetBillionLaughsAttackProtectionMaximumAmplification", _PyCFunction_CAST(pyexpat_xmlparser_SetBillionLaughsAttackProtectionMaximumAmplification), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, pyexpat_xmlparser_SetBillionLaughsAttackProtectionMaximumAmplification__doc__}, @@ -551,8 +557,9 @@ PyDoc_STRVAR(pyexpat_xmlparser_SetAllocTrackerActivationThreshold__doc__, "\n" "Sets the number of allocated bytes of dynamic memory needed to activate protection against disproportionate use of RAM.\n" "\n" -"Parser objects usually have an allocation activation threshold of 64 MiB,\n" -"but the actual default value depends on the underlying Expat library."); +"Parser objects usually have an allocation activation threshold of\n" +"64 MiB, but the actual default value depends on the underlying Expat\n" +"library."); #define PYEXPAT_XMLPARSER_SETALLOCTRACKERACTIVATIONTHRESHOLD_METHODDEF \ {"SetAllocTrackerActivationThreshold", _PyCFunction_CAST(pyexpat_xmlparser_SetAllocTrackerActivationThreshold), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, pyexpat_xmlparser_SetAllocTrackerActivationThreshold__doc__}, @@ -606,18 +613,20 @@ PyDoc_STRVAR(pyexpat_xmlparser_SetAllocTrackerMaximumAmplification__doc__, "\n" "Sets the maximum amplification factor between direct input and bytes of dynamic memory allocated.\n" "\n" -"The amplification factor is calculated as \"allocated / direct\" while parsing,\n" -"where \"direct\" is the number of bytes read from the primary document in parsing\n" -"and \"allocated\" is the number of bytes of dynamic memory allocated in the parser\n" -"hierarchy.\n" +"The amplification factor is calculated as \"allocated / direct\" while\n" +"parsing, where \"direct\" is the number of bytes read from the primary\n" +"document in parsing and \"allocated\" is the number of bytes of\n" +"dynamic memory allocated in the parser hierarchy.\n" "\n" -"The \'max_factor\' value must be a non-NaN floating point value greater than\n" -"or equal to 1.0. Amplification factors greater than 100.0 can be observed\n" -"near the start of parsing even with benign files in practice. In particular,\n" -"the activation threshold should be carefully chosen to avoid false positives.\n" +"The \'max_factor\' value must be a non-NaN floating point value\n" +"greater than or equal to 1.0. Amplification factors greater than\n" +"100.0 can be observed near the start of parsing even with benign\n" +"files in practice. In particular, the activation threshold should\n" +"be carefully chosen to avoid false positives.\n" "\n" "Parser objects usually have a maximum amplification factor of 100,\n" -"but the actual default value depends on the underlying Expat library."); +"but the actual default value depends on the underlying Expat\n" +"library."); #define PYEXPAT_XMLPARSER_SETALLOCTRACKERMAXIMUMAMPLIFICATION_METHODDEF \ {"SetAllocTrackerMaximumAmplification", _PyCFunction_CAST(pyexpat_xmlparser_SetAllocTrackerMaximumAmplification), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, pyexpat_xmlparser_SetAllocTrackerMaximumAmplification__doc__}, @@ -830,4 +839,4 @@ pyexpat_ErrorString(PyObject *module, PyObject *arg) #ifndef PYEXPAT_XMLPARSER_SETALLOCTRACKERMAXIMUMAMPLIFICATION_METHODDEF #define PYEXPAT_XMLPARSER_SETALLOCTRACKERMAXIMUMAMPLIFICATION_METHODDEF #endif /* !defined(PYEXPAT_XMLPARSER_SETALLOCTRACKERMAXIMUMAMPLIFICATION_METHODDEF) */ -/*[clinic end generated code: output=81101a16a409daf6 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=270a0bfe3300e8a1 input=a9049054013a1b77]*/ diff --git a/Modules/pyexpat.c b/Modules/pyexpat.c index 64314e5dff93a1..d204b6f27d9908 100644 --- a/Modules/pyexpat.c +++ b/Modules/pyexpat.c @@ -830,6 +830,7 @@ get_parse_result(pyexpat_state *state, xmlparseobject *self, int rv) #define MAX_CHUNK_SIZE (1 << 20) /*[clinic input] +@permit_long_summary pyexpat.xmlparser.SetReparseDeferralEnabled enabled: bool @@ -841,7 +842,7 @@ Enable/Disable reparse deferral; enabled by default with Expat >=2.6.0. static PyObject * pyexpat_xmlparser_SetReparseDeferralEnabled_impl(xmlparseobject *self, int enabled) -/*[clinic end generated code: output=5ec539e3b63c8c49 input=021eb9e0bafc32c5]*/ +/*[clinic end generated code: output=5ec539e3b63c8c49 input=6d3743500dcee799]*/ { #if XML_COMBINED_VERSION >= 20600 XML_SetReparseDeferralEnabled(self->itself, enabled ? XML_TRUE : XML_FALSE); @@ -1053,18 +1054,19 @@ pyexpat_xmlparser_GetBase_impl(xmlparseobject *self) } /*[clinic input] -@permit_long_docstring_body +@permit_long_summary pyexpat.xmlparser.GetInputContext Return the untranslated text of the input that caused the current event. -If the event was generated by a large amount of text (such as a start tag -for an element with many attributes), not all of the text may be available. +If the event was generated by a large amount of text (such as +a start tag for an element with many attributes), not all of the +text may be available. [clinic start generated code]*/ static PyObject * pyexpat_xmlparser_GetInputContext_impl(xmlparseobject *self) -/*[clinic end generated code: output=a88026d683fc22cc input=925cea010fdfa682]*/ +/*[clinic end generated code: output=a88026d683fc22cc input=a672f48f09bb73d2]*/ { if (self->in_callback) { int offset, size; @@ -1191,7 +1193,6 @@ pyexpat_xmlparser_SetParamEntityParsing_impl(xmlparseobject *self, int flag) #if XML_COMBINED_VERSION >= 19505 /*[clinic input] @permit_long_summary -@permit_long_docstring_body pyexpat.xmlparser.UseForeignDTD cls: defining_class @@ -1200,15 +1201,16 @@ pyexpat.xmlparser.UseForeignDTD Allows the application to provide an artificial external subset if one is not specified as part of the document instance. -This readily allows the use of a 'default' document type controlled by the -application, while still getting the advantage of providing document type -information to the parser. 'flag' defaults to True if not provided. +This readily allows the use of a 'default' document type controlled +by the application, while still getting the advantage of providing +document type information to the parser. 'flag' defaults to True if +not provided. [clinic start generated code]*/ static PyObject * pyexpat_xmlparser_UseForeignDTD_impl(xmlparseobject *self, PyTypeObject *cls, int flag) -/*[clinic end generated code: output=d7d98252bd25a20f input=c2264845d8c0029c]*/ +/*[clinic end generated code: output=d7d98252bd25a20f input=2920baa5bf24714d]*/ { pyexpat_state *state = PyType_GetModuleState(cls); enum XML_Error rc; @@ -1268,7 +1270,6 @@ set_maximum_amplification(xmlparseobject *self, #if XML_COMBINED_VERSION >= 20400 /*[clinic input] @permit_long_summary -@permit_long_docstring_body pyexpat.xmlparser.SetBillionLaughsAttackProtectionActivationThreshold cls: defining_class @@ -1277,21 +1278,22 @@ pyexpat.xmlparser.SetBillionLaughsAttackProtectionActivationThreshold Sets the number of output bytes needed to activate protection against billion laughs attacks. -The number of output bytes includes amplification from entity expansion -and reading DTD files. +The number of output bytes includes amplification from entity +expansion and reading DTD files. -Parser objects usually have a protection activation threshold of 8 MiB, -but the actual default value depends on the underlying Expat library. +Parser objects usually have a protection activation threshold of +8 MiB, but the actual default value depends on the underlying Expat +library. -Activation thresholds below 4 MiB are known to break support for DITA 1.3 -payload and are hence not recommended. +Activation thresholds below 4 MiB are known to break support for +DITA 1.3 payload and are hence not recommended. [clinic start generated code]*/ static PyObject * pyexpat_xmlparser_SetBillionLaughsAttackProtectionActivationThreshold_impl(xmlparseobject *self, PyTypeObject *cls, unsigned long long threshold) -/*[clinic end generated code: output=0c082342f1c78114 input=fa2f91f26b62a42a]*/ +/*[clinic end generated code: output=0c082342f1c78114 input=8d84b0e3a873cdba]*/ { return set_activation_threshold( self, cls, threshold, @@ -1303,7 +1305,6 @@ pyexpat_xmlparser_SetBillionLaughsAttackProtectionActivationThreshold_impl(xmlpa #if XML_COMBINED_VERSION >= 20400 /*[clinic input] @permit_long_summary -@permit_long_docstring_body pyexpat.xmlparser.SetBillionLaughsAttackProtectionMaximumAmplification cls: defining_class @@ -1312,25 +1313,28 @@ pyexpat.xmlparser.SetBillionLaughsAttackProtectionMaximumAmplification Sets the maximum tolerated amplification factor for protection against billion laughs attacks. -The amplification factor is calculated as "(direct + indirect) / direct" -while parsing, where "direct" is the number of bytes read from the primary -document in parsing and "indirect" is the number of bytes added by expanding -entities and reading external DTD files, combined. +The amplification factor is calculated as "(direct + indirect) / +direct" while parsing, where "direct" is the number of bytes read +from the primary document in parsing and "indirect" is the number of +bytes added by expanding entities and reading external DTD files, +combined. -The 'max_factor' value must be a non-NaN floating point value greater than -or equal to 1.0. Amplification factors greater than 30,000 can be observed -in the middle of parsing even with benign files in practice. In particular, -the activation threshold should be carefully chosen to avoid false positives. +The 'max_factor' value must be a non-NaN floating point value +greater than or equal to 1.0. Amplification factors greater than +30,000 can be observed in the middle of parsing even with benign +files in practice. In particular, the activation threshold should +be carefully chosen to avoid false positives. Parser objects usually have a maximum amplification factor of 100, -but the actual default value depends on the underlying Expat library. +but the actual default value depends on the underlying Expat +library. [clinic start generated code]*/ static PyObject * pyexpat_xmlparser_SetBillionLaughsAttackProtectionMaximumAmplification_impl(xmlparseobject *self, PyTypeObject *cls, float max_factor) -/*[clinic end generated code: output=c590439eadf463fa input=cc1e97c1fd2bd950]*/ +/*[clinic end generated code: output=c590439eadf463fa input=d0f11971c5b9e98b]*/ { return set_maximum_amplification( self, cls, max_factor, @@ -1342,7 +1346,6 @@ pyexpat_xmlparser_SetBillionLaughsAttackProtectionMaximumAmplification_impl(xmlp #if XML_COMBINED_VERSION >= 20702 /*[clinic input] @permit_long_summary -@permit_long_docstring_body pyexpat.xmlparser.SetAllocTrackerActivationThreshold cls: defining_class @@ -1351,15 +1354,16 @@ pyexpat.xmlparser.SetAllocTrackerActivationThreshold Sets the number of allocated bytes of dynamic memory needed to activate protection against disproportionate use of RAM. -Parser objects usually have an allocation activation threshold of 64 MiB, -but the actual default value depends on the underlying Expat library. +Parser objects usually have an allocation activation threshold of +64 MiB, but the actual default value depends on the underlying Expat +library. [clinic start generated code]*/ static PyObject * pyexpat_xmlparser_SetAllocTrackerActivationThreshold_impl(xmlparseobject *self, PyTypeObject *cls, unsigned long long threshold) -/*[clinic end generated code: output=bed7e93207ba08c5 input=b7a7a3e3d054286a]*/ +/*[clinic end generated code: output=bed7e93207ba08c5 input=4728360b545de87a]*/ { return set_activation_threshold( self, cls, threshold, @@ -1371,7 +1375,6 @@ pyexpat_xmlparser_SetAllocTrackerActivationThreshold_impl(xmlparseobject *self, #if XML_COMBINED_VERSION >= 20702 /*[clinic input] @permit_long_summary -@permit_long_docstring_body pyexpat.xmlparser.SetAllocTrackerMaximumAmplification cls: defining_class @@ -1380,25 +1383,27 @@ pyexpat.xmlparser.SetAllocTrackerMaximumAmplification Sets the maximum amplification factor between direct input and bytes of dynamic memory allocated. -The amplification factor is calculated as "allocated / direct" while parsing, -where "direct" is the number of bytes read from the primary document in parsing -and "allocated" is the number of bytes of dynamic memory allocated in the parser -hierarchy. +The amplification factor is calculated as "allocated / direct" while +parsing, where "direct" is the number of bytes read from the primary +document in parsing and "allocated" is the number of bytes of +dynamic memory allocated in the parser hierarchy. -The 'max_factor' value must be a non-NaN floating point value greater than -or equal to 1.0. Amplification factors greater than 100.0 can be observed -near the start of parsing even with benign files in practice. In particular, -the activation threshold should be carefully chosen to avoid false positives. +The 'max_factor' value must be a non-NaN floating point value +greater than or equal to 1.0. Amplification factors greater than +100.0 can be observed near the start of parsing even with benign +files in practice. In particular, the activation threshold should +be carefully chosen to avoid false positives. Parser objects usually have a maximum amplification factor of 100, -but the actual default value depends on the underlying Expat library. +but the actual default value depends on the underlying Expat +library. [clinic start generated code]*/ static PyObject * pyexpat_xmlparser_SetAllocTrackerMaximumAmplification_impl(xmlparseobject *self, PyTypeObject *cls, float max_factor) -/*[clinic end generated code: output=6e44bd48c9b112a0 input=c6af7ccb76ae5c6b]*/ +/*[clinic end generated code: output=6e44bd48c9b112a0 input=dd23ea3ef2069b69]*/ { return set_maximum_amplification( self, cls, max_factor, From 79937e3cf12ca9700da28389dd357014e9ae6a3b Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 24 May 2026 15:43:38 +0200 Subject: [PATCH 134/818] [3.15] gh-150285: Fix too long docstrings in the sqlite3 module (GH-150290) (GH-150340) (cherry picked from commit 0466560b310fa74c38270328d66d6a16df95ec34) Co-authored-by: Serhiy Storchaka --- Modules/_sqlite/blob.c | 26 ++++++------- Modules/_sqlite/clinic/blob.c.h | 19 ++++----- Modules/_sqlite/clinic/connection.c.h | 41 +++++++++++--------- Modules/_sqlite/connection.c | 56 +++++++++++++-------------- 4 files changed, 72 insertions(+), 70 deletions(-) diff --git a/Modules/_sqlite/blob.c b/Modules/_sqlite/blob.c index 8dad94556236bd..2cc62751054278 100644 --- a/Modules/_sqlite/blob.c +++ b/Modules/_sqlite/blob.c @@ -166,7 +166,6 @@ read_multiple(pysqlite_Blob *self, Py_ssize_t length, Py_ssize_t offset) /*[clinic input] -@permit_long_docstring_body _sqlite3.Blob.read as blob_read length: int = -1 @@ -175,14 +174,14 @@ _sqlite3.Blob.read as blob_read Read data at the current offset position. -If the end of the blob is reached, the data up to end of file will be returned. -When length is not specified, or is negative, Blob.read() will read until the -end of the blob. +If the end of the blob is reached, the data up to end of file will +be returned. When length is not specified, or is negative, +Blob.read() will read until the end of the blob. [clinic start generated code]*/ static PyObject * blob_read_impl(pysqlite_Blob *self, int length) -/*[clinic end generated code: output=1fc99b2541360dde input=e5715bcddbcfca5a]*/ +/*[clinic end generated code: output=1fc99b2541360dde input=6b745ad37720e556]*/ { if (!check_blob(self)) { return NULL; @@ -235,7 +234,6 @@ inner_write(pysqlite_Blob *self, const void *buf, Py_ssize_t len, /*[clinic input] -@permit_long_docstring_body _sqlite3.Blob.write as blob_write data: Py_buffer @@ -243,13 +241,13 @@ _sqlite3.Blob.write as blob_write Write data at the current offset. -This function cannot change the blob length. Writing beyond the end of the -blob will result in an exception being raised. +This function cannot change the blob length. Writing beyond the end +of the blob will result in an exception being raised. [clinic start generated code]*/ static PyObject * blob_write_impl(pysqlite_Blob *self, Py_buffer *data) -/*[clinic end generated code: output=b34cf22601b570b2 input=203d3458f244814b]*/ +/*[clinic end generated code: output=b34cf22601b570b2 input=0d372cb0240a5d49]*/ { if (!check_blob(self)) { return NULL; @@ -265,7 +263,6 @@ blob_write_impl(pysqlite_Blob *self, Py_buffer *data) /*[clinic input] -@permit_long_docstring_body _sqlite3.Blob.seek as blob_seek offset: int @@ -274,14 +271,15 @@ _sqlite3.Blob.seek as blob_seek Set the current access position to offset. -The origin argument defaults to os.SEEK_SET (absolute blob positioning). -Other values for origin are os.SEEK_CUR (seek relative to the current position) -and os.SEEK_END (seek relative to the blob's end). +The origin argument defaults to os.SEEK_SET (absolute blob +positioning). Other values for origin are os.SEEK_CUR (seek +relative to the current position) and os.SEEK_END (seek relative to +the blob's end). [clinic start generated code]*/ static PyObject * blob_seek_impl(pysqlite_Blob *self, int offset, int origin) -/*[clinic end generated code: output=854c5a0e208547a5 input=ee4d88e1dc0b1048]*/ +/*[clinic end generated code: output=854c5a0e208547a5 input=84aea1b6b48607dd]*/ { if (!check_blob(self)) { return NULL; diff --git a/Modules/_sqlite/clinic/blob.c.h b/Modules/_sqlite/clinic/blob.c.h index 921e7cbd7ffcab..929703257f04be 100644 --- a/Modules/_sqlite/clinic/blob.c.h +++ b/Modules/_sqlite/clinic/blob.c.h @@ -31,9 +31,9 @@ PyDoc_STRVAR(blob_read__doc__, " length\n" " Read length in bytes.\n" "\n" -"If the end of the blob is reached, the data up to end of file will be returned.\n" -"When length is not specified, or is negative, Blob.read() will read until the\n" -"end of the blob."); +"If the end of the blob is reached, the data up to end of file will\n" +"be returned. When length is not specified, or is negative,\n" +"Blob.read() will read until the end of the blob."); #define BLOB_READ_METHODDEF \ {"read", _PyCFunction_CAST(blob_read), METH_FASTCALL, blob_read__doc__}, @@ -70,8 +70,8 @@ PyDoc_STRVAR(blob_write__doc__, "\n" "Write data at the current offset.\n" "\n" -"This function cannot change the blob length. Writing beyond the end of the\n" -"blob will result in an exception being raised."); +"This function cannot change the blob length. Writing beyond the end\n" +"of the blob will result in an exception being raised."); #define BLOB_WRITE_METHODDEF \ {"write", (PyCFunction)blob_write, METH_O, blob_write__doc__}, @@ -105,9 +105,10 @@ PyDoc_STRVAR(blob_seek__doc__, "\n" "Set the current access position to offset.\n" "\n" -"The origin argument defaults to os.SEEK_SET (absolute blob positioning).\n" -"Other values for origin are os.SEEK_CUR (seek relative to the current position)\n" -"and os.SEEK_END (seek relative to the blob\'s end)."); +"The origin argument defaults to os.SEEK_SET (absolute blob\n" +"positioning). Other values for origin are os.SEEK_CUR (seek\n" +"relative to the current position) and os.SEEK_END (seek relative to\n" +"the blob\'s end)."); #define BLOB_SEEK_METHODDEF \ {"seek", _PyCFunction_CAST(blob_seek), METH_FASTCALL, blob_seek__doc__}, @@ -211,4 +212,4 @@ blob_exit(PyObject *self, PyObject *const *args, Py_ssize_t nargs) exit: return return_value; } -/*[clinic end generated code: output=f03f4ba622b67ae0 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=b0e3d38063739b17 input=a9049054013a1b77]*/ diff --git a/Modules/_sqlite/clinic/connection.c.h b/Modules/_sqlite/clinic/connection.c.h index abb864eb030757..b645bf3464bcea 100644 --- a/Modules/_sqlite/clinic/connection.c.h +++ b/Modules/_sqlite/clinic/connection.c.h @@ -685,13 +685,14 @@ PyDoc_STRVAR(pysqlite_connection_set_progress_handler__doc__, "\n" " progress_handler\n" " A callable that takes no arguments.\n" -" If the callable returns non-zero, the current query is terminated,\n" -" and an exception is raised.\n" +" If the callable returns non-zero, the current query is\n" +" terminated, and an exception is raised.\n" " n\n" " The number of SQLite virtual machine instructions that are\n" " executed between invocations of \'progress_handler\'.\n" "\n" -"If \'progress_handler\' is None or \'n\' is 0, the progress handler is disabled."); +"If \'progress_handler\' is None or \'n\' is 0, the progress handler is\n" +"disabled."); #define PYSQLITE_CONNECTION_SET_PROGRESS_HANDLER_METHODDEF \ {"set_progress_handler", _PyCFunction_CAST(pysqlite_connection_set_progress_handler), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, pysqlite_connection_set_progress_handler__doc__}, @@ -1303,10 +1304,10 @@ PyDoc_STRVAR(serialize__doc__, " name\n" " Which database to serialize.\n" "\n" -"For an ordinary on-disk database file, the serialization is just a copy of the\n" -"disk file. For an in-memory database or a \"temp\" database, the serialization is\n" -"the same sequence of bytes which would be written to disk if that database\n" -"were backed up to disk."); +"For an ordinary on-disk database file, the serialization is just\n" +"a copy of the disk file. For an in-memory database or a \"temp\"\n" +"database, the serialization is the same sequence of bytes which\n" +"would be written to disk if that database were backed up to disk."); #define SERIALIZE_METHODDEF \ {"serialize", _PyCFunction_CAST(serialize), METH_FASTCALL|METH_KEYWORDS, serialize__doc__}, @@ -1392,12 +1393,13 @@ PyDoc_STRVAR(deserialize__doc__, " name\n" " Which database to reopen with the deserialization.\n" "\n" -"The deserialize interface causes the database connection to disconnect from the\n" -"target database, and then reopen it as an in-memory database based on the given\n" -"serialized data.\n" +"The deserialize interface causes the database connection to\n" +"disconnect from the target database, and then reopen it as\n" +"an in-memory database based on the given serialized data.\n" "\n" -"The deserialize interface will fail with SQLITE_BUSY if the database is\n" -"currently in a read transaction or is involved in a backup operation."); +"The deserialize interface will fail with SQLITE_BUSY if the database\n" +"is currently in a read transaction or is involved in a backup\n" +"operation."); #define DESERIALIZE_METHODDEF \ {"deserialize", _PyCFunction_CAST(deserialize), METH_FASTCALL|METH_KEYWORDS, deserialize__doc__}, @@ -1518,7 +1520,8 @@ PyDoc_STRVAR(pysqlite_connection_exit__doc__, "\n" "Called when the connection is used as a context manager.\n" "\n" -"If there was any exception, a rollback takes place; otherwise we commit."); +"If there was any exception, a rollback takes place; otherwise we\n" +"commit."); #define PYSQLITE_CONNECTION_EXIT_METHODDEF \ {"__exit__", _PyCFunction_CAST(pysqlite_connection_exit), METH_FASTCALL, pysqlite_connection_exit__doc__}, @@ -1556,12 +1559,12 @@ PyDoc_STRVAR(setlimit__doc__, " category\n" " The limit category to be set.\n" " limit\n" -" The new limit. If the new limit is a negative number, the limit is\n" -" unchanged.\n" +" The new limit. If the new limit is a negative number, the limit\n" +" is unchanged.\n" "\n" -"Attempts to increase a limit above its hard upper bound are silently truncated\n" -"to the hard upper bound. Regardless of whether or not the limit was changed,\n" -"the prior value of the limit is returned."); +"Attempts to increase a limit above its hard upper bound are silently\n" +"truncated to the hard upper bound. Regardless of whether or not the\n" +"limit was changed, the prior value of the limit is returned."); #define SETLIMIT_METHODDEF \ {"setlimit", _PyCFunction_CAST(setlimit), METH_FASTCALL, setlimit__doc__}, @@ -1722,4 +1725,4 @@ getconfig(PyObject *self, PyObject *arg) #ifndef DESERIALIZE_METHODDEF #define DESERIALIZE_METHODDEF #endif /* !defined(DESERIALIZE_METHODDEF) */ -/*[clinic end generated code: output=16d44c1d8a45e622 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=1418b72751ef68fc input=a9049054013a1b77]*/ diff --git a/Modules/_sqlite/connection.c b/Modules/_sqlite/connection.c index bd44ff31b87c67..f596cc1ab36a19 100644 --- a/Modules/_sqlite/connection.c +++ b/Modules/_sqlite/connection.c @@ -1561,14 +1561,13 @@ pysqlite_connection_set_authorizer_impl(pysqlite_Connection *self, } /*[clinic input] -@permit_long_docstring_body _sqlite3.Connection.set_progress_handler as pysqlite_connection_set_progress_handler cls: defining_class progress_handler as callable: object A callable that takes no arguments. - If the callable returns non-zero, the current query is terminated, - and an exception is raised. + If the callable returns non-zero, the current query is + terminated, and an exception is raised. / n: int The number of SQLite virtual machine instructions that are @@ -1576,14 +1575,15 @@ _sqlite3.Connection.set_progress_handler as pysqlite_connection_set_progress_han Set progress handler callback. -If 'progress_handler' is None or 'n' is 0, the progress handler is disabled. +If 'progress_handler' is None or 'n' is 0, the progress handler is +disabled. [clinic start generated code]*/ static PyObject * pysqlite_connection_set_progress_handler_impl(pysqlite_Connection *self, PyTypeObject *cls, PyObject *callable, int n) -/*[clinic end generated code: output=0739957fd8034a50 input=3ecce6c915922ad4]*/ +/*[clinic end generated code: output=0739957fd8034a50 input=fd0d5abb004f370f]*/ { if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) { return NULL; @@ -1606,6 +1606,7 @@ pysqlite_connection_set_progress_handler_impl(pysqlite_Connection *self, } /*[clinic input] +@permit_long_summary _sqlite3.Connection.set_trace_callback as pysqlite_connection_set_trace_callback cls: defining_class @@ -1619,7 +1620,7 @@ static PyObject * pysqlite_connection_set_trace_callback_impl(pysqlite_Connection *self, PyTypeObject *cls, PyObject *callable) -/*[clinic end generated code: output=d91048c03bfcee05 input=f4f59bf2f87f2026]*/ +/*[clinic end generated code: output=d91048c03bfcee05 input=edfd7d890200a9cb]*/ { if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) { return NULL; @@ -2212,7 +2213,6 @@ pysqlite_connection_create_collation_impl(pysqlite_Connection *self, #ifdef PY_SQLITE_HAVE_SERIALIZE /*[clinic input] -@permit_long_docstring_body _sqlite3.Connection.serialize as serialize * @@ -2221,15 +2221,15 @@ _sqlite3.Connection.serialize as serialize Serialize a database into a byte string. -For an ordinary on-disk database file, the serialization is just a copy of the -disk file. For an in-memory database or a "temp" database, the serialization is -the same sequence of bytes which would be written to disk if that database -were backed up to disk. +For an ordinary on-disk database file, the serialization is just +a copy of the disk file. For an in-memory database or a "temp" +database, the serialization is the same sequence of bytes which +would be written to disk if that database were backed up to disk. [clinic start generated code]*/ static PyObject * serialize_impl(pysqlite_Connection *self, const char *name) -/*[clinic end generated code: output=97342b0e55239dd3 input=963e617cdf75c747]*/ +/*[clinic end generated code: output=97342b0e55239dd3 input=7e48654e8e082fa8]*/ { if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) { return NULL; @@ -2263,7 +2263,6 @@ serialize_impl(pysqlite_Connection *self, const char *name) } /*[clinic input] -@permit_long_docstring_body _sqlite3.Connection.deserialize as deserialize data: Py_buffer(accept={buffer, str}) @@ -2275,18 +2274,19 @@ _sqlite3.Connection.deserialize as deserialize Load a serialized database. -The deserialize interface causes the database connection to disconnect from the -target database, and then reopen it as an in-memory database based on the given -serialized data. +The deserialize interface causes the database connection to +disconnect from the target database, and then reopen it as +an in-memory database based on the given serialized data. -The deserialize interface will fail with SQLITE_BUSY if the database is -currently in a read transaction or is involved in a backup operation. +The deserialize interface will fail with SQLITE_BUSY if the database +is currently in a read transaction or is involved in a backup +operation. [clinic start generated code]*/ static PyObject * deserialize_impl(pysqlite_Connection *self, Py_buffer *data, const char *name) -/*[clinic end generated code: output=e394c798b98bad89 input=037e94599aaa5b5c]*/ +/*[clinic end generated code: output=e394c798b98bad89 input=5d20e028d98c0686]*/ { if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) { return NULL; @@ -2359,13 +2359,14 @@ _sqlite3.Connection.__exit__ as pysqlite_connection_exit Called when the connection is used as a context manager. -If there was any exception, a rollback takes place; otherwise we commit. +If there was any exception, a rollback takes place; otherwise we +commit. [clinic start generated code]*/ static PyObject * pysqlite_connection_exit_impl(pysqlite_Connection *self, PyObject *exc_type, PyObject *exc_value, PyObject *exc_tb) -/*[clinic end generated code: output=0705200e9321202a input=bd66f1532c9c54a7]*/ +/*[clinic end generated code: output=0705200e9321202a input=8fdb0392ee6f3466]*/ { int commit = 0; PyObject* result; @@ -2400,26 +2401,25 @@ pysqlite_connection_exit_impl(pysqlite_Connection *self, PyObject *exc_type, } /*[clinic input] -@permit_long_docstring_body _sqlite3.Connection.setlimit as setlimit category: int The limit category to be set. limit: int - The new limit. If the new limit is a negative number, the limit is - unchanged. + The new limit. If the new limit is a negative number, the limit + is unchanged. / Set connection run-time limits. -Attempts to increase a limit above its hard upper bound are silently truncated -to the hard upper bound. Regardless of whether or not the limit was changed, -the prior value of the limit is returned. +Attempts to increase a limit above its hard upper bound are silently +truncated to the hard upper bound. Regardless of whether or not the +limit was changed, the prior value of the limit is returned. [clinic start generated code]*/ static PyObject * setlimit_impl(pysqlite_Connection *self, int category, int limit) -/*[clinic end generated code: output=0d208213f8d68ccd input=bf06e06a21eb37e2]*/ +/*[clinic end generated code: output=0d208213f8d68ccd input=5c2e430091206677]*/ { if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) { return NULL; From 739552caae245ddafd42a3641765aa0961419bce Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sun, 24 May 2026 16:53:29 +0300 Subject: [PATCH 135/818] [3.15] gh-150285: Fix too long docstrings in the os module (GH-150296) (GH-150341) (cherry picked from commit a5cb7c34dd25aaa639a512f0dbbaaa6c9e03f1a1) --- Lib/os.py | 46 +-- Modules/clinic/posixmodule.c.h | 389 +++++++++++++----------- Modules/posixmodule.c | 534 +++++++++++++++++---------------- 3 files changed, 511 insertions(+), 458 deletions(-) diff --git a/Lib/os.py b/Lib/os.py index 1ca4648cc95c3e..a5e1d805556998 100644 --- a/Lib/os.py +++ b/Lib/os.py @@ -222,14 +222,14 @@ def _add(str, fn): def makedirs(name, mode=0o777, exist_ok=False, *, parent_mode=None): """makedirs(name [, mode=0o777][, exist_ok=False][, parent_mode=None]) - Super-mkdir; create a leaf directory and all intermediate ones. Works like - mkdir, except that any intermediate path segment (not just the rightmost) - will be created if it does not exist. If the target directory already - exists, raise an OSError if exist_ok is False. Otherwise no exception is - raised. If parent_mode is not None, it will be used as the mode for any - newly-created, intermediate-level directories. Otherwise, intermediate - directories are created with the default permissions (respecting umask). - This is recursive. + Super-mkdir; create a leaf directory and all intermediate ones. Works + like mkdir, except that any intermediate path segment (not just the + rightmost) will be created if it does not exist. If the target + directory already exists, raise an OSError if exist_ok is False. + Otherwise no exception is raised. If parent_mode is not None, it will + be used as the mode for any newly-created, intermediate-level + directories. Otherwise, intermediate directories are created with the + default permissions (respecting umask). This is recursive. """ head, tail = path.split(name) @@ -321,12 +321,12 @@ def walk(top, topdown=True, onerror=None, followlinks=False): dirpath, dirnames, filenames dirpath is a string, the path to the directory. dirnames is a list of - the names of the subdirectories in dirpath (including symlinks to directories, - and excluding '.' and '..'). + the names of the subdirectories in dirpath (including symlinks to + directories, and excluding '.' and '..'). filenames is a list of the names of the non-directory files in dirpath. - Note that the names in the lists are just names, with no path components. - To get a full path (which begins with top) to a file or directory in - dirpath, do os.path.join(dirpath, name). + Note that the names in the lists are just names, with no path + components. To get a full path (which begins with top) to a file or + directory in dirpath, do os.path.join(dirpath, name). If optional arg 'topdown' is true or not specified, the triple for a directory is generated before the triples for any of its subdirectories @@ -336,13 +336,13 @@ def walk(top, topdown=True, onerror=None, followlinks=False): When topdown is true, the caller can modify the dirnames list in-place (e.g., via del or slice assignment), and walk will only recurse into the - subdirectories whose names remain in dirnames; this can be used to prune the - search, or to impose a specific order of visiting. Modifying dirnames when - topdown is false has no effect on the behavior of os.walk(), since the - directories in dirnames have already been generated by the time dirnames - itself is generated. No matter the value of topdown, the list of - subdirectories is retrieved before the tuples for the directory and its - subdirectories are generated. + subdirectories whose names remain in dirnames; this can be used to prune + the search, or to impose a specific order of visiting. Modifying + dirnames when topdown is false has no effect on the behavior of + os.walk(), since the directories in dirnames have already been generated + by the time dirnames itself is generated. No matter the value of + topdown, the list of subdirectories is retrieved before the tuples for + the directory and its subdirectories are generated. By default errors from the os.scandir() call are ignored. If optional arg 'onerror' is specified, it should be a function; it @@ -469,9 +469,9 @@ def fwalk(top=".", topdown=True, onerror=None, *, follow_symlinks=False, dir_fd= The advantage of fwalk() over walk() is that it's safe against symlink races (when follow_symlinks is False). - If dir_fd is not None, it should be a file descriptor open to a directory, - and top should be relative; top will then be relative to that directory. - (dir_fd is always supported for fwalk.) + If dir_fd is not None, it should be a file descriptor open to + a directory, and top should be relative; top will then be relative to + that directory. (dir_fd is always supported for fwalk.) Caution: Since fwalk() yields file descriptors, those are only valid until the diff --git a/Modules/clinic/posixmodule.c.h b/Modules/clinic/posixmodule.c.h index ad4c5dd1c9bc08..45e509d003085b 100644 --- a/Modules/clinic/posixmodule.c.h +++ b/Modules/clinic/posixmodule.c.h @@ -512,9 +512,9 @@ PyDoc_STRVAR(os_chdir__doc__, "\n" "Change the current working directory to the specified path.\n" "\n" -"path may always be specified as a string.\n" -"On some platforms, path may also be specified as an open file descriptor.\n" -"If this functionality is unavailable, using it raises an exception."); +"path may always be specified as a string. On some platforms, path may\n" +"also be specified as an open file descriptor. If this functionality is\n" +"unavailable, using it raises an exception."); #define OS_CHDIR_METHODDEF \ {"chdir", _PyCFunction_CAST(os_chdir), METH_FASTCALL|METH_KEYWORDS, os_chdir__doc__}, @@ -649,14 +649,15 @@ PyDoc_STRVAR(os_chmod__doc__, "Change the access permissions of a file.\n" "\n" " path\n" -" Path to be modified. May always be specified as a str, bytes, or a path-like object.\n" -" On some platforms, path may also be specified as an open file descriptor.\n" -" If this functionality is unavailable, using it raises an exception.\n" +" Path to be modified. May always be specified as a str, bytes, or\n" +" a path-like object. On some platforms, path may also be specified\n" +" as an open file descriptor. If this functionality is unavailable,\n" +" using it raises an exception.\n" " mode\n" " Operating-system mode bitfield.\n" -" Be careful when using number literals for *mode*. The conventional UNIX notation for\n" -" numeric modes uses an octal base, which needs to be indicated with a ``0o`` prefix in\n" -" Python.\n" +" Be careful when using number literals for *mode*. The conventional\n" +" UNIX notation for numeric modes uses an octal base, which needs to\n" +" be indicated with a ``0o`` prefix in Python.\n" " dir_fd\n" " If not None, it should be a file descriptor open to a directory,\n" " and path should be relative; path will then be relative to that\n" @@ -765,9 +766,9 @@ PyDoc_STRVAR(os_fchmod__doc__, " The file descriptor of the file to be modified.\n" " mode\n" " Operating-system mode bitfield.\n" -" Be careful when using number literals for *mode*. The conventional UNIX notation for\n" -" numeric modes uses an octal base, which needs to be indicated with a ``0o`` prefix in\n" -" Python.\n" +" Be careful when using number literals for *mode*. The conventional\n" +" UNIX notation for numeric modes uses an octal base, which needs to\n" +" be indicated with a ``0o`` prefix in Python.\n" "\n" "Equivalent to os.chmod(fd, mode)."); @@ -841,8 +842,8 @@ PyDoc_STRVAR(os_lchmod__doc__, "\n" "Change the access permissions of a file, without following symbolic links.\n" "\n" -"If path is a symlink, this affects the link itself rather than the target.\n" -"Equivalent to chmod(path, mode, follow_symlinks=False).\""); +"If path is a symlink, this affects the link itself rather than the\n" +"target. Equivalent to chmod(path, mode, follow_symlinks=False)."); #define OS_LCHMOD_METHODDEF \ {"lchmod", _PyCFunction_CAST(os_lchmod), METH_FASTCALL|METH_KEYWORDS, os_lchmod__doc__}, @@ -916,9 +917,9 @@ PyDoc_STRVAR(os_chflags__doc__, "\n" "Set file flags.\n" "\n" -"If follow_symlinks is False, and the last element of the path is a symbolic\n" -" link, chflags will change flags on the symbolic link itself instead of the\n" -" file the link points to.\n" +"If follow_symlinks is False, and the last element of the path is\n" +"a symbolic link, chflags() will change flags on the symbolic link itself\n" +"instead of the file the link points to.\n" "follow_symlinks may not be implemented on your platform. If it is\n" "unavailable, using it will raise a NotImplementedError."); @@ -1329,10 +1330,11 @@ PyDoc_STRVAR(os_chown__doc__, "chown($module, /, path, uid, gid, *, dir_fd=None, follow_symlinks=True)\n" "--\n" "\n" -"Change the owner and group id of path to the numeric uid and gid.\\\n" +"Change the owner and group id of path to the numeric uid and gid.\n" "\n" " path\n" -" Path to be examined; can be string, bytes, a path-like object, or open-file-descriptor int.\n" +" Path to be examined; can be string, bytes, a path-like object, or\n" +" open-file-descriptor int.\n" " dir_fd\n" " If not None, it should be a file descriptor open to a directory,\n" " and path should be relative; path will then be relative to that\n" @@ -1342,18 +1344,19 @@ PyDoc_STRVAR(os_chown__doc__, " stat will examine the symbolic link itself instead of the file\n" " the link points to.\n" "\n" -"path may always be specified as a string.\n" -"On some platforms, path may also be specified as an open file descriptor.\n" -" If this functionality is unavailable, using it raises an exception.\n" -"If dir_fd is not None, it should be a file descriptor open to a directory,\n" -" and path should be relative; path will then be relative to that directory.\n" -"If follow_symlinks is False, and the last element of the path is a symbolic\n" -" link, chown will modify the symbolic link itself instead of the file the\n" -" link points to.\n" +"path may always be specified as a string. On some platforms, path may\n" +"also be specified as an open file descriptor. If this functionality is\n" +"unavailable, using it raises an exception.\n" +"If dir_fd is not None, it should be a file descriptor open to\n" +"a directory, and path should be relative; path will then be relative to\n" +"that directory.\n" +"If follow_symlinks is False, and the last element of the path is\n" +"a symbolic link, chown will modify the symbolic link itself instead of\n" +"the file the link points to.\n" "It is an error to use dir_fd or follow_symlinks when specifying path as\n" -" an open file descriptor.\n" -"dir_fd and follow_symlinks may not be implemented on your platform.\n" -" If they are unavailable, using them will raise a NotImplementedError."); +"an open file descriptor.\n" +"dir_fd and follow_symlinks may not be implemented on your platform. If\n" +"they are unavailable, using them will raise a NotImplementedError."); #define OS_CHOWN_METHODDEF \ {"chown", _PyCFunction_CAST(os_chown), METH_FASTCALL|METH_KEYWORDS, os_chown__doc__}, @@ -1641,14 +1644,15 @@ PyDoc_STRVAR(os_link__doc__, "Create a hard link to a file.\n" "\n" "If either src_dir_fd or dst_dir_fd is not None, it should be a file\n" -" descriptor open to a directory, and the respective path string (src or dst)\n" -" should be relative; the path will then be relative to that directory.\n" +"descriptor open to a directory, and the respective path string (src or\n" +"dst) should be relative; the path will then be relative to that\n" +"directory.\n" "If follow_symlinks is False, and the last element of src is a symbolic\n" -" link, link will create a link to the symbolic link itself instead of the\n" -" file the link points to.\n" -"src_dir_fd, dst_dir_fd, and follow_symlinks may not be implemented on your\n" -" platform. If they are unavailable, using them will raise a\n" -" NotImplementedError."); +"link, link will create a link to the symbolic link itself instead of the\n" +"file the link points to.\n" +"src_dir_fd, dst_dir_fd, and follow_symlinks may not be implemented on\n" +"your platform. If they are unavailable, using them will raise\n" +"a NotImplementedError."); #define OS_LINK_METHODDEF \ {"link", _PyCFunction_CAST(os_link), METH_FASTCALL|METH_KEYWORDS, os_link__doc__}, @@ -1750,13 +1754,13 @@ PyDoc_STRVAR(os_listdir__doc__, "\n" "Return a list containing the names of the files in the directory.\n" "\n" -"path can be specified as either str, bytes, or a path-like object. If path is bytes,\n" -" the filenames returned will also be bytes; in all other circumstances\n" -" the filenames returned will be str.\n" +"path can be specified as either str, bytes, or a path-like object. If\n" +"path is bytes, the filenames returned will also be bytes; in all other\n" +"circumstances the filenames returned will be str.\n" "If path is None, uses the path=\'.\'.\n" -"On some platforms, path may also be specified as an open file descriptor;\\\n" -" the file descriptor must refer to a directory.\n" -" If this functionality is unavailable, using it raises NotImplementedError.\n" +"On some platforms, path may also be specified as an open file\n" +"descriptor; the file descriptor must refer to a directory. If this\n" +"functionality is unavailable, using it raises NotImplementedError.\n" "\n" "The list is in arbitrary order. It does not include the special\n" "entries \'.\' and \'..\' even if they are present in the directory."); @@ -2709,13 +2713,14 @@ PyDoc_STRVAR(os_mkdir__doc__, "\n" "Create a directory.\n" "\n" -"If dir_fd is not None, it should be a file descriptor open to a directory,\n" -" and path should be relative; path will then be relative to that directory.\n" -"dir_fd may not be implemented on your platform.\n" -" If it is unavailable, using it will raise a NotImplementedError.\n" +"If dir_fd is not None, it should be a file descriptor open to\n" +"a directory, and path should be relative; path will then be relative to\n" +"that directory.\n" +"dir_fd may not be implemented on your platform. If it is unavailable,\n" +"using it will raise a NotImplementedError.\n" "\n" -"The mode argument is ignored on Windows. Where it is used, the current umask\n" -"value is first masked out."); +"The mode argument is ignored on Windows. Where it is used, the current\n" +"umask value is first masked out."); #define OS_MKDIR_METHODDEF \ {"mkdir", _PyCFunction_CAST(os_mkdir), METH_FASTCALL|METH_KEYWORDS, os_mkdir__doc__}, @@ -2981,10 +2986,11 @@ PyDoc_STRVAR(os_rename__doc__, "Rename a file or directory.\n" "\n" "If either src_dir_fd or dst_dir_fd is not None, it should be a file\n" -" descriptor open to a directory, and the respective path string (src or dst)\n" -" should be relative; the path will then be relative to that directory.\n" +"descriptor open to a directory, and the respective path string (src or\n" +"dst) should be relative; the path will then be relative to that\n" +"directory.\n" "src_dir_fd and dst_dir_fd, may not be implemented on your platform.\n" -" If they are unavailable, using them will raise a NotImplementedError."); +"If they are unavailable, using them will raise a NotImplementedError."); #define OS_RENAME_METHODDEF \ {"rename", _PyCFunction_CAST(os_rename), METH_FASTCALL|METH_KEYWORDS, os_rename__doc__}, @@ -3075,10 +3081,11 @@ PyDoc_STRVAR(os_replace__doc__, "Rename a file or directory, overwriting the destination.\n" "\n" "If either src_dir_fd or dst_dir_fd is not None, it should be a file\n" -" descriptor open to a directory, and the respective path string (src or dst)\n" -" should be relative; the path will then be relative to that directory.\n" +"descriptor open to a directory, and the respective path string (src or\n" +"dst) should be relative; the path will then be relative to that\n" +"directory.\n" "src_dir_fd and dst_dir_fd, may not be implemented on your platform.\n" -" If they are unavailable, using them will raise a NotImplementedError."); +"If they are unavailable, using them will raise a NotImplementedError."); #define OS_REPLACE_METHODDEF \ {"replace", _PyCFunction_CAST(os_replace), METH_FASTCALL|METH_KEYWORDS, os_replace__doc__}, @@ -3168,10 +3175,11 @@ PyDoc_STRVAR(os_rmdir__doc__, "\n" "Remove a directory.\n" "\n" -"If dir_fd is not None, it should be a file descriptor open to a directory,\n" -" and path should be relative; path will then be relative to that directory.\n" +"If dir_fd is not None, it should be a file descriptor open to\n" +"a directory, and path should be relative; path will then be relative\n" +"to that directory.\n" "dir_fd may not be implemented on your platform.\n" -" If it is unavailable, using it will raise a NotImplementedError."); +"If it is unavailable, using it will raise a NotImplementedError."); #define OS_RMDIR_METHODDEF \ {"rmdir", _PyCFunction_CAST(os_rmdir), METH_FASTCALL|METH_KEYWORDS, os_rmdir__doc__}, @@ -3426,10 +3434,11 @@ PyDoc_STRVAR(os_unlink__doc__, "\n" "Remove a file (same as remove()).\n" "\n" -"If dir_fd is not None, it should be a file descriptor open to a directory,\n" -" and path should be relative; path will then be relative to that directory.\n" +"If dir_fd is not None, it should be a file descriptor open to\n" +"a directory, and path should be relative; path will then be relative to\n" +"that directory.\n" "dir_fd may not be implemented on your platform.\n" -" If it is unavailable, using it will raise a NotImplementedError."); +"If it is unavailable, using it will raise a NotImplementedError."); #define OS_UNLINK_METHODDEF \ {"unlink", _PyCFunction_CAST(os_unlink), METH_FASTCALL|METH_KEYWORDS, os_unlink__doc__}, @@ -3503,10 +3512,11 @@ PyDoc_STRVAR(os_remove__doc__, "\n" "Remove a file (same as unlink()).\n" "\n" -"If dir_fd is not None, it should be a file descriptor open to a directory,\n" -" and path should be relative; path will then be relative to that directory.\n" +"If dir_fd is not None, it should be a file descriptor open to\n" +"a directory, and path should be relative; path will then be relative\n" +"to that directory.\n" "dir_fd may not be implemented on your platform.\n" -" If it is unavailable, using it will raise a NotImplementedError."); +"If it is unavailable, using it will raise a NotImplementedError."); #define OS_REMOVE_METHODDEF \ {"remove", _PyCFunction_CAST(os_remove), METH_FASTCALL|METH_KEYWORDS, os_remove__doc__}, @@ -3606,27 +3616,28 @@ PyDoc_STRVAR(os_utime__doc__, "\n" "Set the access and modified time of path.\n" "\n" -"path may always be specified as a string.\n" -"On some platforms, path may also be specified as an open file descriptor.\n" -" If this functionality is unavailable, using it raises an exception.\n" +"path may always be specified as a string. On some platforms, path may\n" +"also be specified as an open file descriptor. If this functionality is\n" +"unavailable, using it raises an exception.\n" "\n" "If times is not None, it must be a tuple (atime, mtime);\n" -" atime and mtime should be expressed as float seconds since the epoch.\n" +"atime and mtime should be expressed as float seconds since the epoch.\n" "If ns is specified, it must be a tuple (atime_ns, mtime_ns);\n" -" atime_ns and mtime_ns should be expressed as integer nanoseconds\n" -" since the epoch.\n" +"atime_ns and mtime_ns should be expressed as integer nanoseconds\n" +"since the epoch.\n" "If times is None and ns is unspecified, utime uses the current time.\n" "Specifying tuples for both times and ns is an error.\n" "\n" -"If dir_fd is not None, it should be a file descriptor open to a directory,\n" -" and path should be relative; path will then be relative to that directory.\n" -"If follow_symlinks is False, and the last element of the path is a symbolic\n" -" link, utime will modify the symbolic link itself instead of the file the\n" -" link points to.\n" -"It is an error to use dir_fd or follow_symlinks when specifying path\n" -" as an open file descriptor.\n" +"If dir_fd is not None, it should be a file descriptor open to\n" +"a directory, and path should be relative; path will then be relative to\n" +"that directory.\n" +"If follow_symlinks is False, and the last element of the path is\n" +"a symbolic link, utime will modify the symbolic link itself instead of\n" +"the file the link points to.\n" +"It is an error to use dir_fd or follow_symlinks when specifying path as\n" +"an open file descriptor.\n" "dir_fd and follow_symlinks may not be available on your platform.\n" -" If they are unavailable, using them will raise a NotImplementedError."); +"If they are unavailable, using them will raise a NotImplementedError."); #define OS_UTIME_METHODDEF \ {"utime", _PyCFunction_CAST(os_utime), METH_FASTCALL|METH_KEYWORDS, os_utime__doc__}, @@ -3929,7 +3940,8 @@ PyDoc_STRVAR(os_posix_spawn__doc__, " resetids\n" " If the value is `true` the POSIX_SPAWN_RESETIDS will be activated.\n" " setsid\n" -" If the value is `true` the POSIX_SPAWN_SETSID or POSIX_SPAWN_SETSID_NP will be activated.\n" +" If the value is `true` the POSIX_SPAWN_SETSID or POSIX_SPAWN_SETSID_NP\n" +" will be activated.\n" " setsigmask\n" " The sigmask to use with the POSIX_SPAWN_SETSIGMASK flag.\n" " setsigdef\n" @@ -4082,7 +4094,8 @@ PyDoc_STRVAR(os_posix_spawnp__doc__, " resetids\n" " If the value is `True` the POSIX_SPAWN_RESETIDS will be activated.\n" " setsid\n" -" If the value is `True` the POSIX_SPAWN_SETSID or POSIX_SPAWN_SETSID_NP will be activated.\n" +" If the value is `True` the POSIX_SPAWN_SETSID or POSIX_SPAWN_SETSID_NP\n" +" will be activated.\n" " setsigmask\n" " The sigmask to use with the POSIX_SPAWN_SETSIGMASK flag.\n" " setsigdef\n" @@ -4953,8 +4966,8 @@ PyDoc_STRVAR(os_posix_openpt__doc__, "Open and return a file descriptor for a master pseudo-terminal device.\n" "\n" "Performs a posix_openpt() C function call. The oflag argument is used to\n" -"set file status flags and file access modes as specified in the manual page\n" -"of posix_openpt() of your system."); +"set file status flags and file access modes as specified in the manual\n" +"page of posix_openpt() of your system."); #define OS_POSIX_OPENPT_METHODDEF \ {"posix_openpt", (PyCFunction)os_posix_openpt, METH_O, os_posix_openpt__doc__}, @@ -5411,9 +5424,9 @@ PyDoc_STRVAR(os_initgroups__doc__, "\n" "Initialize the group access list.\n" "\n" -"Call the system initgroups() to initialize the group access list with all of\n" -"the groups of which the specified username is a member, plus the specified\n" -"group id."); +"Call the system initgroups() to initialize the group access list with\n" +"all of the groups of which the specified username is a member, plus the\n" +"specified group id."); #define OS_INITGROUPS_METHODDEF \ {"initgroups", _PyCFunction_CAST(os_initgroups), METH_FASTCALL, os_initgroups__doc__}, @@ -5457,9 +5470,9 @@ PyDoc_STRVAR(os_initgroups__doc__, "\n" "Initialize the group access list.\n" "\n" -"Call the system initgroups() to initialize the group access list with all of\n" -"the groups of which the specified username is a member, plus the specified\n" -"group id."); +"Call the system initgroups() to initialize the group access list with\n" +"all of the groups of which the specified username is a member, plus the\n" +"specified group id."); #define OS_INITGROUPS_METHODDEF \ {"initgroups", _PyCFunction_CAST(os_initgroups), METH_FASTCALL, os_initgroups__doc__}, @@ -5612,7 +5625,8 @@ PyDoc_STRVAR(os_getppid__doc__, "Return the parent\'s process id.\n" "\n" "If the parent process has already exited, Windows machines will still\n" -"return its id; others systems will return the id of the \'init\' process (1)."); +"return its id; others systems will return the id of the \'init\' proces\n" +"(1)."); #define OS_GETPPID_METHODDEF \ {"getppid", (PyCFunction)os_getppid, METH_NOARGS, os_getppid__doc__}, @@ -6162,8 +6176,8 @@ PyDoc_STRVAR(os_waitid__doc__, " Constructed from the ORing of one or more of WEXITED, WSTOPPED\n" " or WCONTINUED and additionally may be ORed with WNOHANG or WNOWAIT.\n" "\n" -"Returns either waitid_result or None if WNOHANG is specified and there are\n" -"no children in a waitable state."); +"Returns either waitid_result or None if WNOHANG is specified and there\n" +"are no children in a waitable state."); #define OS_WAITID_METHODDEF \ {"waitid", _PyCFunction_CAST(os_waitid), METH_FASTCALL, os_waitid__doc__}, @@ -6324,8 +6338,8 @@ PyDoc_STRVAR(os_pidfd_open__doc__, "\n" "Return a file descriptor referring to the process *pid*.\n" "\n" -"The descriptor can be used to perform process management without races and\n" -"signals."); +"The descriptor can be used to perform process management without races\n" +"and signals."); #define OS_PIDFD_OPEN_METHODDEF \ {"pidfd_open", _PyCFunction_CAST(os_pidfd_open), METH_FASTCALL|METH_KEYWORDS, os_pidfd_open__doc__}, @@ -6549,8 +6563,9 @@ PyDoc_STRVAR(os_readlink__doc__, "\n" "Return a string representing the path to which the symbolic link points.\n" "\n" -"If dir_fd is not None, it should be a file descriptor open to a directory,\n" -"and path should be relative; path will then be relative to that directory.\n" +"If dir_fd is not None, it should be a file descriptor open to\n" +"a directory, and path should be relative; path will then be relative to\n" +"that directory.\n" "\n" "dir_fd may not be implemented on your platform. If it is unavailable,\n" "using it will raise a NotImplementedError."); @@ -6632,14 +6647,15 @@ PyDoc_STRVAR(os_symlink__doc__, "Create a symbolic link pointing to src named dst.\n" "\n" "target_is_directory is required on Windows if the target is to be\n" -" interpreted as a directory. (On Windows, symlink requires\n" -" Windows 6.0 or greater, and raises a NotImplementedError otherwise.)\n" -" target_is_directory is ignored on non-Windows platforms.\n" +"interpreted as a directory. (On Windows, symlink requires Windows 6.0\n" +"or greater, and raises a NotImplementedError otherwise.)\n" +"target_is_directory is ignored on non-Windows platforms.\n" "\n" -"If dir_fd is not None, it should be a file descriptor open to a directory,\n" -" and path should be relative; path will then be relative to that directory.\n" -"dir_fd may not be implemented on your platform.\n" -" If it is unavailable, using it will raise a NotImplementedError."); +"If dir_fd is not None, it should be a file descriptor open to\n" +"a directory, and path should be relative; path will then be relative\n" +"to that directory.\n" +"dir_fd may not be implemented on your platform. If it is unavailable,\n" +"using it will raise a NotImplementedError."); #define OS_SYMLINK_METHODDEF \ {"symlink", _PyCFunction_CAST(os_symlink), METH_FASTCALL|METH_KEYWORDS, os_symlink__doc__}, @@ -7307,10 +7323,11 @@ PyDoc_STRVAR(os_open__doc__, "\n" "Open a file for low level IO. Returns a file descriptor (integer).\n" "\n" -"If dir_fd is not None, it should be a file descriptor open to a directory,\n" -" and path should be relative; path will then be relative to that directory.\n" -"dir_fd may not be implemented on your platform.\n" -" If it is unavailable, using it will raise a NotImplementedError."); +"If dir_fd is not None, it should be a file descriptor open to\n" +"a directory, and path should be relative; path will then be relative to\n" +"that directory.\n" +"dir_fd may not be implemented on your platform. If it is unavailable,\n" +"using it will raise a NotImplementedError."); #define OS_OPEN_METHODDEF \ {"open", _PyCFunction_CAST(os_open), METH_FASTCALL|METH_KEYWORDS, os_open__doc__}, @@ -7684,7 +7701,8 @@ PyDoc_STRVAR(os_lseek__doc__, " - SEEK_CUR: seek from the current file position.\n" " - SEEK_END: seek from the end of the file.\n" "\n" -"The return value is the number of bytes relative to the beginning of the file."); +"The return value is the number of bytes relative to the beginning of\n" +"the file."); #define OS_LSEEK_METHODDEF \ {"lseek", _PyCFunction_CAST(os_lseek), METH_FASTCALL, os_lseek__doc__}, @@ -7775,15 +7793,15 @@ PyDoc_STRVAR(os_readinto__doc__, "\n" "Read into a buffer object from a file descriptor.\n" "\n" -"The buffer should be mutable and bytes-like. On success, returns the number of\n" -"bytes read. Less bytes may be read than the size of the buffer. The underlying\n" -"system call will be retried when interrupted by a signal, unless the signal\n" -"handler raises an exception. Other errors will not be retried and an error will\n" -"be raised.\n" +"The buffer should be mutable and bytes-like. On success, returns the\n" +"number of bytes read. Less bytes may be read than the size of the\n" +"buffer. The underlying system call will be retried when interrupted by\n" +"a signal, unless the signal handler raises an exception. Other errors\n" +"will not be retried and an error will be raised.\n" "\n" -"Returns 0 if *fd* is at end of file or if the provided *buffer* has length 0\n" -"(which can be used to check for errors without reading data). Never returns\n" -"negative."); +"Returns 0 if *fd* is at end of file or if the provided *buffer* has\n" +"length 0 (which can be used to check for errors without reading data).\n" +"Never returns negative."); #define OS_READINTO_METHODDEF \ {"readinto", _PyCFunction_CAST(os_readinto), METH_FASTCALL, os_readinto__doc__}, @@ -7938,14 +7956,15 @@ PyDoc_STRVAR(os_preadv__doc__, "\n" "Reads from a file descriptor into a number of mutable bytes-like objects.\n" "\n" -"Combines the functionality of readv() and pread(). As readv(), it will\n" -"transfer data into each buffer until it is full and then move on to the next\n" -"buffer in the sequence to hold the rest of the data. Its fourth argument,\n" -"specifies the file offset at which the input operation is to be performed. It\n" -"will return the total number of bytes read (which can be less than the total\n" -"capacity of all the objects).\n" +"Combines the functionality of readv() and pread(). As readv(), it will\n" +"transfer data into each buffer until it is full and then move on to the\n" +"next buffer in the sequence to hold the rest of the data. Its fourth\n" +"argument, specifies the file offset at which the input operation is to\n" +"be performed. It will return the total number of bytes read (which can\n" +"be less than the total capacity of all the objects).\n" "\n" -"The flags argument contains a bitwise OR of zero or more of the following flags:\n" +"The flags argument contains a bitwise OR of zero or more of the\n" +"following flags:\n" "\n" "- RWF_HIPRI\n" "- RWF_NOWAIT\n" @@ -8679,14 +8698,16 @@ PyDoc_STRVAR(os_pwritev__doc__, "\n" "Writes the contents of bytes-like objects to a file descriptor at a given offset.\n" "\n" -"Combines the functionality of writev() and pwrite(). All buffers must be a sequence\n" -"of bytes-like objects. Buffers are processed in array order. Entire contents of first\n" -"buffer is written before proceeding to second, and so on. The operating system may\n" -"set a limit (sysconf() value SC_IOV_MAX) on the number of buffers that can be used.\n" -"This function writes the contents of each object to the file descriptor and returns\n" -"the total number of bytes written.\n" +"Combines the functionality of writev() and pwrite(). All buffers must be\n" +"a sequence of bytes-like objects. Buffers are processed in array order.\n" +"Entire contents of first buffer is written before proceeding to second,\n" +"and so on. The operating system may set a limit (sysconf() value\n" +"SC_IOV_MAX) on the number of buffers that can be used.\n" +"This function writes the contents of each object to the file descriptor\n" +"and returns the total number of bytes written.\n" "\n" -"The flags argument contains a bitwise OR of zero or more of the following flags:\n" +"The flags argument contains a bitwise OR of zero or more of the\n" +"following flags:\n" "\n" "- RWF_DSYNC\n" "- RWF_SYNC\n" @@ -9001,10 +9022,11 @@ PyDoc_STRVAR(os_mkfifo__doc__, "\n" "Create a \"fifo\" (a POSIX named pipe).\n" "\n" -"If dir_fd is not None, it should be a file descriptor open to a directory,\n" -" and path should be relative; path will then be relative to that directory.\n" -"dir_fd may not be implemented on your platform.\n" -" If it is unavailable, using it will raise a NotImplementedError."); +"If dir_fd is not None, it should be a file descriptor open to\n" +"a directory, and path should be relative; path will then be relative to\n" +"that directory.\n" +"dir_fd may not be implemented on your platform. If it is unavailable,\n" +"using it will raise a NotImplementedError."); #define OS_MKFIFO_METHODDEF \ {"mkfifo", _PyCFunction_CAST(os_mkfifo), METH_FASTCALL|METH_KEYWORDS, os_mkfifo__doc__}, @@ -9096,17 +9118,18 @@ PyDoc_STRVAR(os_mknod__doc__, "\n" "Create a node in the file system.\n" "\n" -"Create a node in the file system (file, device special file or named pipe)\n" -"at path. mode specifies both the permissions to use and the\n" +"Create a node in the file system (file, device special file or named\n" +"pipe) at path. mode specifies both the permissions to use and the\n" "type of node to be created, being combined (bitwise OR) with one of\n" -"S_IFREG, S_IFCHR, S_IFBLK, and S_IFIFO. If S_IFCHR or S_IFBLK is set on mode,\n" -"device defines the newly created device special file (probably using\n" -"os.makedev()). Otherwise device is ignored.\n" +"S_IFREG, S_IFCHR, S_IFBLK, and S_IFIFO. If S_IFCHR or S_IFBLK is set\n" +"on mode, device defines the newly created device special file (probably\n" +"using os.makedev()). Otherwise device is ignored.\n" "\n" -"If dir_fd is not None, it should be a file descriptor open to a directory,\n" -" and path should be relative; path will then be relative to that directory.\n" -"dir_fd may not be implemented on your platform.\n" -" If it is unavailable, using it will raise a NotImplementedError."); +"If dir_fd is not None, it should be a file descriptor open to\n" +"a directory, and path should be relative; path will then be relative\n" +"to that directory.\n" +"dir_fd may not be implemented on your platform. If it is unavailable,\n" +"using it will raise a NotImplementedError."); #define OS_MKNOD_METHODDEF \ {"mknod", _PyCFunction_CAST(os_mknod), METH_FASTCALL|METH_KEYWORDS, os_mknod__doc__}, @@ -9352,8 +9375,9 @@ PyDoc_STRVAR(os_truncate__doc__, "\n" "Truncate a file, specified by path, to a specific length.\n" "\n" -"On some platforms, path may also be specified as an open file descriptor.\n" -" If this functionality is unavailable, using it raises an exception."); +"On some platforms, path may also be specified as an open file\n" +"descriptor. If this functionality is unavailable, using it raises\n" +"an exception."); #define OS_TRUNCATE_METHODDEF \ {"truncate", _PyCFunction_CAST(os_truncate), METH_FASTCALL|METH_KEYWORDS, os_truncate__doc__}, @@ -9427,7 +9451,8 @@ PyDoc_STRVAR(os_posix_fallocate__doc__, "Ensure a file has allocated at least a particular number of bytes on disk.\n" "\n" "Ensure that the file specified by fd encompasses a range of bytes\n" -"starting at offset bytes from the beginning and continuing for length bytes."); +"starting at offset bytes from the beginning and continuing for length\n" +"bytes."); #define OS_POSIX_FALLOCATE_METHODDEF \ {"posix_fallocate", _PyCFunction_CAST(os_posix_fallocate), METH_FASTCALL, os_posix_fallocate__doc__}, @@ -9473,8 +9498,8 @@ PyDoc_STRVAR(os_posix_fadvise__doc__, "\n" "Announce an intention to access data in a specific pattern.\n" "\n" -"Announce an intention to access data in a specific pattern, thus allowing\n" -"the kernel to make optimizations.\n" +"Announce an intention to access data in a specific pattern, thus\n" +"allowing the kernel to make optimizations.\n" "The advice applies to the region of the file specified by fd starting at\n" "offset and continuing for length bytes.\n" "advice is one of POSIX_FADV_NORMAL, POSIX_FADV_SEQUENTIAL,\n" @@ -10296,8 +10321,9 @@ PyDoc_STRVAR(os_statvfs__doc__, "Perform a statvfs system call on the given path.\n" "\n" "path may always be specified as a string.\n" -"On some platforms, path may also be specified as an open file descriptor.\n" -" If this functionality is unavailable, using it raises an exception."); +"On some platforms, path may also be specified as an open file\n" +"descriptor. If this functionality is unavailable, using it raises\n" +"an exception."); #define OS_STATVFS_METHODDEF \ {"statvfs", _PyCFunction_CAST(os_statvfs), METH_FASTCALL|METH_KEYWORDS, os_statvfs__doc__}, @@ -10480,8 +10506,9 @@ PyDoc_STRVAR(os_pathconf__doc__, "Return the configuration limit name for the file or directory path.\n" "\n" "If there is no limit, return -1.\n" -"On some platforms, path may also be specified as an open file descriptor.\n" -" If this functionality is unavailable, using it raises an exception."); +"On some platforms, path may also be specified as an open file\n" +"descriptor. If this functionality is unavailable, using it raises\n" +"an exception."); #define OS_PATHCONF_METHODDEF \ {"pathconf", _PyCFunction_CAST(os_pathconf), METH_FASTCALL|METH_KEYWORDS, os_pathconf__doc__}, @@ -10624,8 +10651,8 @@ PyDoc_STRVAR(os_abort__doc__, "\n" "Abort the interpreter immediately.\n" "\n" -"This function \'dumps core\' or otherwise fails in the hardest way possible\n" -"on the hosting operating system. This function never returns."); +"This function \'dumps core\' or otherwise fails in the hardest way\n" +"possible on the hosting operating system. This function never returns."); #define OS_ABORT_METHODDEF \ {"abort", (PyCFunction)os_abort, METH_NOARGS, os_abort__doc__}, @@ -11013,10 +11040,11 @@ PyDoc_STRVAR(os_getxattr__doc__, "\n" "Return the value of extended attribute attribute on path.\n" "\n" -"path may be either a string, a path-like object, or an open file descriptor.\n" -"If follow_symlinks is False, and the last element of the path is a symbolic\n" -" link, getxattr will examine the symbolic link itself instead of the file\n" -" the link points to."); +"path may be either a string, a path-like object, or an open file\n" +"descriptor.\n" +"If follow_symlinks is False, and the last element of the path is\n" +"a symbolic link, getxattr will examine the symbolic link itself\n" +"instead of the file the link points to."); #define OS_GETXATTR_METHODDEF \ {"getxattr", _PyCFunction_CAST(os_getxattr), METH_FASTCALL|METH_KEYWORDS, os_getxattr__doc__}, @@ -11103,10 +11131,11 @@ PyDoc_STRVAR(os_setxattr__doc__, "\n" "Set extended attribute attribute on path to value.\n" "\n" -"path may be either a string, a path-like object, or an open file descriptor.\n" -"If follow_symlinks is False, and the last element of the path is a symbolic\n" -" link, setxattr will modify the symbolic link itself instead of the file\n" -" the link points to."); +"path may be either a string, a path-like object, or an open file\n" +"descriptor.\n" +"If follow_symlinks is False, and the last element of the path is\n" +"a symbolic link, setxattr will modify the symbolic link itself instead\n" +"of the file the link points to."); #define OS_SETXATTR_METHODDEF \ {"setxattr", _PyCFunction_CAST(os_setxattr), METH_FASTCALL|METH_KEYWORDS, os_setxattr__doc__}, @@ -11214,10 +11243,11 @@ PyDoc_STRVAR(os_removexattr__doc__, "\n" "Remove extended attribute attribute on path.\n" "\n" -"path may be either a string, a path-like object, or an open file descriptor.\n" -"If follow_symlinks is False, and the last element of the path is a symbolic\n" -" link, removexattr will modify the symbolic link itself instead of the file\n" -" the link points to."); +"path may be either a string, a path-like object, or an open file\n" +"descriptor.\n" +"If follow_symlinks is False, and the last element of the path is\n" +"a symbolic link, removexattr will modify the symbolic link itself\n" +"instead of the file the link points to."); #define OS_REMOVEXATTR_METHODDEF \ {"removexattr", _PyCFunction_CAST(os_removexattr), METH_FASTCALL|METH_KEYWORDS, os_removexattr__doc__}, @@ -11303,11 +11333,12 @@ PyDoc_STRVAR(os_listxattr__doc__, "\n" "Return a list of extended attributes on path.\n" "\n" -"path may be either None, a string, a path-like object, or an open file descriptor.\n" -"if path is None, listxattr will examine the current directory.\n" -"If follow_symlinks is False, and the last element of the path is a symbolic\n" -" link, listxattr will examine the symbolic link itself instead of the file\n" -" the link points to."); +"path may be either None, a string, a path-like object, or an open file\n" +"descriptor. If path is None, listxattr will examine the current\n" +"directory.\n" +"If follow_symlinks is False, and the last element of the path is\n" +"a symbolic link, listxattr will examine the symbolic link itself instead\n" +"of the file the link points to."); #define OS_LISTXATTR_METHODDEF \ {"listxattr", _PyCFunction_CAST(os_listxattr), METH_FASTCALL|METH_KEYWORDS, os_listxattr__doc__}, @@ -12329,9 +12360,9 @@ PyDoc_STRVAR(os_scandir__doc__, "\n" "Return an iterator of DirEntry objects for given path.\n" "\n" -"path can be specified as either str, bytes, or a path-like object. If path\n" -"is bytes, the names of yielded DirEntry objects will also be bytes; in\n" -"all other circumstances they will be str.\n" +"path can be specified as either str, bytes, or a path-like object. If\n" +"path is bytes, the names of yielded DirEntry objects will also be bytes;\n" +"in all other circumstances they will be str.\n" "\n" "If path is None, uses the path=\'.\'."); @@ -12403,9 +12434,9 @@ PyDoc_STRVAR(os_fspath__doc__, "\n" "Return the file system path representation of the object.\n" "\n" -"If the object is str or bytes, then allow it to pass through as-is. If the\n" -"object defines __fspath__(), then return the result of that method. All other\n" -"types raise a TypeError."); +"If the object is str or bytes, then allow it to pass through as-is. If\n" +"the object defines __fspath__(), then return the result of that method.\n" +"All other types raise a TypeError."); #define OS_FSPATH_METHODDEF \ {"fspath", _PyCFunction_CAST(os_fspath), METH_FASTCALL|METH_KEYWORDS, os_fspath__doc__}, @@ -12699,8 +12730,8 @@ PyDoc_STRVAR(os_waitstatus_to_exitcode__doc__, "On Windows, return status shifted right by 8 bits.\n" "\n" "On Unix, if the process is being traced or if waitpid() was called with\n" -"WUNTRACED option, the caller must first check if WIFSTOPPED(status) is true.\n" -"This function must not be called if WIFSTOPPED(status) is true."); +"WUNTRACED option, the caller must first check if WIFSTOPPED(status) is\n" +"true. This function must not be called if WIFSTOPPED(status) is true."); #define OS_WAITSTATUS_TO_EXITCODE_METHODDEF \ {"waitstatus_to_exitcode", _PyCFunction_CAST(os_waitstatus_to_exitcode), METH_FASTCALL|METH_KEYWORDS, os_waitstatus_to_exitcode__doc__}, @@ -13611,4 +13642,4 @@ os__emscripten_log(PyObject *module, PyObject *const *args, Py_ssize_t nargs, Py #ifndef OS__EMSCRIPTEN_LOG_METHODDEF #define OS__EMSCRIPTEN_LOG_METHODDEF #endif /* !defined(OS__EMSCRIPTEN_LOG_METHODDEF) */ -/*[clinic end generated code: output=e709b8b783fbc261 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=d6889ab281d7676f input=a9049054013a1b77]*/ diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 5bd53c2146a822..4f745c504a066a 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -2365,7 +2365,7 @@ PyDoc_STRVAR(stat_result__doc__, "stat_result: Result from stat, fstat, or lstat.\n\n\ This object may be accessed either as a tuple of\n\ (mode, ino, dev, nlink, uid, gid, size, atime, mtime, ctime)\n\ -or via the attributes st_mode, st_ino, st_dev, st_nlink, st_uid, and so on.\n\ +or via the attributes st_mode, st_ino, st_dev, st_nlink, and so on.\n\ \n\ Posix/windows: If your platform supports st_blksize, st_blocks, st_rdev,\n\ or st_flags, they are available as attributes only.\n\ @@ -3925,14 +3925,14 @@ os.chdir Change the current working directory to the specified path. -path may always be specified as a string. -On some platforms, path may also be specified as an open file descriptor. -If this functionality is unavailable, using it raises an exception. +path may always be specified as a string. On some platforms, path may +also be specified as an open file descriptor. If this functionality is +unavailable, using it raises an exception. [clinic start generated code]*/ static PyObject * os_chdir_impl(PyObject *module, path_t *path) -/*[clinic end generated code: output=3be6400eee26eaae input=a74ceab5d72adf74]*/ +/*[clinic end generated code: output=3be6400eee26eaae input=64673c342e4369f1]*/ { int result; @@ -4045,15 +4045,16 @@ win32_fchmod(int fd, int mode) os.chmod path: path_t(allow_fd='PATH_HAVE_FCHMOD') - Path to be modified. May always be specified as a str, bytes, or a path-like object. - On some platforms, path may also be specified as an open file descriptor. - If this functionality is unavailable, using it raises an exception. + Path to be modified. May always be specified as a str, bytes, or + a path-like object. On some platforms, path may also be specified + as an open file descriptor. If this functionality is unavailable, + using it raises an exception. mode: int Operating-system mode bitfield. - Be careful when using number literals for *mode*. The conventional UNIX notation for - numeric modes uses an octal base, which needs to be indicated with a ``0o`` prefix in - Python. + Be careful when using number literals for *mode*. The conventional + UNIX notation for numeric modes uses an octal base, which needs to + be indicated with a ``0o`` prefix in Python. * @@ -4080,7 +4081,7 @@ dir_fd and follow_symlinks may not be implemented on your platform. static PyObject * os_chmod_impl(PyObject *module, path_t *path, int mode, int dir_fd, int follow_symlinks) -/*[clinic end generated code: output=5cf6a94915cc7bff input=fcf115d174b9f3d8]*/ +/*[clinic end generated code: output=5cf6a94915cc7bff input=7b6e2eeadd8bf199]*/ { int result; @@ -4216,9 +4217,9 @@ os.fchmod The file descriptor of the file to be modified. mode: int Operating-system mode bitfield. - Be careful when using number literals for *mode*. The conventional UNIX notation for - numeric modes uses an octal base, which needs to be indicated with a ``0o`` prefix in - Python. + Be careful when using number literals for *mode*. The conventional + UNIX notation for numeric modes uses an octal base, which needs to + be indicated with a ``0o`` prefix in Python. Change the access permissions of the file given by file descriptor fd. @@ -4227,7 +4228,7 @@ Equivalent to os.chmod(fd, mode). static PyObject * os_fchmod_impl(PyObject *module, int fd, int mode) -/*[clinic end generated code: output=afd9bc05b4e426b3 input=b5594618bbbc22df]*/ +/*[clinic end generated code: output=afd9bc05b4e426b3 input=d24331f9fdc17f49]*/ { int res; @@ -4261,6 +4262,7 @@ os_fchmod_impl(PyObject *module, int fd, int mode) #if defined(HAVE_LCHMOD) || defined(MS_WINDOWS) /*[clinic input] +@permit_long_summary os.lchmod path: path_t @@ -4268,13 +4270,13 @@ os.lchmod Change the access permissions of a file, without following symbolic links. -If path is a symlink, this affects the link itself rather than the target. -Equivalent to chmod(path, mode, follow_symlinks=False)." +If path is a symlink, this affects the link itself rather than the +target. Equivalent to chmod(path, mode, follow_symlinks=False). [clinic start generated code]*/ static PyObject * os_lchmod_impl(PyObject *module, path_t *path, int mode) -/*[clinic end generated code: output=082344022b51a1d5 input=90c5663c7465d24f]*/ +/*[clinic end generated code: output=082344022b51a1d5 input=13110fb62911b015]*/ { int res; if (PySys_Audit("os.chmod", "Oii", path->object, mode, -1) < 0) { @@ -4312,9 +4314,9 @@ os.chflags Set file flags. -If follow_symlinks is False, and the last element of the path is a symbolic - link, chflags will change flags on the symbolic link itself instead of the - file the link points to. +If follow_symlinks is False, and the last element of the path is +a symbolic link, chflags() will change flags on the symbolic link itself +instead of the file the link points to. follow_symlinks may not be implemented on your platform. If it is unavailable, using it will raise a NotImplementedError. @@ -4323,7 +4325,7 @@ unavailable, using it will raise a NotImplementedError. static PyObject * os_chflags_impl(PyObject *module, path_t *path, unsigned long flags, int follow_symlinks) -/*[clinic end generated code: output=85571c6737661ce9 input=0327e29feb876236]*/ +/*[clinic end generated code: output=85571c6737661ce9 input=31391927707be1de]*/ { int result; @@ -4473,7 +4475,8 @@ os_fdatasync_impl(PyObject *module, int fd) os.chown path : path_t(allow_fd='PATH_HAVE_FCHOWN') - Path to be examined; can be string, bytes, a path-like object, or open-file-descriptor int. + Path to be examined; can be string, bytes, a path-like object, or + open-file-descriptor int. uid: uid_t @@ -4481,7 +4484,7 @@ os.chown * - dir_fd : dir_fd(requires='fchownat') = None + dir_fd: dir_fd(requires='fchownat') = None If not None, it should be a file descriptor open to a directory, and path should be relative; path will then be relative to that directory. @@ -4491,27 +4494,28 @@ os.chown stat will examine the symbolic link itself instead of the file the link points to. -Change the owner and group id of path to the numeric uid and gid.\ +Change the owner and group id of path to the numeric uid and gid. -path may always be specified as a string. -On some platforms, path may also be specified as an open file descriptor. - If this functionality is unavailable, using it raises an exception. -If dir_fd is not None, it should be a file descriptor open to a directory, - and path should be relative; path will then be relative to that directory. -If follow_symlinks is False, and the last element of the path is a symbolic - link, chown will modify the symbolic link itself instead of the file the - link points to. +path may always be specified as a string. On some platforms, path may +also be specified as an open file descriptor. If this functionality is +unavailable, using it raises an exception. +If dir_fd is not None, it should be a file descriptor open to +a directory, and path should be relative; path will then be relative to +that directory. +If follow_symlinks is False, and the last element of the path is +a symbolic link, chown will modify the symbolic link itself instead of +the file the link points to. It is an error to use dir_fd or follow_symlinks when specifying path as - an open file descriptor. -dir_fd and follow_symlinks may not be implemented on your platform. - If they are unavailable, using them will raise a NotImplementedError. +an open file descriptor. +dir_fd and follow_symlinks may not be implemented on your platform. If +they are unavailable, using them will raise a NotImplementedError. [clinic start generated code]*/ static PyObject * os_chown_impl(PyObject *module, path_t *path, uid_t uid, gid_t gid, int dir_fd, int follow_symlinks) -/*[clinic end generated code: output=4beadab0db5f70cd input=b08c5ec67996a97d]*/ +/*[clinic end generated code: output=4beadab0db5f70cd input=509c91b7a0e72f52]*/ { int result; @@ -4795,7 +4799,6 @@ os_getcwdb_impl(PyObject *module) #ifdef HAVE_LINK /*[clinic input] -@permit_long_docstring_body os.link src : path_t @@ -4808,20 +4811,21 @@ os.link Create a hard link to a file. If either src_dir_fd or dst_dir_fd is not None, it should be a file - descriptor open to a directory, and the respective path string (src or dst) - should be relative; the path will then be relative to that directory. +descriptor open to a directory, and the respective path string (src or +dst) should be relative; the path will then be relative to that +directory. If follow_symlinks is False, and the last element of src is a symbolic - link, link will create a link to the symbolic link itself instead of the - file the link points to. -src_dir_fd, dst_dir_fd, and follow_symlinks may not be implemented on your - platform. If they are unavailable, using them will raise a - NotImplementedError. +link, link will create a link to the symbolic link itself instead of the +file the link points to. +src_dir_fd, dst_dir_fd, and follow_symlinks may not be implemented on +your platform. If they are unavailable, using them will raise +a NotImplementedError. [clinic start generated code]*/ static PyObject * os_link_impl(PyObject *module, path_t *src, path_t *dst, int src_dir_fd, int dst_dir_fd, int follow_symlinks) -/*[clinic end generated code: output=7f00f6007fd5269a input=e2a50a6497050e44]*/ +/*[clinic end generated code: output=7f00f6007fd5269a input=a28e6866fbd20a01]*/ { #ifdef MS_WINDOWS BOOL result = FALSE; @@ -5115,30 +5119,28 @@ _posix_listdir(path_t *path, PyObject *list) /*[clinic input] -@permit_long_docstring_body os.listdir path : path_t(nullable=True, allow_fd='PATH_HAVE_FDOPENDIR') = None Return a list containing the names of the files in the directory. -path can be specified as either str, bytes, or a path-like object. If path is bytes, - the filenames returned will also be bytes; in all other circumstances - the filenames returned will be str. +path can be specified as either str, bytes, or a path-like object. If +path is bytes, the filenames returned will also be bytes; in all other +circumstances the filenames returned will be str. If path is None, uses the path='.'. -On some platforms, path may also be specified as an open file descriptor;\ - the file descriptor must refer to a directory. - If this functionality is unavailable, using it raises NotImplementedError. +On some platforms, path may also be specified as an open file +descriptor; the file descriptor must refer to a directory. If this +functionality is unavailable, using it raises NotImplementedError. The list is in arbitrary order. It does not include the special entries '.' and '..' even if they are present in the directory. - [clinic start generated code]*/ static PyObject * os_listdir_impl(PyObject *module, path_t *path) -/*[clinic end generated code: output=293045673fcd1a75 input=0bd1728387391b9a]*/ +/*[clinic end generated code: output=293045673fcd1a75 input=4eefe7c6a42ec9b2]*/ { if (PySys_Audit("os.listdir", "O", path->object ? path->object : Py_None) < 0) { @@ -5597,6 +5599,7 @@ os__getfinalpathname_impl(PyObject *module, path_t *path) } /*[clinic input] +@permit_long_summary os._findfirstfile path: path_t / @@ -5605,7 +5608,7 @@ A function to get the real file name without accessing the file in Windows. static PyObject * os__findfirstfile_impl(PyObject *module, path_t *path) -/*[clinic end generated code: output=106dd3f0779c83dd input=0734dff70f60e1a8]*/ +/*[clinic end generated code: output=106dd3f0779c83dd input=48c319aaa48d05d4]*/ { PyObject *result; HANDLE hFindFile; @@ -6159,22 +6162,21 @@ os.mkdir dir_fd : dir_fd(requires='mkdirat') = None -# "mkdir(path, mode=0o777, *, dir_fd=None)\n\n\ - Create a directory. -If dir_fd is not None, it should be a file descriptor open to a directory, - and path should be relative; path will then be relative to that directory. -dir_fd may not be implemented on your platform. - If it is unavailable, using it will raise a NotImplementedError. +If dir_fd is not None, it should be a file descriptor open to +a directory, and path should be relative; path will then be relative to +that directory. +dir_fd may not be implemented on your platform. If it is unavailable, +using it will raise a NotImplementedError. -The mode argument is ignored on Windows. Where it is used, the current umask -value is first masked out. +The mode argument is ignored on Windows. Where it is used, the current +umask value is first masked out. [clinic start generated code]*/ static PyObject * os_mkdir_impl(PyObject *module, path_t *path, int mode, int dir_fd) -/*[clinic end generated code: output=a70446903abe821f input=a61722e1576fab03]*/ +/*[clinic end generated code: output=a70446903abe821f input=30270d369599634b]*/ { int result; #ifdef MS_WINDOWS @@ -6428,7 +6430,6 @@ internal_rename(path_t *src, path_t *dst, int src_dir_fd, int dst_dir_fd, int is /*[clinic input] -@permit_long_docstring_body os.rename src : path_t @@ -6440,38 +6441,39 @@ os.rename Rename a file or directory. If either src_dir_fd or dst_dir_fd is not None, it should be a file - descriptor open to a directory, and the respective path string (src or dst) - should be relative; the path will then be relative to that directory. +descriptor open to a directory, and the respective path string (src or +dst) should be relative; the path will then be relative to that +directory. src_dir_fd and dst_dir_fd, may not be implemented on your platform. - If they are unavailable, using them will raise a NotImplementedError. +If they are unavailable, using them will raise a NotImplementedError. [clinic start generated code]*/ static PyObject * os_rename_impl(PyObject *module, path_t *src, path_t *dst, int src_dir_fd, int dst_dir_fd) -/*[clinic end generated code: output=59e803072cf41230 input=11aae8c091162766]*/ +/*[clinic end generated code: output=59e803072cf41230 input=7d320d687c715fd6]*/ { return internal_rename(src, dst, src_dir_fd, dst_dir_fd, 0); } /*[clinic input] -@permit_long_docstring_body os.replace = os.rename Rename a file or directory, overwriting the destination. If either src_dir_fd or dst_dir_fd is not None, it should be a file - descriptor open to a directory, and the respective path string (src or dst) - should be relative; the path will then be relative to that directory. +descriptor open to a directory, and the respective path string (src or +dst) should be relative; the path will then be relative to that +directory. src_dir_fd and dst_dir_fd, may not be implemented on your platform. - If they are unavailable, using them will raise a NotImplementedError. +If they are unavailable, using them will raise a NotImplementedError. [clinic start generated code]*/ static PyObject * os_replace_impl(PyObject *module, path_t *src, path_t *dst, int src_dir_fd, int dst_dir_fd) -/*[clinic end generated code: output=1968c02e7857422b input=78d6c8087e90994c]*/ +/*[clinic end generated code: output=1968c02e7857422b input=44ed6b762d5953fc]*/ { return internal_rename(src, dst, src_dir_fd, dst_dir_fd, 1); } @@ -6486,15 +6488,16 @@ os.rmdir Remove a directory. -If dir_fd is not None, it should be a file descriptor open to a directory, - and path should be relative; path will then be relative to that directory. +If dir_fd is not None, it should be a file descriptor open to +a directory, and path should be relative; path will then be relative +to that directory. dir_fd may not be implemented on your platform. - If it is unavailable, using it will raise a NotImplementedError. +If it is unavailable, using it will raise a NotImplementedError. [clinic start generated code]*/ static PyObject * os_rmdir_impl(PyObject *module, path_t *path, int dir_fd) -/*[clinic end generated code: output=080eb54f506e8301 input=38c8b375ca34a7e2]*/ +/*[clinic end generated code: output=080eb54f506e8301 input=84325211e33a98e0]*/ { int result; #ifdef HAVE_UNLINKAT @@ -6665,16 +6668,17 @@ os.unlink Remove a file (same as remove()). -If dir_fd is not None, it should be a file descriptor open to a directory, - and path should be relative; path will then be relative to that directory. +If dir_fd is not None, it should be a file descriptor open to +a directory, and path should be relative; path will then be relative to +that directory. dir_fd may not be implemented on your platform. - If it is unavailable, using it will raise a NotImplementedError. +If it is unavailable, using it will raise a NotImplementedError. [clinic start generated code]*/ static PyObject * os_unlink_impl(PyObject *module, path_t *path, int dir_fd) -/*[clinic end generated code: output=621797807b9963b1 input=d7bcde2b1b2a2552]*/ +/*[clinic end generated code: output=621797807b9963b1 input=1a2ef2579207eab1]*/ { int result; #ifdef HAVE_UNLINKAT @@ -6726,15 +6730,16 @@ os.remove = os.unlink Remove a file (same as unlink()). -If dir_fd is not None, it should be a file descriptor open to a directory, - and path should be relative; path will then be relative to that directory. +If dir_fd is not None, it should be a file descriptor open to +a directory, and path should be relative; path will then be relative +to that directory. dir_fd may not be implemented on your platform. - If it is unavailable, using it will raise a NotImplementedError. +If it is unavailable, using it will raise a NotImplementedError. [clinic start generated code]*/ static PyObject * os_remove_impl(PyObject *module, path_t *path, int dir_fd) -/*[clinic end generated code: output=a8535b28f0068883 input=e05c5ab55cd30983]*/ +/*[clinic end generated code: output=a8535b28f0068883 input=9f6e66912126bd56]*/ { return os_unlink_impl(module, path, dir_fd); } @@ -7056,38 +7061,37 @@ os.utime dir_fd: dir_fd(requires='futimensat') = None follow_symlinks: bool=True -# "utime(path, times=None, *[, ns], dir_fd=None, follow_symlinks=True)\n\ - Set the access and modified time of path. -path may always be specified as a string. -On some platforms, path may also be specified as an open file descriptor. - If this functionality is unavailable, using it raises an exception. +path may always be specified as a string. On some platforms, path may +also be specified as an open file descriptor. If this functionality is +unavailable, using it raises an exception. If times is not None, it must be a tuple (atime, mtime); - atime and mtime should be expressed as float seconds since the epoch. +atime and mtime should be expressed as float seconds since the epoch. If ns is specified, it must be a tuple (atime_ns, mtime_ns); - atime_ns and mtime_ns should be expressed as integer nanoseconds - since the epoch. +atime_ns and mtime_ns should be expressed as integer nanoseconds +since the epoch. If times is None and ns is unspecified, utime uses the current time. Specifying tuples for both times and ns is an error. -If dir_fd is not None, it should be a file descriptor open to a directory, - and path should be relative; path will then be relative to that directory. -If follow_symlinks is False, and the last element of the path is a symbolic - link, utime will modify the symbolic link itself instead of the file the - link points to. -It is an error to use dir_fd or follow_symlinks when specifying path - as an open file descriptor. +If dir_fd is not None, it should be a file descriptor open to +a directory, and path should be relative; path will then be relative to +that directory. +If follow_symlinks is False, and the last element of the path is +a symbolic link, utime will modify the symbolic link itself instead of +the file the link points to. +It is an error to use dir_fd or follow_symlinks when specifying path as +an open file descriptor. dir_fd and follow_symlinks may not be available on your platform. - If they are unavailable, using them will raise a NotImplementedError. +If they are unavailable, using them will raise a NotImplementedError. [clinic start generated code]*/ static PyObject * os_utime_impl(PyObject *module, path_t *path, PyObject *times, PyObject *ns, int dir_fd, int follow_symlinks) -/*[clinic end generated code: output=cfcac69d027b82cf input=2fbd62a2f228f8f4]*/ +/*[clinic end generated code: output=cfcac69d027b82cf input=5ab470b2bc250788]*/ { #ifdef MS_WINDOWS HANDLE hFile; @@ -7244,6 +7248,7 @@ os_utime_impl(PyObject *module, path_t *path, PyObject *times, PyObject *ns, /*[clinic input] +@permit_long_summary os._exit status: int @@ -7253,7 +7258,7 @@ Exit to the system with specified status, without normal exit processing. static PyObject * os__exit_impl(PyObject *module, int status) -/*[clinic end generated code: output=116e52d9c2260d54 input=5e6d57556b0c4a62]*/ +/*[clinic end generated code: output=116e52d9c2260d54 input=c35d282acfebe8fd]*/ { _exit(status); return NULL; /* Make gcc -Wall happy */ @@ -8057,7 +8062,8 @@ os.posix_spawn resetids: bool = False If the value is `true` the POSIX_SPAWN_RESETIDS will be activated. setsid: bool = False - If the value is `true` the POSIX_SPAWN_SETSID or POSIX_SPAWN_SETSID_NP will be activated. + If the value is `true` the POSIX_SPAWN_SETSID or POSIX_SPAWN_SETSID_NP + will be activated. setsigmask: object(c_default='NULL') = () The sigmask to use with the POSIX_SPAWN_SETSIGMASK flag. setsigdef: object(c_default='NULL') = () @@ -8074,7 +8080,7 @@ os_posix_spawn_impl(PyObject *module, path_t *path, PyObject *argv, PyObject *setpgroup, int resetids, int setsid, PyObject *setsigmask, PyObject *setsigdef, PyObject *scheduler) -/*[clinic end generated code: output=14a1098c566bc675 input=69e7c9ebbdcf94a5]*/ +/*[clinic end generated code: output=14a1098c566bc675 input=c7592dcbc96e8114]*/ { return py_posix_spawn(0, module, path, argv, env, file_actions, setpgroup, resetids, setsid, setsigmask, setsigdef, @@ -8103,7 +8109,8 @@ os.posix_spawnp resetids: bool = False If the value is `True` the POSIX_SPAWN_RESETIDS will be activated. setsid: bool = False - If the value is `True` the POSIX_SPAWN_SETSID or POSIX_SPAWN_SETSID_NP will be activated. + If the value is `True` the POSIX_SPAWN_SETSID or POSIX_SPAWN_SETSID_NP + will be activated. setsigmask: object(c_default='NULL') = () The sigmask to use with the POSIX_SPAWN_SETSIGMASK flag. setsigdef: object(c_default='NULL') = () @@ -8120,7 +8127,7 @@ os_posix_spawnp_impl(PyObject *module, path_t *path, PyObject *argv, PyObject *setpgroup, int resetids, int setsid, PyObject *setsigmask, PyObject *setsigdef, PyObject *scheduler) -/*[clinic end generated code: output=7b9aaefe3031238d input=a5c057527c6881a5]*/ +/*[clinic end generated code: output=7b9aaefe3031238d input=43ccc1452cae2be3]*/ { return py_posix_spawn(1, module, path, argv, env, file_actions, setpgroup, resetids, setsid, setsigmask, setsigdef, @@ -9156,13 +9163,13 @@ os.posix_openpt -> int Open and return a file descriptor for a master pseudo-terminal device. Performs a posix_openpt() C function call. The oflag argument is used to -set file status flags and file access modes as specified in the manual page -of posix_openpt() of your system. +set file status flags and file access modes as specified in the manual +page of posix_openpt() of your system. [clinic start generated code]*/ static int os_posix_openpt_impl(PyObject *module, int oflag) -/*[clinic end generated code: output=ee0bc2624305fc79 input=0de33d0e29693caa]*/ +/*[clinic end generated code: output=ee0bc2624305fc79 input=3ce4eb297fa64307]*/ { int fd; @@ -9437,6 +9444,7 @@ os_openpty_impl(PyObject *module) #if defined(HAVE_LOGIN_TTY) || defined(HAVE_FALLBACK_LOGIN_TTY) /*[clinic input] +@permit_long_summary os.login_tty fd: fildes @@ -9451,7 +9459,7 @@ calling process; close fd. static PyObject * os_login_tty_impl(PyObject *module, int fd) -/*[clinic end generated code: output=495a79911b4cc1bc input=5f298565099903a2]*/ +/*[clinic end generated code: output=495a79911b4cc1bc input=b102a7c36e8baf00]*/ { #ifdef HAVE_LOGIN_TTY if (login_tty(fd) == -1) { @@ -9806,14 +9814,14 @@ os.initgroups Initialize the group access list. -Call the system initgroups() to initialize the group access list with all of -the groups of which the specified username is a member, plus the specified -group id. +Call the system initgroups() to initialize the group access list with +all of the groups of which the specified username is a member, plus the +specified group id. [clinic start generated code]*/ static PyObject * os_initgroups_impl(PyObject *module, PyObject *oname, int gid) -/*[clinic end generated code: output=7f074d30a425fd3a input=984e60c7fed88cb4]*/ +/*[clinic end generated code: output=7f074d30a425fd3a input=35f2d4fb7fcc0bdf]*/ #else /*[clinic input] os.initgroups @@ -9824,14 +9832,14 @@ os.initgroups Initialize the group access list. -Call the system initgroups() to initialize the group access list with all of -the groups of which the specified username is a member, plus the specified -group id. +Call the system initgroups() to initialize the group access list with +all of the groups of which the specified username is a member, plus the +specified group id. [clinic start generated code]*/ static PyObject * os_initgroups_impl(PyObject *module, PyObject *oname, gid_t gid) -/*[clinic end generated code: output=59341244521a9e3f input=17d8fbe2dea42ca4]*/ +/*[clinic end generated code: output=59341244521a9e3f input=7e4514dff4526a95]*/ #endif { const char *username = PyBytes_AS_STRING(oname); @@ -10028,12 +10036,13 @@ os.getppid Return the parent's process id. If the parent process has already exited, Windows machines will still -return its id; others systems will return the id of the 'init' process (1). +return its id; others systems will return the id of the 'init' proces +(1). [clinic start generated code]*/ static PyObject * os_getppid_impl(PyObject *module) -/*[clinic end generated code: output=43b2a946a8c603b4 input=e637cb87539c030e]*/ +/*[clinic end generated code: output=43b2a946a8c603b4 input=e17c1de18f41316b]*/ { #ifdef MS_WINDOWS return win32_getppid(); @@ -10587,13 +10596,13 @@ os.waitid Returns the result of waiting for a process or processes. -Returns either waitid_result or None if WNOHANG is specified and there are -no children in a waitable state. +Returns either waitid_result or None if WNOHANG is specified and there +are no children in a waitable state. [clinic start generated code]*/ static PyObject * os_waitid_impl(PyObject *module, idtype_t idtype, id_t id, int options) -/*[clinic end generated code: output=5d2e1c0bde61f4d8 input=d8e7f76e052b7920]*/ +/*[clinic end generated code: output=5d2e1c0bde61f4d8 input=14956bc8d102b5db]*/ { PyObject *result; int res; @@ -10760,13 +10769,13 @@ os.pidfd_open Return a file descriptor referring to the process *pid*. -The descriptor can be used to perform process management without races and -signals. +The descriptor can be used to perform process management without races +and signals. [clinic start generated code]*/ static PyObject * os_pidfd_open_impl(PyObject *module, pid_t pid, unsigned int flags) -/*[clinic end generated code: output=5c7252698947dc41 input=c3fd99ce947ccfef]*/ +/*[clinic end generated code: output=5c7252698947dc41 input=03058b32c389f874]*/ { int fd = syscall(__NR_pidfd_open, pid, flags); if (fd < 0) { @@ -10845,8 +10854,9 @@ os.readlink Return a string representing the path to which the symbolic link points. -If dir_fd is not None, it should be a file descriptor open to a directory, -and path should be relative; path will then be relative to that directory. +If dir_fd is not None, it should be a file descriptor open to +a directory, and path should be relative; path will then be relative to +that directory. dir_fd may not be implemented on your platform. If it is unavailable, using it will raise a NotImplementedError. @@ -10854,7 +10864,7 @@ using it will raise a NotImplementedError. static PyObject * os_readlink_impl(PyObject *module, path_t *path, int dir_fd) -/*[clinic end generated code: output=d21b732a2e814030 input=113c87e0db1ecaf2]*/ +/*[clinic end generated code: output=d21b732a2e814030 input=03d10130870dbca8]*/ { #if defined(HAVE_READLINK) char buffer[MAXPATHLEN+1]; @@ -11049,26 +11059,25 @@ os.symlink * dir_fd: dir_fd(requires='symlinkat')=None -# "symlink(src, dst, target_is_directory=False, *, dir_fd=None)\n\n\ - Create a symbolic link pointing to src named dst. target_is_directory is required on Windows if the target is to be - interpreted as a directory. (On Windows, symlink requires - Windows 6.0 or greater, and raises a NotImplementedError otherwise.) - target_is_directory is ignored on non-Windows platforms. +interpreted as a directory. (On Windows, symlink requires Windows 6.0 +or greater, and raises a NotImplementedError otherwise.) +target_is_directory is ignored on non-Windows platforms. -If dir_fd is not None, it should be a file descriptor open to a directory, - and path should be relative; path will then be relative to that directory. -dir_fd may not be implemented on your platform. - If it is unavailable, using it will raise a NotImplementedError. +If dir_fd is not None, it should be a file descriptor open to +a directory, and path should be relative; path will then be relative +to that directory. +dir_fd may not be implemented on your platform. If it is unavailable, +using it will raise a NotImplementedError. [clinic start generated code]*/ static PyObject * os_symlink_impl(PyObject *module, path_t *src, path_t *dst, int target_is_directory, int dir_fd) -/*[clinic end generated code: output=08ca9f3f3cf960f6 input=e820ec4472547bc3]*/ +/*[clinic end generated code: output=08ca9f3f3cf960f6 input=71b75467b31c45f7]*/ { #ifdef MS_WINDOWS DWORD result; @@ -11627,19 +11636,18 @@ os.open -> int * dir_fd: dir_fd(requires='openat') = None -# "open(path, flags, mode=0o777, *, dir_fd=None)\n\n\ - Open a file for low level IO. Returns a file descriptor (integer). -If dir_fd is not None, it should be a file descriptor open to a directory, - and path should be relative; path will then be relative to that directory. -dir_fd may not be implemented on your platform. - If it is unavailable, using it will raise a NotImplementedError. +If dir_fd is not None, it should be a file descriptor open to +a directory, and path should be relative; path will then be relative to +that directory. +dir_fd may not be implemented on your platform. If it is unavailable, +using it will raise a NotImplementedError. [clinic start generated code]*/ static int os_open_impl(PyObject *module, path_t *path, int flags, int mode, int dir_fd) -/*[clinic end generated code: output=abc7227888c8bc73 input=ad8623b29acd2934]*/ +/*[clinic end generated code: output=abc7227888c8bc73 input=75f7b4eaf92f2225]*/ { int fd; int async_err = 0; @@ -11913,7 +11921,6 @@ os_lockf_impl(PyObject *module, int fd, int command, Py_off_t length) /*[clinic input] -@permit_long_docstring_body os.lseek -> Py_off_t fd: int @@ -11929,12 +11936,13 @@ os.lseek -> Py_off_t Set the position of a file descriptor. Return the new position. -The return value is the number of bytes relative to the beginning of the file. +The return value is the number of bytes relative to the beginning of +the file. [clinic start generated code]*/ static Py_off_t os_lseek_impl(PyObject *module, int fd, Py_off_t position, int how) -/*[clinic end generated code: output=971e1efb6b30bd2f input=4a3de549f07e1c40]*/ +/*[clinic end generated code: output=971e1efb6b30bd2f input=32ea0788da7cb44b]*/ { Py_off_t result; @@ -11998,7 +12006,6 @@ os_read_impl(PyObject *module, int fd, Py_ssize_t length) } /*[clinic input] -@permit_long_docstring_body os.readinto -> Py_ssize_t fd: int buffer: Py_buffer(accept={rwbuffer}) @@ -12006,20 +12013,20 @@ os.readinto -> Py_ssize_t Read into a buffer object from a file descriptor. -The buffer should be mutable and bytes-like. On success, returns the number of -bytes read. Less bytes may be read than the size of the buffer. The underlying -system call will be retried when interrupted by a signal, unless the signal -handler raises an exception. Other errors will not be retried and an error will -be raised. +The buffer should be mutable and bytes-like. On success, returns the +number of bytes read. Less bytes may be read than the size of the +buffer. The underlying system call will be retried when interrupted by +a signal, unless the signal handler raises an exception. Other errors +will not be retried and an error will be raised. -Returns 0 if *fd* is at end of file or if the provided *buffer* has length 0 -(which can be used to check for errors without reading data). Never returns -negative. +Returns 0 if *fd* is at end of file or if the provided *buffer* has +length 0 (which can be used to check for errors without reading data). +Never returns negative. [clinic start generated code]*/ static Py_ssize_t os_readinto_impl(PyObject *module, int fd, Py_buffer *buffer) -/*[clinic end generated code: output=8091a3513c683a80 input=a770382bd3d32f9a]*/ +/*[clinic end generated code: output=8091a3513c683a80 input=2a5f8b212cb5730c]*/ { assert(buffer->len >= 0); Py_ssize_t result = _Py_read(fd, buffer->buf, buffer->len); @@ -12203,7 +12210,7 @@ os_pread_impl(PyObject *module, int fd, Py_ssize_t length, Py_off_t offset) #if defined(HAVE_PREADV) || defined (HAVE_PREADV2) /*[clinic input] -@permit_long_docstring_body +@permit_long_summary os.preadv -> Py_ssize_t fd: int @@ -12214,14 +12221,15 @@ os.preadv -> Py_ssize_t Reads from a file descriptor into a number of mutable bytes-like objects. -Combines the functionality of readv() and pread(). As readv(), it will -transfer data into each buffer until it is full and then move on to the next -buffer in the sequence to hold the rest of the data. Its fourth argument, -specifies the file offset at which the input operation is to be performed. It -will return the total number of bytes read (which can be less than the total -capacity of all the objects). +Combines the functionality of readv() and pread(). As readv(), it will +transfer data into each buffer until it is full and then move on to the +next buffer in the sequence to hold the rest of the data. Its fourth +argument, specifies the file offset at which the input operation is to +be performed. It will return the total number of bytes read (which can +be less than the total capacity of all the objects). -The flags argument contains a bitwise OR of zero or more of the following flags: +The flags argument contains a bitwise OR of zero or more of the +following flags: - RWF_HIPRI - RWF_NOWAIT @@ -12233,7 +12241,7 @@ Using non-zero flags requires Linux 4.6 or newer. static Py_ssize_t os_preadv_impl(PyObject *module, int fd, PyObject *buffers, Py_off_t offset, int flags) -/*[clinic end generated code: output=26fc9c6e58e7ada5 input=34fb3b9ca06f7ba7]*/ +/*[clinic end generated code: output=26fc9c6e58e7ada5 input=bbc70c63b4f4e877]*/ { Py_ssize_t cnt, n; int async_err = 0; @@ -12570,6 +12578,7 @@ os_sendfile_impl(PyObject *module, int out_fd, int in_fd, PyObject *offobj, #if defined(__APPLE__) /*[clinic input] +@permit_long_summary os._fcopyfile in_fd: int @@ -12582,7 +12591,7 @@ Efficiently copy content or metadata of 2 regular file descriptors (macOS). static PyObject * os__fcopyfile_impl(PyObject *module, int in_fd, int out_fd, int flags) -/*[clinic end generated code: output=c9d1a35a992e401b input=1e34638a86948795]*/ +/*[clinic end generated code: output=c9d1a35a992e401b input=80b53ad8863c9101]*/ { int ret; @@ -12771,6 +12780,7 @@ os_pipe2_impl(PyObject *module, int flags) #ifdef HAVE_WRITEV /*[clinic input] +@permit_long_summary os.writev -> Py_ssize_t fd: int buffers: object @@ -12784,7 +12794,7 @@ buffers must be a sequence of bytes-like objects. static Py_ssize_t os_writev_impl(PyObject *module, int fd, PyObject *buffers) -/*[clinic end generated code: output=56565cfac3aac15b input=5b8d17fe4189d2fe]*/ +/*[clinic end generated code: output=56565cfac3aac15b input=5771a0f0c2b326f2]*/ { Py_ssize_t cnt; Py_ssize_t result; @@ -12860,7 +12870,6 @@ os_pwrite_impl(PyObject *module, int fd, Py_buffer *buffer, Py_off_t offset) #if defined(HAVE_PWRITEV) || defined (HAVE_PWRITEV2) /*[clinic input] @permit_long_summary -@permit_long_docstring_body os.pwritev -> Py_ssize_t fd: int @@ -12871,14 +12880,16 @@ os.pwritev -> Py_ssize_t Writes the contents of bytes-like objects to a file descriptor at a given offset. -Combines the functionality of writev() and pwrite(). All buffers must be a sequence -of bytes-like objects. Buffers are processed in array order. Entire contents of first -buffer is written before proceeding to second, and so on. The operating system may -set a limit (sysconf() value SC_IOV_MAX) on the number of buffers that can be used. -This function writes the contents of each object to the file descriptor and returns -the total number of bytes written. +Combines the functionality of writev() and pwrite(). All buffers must be +a sequence of bytes-like objects. Buffers are processed in array order. +Entire contents of first buffer is written before proceeding to second, +and so on. The operating system may set a limit (sysconf() value +SC_IOV_MAX) on the number of buffers that can be used. +This function writes the contents of each object to the file descriptor +and returns the total number of bytes written. -The flags argument contains a bitwise OR of zero or more of the following flags: +The flags argument contains a bitwise OR of zero or more of the +following flags: - RWF_DSYNC - RWF_SYNC @@ -12892,7 +12903,7 @@ Using non-zero flags requires Linux 4.7 or newer. static Py_ssize_t os_pwritev_impl(PyObject *module, int fd, PyObject *buffers, Py_off_t offset, int flags) -/*[clinic end generated code: output=e3dd3e9d11a6a5c7 input=7de72245873f56bf]*/ +/*[clinic end generated code: output=e3dd3e9d11a6a5c7 input=b2e352a22f030e9a]*/ { Py_ssize_t cnt; Py_ssize_t result; @@ -13105,15 +13116,16 @@ os.mkfifo Create a "fifo" (a POSIX named pipe). -If dir_fd is not None, it should be a file descriptor open to a directory, - and path should be relative; path will then be relative to that directory. -dir_fd may not be implemented on your platform. - If it is unavailable, using it will raise a NotImplementedError. +If dir_fd is not None, it should be a file descriptor open to +a directory, and path should be relative; path will then be relative to +that directory. +dir_fd may not be implemented on your platform. If it is unavailable, +using it will raise a NotImplementedError. [clinic start generated code]*/ static PyObject * os_mkfifo_impl(PyObject *module, path_t *path, int mode, int dir_fd) -/*[clinic end generated code: output=ce41cfad0e68c940 input=73032e98a36e0e19]*/ +/*[clinic end generated code: output=ce41cfad0e68c940 input=d2fb917c01e888d6]*/ { int result; int async_err = 0; @@ -13156,7 +13168,6 @@ os_mkfifo_impl(PyObject *module, path_t *path, int mode, int dir_fd) #if defined(HAVE_MKNOD) && defined(HAVE_MAKEDEV) /*[clinic input] -@permit_long_docstring_body os.mknod path: path_t @@ -13167,23 +13178,24 @@ os.mknod Create a node in the file system. -Create a node in the file system (file, device special file or named pipe) -at path. mode specifies both the permissions to use and the +Create a node in the file system (file, device special file or named +pipe) at path. mode specifies both the permissions to use and the type of node to be created, being combined (bitwise OR) with one of -S_IFREG, S_IFCHR, S_IFBLK, and S_IFIFO. If S_IFCHR or S_IFBLK is set on mode, -device defines the newly created device special file (probably using -os.makedev()). Otherwise device is ignored. +S_IFREG, S_IFCHR, S_IFBLK, and S_IFIFO. If S_IFCHR or S_IFBLK is set +on mode, device defines the newly created device special file (probably +using os.makedev()). Otherwise device is ignored. -If dir_fd is not None, it should be a file descriptor open to a directory, - and path should be relative; path will then be relative to that directory. -dir_fd may not be implemented on your platform. - If it is unavailable, using it will raise a NotImplementedError. +If dir_fd is not None, it should be a file descriptor open to +a directory, and path should be relative; path will then be relative +to that directory. +dir_fd may not be implemented on your platform. If it is unavailable, +using it will raise a NotImplementedError. [clinic start generated code]*/ static PyObject * os_mknod_impl(PyObject *module, path_t *path, int mode, dev_t device, int dir_fd) -/*[clinic end generated code: output=92e55d3ca8917461 input=7121c4723d22545b]*/ +/*[clinic end generated code: output=92e55d3ca8917461 input=7d0099e85c6b4cba]*/ { int result; int async_err = 0; @@ -13352,13 +13364,14 @@ os.truncate Truncate a file, specified by path, to a specific length. -On some platforms, path may also be specified as an open file descriptor. - If this functionality is unavailable, using it raises an exception. +On some platforms, path may also be specified as an open file +descriptor. If this functionality is unavailable, using it raises +an exception. [clinic start generated code]*/ static PyObject * os_truncate_impl(PyObject *module, path_t *path, Py_off_t length) -/*[clinic end generated code: output=43009c8df5c0a12b input=77229cf0b50a9b77]*/ +/*[clinic end generated code: output=43009c8df5c0a12b input=ce33fd7808a511c4]*/ { int result; #ifdef MS_WINDOWS @@ -13401,6 +13414,7 @@ os_truncate_impl(PyObject *module, path_t *path, Py_off_t length) OSs, support was dropped in WASI preview2. */ #if defined(HAVE_POSIX_FALLOCATE) && !defined(__wasi__) /*[clinic input] +@permit_long_summary os.posix_fallocate fd: int @@ -13411,13 +13425,14 @@ os.posix_fallocate Ensure a file has allocated at least a particular number of bytes on disk. Ensure that the file specified by fd encompasses a range of bytes -starting at offset bytes from the beginning and continuing for length bytes. +starting at offset bytes from the beginning and continuing for length +bytes. [clinic start generated code]*/ static PyObject * os_posix_fallocate_impl(PyObject *module, int fd, Py_off_t offset, Py_off_t length) -/*[clinic end generated code: output=73f107139564aa9d input=d7a2ef0ab2ca52fb]*/ +/*[clinic end generated code: output=73f107139564aa9d input=c718971d18b96896]*/ { int result; int async_err = 0; @@ -13452,8 +13467,8 @@ os.posix_fadvise Announce an intention to access data in a specific pattern. -Announce an intention to access data in a specific pattern, thus allowing -the kernel to make optimizations. +Announce an intention to access data in a specific pattern, thus +allowing the kernel to make optimizations. The advice applies to the region of the file specified by fd starting at offset and continuing for length bytes. advice is one of POSIX_FADV_NORMAL, POSIX_FADV_SEQUENTIAL, @@ -13464,7 +13479,7 @@ POSIX_FADV_DONTNEED. static PyObject * os_posix_fadvise_impl(PyObject *module, int fd, Py_off_t offset, Py_off_t length, int advice) -/*[clinic end generated code: output=412ef4aa70c98642 input=0fbe554edc2f04b5]*/ +/*[clinic end generated code: output=412ef4aa70c98642 input=961b01a4518ef727]*/ { int result; int async_err = 0; @@ -13720,6 +13735,7 @@ os_WCOREDUMP_impl(PyObject *module, int status) #ifdef WIFCONTINUED /*[clinic input] +@permit_long_summary os.WIFCONTINUED -> bool status: int @@ -13732,7 +13748,7 @@ job control stop. static int os_WIFCONTINUED_impl(PyObject *module, int status) -/*[clinic end generated code: output=1e35295d844364bd input=e777e7d38eb25bd9]*/ +/*[clinic end generated code: output=1e35295d844364bd input=7b577845a0f8b12f]*/ { WAIT_TYPE wait_status; WAIT_STATUS_INT(wait_status) = status; @@ -13845,6 +13861,7 @@ os_WTERMSIG_impl(PyObject *module, int status) #ifdef WSTOPSIG /*[clinic input] +@permit_long_summary os.WSTOPSIG -> int status: int @@ -13854,7 +13871,7 @@ Return the signal that stopped the process that provided the status value. static int os_WSTOPSIG_impl(PyObject *module, int status) -/*[clinic end generated code: output=0ab7586396f5d82b input=46ebf1d1b293c5c1]*/ +/*[clinic end generated code: output=0ab7586396f5d82b input=4698db1a6a320433]*/ { WAIT_TYPE wait_status; WAIT_STATUS_INT(wait_status) = status; @@ -14045,13 +14062,14 @@ os.statvfs Perform a statvfs system call on the given path. path may always be specified as a string. -On some platforms, path may also be specified as an open file descriptor. - If this functionality is unavailable, using it raises an exception. +On some platforms, path may also be specified as an open file +descriptor. If this functionality is unavailable, using it raises +an exception. [clinic start generated code]*/ static PyObject * os_statvfs_impl(PyObject *module, path_t *path) -/*[clinic end generated code: output=87106dd1beb8556e input=3f5c35791c669bd9]*/ +/*[clinic end generated code: output=87106dd1beb8556e input=1cfd9a4fd36f7425]*/ { int result; @@ -14100,6 +14118,7 @@ os_statvfs_impl(PyObject *module, path_t *path) #ifdef MS_WINDOWS /*[clinic input] +@permit_long_summary os._getdiskusage path: path_t @@ -14109,7 +14128,7 @@ Return disk usage statistics about the given path as a (total, free) tuple. static PyObject * os__getdiskusage_impl(PyObject *module, path_t *path) -/*[clinic end generated code: output=3bd3991f5e5c5dfb input=6af8d1b7781cc042]*/ +/*[clinic end generated code: output=3bd3991f5e5c5dfb input=aee7e38bc3e7fb08]*/ { BOOL retval; ULARGE_INTEGER _, total, free; @@ -14330,13 +14349,14 @@ os.pathconf -> long Return the configuration limit name for the file or directory path. If there is no limit, return -1. -On some platforms, path may also be specified as an open file descriptor. - If this functionality is unavailable, using it raises an exception. +On some platforms, path may also be specified as an open file +descriptor. If this functionality is unavailable, using it raises +an exception. [clinic start generated code]*/ static long os_pathconf_impl(PyObject *module, path_t *path, int name) -/*[clinic end generated code: output=5bedee35b293a089 input=6f6072f57b10c787]*/ +/*[clinic end generated code: output=5bedee35b293a089 input=e86f6eacfa006426]*/ { long limit; @@ -15141,13 +15161,13 @@ os.abort Abort the interpreter immediately. -This function 'dumps core' or otherwise fails in the hardest way possible -on the hosting operating system. This function never returns. +This function 'dumps core' or otherwise fails in the hardest way +possible on the hosting operating system. This function never returns. [clinic start generated code]*/ static PyObject * os_abort_impl(PyObject *module) -/*[clinic end generated code: output=dcf52586dad2467c input=cf2c7d98bc504047]*/ +/*[clinic end generated code: output=dcf52586dad2467c input=ee8bd0ed690440ab]*/ { abort(); /*NOTREACHED*/ @@ -15356,6 +15376,7 @@ os_setresgid_impl(PyObject *module, gid_t rgid, gid_t egid, gid_t sgid) #ifdef HAVE_GETRESUID /*[clinic input] +@permit_long_summary os.getresuid Return a tuple of the current process's real, effective, and saved user ids. @@ -15363,7 +15384,7 @@ Return a tuple of the current process's real, effective, and saved user ids. static PyObject * os_getresuid_impl(PyObject *module) -/*[clinic end generated code: output=8e0becff5dece5bf input=41ccfa8e1f6517ad]*/ +/*[clinic end generated code: output=8e0becff5dece5bf input=ddf95881f492cb97]*/ { uid_t ruid, euid, suid; if (getresuid(&ruid, &euid, &suid) < 0) @@ -15408,17 +15429,18 @@ os.getxattr Return the value of extended attribute attribute on path. -path may be either a string, a path-like object, or an open file descriptor. -If follow_symlinks is False, and the last element of the path is a symbolic - link, getxattr will examine the symbolic link itself instead of the file - the link points to. +path may be either a string, a path-like object, or an open file +descriptor. +If follow_symlinks is False, and the last element of the path is +a symbolic link, getxattr will examine the symbolic link itself +instead of the file the link points to. [clinic start generated code]*/ static PyObject * os_getxattr_impl(PyObject *module, path_t *path, path_t *attribute, int follow_symlinks) -/*[clinic end generated code: output=5f2f44200a43cff2 input=025789491708f7eb]*/ +/*[clinic end generated code: output=5f2f44200a43cff2 input=db1021ed738d9754]*/ { if (fd_and_follow_symlinks_invalid("getxattr", path->is_fd, follow_symlinks)) return NULL; @@ -15465,7 +15487,6 @@ os_getxattr_impl(PyObject *module, path_t *path, path_t *attribute, /*[clinic input] -@permit_long_docstring_body os.setxattr path: path_t(allow_fd=True) @@ -15477,17 +15498,18 @@ os.setxattr Set extended attribute attribute on path to value. -path may be either a string, a path-like object, or an open file descriptor. -If follow_symlinks is False, and the last element of the path is a symbolic - link, setxattr will modify the symbolic link itself instead of the file - the link points to. +path may be either a string, a path-like object, or an open file +descriptor. +If follow_symlinks is False, and the last element of the path is +a symbolic link, setxattr will modify the symbolic link itself instead +of the file the link points to. [clinic start generated code]*/ static PyObject * os_setxattr_impl(PyObject *module, path_t *path, path_t *attribute, Py_buffer *value, int flags, int follow_symlinks) -/*[clinic end generated code: output=98b83f63fdde26bb input=4098e6f68699f3d7]*/ +/*[clinic end generated code: output=98b83f63fdde26bb input=6c4ee6724e8947a4]*/ { ssize_t result; @@ -15530,17 +15552,18 @@ os.removexattr Remove extended attribute attribute on path. -path may be either a string, a path-like object, or an open file descriptor. -If follow_symlinks is False, and the last element of the path is a symbolic - link, removexattr will modify the symbolic link itself instead of the file - the link points to. +path may be either a string, a path-like object, or an open file +descriptor. +If follow_symlinks is False, and the last element of the path is +a symbolic link, removexattr will modify the symbolic link itself +instead of the file the link points to. [clinic start generated code]*/ static PyObject * os_removexattr_impl(PyObject *module, path_t *path, path_t *attribute, int follow_symlinks) -/*[clinic end generated code: output=521a51817980cda6 input=3d9a7d36fe2f7c4e]*/ +/*[clinic end generated code: output=521a51817980cda6 input=a7ec62a86aa83f01]*/ { ssize_t result; @@ -15569,7 +15592,6 @@ os_removexattr_impl(PyObject *module, path_t *path, path_t *attribute, /*[clinic input] -@permit_long_docstring_body os.listxattr path: path_t(allow_fd=True, nullable=True) = None @@ -15578,16 +15600,17 @@ os.listxattr Return a list of extended attributes on path. -path may be either None, a string, a path-like object, or an open file descriptor. -if path is None, listxattr will examine the current directory. -If follow_symlinks is False, and the last element of the path is a symbolic - link, listxattr will examine the symbolic link itself instead of the file - the link points to. +path may be either None, a string, a path-like object, or an open file +descriptor. If path is None, listxattr will examine the current +directory. +If follow_symlinks is False, and the last element of the path is +a symbolic link, listxattr will examine the symbolic link itself instead +of the file the link points to. [clinic start generated code]*/ static PyObject * os_listxattr_impl(PyObject *module, path_t *path, int follow_symlinks) -/*[clinic end generated code: output=bebdb4e2ad0ce435 input=48aa9ac8be47dea1]*/ +/*[clinic end generated code: output=bebdb4e2ad0ce435 input=cb4a6414afaa99bd]*/ { Py_ssize_t i; PyObject *result = NULL; @@ -16490,7 +16513,7 @@ static PyMemberDef DirEntry_members[] = { {"name", Py_T_OBJECT_EX, offsetof(DirEntry, name), Py_READONLY, "the entry's base filename, relative to scandir() \"path\" argument"}, {"path", Py_T_OBJECT_EX, offsetof(DirEntry, path), Py_READONLY, - "the entry's full path name; equivalent to os.path.join(scandir_path, entry.name)"}, + "the entry's full path name; equivalent to\nos.path.join(scandir_path, entry.name)"}, {NULL} }; @@ -16984,16 +17007,16 @@ os.scandir Return an iterator of DirEntry objects for given path. -path can be specified as either str, bytes, or a path-like object. If path -is bytes, the names of yielded DirEntry objects will also be bytes; in -all other circumstances they will be str. +path can be specified as either str, bytes, or a path-like object. If +path is bytes, the names of yielded DirEntry objects will also be bytes; +in all other circumstances they will be str. If path is None, uses the path='.'. [clinic start generated code]*/ static PyObject * os_scandir_impl(PyObject *module, path_t *path) -/*[clinic end generated code: output=6eb2668b675ca89e input=6bdd312708fc3bb0]*/ +/*[clinic end generated code: output=6eb2668b675ca89e input=6ab9600993f51577]*/ { ScandirIterator *iterator; #ifdef MS_WINDOWS @@ -17140,21 +17163,20 @@ PyOS_FSPath(PyObject *path) } /*[clinic input] -@permit_long_docstring_body os.fspath path: object Return the file system path representation of the object. -If the object is str or bytes, then allow it to pass through as-is. If the -object defines __fspath__(), then return the result of that method. All other -types raise a TypeError. +If the object is str or bytes, then allow it to pass through as-is. If +the object defines __fspath__(), then return the result of that method. +All other types raise a TypeError. [clinic start generated code]*/ static PyObject * os_fspath_impl(PyObject *module, PyObject *path) -/*[clinic end generated code: output=c3c3b78ecff2914f input=f608743e60a3211e]*/ +/*[clinic end generated code: output=c3c3b78ecff2914f input=d3c54404240d5da0]*/ { return PyOS_FSPath(path); } @@ -17331,13 +17353,13 @@ On Unix: On Windows, return status shifted right by 8 bits. On Unix, if the process is being traced or if waitpid() was called with -WUNTRACED option, the caller must first check if WIFSTOPPED(status) is true. -This function must not be called if WIFSTOPPED(status) is true. +WUNTRACED option, the caller must first check if WIFSTOPPED(status) is +true. This function must not be called if WIFSTOPPED(status) is true. [clinic start generated code]*/ static PyObject * os_waitstatus_to_exitcode_impl(PyObject *module, PyObject *status_obj) -/*[clinic end generated code: output=db50b1b0ba3c7153 input=7fe2d7fdaea3db42]*/ +/*[clinic end generated code: output=db50b1b0ba3c7153 input=3b44a23f5090006c]*/ { #ifndef MS_WINDOWS int status = PyLong_AsInt(status_obj); From d02c2dfc1125d84a6ba867fabaf9401732ec0be9 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 24 May 2026 17:47:29 +0200 Subject: [PATCH 136/818] [3.15] gh-110704: Recommend `distclean` target over `clean` when source tree is not clean (GH-112610) (#150342) gh-110704: Recommend `distclean` target over `clean` when source tree is not clean (GH-112610) Recommend `distclean` target over `clean` when source tree is not clean (cherry picked from commit 34631058f2aec6752ebfc50d40958b247532f536) Co-authored-by: James <6125322+SnoopJ@users.noreply.github.com> Co-authored-by: Gregory P. Smith --- Makefile.pre.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.pre.in b/Makefile.pre.in index dce0139d8d6e35..669a2c9527075c 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -835,7 +835,7 @@ check-clean-src: echo "Building Python out of the source tree (in $(abs_builddir)) requires a clean source tree ($(abs_srcdir))" ; \ echo "Build artifacts such as .o files, executables, and Python/frozen_modules/*.h must not exist within $(srcdir)." ; \ echo "Try to run:" ; \ - echo " (cd \"$(srcdir)\" && make clean || git clean -fdx -e Doc/venv)" ; \ + echo " (cd \"$(srcdir)\" && make distclean || git clean -fdx -e Doc/venv)" ; \ exit 1; \ fi From cf73b17adfd102a34a01efbad89a83dffdec2806 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sun, 24 May 2026 22:31:19 +0300 Subject: [PATCH 137/818] [3.15] gh-150285: Fix too long docstrings in Argument Clinic code (GH-150338) (GH-150350) (cherry picked from commit 287c98f4cb40c15d638651de4b29ae98b92589aa) --- Modules/_abc.c | 8 +- Modules/_asynciomodule.c | 28 ++++--- Modules/_bisectmodule.c | 12 +-- Modules/_bz2module.c | 24 +++--- Modules/_codecsmodule.c | 42 +++++----- Modules/_collectionsmodule.c | 3 +- Modules/_datetimemodule.c | 38 ++++----- Modules/_dbmmodule.c | 5 +- Modules/_elementtree.c | 3 +- Modules/_functoolsmodule.c | 9 +-- Modules/_gdbmmodule.c | 22 +++--- Modules/_hashopenssl.c | 13 ++- Modules/_heapqmodule.c | 9 ++- Modules/_interpqueuesmodule.c | 5 +- Modules/_interpretersmodule.c | 16 ++-- Modules/_json.c | 6 +- Modules/_lzmamodule.c | 24 +++--- .../_multiprocessing/clinic/posixshmem.c.h | 8 +- Modules/_multiprocessing/posixshmem.c | 8 +- Modules/_opcode.c | 4 +- Modules/_posixsubprocess.c | 17 ++-- Modules/_queuemodule.c | 18 +++-- Modules/_sre/sre.c | 3 +- Modules/_ssl.c | 79 +++++++++---------- Modules/_struct.c | 6 +- Modules/_testlimitedcapi/clinic/long.c.h | 6 +- Modules/_testlimitedcapi/long.c | 6 +- Modules/_testmultiphase.c | 6 +- Modules/_threadmodule.c | 18 ++--- Modules/_tkinter.c | 6 +- Modules/_tracemalloc.c | 6 +- Modules/arraymodule.c | 32 ++++---- Modules/cjkcodecs/clinic/multibytecodec.c.h | 18 +++-- Modules/cjkcodecs/multibytecodec.c | 22 +++--- Modules/clinic/_abc.c.h | 8 +- Modules/clinic/_asynciomodule.c.h | 19 ++--- Modules/clinic/_bisectmodule.c.h | 10 +-- Modules/clinic/_bz2module.c.h | 23 +++--- Modules/clinic/_codecsmodule.c.h | 34 ++++---- Modules/clinic/_datetimemodule.c.h | 21 ++--- Modules/clinic/_dbmmodule.c.h | 5 +- Modules/clinic/_functoolsmodule.c.h | 8 +- Modules/clinic/_gdbmmodule.c.h | 18 ++--- Modules/clinic/_hashopenssl.c.h | 10 +-- Modules/clinic/_heapqmodule.c.h | 6 +- Modules/clinic/_interpqueuesmodule.c.h | 5 +- Modules/clinic/_interpretersmodule.c.h | 10 ++- Modules/clinic/_json.c.h | 6 +- Modules/clinic/_lzmamodule.c.h | 23 +++--- Modules/clinic/_posixsubprocess.c.h | 16 ++-- Modules/clinic/_queuemodule.c.h | 16 ++-- Modules/clinic/_ssl.c.h | 55 +++++++------ Modules/clinic/_testmultiphase.c.h | 6 +- Modules/clinic/_threadmodule.c.h | 16 ++-- Modules/clinic/_tkinter.c.h | 5 +- Modules/clinic/arraymodule.c.h | 23 +++--- Modules/clinic/cmathmodule.c.h | 14 ++-- Modules/clinic/faulthandler.c.h | 8 +- Modules/clinic/gcmodule.c.h | 13 +-- Modules/clinic/hmacmodule.c.h | 6 +- Modules/clinic/itertoolsmodule.c.h | 6 +- Modules/clinic/mathmodule.c.h | 6 +- Modules/clinic/overlapped.c.h | 7 +- Modules/clinic/selectmodule.c.h | 35 ++++---- Modules/clinic/signalmodule.c.h | 17 ++-- Modules/clinic/socketmodule.c.h | 22 +++--- Modules/clinic/termios.c.h | 5 +- Modules/clinic/zlibmodule.c.h | 27 ++++--- Modules/cmathmodule.c | 17 ++-- Modules/faulthandler.c | 8 +- Modules/gcmodule.c | 17 ++-- Modules/hmacmodule.c | 7 +- Modules/itertoolsmodule.c | 15 ++-- Modules/mathmodule.c | 11 +-- Modules/overlapped.c | 7 +- Modules/readline.c | 6 +- Modules/selectmodule.c | 51 ++++++------ Modules/signalmodule.c | 23 +++--- Modules/socketmodule.c | 30 +++---- Modules/termios.c | 9 ++- Modules/unicodedata.c | 15 ++-- Modules/zlibmodule.c | 32 ++++---- Python/clinic/context.c.h | 27 ++++--- Python/clinic/import.c.h | 7 +- Python/clinic/marshal.c.h | 10 +-- Python/clinic/sysmodule.c.h | 26 +++--- Python/context.c | 38 ++++----- Python/import.c | 14 ++-- Python/marshal.c | 13 ++- Python/sysmodule.c | 40 +++++----- Tools/clinic/libclinic/function.py | 8 +- 91 files changed, 768 insertions(+), 702 deletions(-) diff --git a/Modules/_abc.c b/Modules/_abc.c index 3c4e0280525e1e..5826efbfecb690 100644 --- a/Modules/_abc.c +++ b/Modules/_abc.c @@ -915,14 +915,14 @@ _abc.get_cache_token Returns the current ABC cache token. -The token is an opaque object (supporting equality testing) identifying the -current version of the ABC cache for virtual subclasses. The token changes -with every call to register() on any ABC. +The token is an opaque object (supporting equality testing) identifying +the current version of the ABC cache for virtual subclasses. The token +changes with every call to register() on any ABC. [clinic start generated code]*/ static PyObject * _abc_get_cache_token_impl(PyObject *module) -/*[clinic end generated code: output=c7d87841e033dacc input=70413d1c423ad9f9]*/ +/*[clinic end generated code: output=c7d87841e033dacc input=d87acc04492f6bf3]*/ { _abcmodule_state *state = get_abc_state(module); return PyLong_FromUnsignedLongLong(get_invalidation_counter(state)); diff --git a/Modules/_asynciomodule.c b/Modules/_asynciomodule.c index 9679a7dde31b0d..7fa415a08b1551 100644 --- a/Modules/_asynciomodule.c +++ b/Modules/_asynciomodule.c @@ -955,12 +955,13 @@ Return the result this future represents. If the future has been cancelled, raises CancelledError. If the future's result isn't yet available, raises InvalidStateError. If -the future is done and has an exception set, this exception is raised. +the future is done and has an exception set, this exception is +raised. [clinic start generated code]*/ static PyObject * _asyncio_Future_result_impl(FutureObj *self) -/*[clinic end generated code: output=f35f940936a4b1e5 input=61d89f48e4c8b670]*/ +/*[clinic end generated code: output=f35f940936a4b1e5 input=ee20e126776cbb04]*/ { asyncio_state *state = get_asyncio_state_by_def((PyObject *)self); PyObject *result; @@ -1095,15 +1096,15 @@ _asyncio.Future.add_done_callback Add a callback to be run when the future becomes done. -The callback is called with a single argument - the future object. If -the future is already done when this is called, the callback is +The callback is called with a single argument - the future object. +If the future is already done when this is called, the callback is scheduled with call_soon. [clinic start generated code]*/ static PyObject * _asyncio_Future_add_done_callback_impl(FutureObj *self, PyTypeObject *cls, PyObject *fn, PyObject *context) -/*[clinic end generated code: output=922e9a4cbd601167 input=37d97f941beb7b3e]*/ +/*[clinic end generated code: output=922e9a4cbd601167 input=f4f6adb074cd3e0f]*/ { asyncio_state *state = get_asyncio_state_by_cls(cls); if (context == NULL) { @@ -1252,15 +1253,15 @@ _asyncio.Future.cancel Cancel the future and schedule callbacks. -If the future is already done or cancelled, return False. Otherwise, -change the future's state to cancelled, schedule the callbacks and -return True. +If the future is already done or cancelled, return False. +Otherwise, change the future's state to cancelled, schedule the +callbacks and return True. [clinic start generated code]*/ static PyObject * _asyncio_Future_cancel_impl(FutureObj *self, PyTypeObject *cls, PyObject *msg) -/*[clinic end generated code: output=074956f35904b034 input=44ab4003da839970]*/ +/*[clinic end generated code: output=074956f35904b034 input=0c9157547a964c4c]*/ { asyncio_state *state = get_asyncio_state_by_cls(cls); ENSURE_FUTURE_ALIVE(state, self) @@ -1292,13 +1293,13 @@ _asyncio.Future.done Return True if the future is done. -Done means either that a result / exception are available, or that the -future was cancelled. +Done means either that a result / exception are available, or that +the future was cancelled. [clinic start generated code]*/ static PyObject * _asyncio_Future_done_impl(FutureObj *self) -/*[clinic end generated code: output=244c5ac351145096 input=7204d3cc63bef7f3]*/ +/*[clinic end generated code: output=244c5ac351145096 input=acf2c2347f3c01d8]*/ { if (!future_is_alive(self) || self->fut_state == STATE_PENDING) { Py_RETURN_FALSE; @@ -3844,6 +3845,7 @@ _asyncio__leave_task_impl(PyObject *module, PyObject *loop, PyObject *task) /*[clinic input] +@permit_long_summary _asyncio._swap_current_task loop: object @@ -3858,7 +3860,7 @@ This is intended for use during eager coroutine execution. static PyObject * _asyncio__swap_current_task_impl(PyObject *module, PyObject *loop, PyObject *task) -/*[clinic end generated code: output=9f88de958df74c7e input=c9c72208d3d38b6c]*/ +/*[clinic end generated code: output=9f88de958df74c7e input=ec14ed25855e3068]*/ { _PyThreadStateImpl *ts = (_PyThreadStateImpl *)_PyThreadState_GET(); return swap_current_task(ts, loop, task); diff --git a/Modules/_bisectmodule.c b/Modules/_bisectmodule.c index 329aa8e117ec3c..a953f8bfa11aea 100644 --- a/Modules/_bisectmodule.c +++ b/Modules/_bisectmodule.c @@ -157,8 +157,8 @@ _bisect.bisect_right -> Py_ssize_t Return the index where to insert item x in list a, assuming a is sorted. The return value i is such that all e in a[:i] have e <= x, and all e in -a[i:] have e > x. So if x already appears in the list, a.insert(i, x) will -insert just after the rightmost x already there. +a[i:] have e > x. So if x already appears in the list, a.insert(i, x) +will insert just after the rightmost x already there. Optional args lo (default 0) and hi (default len(a)) bound the slice of a to be searched. @@ -169,7 +169,7 @@ A custom key function can be supplied to customize the sort order. static Py_ssize_t _bisect_bisect_right_impl(PyObject *module, PyObject *a, PyObject *x, Py_ssize_t lo, Py_ssize_t hi, PyObject *key) -/*[clinic end generated code: output=3a4bc09cc7c8a73d input=b476bc45667273ac]*/ +/*[clinic end generated code: output=3a4bc09cc7c8a73d input=27717afe1a61bfaa]*/ { return internal_bisect_right(a, x, lo, hi, key); } @@ -338,8 +338,8 @@ _bisect.bisect_left -> Py_ssize_t Return the index where to insert item x in list a, assuming a is sorted. The return value i is such that all e in a[:i] have e < x, and all e in -a[i:] have e >= x. So if x already appears in the list, a.insert(i, x) will -insert just before the leftmost x already there. +a[i:] have e >= x. So if x already appears in the list, a.insert(i, x) +will insert just before the leftmost x already there. Optional args lo (default 0) and hi (default len(a)) bound the slice of a to be searched. @@ -350,7 +350,7 @@ A custom key function can be supplied to customize the sort order. static Py_ssize_t _bisect_bisect_left_impl(PyObject *module, PyObject *a, PyObject *x, Py_ssize_t lo, Py_ssize_t hi, PyObject *key) -/*[clinic end generated code: output=70749d6e5cae9284 input=9b4d49b5ddecfad7]*/ +/*[clinic end generated code: output=70749d6e5cae9284 input=259fedbe35e882e1]*/ { return internal_bisect_left(a, x, lo, hi, key); } diff --git a/Modules/_bz2module.c b/Modules/_bz2module.c index 4bff90e6fd2b2e..4cf8beed9ee3eb 100644 --- a/Modules/_bz2module.c +++ b/Modules/_bz2module.c @@ -577,7 +577,6 @@ decompress(BZ2Decompressor *d, char *data, size_t len, Py_ssize_t max_length) } /*[clinic input] -@permit_long_docstring_body _bz2.BZ2Decompressor.decompress data: Py_buffer @@ -585,24 +584,25 @@ _bz2.BZ2Decompressor.decompress Decompress *data*, returning uncompressed data as bytes. -If *max_length* is nonnegative, returns at most *max_length* bytes of -decompressed data. If this limit is reached and further output can be -produced, *self.needs_input* will be set to ``False``. In this case, the next -call to *decompress()* may provide *data* as b'' to obtain more of the output. +If *max_length* is nonnegative, returns at most *max_length* bytes +of decompressed data. If this limit is reached and further output +can be produced, *self.needs_input* will be set to ``False``. In +this case, the next call to *decompress()* may provide *data* as b'' +to obtain more of the output. -If all of the input data was decompressed and returned (either because this -was less than *max_length* bytes, or because *max_length* was negative), -*self.needs_input* will be set to True. +If all of the input data was decompressed and returned (either +because this was less than *max_length* bytes, or because +*max_length* was negative), *self.needs_input* will be set to True. -Attempting to decompress data after the end of stream is reached raises an -EOFError. Any data found after the end of the stream is ignored and saved in -the unused_data attribute. +Attempting to decompress data after the end of stream is reached +raises an EOFError. Any data found after the end of the stream is +ignored and saved in the unused_data attribute. [clinic start generated code]*/ static PyObject * _bz2_BZ2Decompressor_decompress_impl(BZ2Decompressor *self, Py_buffer *data, Py_ssize_t max_length) -/*[clinic end generated code: output=23e41045deb240a3 input=3703e78f91757655]*/ +/*[clinic end generated code: output=23e41045deb240a3 input=7f68faa9ff7a1b51]*/ { PyObject *result = NULL; diff --git a/Modules/_codecsmodule.c b/Modules/_codecsmodule.c index ff52bfd8291ac1..272182f7bf49ac 100644 --- a/Modules/_codecsmodule.c +++ b/Modules/_codecsmodule.c @@ -55,14 +55,15 @@ _codecs.register Register a codec search function. -Search functions are expected to take one argument, the encoding name in -all lower case letters, and either return None, or a tuple of functions -(encoder, decoder, stream_reader, stream_writer) (or a CodecInfo object). +Search functions are expected to take one argument, the encoding +name in all lower case letters, and either return None, or a tuple +of functions (encoder, decoder, stream_reader, stream_writer) (or +a CodecInfo object). [clinic start generated code]*/ static PyObject * _codecs_register(PyObject *module, PyObject *search_function) -/*[clinic end generated code: output=d1bf21e99db7d6d3 input=369578467955cae4]*/ +/*[clinic end generated code: output=d1bf21e99db7d6d3 input=2321d8c8c0420dfc]*/ { if (PyCodec_Register(search_function)) return NULL; @@ -116,16 +117,16 @@ _codecs.encode Encodes obj using the codec registered for encoding. The default encoding is 'utf-8'. errors may be given to set a -different error handling scheme. Default is 'strict' meaning that encoding -errors raise a ValueError. Other possible values are 'ignore', 'replace' -and 'backslashreplace' as well as any other name registered with -codecs.register_error that can handle ValueErrors. +different error handling scheme. Default is 'strict' meaning that +encoding errors raise a ValueError. Other possible values are 'ignore', +'replace' and 'backslashreplace' as well as any other name registered +with codecs.register_error that can handle ValueErrors. [clinic start generated code]*/ static PyObject * _codecs_encode_impl(PyObject *module, PyObject *obj, const char *encoding, const char *errors) -/*[clinic end generated code: output=385148eb9a067c86 input=cd5b685040ff61f0]*/ +/*[clinic end generated code: output=385148eb9a067c86 input=e5271d443e391d7f]*/ { if (encoding == NULL) encoding = PyUnicode_GetDefaultEncoding(); @@ -143,16 +144,16 @@ _codecs.decode Decodes obj using the codec registered for encoding. Default encoding is 'utf-8'. errors may be given to set a -different error handling scheme. Default is 'strict' meaning that encoding -errors raise a ValueError. Other possible values are 'ignore', 'replace' -and 'backslashreplace' as well as any other name registered with -codecs.register_error that can handle ValueErrors. +different error handling scheme. Default is 'strict' meaning that +encoding errors raise a ValueError. Other possible values are 'ignore', +'replace' and 'backslashreplace' as well as any other name registered +with codecs.register_error that can handle ValueErrors. [clinic start generated code]*/ static PyObject * _codecs_decode_impl(PyObject *module, PyObject *obj, const char *encoding, const char *errors) -/*[clinic end generated code: output=679882417dc3a0bd input=7702c0cc2fa1add6]*/ +/*[clinic end generated code: output=679882417dc3a0bd input=3e6254628f9ca538]*/ { if (encoding == NULL) encoding = PyUnicode_GetDefaultEncoding(); @@ -962,14 +963,15 @@ _codecs.register_error Register the specified error handler under the name errors. handler must be a callable object, that will be called with an exception -instance containing information about the location of the encoding/decoding -error and must return a (replacement, new position) tuple. +instance containing information about the location of the +encoding/decoding error and must return a (replacement, new position) +tuple. [clinic start generated code]*/ static PyObject * _codecs_register_error_impl(PyObject *module, const char *errors, PyObject *handler) -/*[clinic end generated code: output=fa2f7d1879b3067d input=5e6709203c2e33fe]*/ +/*[clinic end generated code: output=fa2f7d1879b3067d input=5bea01dfe835d9d8]*/ { if (PyCodec_RegisterError(errors, handler)) return NULL; @@ -1007,13 +1009,13 @@ _codecs.lookup_error lookup_error(errors) -> handler -Return the error handler for the specified error handling name or raise a -LookupError, if no handler exists under this name. +Return the error handler for the specified error handling name or raise +a LookupError, if no handler exists under this name. [clinic start generated code]*/ static PyObject * _codecs_lookup_error_impl(PyObject *module, const char *name) -/*[clinic end generated code: output=087f05dc0c9a98cc input=4775dd65e6235aba]*/ +/*[clinic end generated code: output=087f05dc0c9a98cc input=86cfb6a7a9c67113]*/ { return PyCodec_LookupError(name); } diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c index 4ff05727ebc8ce..d702d655a406b6 100644 --- a/Modules/_collectionsmodule.c +++ b/Modules/_collectionsmodule.c @@ -1077,6 +1077,7 @@ _deque_rotate(dequeobject *deque, Py_ssize_t n) } /*[clinic input] +@permit_long_summary @critical_section _collections.deque.rotate as deque_rotate @@ -1089,7 +1090,7 @@ Rotate the deque n steps to the right. If n is negative, rotates left. static PyObject * deque_rotate_impl(dequeobject *deque, Py_ssize_t n) -/*[clinic end generated code: output=96c2402a371eb15d input=5bf834296246e002]*/ +/*[clinic end generated code: output=96c2402a371eb15d input=3543c3b2297de8f1]*/ { if (!_deque_rotate(deque, n)) Py_RETURN_NONE; diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index 163e499d957b2e..59af7afcfcc644 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -3325,7 +3325,6 @@ datetime_date_today_impl(PyTypeObject *type) } /*[clinic input] -@permit_long_docstring_body @classmethod datetime.date.fromtimestamp @@ -3334,13 +3333,13 @@ datetime.date.fromtimestamp Create a date from a POSIX timestamp. -The timestamp is a number, e.g. created via time.time(), that is interpreted -as local time. +The timestamp is a number, e.g. created via time.time(), that is +interpreted as local time. [clinic start generated code]*/ static PyObject * datetime_date_fromtimestamp_impl(PyTypeObject *type, PyObject *timestamp) -/*[clinic end generated code: output=59def4e32c028fb6 input=55ff6940f0a8339f]*/ +/*[clinic end generated code: output=59def4e32c028fb6 input=15720eef43b169a1]*/ { return date_fromtimestamp(type, timestamp); } @@ -3476,6 +3475,7 @@ datetime_date_fromisocalendar_impl(PyTypeObject *type, int year, int week, } /*[clinic input] +@permit_long_summary @classmethod datetime.date.strptime @@ -3492,7 +3492,7 @@ For a list of supported format codes, see the documentation: static PyObject * datetime_date_strptime_impl(PyTypeObject *type, PyObject *string, PyObject *format) -/*[clinic end generated code: output=454d473bee2d5161 input=31d57bb789433e99]*/ +/*[clinic end generated code: output=454d473bee2d5161 input=2db8f0b2b5242deb]*/ { PyObject *result; @@ -4744,6 +4744,7 @@ datetime_time_impl(PyTypeObject *type, int hour, int minute, int second, } /*[clinic input] +@permit_long_summary @classmethod datetime.time.strptime @@ -4760,7 +4761,7 @@ For a list of supported format codes, see the documentation: static PyObject * datetime_time_strptime_impl(PyTypeObject *type, PyObject *string, PyObject *format) -/*[clinic end generated code: output=ae05a9bc0241d3bf input=82ba425ecacc54aa]*/ +/*[clinic end generated code: output=ae05a9bc0241d3bf input=f01d0b9eb5383da5]*/ { PyObject *result; @@ -4856,8 +4857,8 @@ datetime.time.isoformat Return the time formatted according to ISO. -The full format is 'HH:MM:SS.mmmmmm+zz:zz'. By default, the fractional -part is omitted if self.microsecond == 0. +The full format is 'HH:MM:SS.mmmmmm+zz:zz'. By default, the +fractional part is omitted if self.microsecond == 0. The optional argument timespec specifies the number of additional terms of the time to include. Valid options are 'auto', 'hours', @@ -4866,7 +4867,7 @@ terms of the time to include. Valid options are 'auto', 'hours', static PyObject * datetime_time_isoformat_impl(PyDateTime_Time *self, const char *timespec) -/*[clinic end generated code: output=2bcc7cab65c35545 input=afbbbd953d10ad07]*/ +/*[clinic end generated code: output=2bcc7cab65c35545 input=0efae103081060f4]*/ { char buf[100]; @@ -4927,14 +4928,14 @@ datetime_time_isoformat_impl(PyDateTime_Time *self, const char *timespec) } /*[clinic input] -@permit_long_docstring_body datetime.time.strftime format: unicode Format using strftime(). -The date part of the timestamp passed to underlying strftime should not be used. +The date part of the timestamp passed to underlying strftime should +not be used. For a list of supported format codes, see the documentation: https://docs.python.org/3/library/datetime.html#format-codes @@ -4942,7 +4943,7 @@ For a list of supported format codes, see the documentation: static PyObject * datetime_time_strftime_impl(PyDateTime_Time *self, PyObject *format) -/*[clinic end generated code: output=10f65af20e2a78c7 input=c4a5bbecd798654b]*/ +/*[clinic end generated code: output=10f65af20e2a78c7 input=184e1c0d7d356c5d]*/ { PyObject *result; PyObject *tuple; @@ -5510,15 +5511,15 @@ datetime.datetime.__new__ A combination of a date and a time. -The year, month and day arguments are required. tzinfo may be None, or an -instance of a tzinfo subclass. The remaining arguments may be ints. +The year, month and day arguments are required. tzinfo may be None, or +an instance of a tzinfo subclass. The remaining arguments may be ints. [clinic start generated code]*/ static PyObject * datetime_datetime_impl(PyTypeObject *type, int year, int month, int day, int hour, int minute, int second, int microsecond, PyObject *tzinfo, int fold) -/*[clinic end generated code: output=47983ddb47d36037 input=2af468d7a9c1e568]*/ +/*[clinic end generated code: output=47983ddb47d36037 input=c7fd85dcf6fe9691]*/ { return new_datetime_ex2(year, month, day, hour, minute, second, microsecond, @@ -5735,7 +5736,6 @@ datetime_datetime_utcnow_impl(PyTypeObject *type) } /*[clinic input] -@permit_long_docstring_body @classmethod datetime.datetime.fromtimestamp @@ -5744,14 +5744,14 @@ datetime.datetime.fromtimestamp Create a datetime from a POSIX timestamp. -The timestamp is a number, e.g. created via time.time(), that is interpreted -as local time. +The timestamp is a number, e.g. created via time.time(), that is +interpreted as local time. [clinic start generated code]*/ static PyObject * datetime_datetime_fromtimestamp_impl(PyTypeObject *type, PyObject *timestamp, PyObject *tzinfo) -/*[clinic end generated code: output=9c47ea2b2ebdaded input=d6b5b2095c5a34b2]*/ +/*[clinic end generated code: output=9c47ea2b2ebdaded input=7a2bc81a049ea287]*/ { PyObject *self; if (check_tzinfo_subclass(tzinfo) < 0) diff --git a/Modules/_dbmmodule.c b/Modules/_dbmmodule.c index 6b07ef74cfa51d..a9f4f27d9eb742 100644 --- a/Modules/_dbmmodule.c +++ b/Modules/_dbmmodule.c @@ -431,13 +431,14 @@ _dbm.dbm.setdefault Return the value for key if present, otherwise default. -If key is not in the database, it is inserted with default as the value. +If key is not in the database, it is inserted with default as the +value. [clinic start generated code]*/ static PyObject * _dbm_dbm_setdefault_impl(dbmobject *self, PyTypeObject *cls, const char *key, Py_ssize_t key_length, PyObject *default_value) -/*[clinic end generated code: output=9c2f6ea6d0fb576c input=c01510ef7571e13b]*/ +/*[clinic end generated code: output=9c2f6ea6d0fb576c input=81224965c110f830]*/ { datum dbm_key, val; Py_ssize_t tmp_size; diff --git a/Modules/_elementtree.c b/Modules/_elementtree.c index 9e794be5c109ba..eb69df22c6ef0a 100644 --- a/Modules/_elementtree.c +++ b/Modules/_elementtree.c @@ -2570,6 +2570,7 @@ treebuilder_dealloc(PyObject *self) /* helpers for handling of arbitrary element-like objects */ /*[clinic input] +@permit_long_summary _elementtree._set_factories comment_factory: object @@ -2584,7 +2585,7 @@ For internal use only. static PyObject * _elementtree__set_factories_impl(PyObject *module, PyObject *comment_factory, PyObject *pi_factory) -/*[clinic end generated code: output=813b408adee26535 input=99d17627aea7fb3b]*/ +/*[clinic end generated code: output=813b408adee26535 input=0f415cb6b821f768]*/ { elementtreestate *st = get_elementtree_state(module); PyObject *old; diff --git a/Modules/_functoolsmodule.c b/Modules/_functoolsmodule.c index c702eecc700ac8..393b59883e89f3 100644 --- a/Modules/_functoolsmodule.c +++ b/Modules/_functoolsmodule.c @@ -1060,7 +1060,6 @@ _functools_cmp_to_key_impl(PyObject *module, PyObject *mycmp) /*[clinic input] @permit_long_summary -@permit_long_docstring_body _functools.reduce function as func: object @@ -1070,9 +1069,9 @@ _functools.reduce Apply a function of two arguments cumulatively to the items of an iterable, from left to right. -This effectively reduces the iterable to a single value. If initial is present, -it is placed before the items of the iterable in the calculation, and serves as -a default when the iterable is empty. +This effectively reduces the iterable to a single value. If initial is +present, it is placed before the items of the iterable in the +calculation, and serves as a default when the iterable is empty. For example, reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) calculates ((((1 + 2) + 3) + 4) + 5). @@ -1081,7 +1080,7 @@ calculates ((((1 + 2) + 3) + 4) + 5). static PyObject * _functools_reduce_impl(PyObject *module, PyObject *func, PyObject *seq, PyObject *result) -/*[clinic end generated code: output=30d898fe1267c79d input=5c9088c98ffe2793]*/ +/*[clinic end generated code: output=30d898fe1267c79d input=ff4d5c73100e72e8]*/ { PyObject *args, *it; diff --git a/Modules/_gdbmmodule.c b/Modules/_gdbmmodule.c index faffe8d28c5b5e..20d482021656a5 100644 --- a/Modules/_gdbmmodule.c +++ b/Modules/_gdbmmodule.c @@ -520,14 +520,14 @@ _gdbm.gdbm.firstkey Return the starting key for the traversal. -It's possible to loop over every key in the database using this method -and the nextkey() method. The traversal is ordered by GDBM's internal -hash values, and won't be sorted by the key values. +It's possible to loop over every key in the database using this +method and the nextkey() method. The traversal is ordered by GDBM's +internal hash values, and won't be sorted by the key values. [clinic start generated code]*/ static PyObject * _gdbm_gdbm_firstkey_impl(gdbmobject *self, PyTypeObject *cls) -/*[clinic end generated code: output=139275e9c8b60827 input=aad5a7c886c542f5]*/ +/*[clinic end generated code: output=139275e9c8b60827 input=ba40f0d81eae0f35]*/ { PyObject *v; datum key; @@ -556,8 +556,8 @@ _gdbm.gdbm.nextkey Returns the key that follows key in the traversal. -The following code prints every key in the database db, without having -to create a list in memory that contains them all: +The following code prints every key in the database db, without +having to create a list in memory that contains them all: k = db.firstkey() while k is not None: @@ -568,7 +568,7 @@ to create a list in memory that contains them all: static PyObject * _gdbm_gdbm_nextkey_impl(gdbmobject *self, PyTypeObject *cls, const char *key, Py_ssize_t key_length) -/*[clinic end generated code: output=c81a69300ef41766 input=181f1130d5bfeb1e]*/ +/*[clinic end generated code: output=c81a69300ef41766 input=78293a913b02387e]*/ { PyObject *v; datum dbm_key, nextkey; @@ -599,14 +599,14 @@ Reorganize the database. If you have carried out a lot of deletions and would like to shrink the space used by the GDBM file, this routine will reorganize the -database. GDBM will not shorten the length of a database file except -by using this reorganization; otherwise, deleted file space will be -kept and reused as new (key,value) pairs are added. +database. GDBM will not shorten the length of a database file +except by using this reorganization; otherwise, deleted file space +will be kept and reused as new (key,value) pairs are added. [clinic start generated code]*/ static PyObject * _gdbm_gdbm_reorganize_impl(gdbmobject *self, PyTypeObject *cls) -/*[clinic end generated code: output=d77c69e8e3dd644a input=3e3ca0d2ea787861]*/ +/*[clinic end generated code: output=d77c69e8e3dd644a input=d7fcf03051c6f7cd]*/ { _gdbm_state *state = PyType_GetModuleState(cls); assert(state != NULL); diff --git a/Modules/_hashopenssl.c b/Modules/_hashopenssl.c index fa3eceb74d1694..f895c9037485c4 100644 --- a/Modules/_hashopenssl.c +++ b/Modules/_hashopenssl.c @@ -2369,18 +2369,17 @@ _hashlib_HMAC_digest_impl(HMACobject *self) /*[clinic input] @permit_long_summary -@permit_long_docstring_body _hashlib.HMAC.hexdigest Return hexadecimal digest of the bytes passed to the update() method so far. -This may be used to exchange the value safely in email or other non-binary -environments. +This may be used to exchange the value safely in email or other +non-binary environments. [clinic start generated code]*/ static PyObject * _hashlib_HMAC_hexdigest_impl(HMACobject *self) -/*[clinic end generated code: output=80d825be1eaae6a7 input=5e48db83ab1a4d19]*/ +/*[clinic end generated code: output=80d825be1eaae6a7 input=e37a84c36a43787c]*/ { unsigned char buf[EVP_MAX_MD_SIZE]; Py_ssize_t n = _hmac_digest(self, buf); @@ -2540,8 +2539,8 @@ _hashlib.get_fips_mode -> int Determine the OpenSSL FIPS mode of operation. For OpenSSL 3.0.0 and newer it returns the state of the default provider -in the default OSSL context. It's not quite the same as FIPS_mode() but good -enough for unittests. +in the default OSSL context. It's not quite the same as FIPS_mode() but +good enough for unittests. Effectively any non-zero return value indicates FIPS mode; values other than 1 may have additional significance. @@ -2549,7 +2548,7 @@ values other than 1 may have additional significance. static int _hashlib_get_fips_mode_impl(PyObject *module) -/*[clinic end generated code: output=87eece1bab4d3fa9 input=2db61538c41c6fef]*/ +/*[clinic end generated code: output=87eece1bab4d3fa9 input=a6cdb6901421d122]*/ { #ifdef Py_HAS_OPENSSL3_SUPPORT diff --git a/Modules/_heapqmodule.c b/Modules/_heapqmodule.c index c705376f4edbf0..014c838694975d 100644 --- a/Modules/_heapqmodule.c +++ b/Modules/_heapqmodule.c @@ -247,6 +247,7 @@ _heapq_heapreplace_impl(PyObject *module, PyObject *heap, PyObject *item) } /*[clinic input] +@permit_long_summary @critical_section heap _heapq.heappushpop @@ -262,7 +263,7 @@ a separate call to heappop(). static PyObject * _heapq_heappushpop_impl(PyObject *module, PyObject *heap, PyObject *item) -/*[clinic end generated code: output=67231dc98ed5774f input=db05c81b1dd92c44]*/ +/*[clinic end generated code: output=67231dc98ed5774f input=491178a1c7d417ba]*/ { PyObject *returnitem; int cmp; @@ -593,13 +594,13 @@ _heapq.heappushpop_max Maxheap variant of heappushpop. -The combined action runs more efficiently than heappush_max() followed by -a separate call to heappop_max(). +The combined action runs more efficiently than heappush_max() +followed by a separate call to heappop_max(). [clinic start generated code]*/ static PyObject * _heapq_heappushpop_max_impl(PyObject *module, PyObject *heap, PyObject *item) -/*[clinic end generated code: output=ff0019f0941aca0d input=24d0defa6fd6df4a]*/ +/*[clinic end generated code: output=ff0019f0941aca0d input=52030929667a4c08]*/ { PyObject *returnitem; int cmp; diff --git a/Modules/_interpqueuesmodule.c b/Modules/_interpqueuesmodule.c index b23aa5f39489d9..9979cd3457e101 100644 --- a/Modules/_interpqueuesmodule.c +++ b/Modules/_interpqueuesmodule.c @@ -1553,12 +1553,13 @@ _interpqueues.destroy Clear and destroy the queue. -Afterward attempts to use the queue will behave as though it never existed. +Afterward attempts to use the queue will behave as though it never +existed. [clinic start generated code]*/ static PyObject * _interpqueues_destroy_impl(PyObject *module, int64_t qid) -/*[clinic end generated code: output=46b35623f080cbff input=8632bba87f81e3e9]*/ +/*[clinic end generated code: output=46b35623f080cbff input=75136ad807e28677]*/ { int err = queue_destroy(&_globals.queues, qid); if (handle_queue_error(err, module, qid)) { diff --git a/Modules/_interpretersmodule.c b/Modules/_interpretersmodule.c index 4c9be1d525d587..e7a91ced48f176 100644 --- a/Modules/_interpretersmodule.c +++ b/Modules/_interpretersmodule.c @@ -1219,7 +1219,8 @@ _interpreters.run_func Execute the body of the provided function in the identified interpreter. Code objects are also supported. In both cases, closures and args -are not supported. Methods and other callables are not supported either. +are not supported. Methods and other callables are not supported +either. (See _interpreters.exec().) [clinic start generated code]*/ @@ -1227,7 +1228,7 @@ are not supported. Methods and other callables are not supported either. static PyObject * _interpreters_run_func_impl(PyObject *module, PyObject *id, PyObject *func, PyObject *shared, int restricted) -/*[clinic end generated code: output=131f7202ca4a0c5e input=2d62bb9b9eaf4948]*/ +/*[clinic end generated code: output=131f7202ca4a0c5e input=162b29823b33d5cc]*/ { #define FUNCNAME MODULE_NAME_STR ".run_func" PyThreadState *tstate = _PyThreadState_GET(); @@ -1374,6 +1375,7 @@ _interpreters_is_running_impl(PyObject *module, PyObject *id, int restricted) /*[clinic input] +@permit_long_summary _interpreters.get_config id: object * @@ -1384,7 +1386,7 @@ Return a representation of the config used to initialize the interpreter. static PyObject * _interpreters_get_config_impl(PyObject *module, PyObject *id, int restricted) -/*[clinic end generated code: output=56773353b9b7224a input=59519a01c22d96d1]*/ +/*[clinic end generated code: output=56773353b9b7224a input=8272d9ea9e4fb42a]*/ { if (id == Py_None) { id = NULL; @@ -1490,19 +1492,19 @@ _interpreters_decref_impl(PyObject *module, PyObject *id, int restricted) /*[clinic input] -@permit_long_docstring_body _interpreters.capture_exception exc as exc_arg: object = None Return a snapshot of an exception. -If "exc" is None then the current exception, if any, is used (but not cleared). -The returned snapshot is the same as what _interpreters.exec() returns. +If "exc" is None then the current exception, if any, is used (but not +cleared). The returned snapshot is the same as what +_interpreters.exec() returns. [clinic start generated code]*/ static PyObject * _interpreters_capture_exception_impl(PyObject *module, PyObject *exc_arg) -/*[clinic end generated code: output=ef3f5393ef9c88a6 input=6c4dcb78fb722217]*/ +/*[clinic end generated code: output=ef3f5393ef9c88a6 input=4e6289f8f2a47b5b]*/ { PyObject *exc = exc_arg; if (exc == NULL || exc == Py_None) { diff --git a/Modules/_json.c b/Modules/_json.c index 1f454768355cc0..6c4f38834631d3 100644 --- a/Modules/_json.c +++ b/Modules/_json.c @@ -657,14 +657,14 @@ JSON string. Unescapes all valid JSON string escape sequences and raises ValueError on attempt to decode an invalid string. If strict is False then literal control characters are allowed in the string. -Returns a tuple of the decoded string and the index of the character in s -after the end quote. +Returns a tuple of the decoded string and the index of the character in +s after the end quote. [clinic start generated code]*/ static PyObject * py_scanstring_impl(PyObject *module, PyObject *pystr, Py_ssize_t end, int strict) -/*[clinic end generated code: output=961740cfae07cdb3 input=cff59e47498f4d8e]*/ +/*[clinic end generated code: output=961740cfae07cdb3 input=6d5abb5947ccc297]*/ { Py_ssize_t next_end = -1; PyObject *rval = scanstring_unicode(pystr, end, strict, &next_end); diff --git a/Modules/_lzmamodule.c b/Modules/_lzmamodule.c index 00ee68dcea2d0d..237aae544a847b 100644 --- a/Modules/_lzmamodule.c +++ b/Modules/_lzmamodule.c @@ -1106,7 +1106,6 @@ decompress(Decompressor *d, uint8_t *data, size_t len, Py_ssize_t max_length) } /*[clinic input] -@permit_long_docstring_body _lzma.LZMADecompressor.decompress data: Py_buffer @@ -1114,24 +1113,25 @@ _lzma.LZMADecompressor.decompress Decompress *data*, returning uncompressed data as bytes. -If *max_length* is nonnegative, returns at most *max_length* bytes of -decompressed data. If this limit is reached and further output can be -produced, *self.needs_input* will be set to ``False``. In this case, the next -call to *decompress()* may provide *data* as b'' to obtain more of the output. +If *max_length* is nonnegative, returns at most *max_length* bytes +of decompressed data. If this limit is reached and further output +can be produced, *self.needs_input* will be set to ``False``. In +this case, the next call to *decompress()* may provide *data* as b'' +to obtain more of the output. -If all of the input data was decompressed and returned (either because this -was less than *max_length* bytes, or because *max_length* was negative), -*self.needs_input* will be set to True. +If all of the input data was decompressed and returned (either +because this was less than *max_length* bytes, or because +*max_length* was negative), *self.needs_input* will be set to True. -Attempting to decompress data after the end of stream is reached raises an -EOFError. Any data found after the end of the stream is ignored and saved in -the unused_data attribute. +Attempting to decompress data after the end of stream is reached +raises an EOFError. Any data found after the end of the stream is +ignored and saved in the unused_data attribute. [clinic start generated code]*/ static PyObject * _lzma_LZMADecompressor_decompress_impl(Decompressor *self, Py_buffer *data, Py_ssize_t max_length) -/*[clinic end generated code: output=ef4e20ec7122241d input=d5cbd45801b4b8b0]*/ +/*[clinic end generated code: output=ef4e20ec7122241d input=0eb62669c4315dee]*/ { PyObject *result = NULL; diff --git a/Modules/_multiprocessing/clinic/posixshmem.c.h b/Modules/_multiprocessing/clinic/posixshmem.c.h index a545ff4d80f067..a4d7273aea718a 100644 --- a/Modules/_multiprocessing/clinic/posixshmem.c.h +++ b/Modules/_multiprocessing/clinic/posixshmem.c.h @@ -50,9 +50,9 @@ PyDoc_STRVAR(_posixshmem_shm_unlink__doc__, "\n" "Remove a shared memory object (similar to unlink()).\n" "\n" -"Remove a shared memory object name, and, once all processes have unmapped\n" -"the object, de-allocates and destroys the contents of the associated memory\n" -"region."); +"Remove a shared memory object name, and, once all processes have\n" +"unmapped the object, de-allocates and destroys the contents of the\n" +"associated memory region."); #define _POSIXSHMEM_SHM_UNLINK_METHODDEF \ {"shm_unlink", (PyCFunction)_posixshmem_shm_unlink, METH_O, _posixshmem_shm_unlink__doc__}, @@ -86,4 +86,4 @@ _posixshmem_shm_unlink(PyObject *module, PyObject *arg) #ifndef _POSIXSHMEM_SHM_UNLINK_METHODDEF #define _POSIXSHMEM_SHM_UNLINK_METHODDEF #endif /* !defined(_POSIXSHMEM_SHM_UNLINK_METHODDEF) */ -/*[clinic end generated code: output=74588a5abba6e36c input=a9049054013a1b77]*/ +/*[clinic end generated code: output=e69afacce7b0595e input=a9049054013a1b77]*/ diff --git a/Modules/_multiprocessing/posixshmem.c b/Modules/_multiprocessing/posixshmem.c index ab45e4136c7d46..22b4af212662b3 100644 --- a/Modules/_multiprocessing/posixshmem.c +++ b/Modules/_multiprocessing/posixshmem.c @@ -81,15 +81,15 @@ _posixshmem.shm_unlink Remove a shared memory object (similar to unlink()). -Remove a shared memory object name, and, once all processes have unmapped -the object, de-allocates and destroys the contents of the associated memory -region. +Remove a shared memory object name, and, once all processes have +unmapped the object, de-allocates and destroys the contents of the +associated memory region. [clinic start generated code]*/ static PyObject * _posixshmem_shm_unlink_impl(PyObject *module, PyObject *path) -/*[clinic end generated code: output=42f8b23d134b9ff5 input=298369d013dcad63]*/ +/*[clinic end generated code: output=42f8b23d134b9ff5 input=cf7a30ec6503cf78]*/ { int rv; int async_err = 0; diff --git a/Modules/_opcode.c b/Modules/_opcode.c index dedf17f76dfc9b..2a34559fd1f437 100644 --- a/Modules/_opcode.c +++ b/Modules/_opcode.c @@ -119,7 +119,7 @@ _opcode_has_const_impl(PyObject *module, int opcode) } /*[clinic input] - +@permit_long_summary _opcode.has_name -> bool opcode: int @@ -129,7 +129,7 @@ Return True if the opcode accesses an attribute by name, False otherwise. static int _opcode_has_name_impl(PyObject *module, int opcode) -/*[clinic end generated code: output=b49a83555c2fa517 input=448aa5e4bcc947ba]*/ +/*[clinic end generated code: output=b49a83555c2fa517 input=8faf669024d97fad]*/ { return IS_VALID_OPCODE(opcode) && OPCODE_HAS_NAME(opcode); } diff --git a/Modules/_posixsubprocess.c b/Modules/_posixsubprocess.c index b7f39ea3d499e4..bcee5633987797 100644 --- a/Modules/_posixsubprocess.c +++ b/Modules/_posixsubprocess.c @@ -962,7 +962,6 @@ do_fork_exec(char *const exec_array[], } /*[clinic input] -@permit_long_docstring_body _posixsubprocess.fork_exec as subprocess_fork_exec args as process_args: object executable_list: object @@ -990,15 +989,15 @@ _posixsubprocess.fork_exec as subprocess_fork_exec Spawn a fresh new child process. -Fork a child process, close parent file descriptors as appropriate in the -child and duplicate the few that are needed before calling exec() in the -child process. +Fork a child process, close parent file descriptors as appropriate in +the child and duplicate the few that are needed before calling exec() in +the child process. -If close_fds is True, close file descriptors 3 and higher, except those listed -in the sorted tuple pass_fds. +If close_fds is True, close file descriptors 3 and higher, except those +listed in the sorted tuple pass_fds. -The preexec_fn, if supplied, will be called immediately before closing file -descriptors and exec. +The preexec_fn, if supplied, will be called immediately before closing +file descriptors and exec. WARNING: preexec_fn is NOT SAFE if your application uses threads. It may trigger infrequent, difficult to debug deadlocks. @@ -1023,7 +1022,7 @@ subprocess_fork_exec_impl(PyObject *module, PyObject *process_args, PyObject *extra_groups_packed, PyObject *uid_object, int child_umask, PyObject *preexec_fn) -/*[clinic end generated code: output=288464dc56e373c7 input=58e0db771686f4f6]*/ +/*[clinic end generated code: output=288464dc56e373c7 input=5e56eac3e036e349]*/ { PyObject *converted_args = NULL, *fast_args = NULL; PyObject *preexec_fn_args_tuple = NULL; diff --git a/Modules/_queuemodule.c b/Modules/_queuemodule.c index d5ba36273c8262..7205c095cc87b8 100644 --- a/Modules/_queuemodule.c +++ b/Modules/_queuemodule.c @@ -291,15 +291,16 @@ _queue.SimpleQueue.put Put the item on the queue. -The optional 'block' and 'timeout' arguments are ignored, as this method -never blocks. They are provided for compatibility with the Queue class. +The optional 'block' and 'timeout' arguments are ignored, as this +method never blocks. They are provided for compatibility with the +Queue class. [clinic start generated code]*/ static PyObject * _queue_SimpleQueue_put_impl(simplequeueobject *self, PyObject *item, int block, PyObject *timeout) -/*[clinic end generated code: output=4333136e88f90d8b input=a16dbb33363c0fa8]*/ +/*[clinic end generated code: output=4333136e88f90d8b input=9f9ff270a74670c3]*/ { if (self->has_threads_waiting) { HandoffData data = { @@ -360,10 +361,11 @@ _queue.SimpleQueue.get Remove and return an item from the queue. -If optional args 'block' is true and 'timeout' is None (the default), -block if necessary until an item is available. If 'timeout' is -a non-negative number, it blocks at most 'timeout' seconds and raises -the Empty exception if no item was available within that time. +If optional args 'block' is true and 'timeout' is None (the +default), block if necessary until an item is available. If +'timeout' is a non-negative number, it blocks at most 'timeout' +seconds and raises the Empty exception if no item was available +within that time. Otherwise ('block' is false), return an item if one is immediately available, else raise the Empty exception ('timeout' is ignored in that case). @@ -373,7 +375,7 @@ in that case). static PyObject * _queue_SimpleQueue_get_impl(simplequeueobject *self, PyTypeObject *cls, int block, PyObject *timeout_obj) -/*[clinic end generated code: output=5c2cca914cd1e55b input=f7836c65e5839c51]*/ +/*[clinic end generated code: output=5c2cca914cd1e55b input=afa0889bbc6b4761]*/ { PyTime_t endtime = 0; diff --git a/Modules/_sre/sre.c b/Modules/_sre/sre.c index 044eb6e5f1fb66..7a07ed1d7aca20 100644 --- a/Modules/_sre/sre.c +++ b/Modules/_sre/sre.c @@ -2587,6 +2587,7 @@ _pair(Py_ssize_t i1, Py_ssize_t i2) } /*[clinic input] +@permit_long_summary _sre.SRE_Match.span group: object(c_default="NULL") = 0 @@ -2597,7 +2598,7 @@ For match object m, return the 2-tuple (m.start(group), m.end(group)). static PyObject * _sre_SRE_Match_span_impl(MatchObject *self, PyObject *group) -/*[clinic end generated code: output=f02ae40594d14fe6 input=8fa6014e982d71d4]*/ +/*[clinic end generated code: output=f02ae40594d14fe6 input=834cfe444f0f55cf]*/ { Py_ssize_t index = match_getindex(self, group); diff --git a/Modules/_ssl.c b/Modules/_ssl.c index 3224ca7d0f93b9..69472ae01a5016 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -2357,27 +2357,26 @@ _ssl__SSLSocket_compression_impl(PySSLSocket *self) } /*[clinic input] -@permit_long_docstring_body @critical_section @getter _ssl._SSLSocket.context This changes the context associated with the SSLSocket. -This is typically used from within a callback function set by the sni_callback -on the SSLContext to change the certificate information associated with the -SSLSocket before the cryptographic exchange handshake messages. +This is typically used from within a callback function set by the +sni_callback on the SSLContext to change the certificate information +associated with the SSLSocket before the cryptographic exchange +handshake messages. [clinic start generated code]*/ static PyObject * _ssl__SSLSocket_context_get_impl(PySSLSocket *self) -/*[clinic end generated code: output=d23e82f72f32e3d7 input=0cc8e773a079295e]*/ +/*[clinic end generated code: output=d23e82f72f32e3d7 input=b845dea1f9710ebe]*/ { return Py_NewRef(self->ctx); } /*[clinic input] -@permit_long_docstring_body @critical_section @setter _ssl._SSLSocket.context @@ -2385,7 +2384,7 @@ _ssl._SSLSocket.context static int _ssl__SSLSocket_context_set_impl(PySSLSocket *self, PyObject *value) -/*[clinic end generated code: output=6b0a6cc5cf33d9fe input=f7fc1674b660df96]*/ +/*[clinic end generated code: output=6b0a6cc5cf33d9fe input=48ece77724fd9dd4]*/ { if (PyObject_TypeCheck(value, self->ctx->state->PySSLContext_Type)) { Py_SETREF(self->ctx, (PySSLContext *)Py_NewRef(value)); @@ -2635,7 +2634,6 @@ _ssl__SSLSocket_uses_ktls_for_recv_impl(PySSLSocket *self) #ifdef BIO_get_ktls_send /*[clinic input] @permit_long_summary -@permit_long_docstring_body @critical_section _ssl._SSLSocket.sendfile fd: int @@ -2646,9 +2644,9 @@ _ssl._SSLSocket.sendfile Write size bytes from offset in the file descriptor fd to the SSL connection. -This method uses the zero-copy technique and returns the number of bytes -written. It should be called only when Kernel TLS is used for sending data in -the connection. +This method uses the zero-copy technique and returns the number of +bytes written. It should be called only when Kernel TLS is used for +sending data in the connection. The meaning of flags is platform dependent. [clinic start generated code]*/ @@ -2656,7 +2654,7 @@ The meaning of flags is platform dependent. static PyObject * _ssl__SSLSocket_sendfile_impl(PySSLSocket *self, int fd, Py_off_t offset, size_t size, int flags) -/*[clinic end generated code: output=0c6815b0719ca8d5 input=1f193e681bbae664]*/ +/*[clinic end generated code: output=0c6815b0719ca8d5 input=68c7fbf90c9a8a1b]*/ { Py_ssize_t retval; int sockstate; @@ -3175,22 +3173,22 @@ _ssl__SSLSocket_shutdown_impl(PySSLSocket *self) } /*[clinic input] -@permit_long_docstring_body @critical_section _ssl._SSLSocket.get_channel_binding cb_type: str = "tls-unique" Get channel binding data for current connection. -Raise ValueError if the requested `cb_type` is not supported. Return bytes -of the data or None if the data is not available (e.g. before the handshake). +Raise ValueError if the requested `cb_type` is not supported. +Return bytes of the data or None if the data is not available (e.g. +before the handshake). Only 'tls-unique' channel binding data from RFC 5929 is supported. [clinic start generated code]*/ static PyObject * _ssl__SSLSocket_get_channel_binding_impl(PySSLSocket *self, const char *cb_type) -/*[clinic end generated code: output=34bac9acb6a61d31 input=26fad522435ecca1]*/ +/*[clinic end generated code: output=34bac9acb6a61d31 input=bed81ef7936535a0]*/ { char buf[PySSL_CB_MAXLEN]; size_t len; @@ -5260,22 +5258,22 @@ _servername_callback(SSL *s, int *al, void *args) /*[clinic input] @permit_long_summary -@permit_long_docstring_body @critical_section @getter _ssl._SSLContext.sni_callback Set a callback that will be called when a server name is provided by the SSL/TLS client in the SNI extension. -If the argument is None then the callback is disabled. The method is called -with the SSLSocket, the server name as a string, and the SSLContext object. +If the argument is None then the callback is disabled. The method +is called with the SSLSocket, the server name as a string, and the +SSLContext object. See RFC 6066 for details of the SNI extension. [clinic start generated code]*/ static PyObject * _ssl__SSLContext_sni_callback_get_impl(PySSLContext *self) -/*[clinic end generated code: output=961e6575cdfaf036 input=3aee06696b0874d9]*/ +/*[clinic end generated code: output=961e6575cdfaf036 input=a319bc8fc15d6fc8]*/ { PyObject *cb = self->set_sni_cb; if (cb == NULL) { @@ -5286,7 +5284,6 @@ _ssl__SSLContext_sni_callback_get_impl(PySSLContext *self) /*[clinic input] @permit_long_summary -@permit_long_docstring_body @critical_section @setter _ssl._SSLContext.sni_callback @@ -5294,7 +5291,7 @@ _ssl._SSLContext.sni_callback static int _ssl__SSLContext_sni_callback_set_impl(PySSLContext *self, PyObject *value) -/*[clinic end generated code: output=b32736c6b891f61a input=332def1d8c81d549]*/ +/*[clinic end generated code: output=b32736c6b891f61a input=402b43fb06c1139e]*/ { if (self->protocol == PY_SSL_VERSION_TLS_CLIENT) { PyErr_SetString(PyExc_ValueError, @@ -5369,16 +5366,16 @@ _ssl._SSLContext.cert_store_stats Returns quantities of loaded X.509 certificates. -X.509 certificates with a CA extension and certificate revocation lists -inside the context's cert store. +X.509 certificates with a CA extension and certificate revocation +lists inside the context's cert store. -NOTE: Certificates in a capath directory aren't loaded unless they have -been used at least once. +NOTE: Certificates in a capath directory aren't loaded unless they +have been used at least once. [clinic start generated code]*/ static PyObject * _ssl__SSLContext_cert_store_stats_impl(PySSLContext *self) -/*[clinic end generated code: output=5f356f4d9cca874d input=d13c6e3f2b48539b]*/ +/*[clinic end generated code: output=5f356f4d9cca874d input=9e5094e094b892a3]*/ { X509_STORE *store; STACK_OF(X509_OBJECT) *objs; @@ -5421,16 +5418,16 @@ _ssl._SSLContext.get_ca_certs Returns a list of dicts with information of loaded CA certs. -If the optional argument is True, returns a DER-encoded copy of the CA -certificate. +If the optional argument is True, returns a DER-encoded copy of the +CA certificate. -NOTE: Certificates in a capath directory aren't loaded unless they have -been used at least once. +NOTE: Certificates in a capath directory aren't loaded unless they +have been used at least once. [clinic start generated code]*/ static PyObject * _ssl__SSLContext_get_ca_certs_impl(PySSLContext *self, int binary_form) -/*[clinic end generated code: output=0d58f148f37e2938 input=eb0592909c9ad6e7]*/ +/*[clinic end generated code: output=0d58f148f37e2938 input=9f71af5aa4e67076]*/ { X509_STORE *store; STACK_OF(X509_OBJECT) *objs; @@ -6319,13 +6316,13 @@ _ssl.RAND_status Returns True if the OpenSSL PRNG has been seeded with enough data and False if not. -It is necessary to seed the PRNG with RAND_add() on some platforms before -using the ssl() function. +It is necessary to seed the PRNG with RAND_add() on some platforms +before using the ssl() function. [clinic start generated code]*/ static PyObject * _ssl_RAND_status_impl(PyObject *module) -/*[clinic end generated code: output=7e0aaa2d39fdc1ad input=aba24a3f3af3b184]*/ +/*[clinic end generated code: output=7e0aaa2d39fdc1ad input=52b061f4a24ff3a1]*/ { return PyBool_FromLong(RAND_status()); } @@ -6621,16 +6618,16 @@ _ssl.enum_certificates Retrieve certificates from Windows' cert store. -store_name may be one of 'CA', 'ROOT' or 'MY'. The system may provide -more cert storages, too. The function returns a list of (bytes, -encoding_type, trust) tuples. The encoding_type flag can be interpreted -with X509_ASN_ENCODING or PKCS_7_ASN_ENCODING. The trust setting is either -a set of OIDs or the boolean True. +store_name may be one of 'CA', 'ROOT' or 'MY'. The system may +provide more cert storages, too. The function returns a list of +(bytes, encoding_type, trust) tuples. The encoding_type flag can be +interpreted with X509_ASN_ENCODING or PKCS_7_ASN_ENCODING. The +trust setting is either a set of OIDs or the boolean True. [clinic start generated code]*/ static PyObject * _ssl_enum_certificates_impl(PyObject *module, const char *store_name) -/*[clinic end generated code: output=5134dc8bb3a3c893 input=263c22e6c6988cf3]*/ +/*[clinic end generated code: output=5134dc8bb3a3c893 input=ef81b4bd1b7ab8e9]*/ { HCERTSTORE hCollectionStore = NULL; PCCERT_CONTEXT pCertCtx = NULL; diff --git a/Modules/_struct.c b/Modules/_struct.c index 3a970d99bb3d6d..8c611a708d02a9 100644 --- a/Modules/_struct.c +++ b/Modules/_struct.c @@ -2721,6 +2721,7 @@ pack_into_impl(PyObject *module, PyStructObject *s_object, Py_buffer *buffer, } /*[clinic input] +@permit_long_summary unpack format as s_object: cache_struct @@ -2735,12 +2736,13 @@ for more on format strings. static PyObject * unpack_impl(PyObject *module, PyStructObject *s_object, Py_buffer *buffer) -/*[clinic end generated code: output=48ddd4d88eca8551 input=7df28c5d0b5b6f4e]*/ +/*[clinic end generated code: output=48ddd4d88eca8551 input=53a60a65830bd1e1]*/ { return Struct_unpack_impl(s_object, buffer); } /*[clinic input] +@permit_long_summary unpack_from format as s_object: cache_struct @@ -2757,7 +2759,7 @@ help(struct) for more on format strings. static PyObject * unpack_from_impl(PyObject *module, PyStructObject *s_object, Py_buffer *buffer, Py_ssize_t offset) -/*[clinic end generated code: output=1042631674c6e0d3 input=599262b23559f6c5]*/ +/*[clinic end generated code: output=1042631674c6e0d3 input=3e46619756fb0293]*/ { return Struct_unpack_from_impl(s_object, buffer, offset); } diff --git a/Modules/_testlimitedcapi/clinic/long.c.h b/Modules/_testlimitedcapi/clinic/long.c.h index ebaeb53921a82f..f9852aba266a57 100644 --- a/Modules/_testlimitedcapi/clinic/long.c.h +++ b/Modules/_testlimitedcapi/clinic/long.c.h @@ -84,8 +84,8 @@ PyDoc_STRVAR(_testlimitedcapi_test_long_as_size_t__doc__, "\n" "Test the PyLong_As{Size,Ssize}_t API.\n" "\n" -"At present this just tests that non-integer arguments are handled correctly.\n" -"It should be extended to test overflow handling."); +"At present this just tests that non-integer arguments are handled\n" +"correctly. It should be extended to test overflow handling."); #define _TESTLIMITEDCAPI_TEST_LONG_AS_SIZE_T_METHODDEF \ {"test_long_as_size_t", (PyCFunction)_testlimitedcapi_test_long_as_size_t, METH_NOARGS, _testlimitedcapi_test_long_as_size_t__doc__}, @@ -140,4 +140,4 @@ PyDoc_STRVAR(_testlimitedcapi_PyLong_AsInt__doc__, #define _TESTLIMITEDCAPI_PYLONG_ASINT_METHODDEF \ {"PyLong_AsInt", (PyCFunction)_testlimitedcapi_PyLong_AsInt, METH_O, _testlimitedcapi_PyLong_AsInt__doc__}, -/*[clinic end generated code: output=bc52b73c599f96c2 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=fb5c95bd0a4bdad8 input=a9049054013a1b77]*/ diff --git a/Modules/_testlimitedcapi/long.c b/Modules/_testlimitedcapi/long.c index 34bc7331da9247..99b9e96760d50d 100644 --- a/Modules/_testlimitedcapi/long.c +++ b/Modules/_testlimitedcapi/long.c @@ -451,13 +451,13 @@ _testlimitedcapi.test_long_as_size_t Test the PyLong_As{Size,Ssize}_t API. -At present this just tests that non-integer arguments are handled correctly. -It should be extended to test overflow handling. +At present this just tests that non-integer arguments are handled +correctly. It should be extended to test overflow handling. [clinic start generated code]*/ static PyObject * _testlimitedcapi_test_long_as_size_t_impl(PyObject *module) -/*[clinic end generated code: output=297a9f14a42f55af input=8923d8f2038c46f4]*/ +/*[clinic end generated code: output=297a9f14a42f55af input=692e73744b35bf6e]*/ { size_t out_u; Py_ssize_t out_s; diff --git a/Modules/_testmultiphase.c b/Modules/_testmultiphase.c index 128e3f79ecd99c..57ba61e67f1d7f 100644 --- a/Modules/_testmultiphase.c +++ b/Modules/_testmultiphase.c @@ -141,14 +141,14 @@ _testmultiphase.StateAccessType.get_defining_module Return the module of the defining class. -Also tests that result of PyType_GetModuleByDef matches defining_class's -module. +Also tests that result of PyType_GetModuleByDef matches +defining_class's module. [clinic start generated code]*/ static PyObject * _testmultiphase_StateAccessType_get_defining_module_impl(StateAccessTypeObject *self, PyTypeObject *cls) -/*[clinic end generated code: output=ba2a14284a5d0921 input=d2c7245c8a9d06f8]*/ +/*[clinic end generated code: output=ba2a14284a5d0921 input=903e7f66555d65ae]*/ { PyObject *retval; retval = PyType_GetModule(cls); diff --git a/Modules/_threadmodule.c b/Modules/_threadmodule.c index 135b53111014d1..7a34c5a5a0ef6b 100644 --- a/Modules/_threadmodule.c +++ b/Modules/_threadmodule.c @@ -820,8 +820,8 @@ _thread.lock.acquire Lock the lock. -Without argument, this blocks if the lock is already -locked (even by the same thread), waiting for another thread to release +Without argument, this blocks if the lock is already locked +(even by the same thread), waiting for another thread to release the lock, and return True once the lock is acquired. With an argument, this will only block if the argument is true, and the return value reflects whether the lock is acquired. @@ -831,7 +831,7 @@ The blocking operation is interruptible. static PyObject * _thread_lock_acquire_impl(lockobject *self, int blocking, PyObject *timeoutobj) -/*[clinic end generated code: output=569d6b25d508bf6f input=13e999649bc1c798]*/ +/*[clinic end generated code: output=569d6b25d508bf6f input=73e75b3d2ec32677]*/ { PyTime_t timeout; @@ -1131,19 +1131,19 @@ _thread.RLock.release Release the lock. -Allows another thread that is blocked waiting for -the lock to acquire the lock. The lock must be in the locked state, +Allows another thread that is blocked waiting for the lock +to acquire the lock. The lock must be in the locked state, and must be locked by the same thread that unlocks it; otherwise a `RuntimeError` is raised. -Do note that if the lock was acquire()d several times in a row by the -current thread, release() needs to be called as many times for the lock -to be available for other threads. +Do note that if the lock was acquire()d several times in a row by +the current thread, release() needs to be called as many times for +the lock to be available for other threads. [clinic start generated code]*/ static PyObject * _thread_RLock_release_impl(rlockobject *self) -/*[clinic end generated code: output=51f4a013c5fae2c5 input=d425daf1a5782e63]*/ +/*[clinic end generated code: output=51f4a013c5fae2c5 input=7c188f60189be13a]*/ { if (_PyRecursiveMutex_TryUnlock(&self->lock) < 0) { PyErr_SetString(PyExc_RuntimeError, diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c index bbe2a428454e0c..58fdabecf16ada 100644 --- a/Modules/_tkinter.c +++ b/Modules/_tkinter.c @@ -3219,7 +3219,6 @@ _tkinter_create_impl(PyObject *module, const char *screenName, /*[clinic input] @permit_long_summary -@permit_long_docstring_body _tkinter.setbusywaitinterval new_val: int @@ -3227,12 +3226,13 @@ _tkinter.setbusywaitinterval Set the busy-wait interval in milliseconds between successive calls to Tcl_DoOneEvent in a threaded Python interpreter. -It should be set to a divisor of the maximum time between frames in an animation. +It should be set to a divisor of the maximum time between frames in +an animation. [clinic start generated code]*/ static PyObject * _tkinter_setbusywaitinterval_impl(PyObject *module, int new_val) -/*[clinic end generated code: output=42bf7757dc2d0ab6 input=07b82a04b56625e1]*/ +/*[clinic end generated code: output=42bf7757dc2d0ab6 input=0360dd95c8bd8619]*/ { if (new_val < 0) { PyErr_SetString(PyExc_ValueError, diff --git a/Modules/_tracemalloc.c b/Modules/_tracemalloc.c index 56d83ea0dcb2a7..a97b0e0bfeefba 100644 --- a/Modules/_tracemalloc.c +++ b/Modules/_tracemalloc.c @@ -11,6 +11,7 @@ module _tracemalloc /*[clinic input] +@permit_long_summary _tracemalloc.is_tracing Return True if the tracemalloc module is tracing Python memory allocations. @@ -18,7 +19,7 @@ Return True if the tracemalloc module is tracing Python memory allocations. static PyObject * _tracemalloc_is_tracing_impl(PyObject *module) -/*[clinic end generated code: output=2d763b42601cd3ef input=af104b0a00192f63]*/ +/*[clinic end generated code: output=2d763b42601cd3ef input=cac4fc9096babeac]*/ { return PyBool_FromLong(_PyTraceMalloc_IsTracing()); } @@ -153,6 +154,7 @@ _tracemalloc_get_tracemalloc_memory_impl(PyObject *module) /*[clinic input] +@permit_long_summary _tracemalloc.get_traced_memory Get the current size and peak size of memory blocks traced by tracemalloc. @@ -162,7 +164,7 @@ Returns a tuple: (current: int, peak: int). static PyObject * _tracemalloc_get_traced_memory_impl(PyObject *module) -/*[clinic end generated code: output=5b167189adb9e782 input=61ddb5478400ff66]*/ +/*[clinic end generated code: output=5b167189adb9e782 input=b06e7a1a4914fc21]*/ { return _PyTraceMalloc_GetTracedMemory(); } diff --git a/Modules/arraymodule.c b/Modules/arraymodule.c index 472c59ea8c9882..7f367d639983ae 100644 --- a/Modules/arraymodule.c +++ b/Modules/arraymodule.c @@ -1534,13 +1534,13 @@ array.array.buffer_info Return a tuple (address, length) giving the current memory address and the length in items of the buffer used to hold array's contents. -The length should be multiplied by the itemsize attribute to calculate -the buffer length in bytes. +The length should be multiplied by the itemsize attribute to +calculate the buffer length in bytes. [clinic start generated code]*/ static PyObject * array_array_buffer_info_impl(arrayobject *self) -/*[clinic end generated code: output=9b2a4ec3ae7e98e7 input=63d9ad83ba60cda8]*/ +/*[clinic end generated code: output=9b2a4ec3ae7e98e7 input=c2771b9f6a8e1c86]*/ { PyObject* item1 = PyLong_FromVoidPtr(self->ob_item); if (item1 == NULL) { @@ -1572,19 +1572,18 @@ array_array_append_impl(arrayobject *self, PyObject *v) } /*[clinic input] -@permit_long_docstring_body array.array.byteswap Byteswap all items of the array. -If the items in the array are not 1, 2, 4, 8 or 16 bytes in size, RuntimeError -is raised. Note, that for complex types the order of +If the items in the array are not 1, 2, 4, 8 or 16 bytes in size, +RuntimeError is raised. Note, that for complex types the order of components (the real part, followed by imaginary part) is preserved. [clinic start generated code]*/ static PyObject * array_array_byteswap_impl(arrayobject *self) -/*[clinic end generated code: output=5f8236cbdf0d90b5 input=aafda275f48191d0]*/ +/*[clinic end generated code: output=5f8236cbdf0d90b5 input=8732f800e1b47bac]*/ { char *p; Py_ssize_t i; @@ -1967,7 +1966,6 @@ array_array_tobytes_impl(arrayobject *self) } /*[clinic input] -@permit_long_docstring_body array.array.fromunicode ustr: unicode @@ -1975,14 +1973,14 @@ array.array.fromunicode Extends this array with data from the unicode string ustr. -The array must be a unicode type array; otherwise a ValueError is raised. -Use array.frombytes(ustr.encode(...)) to append Unicode data to an array of -some other type. +The array must be a unicode type array; otherwise a ValueError is +raised. Use array.frombytes(ustr.encode(...)) to append Unicode +data to an array of some other type. [clinic start generated code]*/ static PyObject * array_array_fromunicode_impl(arrayobject *self, PyObject *ustr) -/*[clinic end generated code: output=24359f5e001a7f2b input=158d47c302f27ca1]*/ +/*[clinic end generated code: output=24359f5e001a7f2b input=01fa592ec7b948b6]*/ { const char *typecode = self->ob_descr->typecode; if (strcmp(typecode, "u") != 0 && strcmp(typecode, "w") != 0) { @@ -2030,19 +2028,19 @@ array_array_fromunicode_impl(arrayobject *self, PyObject *ustr) } /*[clinic input] -@permit_long_docstring_body array.array.tounicode Extends this array with data from the unicode string ustr. -Convert the array to a unicode string. The array must be a unicode type array; -otherwise a ValueError is raised. Use array.tobytes().decode() to obtain a -unicode string from an array of some other type. +Convert the array to a unicode string. The array must be a unicode +type array; otherwise a ValueError is raised. Use +array.tobytes().decode() to obtain a unicode string from an array of +some other type. [clinic start generated code]*/ static PyObject * array_array_tounicode_impl(arrayobject *self) -/*[clinic end generated code: output=08e442378336e1ef input=6690997213d219db]*/ +/*[clinic end generated code: output=08e442378336e1ef input=d4d5f398aa71a2be]*/ { const char *typecode = self->ob_descr->typecode; if (strcmp(typecode, "u") != 0 && strcmp(typecode, "w") != 0) { diff --git a/Modules/cjkcodecs/clinic/multibytecodec.c.h b/Modules/cjkcodecs/clinic/multibytecodec.c.h index b3663180d726e5..32588b0561e1ac 100644 --- a/Modules/cjkcodecs/clinic/multibytecodec.c.h +++ b/Modules/cjkcodecs/clinic/multibytecodec.c.h @@ -14,10 +14,11 @@ PyDoc_STRVAR(_multibytecodec_MultibyteCodec_encode__doc__, "\n" "Return an encoded string version of \'input\'.\n" "\n" -"\'errors\' may be given to set a different error handling scheme. Default is\n" -"\'strict\' meaning that encoding errors raise a UnicodeEncodeError. Other possible\n" -"values are \'ignore\', \'replace\' and \'xmlcharrefreplace\' as well as any other name\n" -"registered with codecs.register_error that can handle UnicodeEncodeErrors."); +"\'errors\' may be given to set a different error handling scheme.\n" +"Default is \'strict\' meaning that encoding errors raise\n" +"a UnicodeEncodeError. Other possible values are \'ignore\', \'replace\'\n" +"and \'xmlcharrefreplace\' as well as any other name registered with\n" +"codecs.register_error that can handle UnicodeEncodeErrors."); #define _MULTIBYTECODEC_MULTIBYTECODEC_ENCODE_METHODDEF \ {"encode", _PyCFunction_CAST(_multibytecodec_MultibyteCodec_encode), METH_FASTCALL|METH_KEYWORDS, _multibytecodec_MultibyteCodec_encode__doc__}, @@ -103,9 +104,10 @@ PyDoc_STRVAR(_multibytecodec_MultibyteCodec_decode__doc__, "\n" "Decodes \'input\'.\n" "\n" -"\'errors\' may be given to set a different error handling scheme. Default is\n" -"\'strict\' meaning that encoding errors raise a UnicodeDecodeError. Other possible\n" -"values are \'ignore\' and \'replace\' as well as any other name registered with\n" +"\'errors\' may be given to set a different error handling scheme.\n" +"Default is \'strict\' meaning that encoding errors raise\n" +"a UnicodeDecodeError. Other possible values are \'ignore\' and\n" +"\'replace\' as well as any other name registered with\n" "codecs.register_error that is able to handle UnicodeDecodeErrors.\""); #define _MULTIBYTECODEC_MULTIBYTECODEC_DECODE_METHODDEF \ @@ -696,4 +698,4 @@ PyDoc_STRVAR(_multibytecodec___create_codec__doc__, #define _MULTIBYTECODEC___CREATE_CODEC_METHODDEF \ {"__create_codec", (PyCFunction)_multibytecodec___create_codec, METH_O, _multibytecodec___create_codec__doc__}, -/*[clinic end generated code: output=014f4f6bb9d29594 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=a84b1544d7d01abb input=a9049054013a1b77]*/ diff --git a/Modules/cjkcodecs/multibytecodec.c b/Modules/cjkcodecs/multibytecodec.c index f1124147e2b0a7..32c96c9d2cb3cd 100644 --- a/Modules/cjkcodecs/multibytecodec.c +++ b/Modules/cjkcodecs/multibytecodec.c @@ -582,7 +582,6 @@ multibytecodec_encode(const MultibyteCodec *codec, } /*[clinic input] -@permit_long_docstring_body _multibytecodec.MultibyteCodec.encode input: object @@ -590,17 +589,18 @@ _multibytecodec.MultibyteCodec.encode Return an encoded string version of 'input'. -'errors' may be given to set a different error handling scheme. Default is -'strict' meaning that encoding errors raise a UnicodeEncodeError. Other possible -values are 'ignore', 'replace' and 'xmlcharrefreplace' as well as any other name -registered with codecs.register_error that can handle UnicodeEncodeErrors. +'errors' may be given to set a different error handling scheme. +Default is 'strict' meaning that encoding errors raise +a UnicodeEncodeError. Other possible values are 'ignore', 'replace' +and 'xmlcharrefreplace' as well as any other name registered with +codecs.register_error that can handle UnicodeEncodeErrors. [clinic start generated code]*/ static PyObject * _multibytecodec_MultibyteCodec_encode_impl(MultibyteCodecObject *self, PyObject *input, const char *errors) -/*[clinic end generated code: output=7b26652045ba56a9 input=0980aede2c564df8]*/ +/*[clinic end generated code: output=7b26652045ba56a9 input=980002ed1447697b]*/ { MultibyteCodec_State state; PyObject *errorcb, *r, *ucvt; @@ -648,7 +648,6 @@ _multibytecodec_MultibyteCodec_encode_impl(MultibyteCodecObject *self, } /*[clinic input] -@permit_long_docstring_body _multibytecodec.MultibyteCodec.decode input: Py_buffer @@ -656,9 +655,10 @@ _multibytecodec.MultibyteCodec.decode Decodes 'input'. -'errors' may be given to set a different error handling scheme. Default is -'strict' meaning that encoding errors raise a UnicodeDecodeError. Other possible -values are 'ignore' and 'replace' as well as any other name registered with +'errors' may be given to set a different error handling scheme. +Default is 'strict' meaning that encoding errors raise +a UnicodeDecodeError. Other possible values are 'ignore' and +'replace' as well as any other name registered with codecs.register_error that is able to handle UnicodeDecodeErrors." [clinic start generated code]*/ @@ -666,7 +666,7 @@ static PyObject * _multibytecodec_MultibyteCodec_decode_impl(MultibyteCodecObject *self, Py_buffer *input, const char *errors) -/*[clinic end generated code: output=ff419f65bad6cc77 input=2c657ef914600c7c]*/ +/*[clinic end generated code: output=ff419f65bad6cc77 input=dbf93d8bb98ca440]*/ { MultibyteCodec_State state; MultibyteDecodeBuffer buf; diff --git a/Modules/clinic/_abc.c.h b/Modules/clinic/_abc.c.h index 04681fa2206a2a..fa1c57dc26bf85 100644 --- a/Modules/clinic/_abc.c.h +++ b/Modules/clinic/_abc.c.h @@ -146,9 +146,9 @@ PyDoc_STRVAR(_abc_get_cache_token__doc__, "\n" "Returns the current ABC cache token.\n" "\n" -"The token is an opaque object (supporting equality testing) identifying the\n" -"current version of the ABC cache for virtual subclasses. The token changes\n" -"with every call to register() on any ABC."); +"The token is an opaque object (supporting equality testing) identifying\n" +"the current version of the ABC cache for virtual subclasses. The token\n" +"changes with every call to register() on any ABC."); #define _ABC_GET_CACHE_TOKEN_METHODDEF \ {"get_cache_token", (PyCFunction)_abc_get_cache_token, METH_NOARGS, _abc_get_cache_token__doc__}, @@ -161,4 +161,4 @@ _abc_get_cache_token(PyObject *module, PyObject *Py_UNUSED(ignored)) { return _abc_get_cache_token_impl(module); } -/*[clinic end generated code: output=1989b6716c950e17 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=b05d599656aeb1e1 input=a9049054013a1b77]*/ diff --git a/Modules/clinic/_asynciomodule.c.h b/Modules/clinic/_asynciomodule.c.h index 66953d74213b66..f07a09df5ac7ae 100644 --- a/Modules/clinic/_asynciomodule.c.h +++ b/Modules/clinic/_asynciomodule.c.h @@ -90,7 +90,8 @@ PyDoc_STRVAR(_asyncio_Future_result__doc__, "\n" "If the future has been cancelled, raises CancelledError. If the\n" "future\'s result isn\'t yet available, raises InvalidStateError. If\n" -"the future is done and has an exception set, this exception is raised."); +"the future is done and has an exception set, this exception is\n" +"raised."); #define _ASYNCIO_FUTURE_RESULT_METHODDEF \ {"result", (PyCFunction)_asyncio_Future_result, METH_NOARGS, _asyncio_Future_result__doc__}, @@ -250,8 +251,8 @@ PyDoc_STRVAR(_asyncio_Future_add_done_callback__doc__, "\n" "Add a callback to be run when the future becomes done.\n" "\n" -"The callback is called with a single argument - the future object. If\n" -"the future is already done when this is called, the callback is\n" +"The callback is called with a single argument - the future object.\n" +"If the future is already done when this is called, the callback is\n" "scheduled with call_soon."); #define _ASYNCIO_FUTURE_ADD_DONE_CALLBACK_METHODDEF \ @@ -371,9 +372,9 @@ PyDoc_STRVAR(_asyncio_Future_cancel__doc__, "\n" "Cancel the future and schedule callbacks.\n" "\n" -"If the future is already done or cancelled, return False. Otherwise,\n" -"change the future\'s state to cancelled, schedule the callbacks and\n" -"return True."); +"If the future is already done or cancelled, return False.\n" +"Otherwise, change the future\'s state to cancelled, schedule the\n" +"callbacks and return True."); #define _ASYNCIO_FUTURE_CANCEL_METHODDEF \ {"cancel", _PyCFunction_CAST(_asyncio_Future_cancel), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _asyncio_Future_cancel__doc__}, @@ -465,8 +466,8 @@ PyDoc_STRVAR(_asyncio_Future_done__doc__, "\n" "Return True if the future is done.\n" "\n" -"Done means either that a result / exception are available, or that the\n" -"future was cancelled."); +"Done means either that a result / exception are available, or that\n" +"the future was cancelled."); #define _ASYNCIO_FUTURE_DONE_METHODDEF \ {"done", (PyCFunction)_asyncio_Future_done, METH_NOARGS, _asyncio_Future_done__doc__}, @@ -2232,4 +2233,4 @@ _asyncio_future_discard_from_awaited_by(PyObject *module, PyObject *const *args, exit: return return_value; } -/*[clinic end generated code: output=b69948ed810591d9 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=32996fb47c48245b input=a9049054013a1b77]*/ diff --git a/Modules/clinic/_bisectmodule.c.h b/Modules/clinic/_bisectmodule.c.h index 8f3492cd54b5f2..454131faf4112b 100644 --- a/Modules/clinic/_bisectmodule.c.h +++ b/Modules/clinic/_bisectmodule.c.h @@ -16,8 +16,8 @@ PyDoc_STRVAR(_bisect_bisect_right__doc__, "Return the index where to insert item x in list a, assuming a is sorted.\n" "\n" "The return value i is such that all e in a[:i] have e <= x, and all e in\n" -"a[i:] have e > x. So if x already appears in the list, a.insert(i, x) will\n" -"insert just after the rightmost x already there.\n" +"a[i:] have e > x. So if x already appears in the list, a.insert(i, x)\n" +"will insert just after the rightmost x already there.\n" "\n" "Optional args lo (default 0) and hi (default len(a)) bound the\n" "slice of a to be searched.\n" @@ -245,8 +245,8 @@ PyDoc_STRVAR(_bisect_bisect_left__doc__, "Return the index where to insert item x in list a, assuming a is sorted.\n" "\n" "The return value i is such that all e in a[:i] have e < x, and all e in\n" -"a[i:] have e >= x. So if x already appears in the list, a.insert(i, x) will\n" -"insert just before the leftmost x already there.\n" +"a[i:] have e >= x. So if x already appears in the list, a.insert(i, x)\n" +"will insert just before the leftmost x already there.\n" "\n" "Optional args lo (default 0) and hi (default len(a)) bound the\n" "slice of a to be searched.\n" @@ -466,4 +466,4 @@ _bisect_insort_left(PyObject *module, PyObject *const *args, Py_ssize_t nargs, P exit: return return_value; } -/*[clinic end generated code: output=a3c44ed440dd6d81 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=62345f14c5c01639 input=a9049054013a1b77]*/ diff --git a/Modules/clinic/_bz2module.c.h b/Modules/clinic/_bz2module.c.h index 2bc6524b6a973b..30f2c7965e73ae 100644 --- a/Modules/clinic/_bz2module.c.h +++ b/Modules/clinic/_bz2module.c.h @@ -116,18 +116,19 @@ PyDoc_STRVAR(_bz2_BZ2Decompressor_decompress__doc__, "\n" "Decompress *data*, returning uncompressed data as bytes.\n" "\n" -"If *max_length* is nonnegative, returns at most *max_length* bytes of\n" -"decompressed data. If this limit is reached and further output can be\n" -"produced, *self.needs_input* will be set to ``False``. In this case, the next\n" -"call to *decompress()* may provide *data* as b\'\' to obtain more of the output.\n" +"If *max_length* is nonnegative, returns at most *max_length* bytes\n" +"of decompressed data. If this limit is reached and further output\n" +"can be produced, *self.needs_input* will be set to ``False``. In\n" +"this case, the next call to *decompress()* may provide *data* as b\'\'\n" +"to obtain more of the output.\n" "\n" -"If all of the input data was decompressed and returned (either because this\n" -"was less than *max_length* bytes, or because *max_length* was negative),\n" -"*self.needs_input* will be set to True.\n" +"If all of the input data was decompressed and returned (either\n" +"because this was less than *max_length* bytes, or because\n" +"*max_length* was negative), *self.needs_input* will be set to True.\n" "\n" -"Attempting to decompress data after the end of stream is reached raises an\n" -"EOFError. Any data found after the end of the stream is ignored and saved in\n" -"the unused_data attribute."); +"Attempting to decompress data after the end of stream is reached\n" +"raises an EOFError. Any data found after the end of the stream is\n" +"ignored and saved in the unused_data attribute."); #define _BZ2_BZ2DECOMPRESSOR_DECOMPRESS_METHODDEF \ {"decompress", _PyCFunction_CAST(_bz2_BZ2Decompressor_decompress), METH_FASTCALL|METH_KEYWORDS, _bz2_BZ2Decompressor_decompress__doc__}, @@ -237,4 +238,4 @@ _bz2_BZ2Decompressor(PyTypeObject *type, PyObject *args, PyObject *kwargs) exit: return return_value; } -/*[clinic end generated code: output=552ac6d4c5a101b7 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=1dce5396d592bad7 input=a9049054013a1b77]*/ diff --git a/Modules/clinic/_codecsmodule.c.h b/Modules/clinic/_codecsmodule.c.h index 9e2a7950ebde64..4a40dc660b621c 100644 --- a/Modules/clinic/_codecsmodule.c.h +++ b/Modules/clinic/_codecsmodule.c.h @@ -14,9 +14,10 @@ PyDoc_STRVAR(_codecs_register__doc__, "\n" "Register a codec search function.\n" "\n" -"Search functions are expected to take one argument, the encoding name in\n" -"all lower case letters, and either return None, or a tuple of functions\n" -"(encoder, decoder, stream_reader, stream_writer) (or a CodecInfo object)."); +"Search functions are expected to take one argument, the encoding\n" +"name in all lower case letters, and either return None, or a tuple\n" +"of functions (encoder, decoder, stream_reader, stream_writer) (or\n" +"a CodecInfo object)."); #define _CODECS_REGISTER_METHODDEF \ {"register", (PyCFunction)_codecs_register, METH_O, _codecs_register__doc__}, @@ -76,10 +77,10 @@ PyDoc_STRVAR(_codecs_encode__doc__, "Encodes obj using the codec registered for encoding.\n" "\n" "The default encoding is \'utf-8\'. errors may be given to set a\n" -"different error handling scheme. Default is \'strict\' meaning that encoding\n" -"errors raise a ValueError. Other possible values are \'ignore\', \'replace\'\n" -"and \'backslashreplace\' as well as any other name registered with\n" -"codecs.register_error that can handle ValueErrors."); +"different error handling scheme. Default is \'strict\' meaning that\n" +"encoding errors raise a ValueError. Other possible values are \'ignore\',\n" +"\'replace\' and \'backslashreplace\' as well as any other name registered\n" +"with codecs.register_error that can handle ValueErrors."); #define _CODECS_ENCODE_METHODDEF \ {"encode", _PyCFunction_CAST(_codecs_encode), METH_FASTCALL|METH_KEYWORDS, _codecs_encode__doc__}, @@ -179,10 +180,10 @@ PyDoc_STRVAR(_codecs_decode__doc__, "Decodes obj using the codec registered for encoding.\n" "\n" "Default encoding is \'utf-8\'. errors may be given to set a\n" -"different error handling scheme. Default is \'strict\' meaning that encoding\n" -"errors raise a ValueError. Other possible values are \'ignore\', \'replace\'\n" -"and \'backslashreplace\' as well as any other name registered with\n" -"codecs.register_error that can handle ValueErrors."); +"different error handling scheme. Default is \'strict\' meaning that\n" +"encoding errors raise a ValueError. Other possible values are \'ignore\',\n" +"\'replace\' and \'backslashreplace\' as well as any other name registered\n" +"with codecs.register_error that can handle ValueErrors."); #define _CODECS_DECODE_METHODDEF \ {"decode", _PyCFunction_CAST(_codecs_decode), METH_FASTCALL|METH_KEYWORDS, _codecs_decode__doc__}, @@ -2649,8 +2650,9 @@ PyDoc_STRVAR(_codecs_register_error__doc__, "Register the specified error handler under the name errors.\n" "\n" "handler must be a callable object, that will be called with an exception\n" -"instance containing information about the location of the encoding/decoding\n" -"error and must return a (replacement, new position) tuple."); +"instance containing information about the location of the\n" +"encoding/decoding error and must return a (replacement, new position)\n" +"tuple."); #define _CODECS_REGISTER_ERROR_METHODDEF \ {"register_error", _PyCFunction_CAST(_codecs_register_error), METH_FASTCALL, _codecs_register_error__doc__}, @@ -2745,8 +2747,8 @@ PyDoc_STRVAR(_codecs_lookup_error__doc__, "\n" "lookup_error(errors) -> handler\n" "\n" -"Return the error handler for the specified error handling name or raise a\n" -"LookupError, if no handler exists under this name."); +"Return the error handler for the specified error handling name or raise\n" +"a LookupError, if no handler exists under this name."); #define _CODECS_LOOKUP_ERROR_METHODDEF \ {"lookup_error", (PyCFunction)_codecs_lookup_error, METH_O, _codecs_lookup_error__doc__}, @@ -2866,4 +2868,4 @@ _codecs__normalize_encoding(PyObject *module, PyObject *const *args, Py_ssize_t #ifndef _CODECS_CODE_PAGE_ENCODE_METHODDEF #define _CODECS_CODE_PAGE_ENCODE_METHODDEF #endif /* !defined(_CODECS_CODE_PAGE_ENCODE_METHODDEF) */ -/*[clinic end generated code: output=a968c493bb28be3e input=a9049054013a1b77]*/ +/*[clinic end generated code: output=505edef891a06329 input=a9049054013a1b77]*/ diff --git a/Modules/clinic/_datetimemodule.c.h b/Modules/clinic/_datetimemodule.c.h index ee621c150c31e4..fac41e7aefc7f4 100644 --- a/Modules/clinic/_datetimemodule.c.h +++ b/Modules/clinic/_datetimemodule.c.h @@ -214,8 +214,8 @@ PyDoc_STRVAR(datetime_date_fromtimestamp__doc__, "\n" "Create a date from a POSIX timestamp.\n" "\n" -"The timestamp is a number, e.g. created via time.time(), that is interpreted\n" -"as local time."); +"The timestamp is a number, e.g. created via time.time(), that is\n" +"interpreted as local time."); #define DATETIME_DATE_FROMTIMESTAMP_METHODDEF \ {"fromtimestamp", (PyCFunction)datetime_date_fromtimestamp, METH_O|METH_CLASS, datetime_date_fromtimestamp__doc__}, @@ -897,8 +897,8 @@ PyDoc_STRVAR(datetime_time_isoformat__doc__, "\n" "Return the time formatted according to ISO.\n" "\n" -"The full format is \'HH:MM:SS.mmmmmm+zz:zz\'. By default, the fractional\n" -"part is omitted if self.microsecond == 0.\n" +"The full format is \'HH:MM:SS.mmmmmm+zz:zz\'. By default, the\n" +"fractional part is omitted if self.microsecond == 0.\n" "\n" "The optional argument timespec specifies the number of additional\n" "terms of the time to include. Valid options are \'auto\', \'hours\',\n" @@ -979,7 +979,8 @@ PyDoc_STRVAR(datetime_time_strftime__doc__, "\n" "Format using strftime().\n" "\n" -"The date part of the timestamp passed to underlying strftime should not be used.\n" +"The date part of the timestamp passed to underlying strftime should\n" +"not be used.\n" "\n" "For a list of supported format codes, see the documentation:\n" " https://docs.python.org/3/library/datetime.html#format-codes"); @@ -1269,8 +1270,8 @@ PyDoc_STRVAR(datetime_datetime__doc__, "\n" "A combination of a date and a time.\n" "\n" -"The year, month and day arguments are required. tzinfo may be None, or an\n" -"instance of a tzinfo subclass. The remaining arguments may be ints."); +"The year, month and day arguments are required. tzinfo may be None, or\n" +"an instance of a tzinfo subclass. The remaining arguments may be ints."); static PyObject * datetime_datetime_impl(PyTypeObject *type, int year, int month, int day, @@ -1491,8 +1492,8 @@ PyDoc_STRVAR(datetime_datetime_fromtimestamp__doc__, "\n" "Create a datetime from a POSIX timestamp.\n" "\n" -"The timestamp is a number, e.g. created via time.time(), that is interpreted\n" -"as local time."); +"The timestamp is a number, e.g. created via time.time(), that is\n" +"interpreted as local time."); #define DATETIME_DATETIME_FROMTIMESTAMP_METHODDEF \ {"fromtimestamp", _PyCFunction_CAST(datetime_datetime_fromtimestamp), METH_FASTCALL|METH_KEYWORDS|METH_CLASS, datetime_datetime_fromtimestamp__doc__}, @@ -2090,4 +2091,4 @@ datetime_datetime___reduce__(PyObject *self, PyObject *Py_UNUSED(ignored)) { return datetime_datetime___reduce___impl((PyDateTime_DateTime *)self); } -/*[clinic end generated code: output=69658acff6a43ac4 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=8f63509398651723 input=a9049054013a1b77]*/ diff --git a/Modules/clinic/_dbmmodule.c.h b/Modules/clinic/_dbmmodule.c.h index 091ce9edc43d4b..6c979a4b0081df 100644 --- a/Modules/clinic/_dbmmodule.c.h +++ b/Modules/clinic/_dbmmodule.c.h @@ -113,7 +113,8 @@ PyDoc_STRVAR(_dbm_dbm_setdefault__doc__, "\n" "Return the value for key if present, otherwise default.\n" "\n" -"If key is not in the database, it is inserted with default as the value."); +"If key is not in the database, it is inserted with default as the\n" +"value."); #define _DBM_DBM_SETDEFAULT_METHODDEF \ {"setdefault", _PyCFunction_CAST(_dbm_dbm_setdefault), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _dbm_dbm_setdefault__doc__}, @@ -246,4 +247,4 @@ dbmopen(PyObject *module, PyObject *const *args, Py_ssize_t nargs) exit: return return_value; } -/*[clinic end generated code: output=279511ea7cda38dd input=a9049054013a1b77]*/ +/*[clinic end generated code: output=677deecf525167a5 input=a9049054013a1b77]*/ diff --git a/Modules/clinic/_functoolsmodule.c.h b/Modules/clinic/_functoolsmodule.c.h index 87cdef2ad3cff3..5f350c864f057b 100644 --- a/Modules/clinic/_functoolsmodule.c.h +++ b/Modules/clinic/_functoolsmodule.c.h @@ -77,9 +77,9 @@ PyDoc_STRVAR(_functools_reduce__doc__, "\n" "Apply a function of two arguments cumulatively to the items of an iterable, from left to right.\n" "\n" -"This effectively reduces the iterable to a single value. If initial is present,\n" -"it is placed before the items of the iterable in the calculation, and serves as\n" -"a default when the iterable is empty.\n" +"This effectively reduces the iterable to a single value. If initial is\n" +"present, it is placed before the items of the iterable in the\n" +"calculation, and serves as a default when the iterable is empty.\n" "\n" "For example, reduce(lambda x, y: x+y, [1, 2, 3, 4, 5])\n" "calculates ((((1 + 2) + 3) + 4) + 5)."); @@ -193,4 +193,4 @@ _functools__lru_cache_wrapper_cache_clear(PyObject *self, PyObject *Py_UNUSED(ig return return_value; } -/*[clinic end generated code: output=ac9e26d0a5a23d40 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=6d8fdaeba4b520fa input=a9049054013a1b77]*/ diff --git a/Modules/clinic/_gdbmmodule.c.h b/Modules/clinic/_gdbmmodule.c.h index 6fd6aa3da50335..fe993cc328fbd2 100644 --- a/Modules/clinic/_gdbmmodule.c.h +++ b/Modules/clinic/_gdbmmodule.c.h @@ -138,9 +138,9 @@ PyDoc_STRVAR(_gdbm_gdbm_firstkey__doc__, "\n" "Return the starting key for the traversal.\n" "\n" -"It\'s possible to loop over every key in the database using this method\n" -"and the nextkey() method. The traversal is ordered by GDBM\'s internal\n" -"hash values, and won\'t be sorted by the key values."); +"It\'s possible to loop over every key in the database using this\n" +"method and the nextkey() method. The traversal is ordered by GDBM\'s\n" +"internal hash values, and won\'t be sorted by the key values."); #define _GDBM_GDBM_FIRSTKEY_METHODDEF \ {"firstkey", _PyCFunction_CAST(_gdbm_gdbm_firstkey), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _gdbm_gdbm_firstkey__doc__}, @@ -171,8 +171,8 @@ PyDoc_STRVAR(_gdbm_gdbm_nextkey__doc__, "\n" "Returns the key that follows key in the traversal.\n" "\n" -"The following code prints every key in the database db, without having\n" -"to create a list in memory that contains them all:\n" +"The following code prints every key in the database db, without\n" +"having to create a list in memory that contains them all:\n" "\n" " k = db.firstkey()\n" " while k is not None:\n" @@ -226,9 +226,9 @@ PyDoc_STRVAR(_gdbm_gdbm_reorganize__doc__, "\n" "If you have carried out a lot of deletions and would like to shrink\n" "the space used by the GDBM file, this routine will reorganize the\n" -"database. GDBM will not shorten the length of a database file except\n" -"by using this reorganization; otherwise, deleted file space will be\n" -"kept and reused as new (key,value) pairs are added."); +"database. GDBM will not shorten the length of a database file\n" +"except by using this reorganization; otherwise, deleted file space\n" +"will be kept and reused as new (key,value) pairs are added."); #define _GDBM_GDBM_REORGANIZE_METHODDEF \ {"reorganize", _PyCFunction_CAST(_gdbm_gdbm_reorganize), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _gdbm_gdbm_reorganize__doc__}, @@ -389,4 +389,4 @@ dbmopen(PyObject *module, PyObject *const *args, Py_ssize_t nargs) exit: return return_value; } -/*[clinic end generated code: output=8bca34ce9d4493dd input=a9049054013a1b77]*/ +/*[clinic end generated code: output=429b5db24568292e input=a9049054013a1b77]*/ diff --git a/Modules/clinic/_hashopenssl.c.h b/Modules/clinic/_hashopenssl.c.h index 7ae7be185eceb5..17ed37bbd3b619 100644 --- a/Modules/clinic/_hashopenssl.c.h +++ b/Modules/clinic/_hashopenssl.c.h @@ -1865,8 +1865,8 @@ PyDoc_STRVAR(_hashlib_HMAC_hexdigest__doc__, "\n" "Return hexadecimal digest of the bytes passed to the update() method so far.\n" "\n" -"This may be used to exchange the value safely in email or other non-binary\n" -"environments."); +"This may be used to exchange the value safely in email or other\n" +"non-binary environments."); #define _HASHLIB_HMAC_HEXDIGEST_METHODDEF \ {"hexdigest", (PyCFunction)_hashlib_HMAC_hexdigest, METH_NOARGS, _hashlib_HMAC_hexdigest__doc__}, @@ -1887,8 +1887,8 @@ PyDoc_STRVAR(_hashlib_get_fips_mode__doc__, "Determine the OpenSSL FIPS mode of operation.\n" "\n" "For OpenSSL 3.0.0 and newer it returns the state of the default provider\n" -"in the default OSSL context. It\'s not quite the same as FIPS_mode() but good\n" -"enough for unittests.\n" +"in the default OSSL context. It\'s not quite the same as FIPS_mode() but\n" +"good enough for unittests.\n" "\n" "Effectively any non-zero return value indicates FIPS mode;\n" "values other than 1 may have additional significance."); @@ -1986,4 +1986,4 @@ _hashlib_compare_digest(PyObject *module, PyObject *const *args, Py_ssize_t narg #ifndef _HASHLIB_OPENSSL_SHAKE_256_METHODDEF #define _HASHLIB_OPENSSL_SHAKE_256_METHODDEF #endif /* !defined(_HASHLIB_OPENSSL_SHAKE_256_METHODDEF) */ -/*[clinic end generated code: output=9ba35fcc33795b1e input=a9049054013a1b77]*/ +/*[clinic end generated code: output=cf405e652a340bb2 input=a9049054013a1b77]*/ diff --git a/Modules/clinic/_heapqmodule.c.h b/Modules/clinic/_heapqmodule.c.h index b43155b6c24e3c..f3b8256efc0221 100644 --- a/Modules/clinic/_heapqmodule.c.h +++ b/Modules/clinic/_heapqmodule.c.h @@ -326,8 +326,8 @@ PyDoc_STRVAR(_heapq_heappushpop_max__doc__, "\n" "Maxheap variant of heappushpop.\n" "\n" -"The combined action runs more efficiently than heappush_max() followed by\n" -"a separate call to heappop_max()."); +"The combined action runs more efficiently than heappush_max()\n" +"followed by a separate call to heappop_max()."); #define _HEAPQ_HEAPPUSHPOP_MAX_METHODDEF \ {"heappushpop_max", _PyCFunction_CAST(_heapq_heappushpop_max), METH_FASTCALL, _heapq_heappushpop_max__doc__}, @@ -358,4 +358,4 @@ _heapq_heappushpop_max(PyObject *module, PyObject *const *args, Py_ssize_t nargs exit: return return_value; } -/*[clinic end generated code: output=e83d50002c29a96d input=a9049054013a1b77]*/ +/*[clinic end generated code: output=21e4f248ef6e83d6 input=a9049054013a1b77]*/ diff --git a/Modules/clinic/_interpqueuesmodule.c.h b/Modules/clinic/_interpqueuesmodule.c.h index 3f08a0cb6d36ab..6f27ea73b8866f 100644 --- a/Modules/clinic/_interpqueuesmodule.c.h +++ b/Modules/clinic/_interpqueuesmodule.c.h @@ -109,7 +109,8 @@ PyDoc_STRVAR(_interpqueues_destroy__doc__, "\n" "Clear and destroy the queue.\n" "\n" -"Afterward attempts to use the queue will behave as though it never existed."); +"Afterward attempts to use the queue will behave as though it never\n" +"existed."); #define _INTERPQUEUES_DESTROY_METHODDEF \ {"destroy", _PyCFunction_CAST(_interpqueues_destroy), METH_FASTCALL|METH_KEYWORDS, _interpqueues_destroy__doc__}, @@ -762,4 +763,4 @@ _interpqueues__register_heap_types(PyObject *module, PyObject *const *args, Py_s exit: return return_value; } -/*[clinic end generated code: output=64cea8e1063429b6 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=7e56e5b0c684d294 input=a9049054013a1b77]*/ diff --git a/Modules/clinic/_interpretersmodule.c.h b/Modules/clinic/_interpretersmodule.c.h index d70ffcea527895..72792f9b583a66 100644 --- a/Modules/clinic/_interpretersmodule.c.h +++ b/Modules/clinic/_interpretersmodule.c.h @@ -541,7 +541,8 @@ PyDoc_STRVAR(_interpreters_run_func__doc__, "Execute the body of the provided function in the identified interpreter.\n" "\n" "Code objects are also supported. In both cases, closures and args\n" -"are not supported. Methods and other callables are not supported either.\n" +"are not supported. Methods and other callables are not supported\n" +"either.\n" "\n" "(See _interpreters.exec().)"); @@ -1139,8 +1140,9 @@ PyDoc_STRVAR(_interpreters_capture_exception__doc__, "\n" "Return a snapshot of an exception.\n" "\n" -"If \"exc\" is None then the current exception, if any, is used (but not cleared).\n" -"The returned snapshot is the same as what _interpreters.exec() returns."); +"If \"exc\" is None then the current exception, if any, is used (but not\n" +"cleared). The returned snapshot is the same as what\n" +"_interpreters.exec() returns."); #define _INTERPRETERS_CAPTURE_EXCEPTION_METHODDEF \ {"capture_exception", _PyCFunction_CAST(_interpreters_capture_exception), METH_FASTCALL|METH_KEYWORDS, _interpreters_capture_exception__doc__}, @@ -1198,4 +1200,4 @@ _interpreters_capture_exception(PyObject *module, PyObject *const *args, Py_ssiz exit: return return_value; } -/*[clinic end generated code: output=c80f73761f860f6c input=a9049054013a1b77]*/ +/*[clinic end generated code: output=8c3ca09c304378ad input=a9049054013a1b77]*/ diff --git a/Modules/clinic/_json.c.h b/Modules/clinic/_json.c.h index cd37a236c7611a..d3ed1dfe0515a0 100644 --- a/Modules/clinic/_json.c.h +++ b/Modules/clinic/_json.c.h @@ -16,8 +16,8 @@ PyDoc_STRVAR(py_scanstring__doc__, "ValueError on attempt to decode an invalid string. If strict is False\n" "then literal control characters are allowed in the string.\n" "\n" -"Returns a tuple of the decoded string and the index of the character in s\n" -"after the end quote."); +"Returns a tuple of the decoded string and the index of the character in\n" +"s after the end quote."); #define PY_SCANSTRING_METHODDEF \ {"scanstring", _PyCFunction_CAST(py_scanstring), METH_FASTCALL, py_scanstring__doc__}, @@ -125,4 +125,4 @@ py_encode_basestring(PyObject *module, PyObject *arg) exit: return return_value; } -/*[clinic end generated code: output=5bdd16375c95a4d9 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=ea6e9a271d4ceaf2 input=a9049054013a1b77]*/ diff --git a/Modules/clinic/_lzmamodule.c.h b/Modules/clinic/_lzmamodule.c.h index ebdc81a0dac2f0..bba107e8f806da 100644 --- a/Modules/clinic/_lzmamodule.c.h +++ b/Modules/clinic/_lzmamodule.c.h @@ -74,18 +74,19 @@ PyDoc_STRVAR(_lzma_LZMADecompressor_decompress__doc__, "\n" "Decompress *data*, returning uncompressed data as bytes.\n" "\n" -"If *max_length* is nonnegative, returns at most *max_length* bytes of\n" -"decompressed data. If this limit is reached and further output can be\n" -"produced, *self.needs_input* will be set to ``False``. In this case, the next\n" -"call to *decompress()* may provide *data* as b\'\' to obtain more of the output.\n" +"If *max_length* is nonnegative, returns at most *max_length* bytes\n" +"of decompressed data. If this limit is reached and further output\n" +"can be produced, *self.needs_input* will be set to ``False``. In\n" +"this case, the next call to *decompress()* may provide *data* as b\'\'\n" +"to obtain more of the output.\n" "\n" -"If all of the input data was decompressed and returned (either because this\n" -"was less than *max_length* bytes, or because *max_length* was negative),\n" -"*self.needs_input* will be set to True.\n" +"If all of the input data was decompressed and returned (either\n" +"because this was less than *max_length* bytes, or because\n" +"*max_length* was negative), *self.needs_input* will be set to True.\n" "\n" -"Attempting to decompress data after the end of stream is reached raises an\n" -"EOFError. Any data found after the end of the stream is ignored and saved in\n" -"the unused_data attribute."); +"Attempting to decompress data after the end of stream is reached\n" +"raises an EOFError. Any data found after the end of the stream is\n" +"ignored and saved in the unused_data attribute."); #define _LZMA_LZMADECOMPRESSOR_DECOMPRESS_METHODDEF \ {"decompress", _PyCFunction_CAST(_lzma_LZMADecompressor_decompress), METH_FASTCALL|METH_KEYWORDS, _lzma_LZMADecompressor_decompress__doc__}, @@ -333,4 +334,4 @@ _lzma__decode_filter_properties(PyObject *module, PyObject *const *args, Py_ssiz return return_value; } -/*[clinic end generated code: output=6386084cb43d2533 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=ffc6d673d858048c input=a9049054013a1b77]*/ diff --git a/Modules/clinic/_posixsubprocess.c.h b/Modules/clinic/_posixsubprocess.c.h index d52629cf6eaa5b..e7e9707f182a2e 100644 --- a/Modules/clinic/_posixsubprocess.c.h +++ b/Modules/clinic/_posixsubprocess.c.h @@ -14,15 +14,15 @@ PyDoc_STRVAR(subprocess_fork_exec__doc__, "\n" "Spawn a fresh new child process.\n" "\n" -"Fork a child process, close parent file descriptors as appropriate in the\n" -"child and duplicate the few that are needed before calling exec() in the\n" -"child process.\n" +"Fork a child process, close parent file descriptors as appropriate in\n" +"the child and duplicate the few that are needed before calling exec() in\n" +"the child process.\n" "\n" -"If close_fds is True, close file descriptors 3 and higher, except those listed\n" -"in the sorted tuple pass_fds.\n" +"If close_fds is True, close file descriptors 3 and higher, except those\n" +"listed in the sorted tuple pass_fds.\n" "\n" -"The preexec_fn, if supplied, will be called immediately before closing file\n" -"descriptors and exec.\n" +"The preexec_fn, if supplied, will be called immediately before closing\n" +"file descriptors and exec.\n" "\n" "WARNING: preexec_fn is NOT SAFE if your application uses threads.\n" " It may trigger infrequent, difficult to debug deadlocks.\n" @@ -150,4 +150,4 @@ subprocess_fork_exec(PyObject *module, PyObject *const *args, Py_ssize_t nargs) exit: return return_value; } -/*[clinic end generated code: output=942bc2748a9c2785 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=138941c284792aa1 input=a9049054013a1b77]*/ diff --git a/Modules/clinic/_queuemodule.c.h b/Modules/clinic/_queuemodule.c.h index c9482f40acb9d4..b67dd23f260c9e 100644 --- a/Modules/clinic/_queuemodule.c.h +++ b/Modules/clinic/_queuemodule.c.h @@ -44,8 +44,9 @@ PyDoc_STRVAR(_queue_SimpleQueue_put__doc__, "\n" "Put the item on the queue.\n" "\n" -"The optional \'block\' and \'timeout\' arguments are ignored, as this method\n" -"never blocks. They are provided for compatibility with the Queue class."); +"The optional \'block\' and \'timeout\' arguments are ignored, as this\n" +"method never blocks. They are provided for compatibility with the\n" +"Queue class."); #define _QUEUE_SIMPLEQUEUE_PUT_METHODDEF \ {"put", _PyCFunction_CAST(_queue_SimpleQueue_put), METH_FASTCALL|METH_KEYWORDS, _queue_SimpleQueue_put__doc__}, @@ -188,10 +189,11 @@ PyDoc_STRVAR(_queue_SimpleQueue_get__doc__, "\n" "Remove and return an item from the queue.\n" "\n" -"If optional args \'block\' is true and \'timeout\' is None (the default),\n" -"block if necessary until an item is available. If \'timeout\' is\n" -"a non-negative number, it blocks at most \'timeout\' seconds and raises\n" -"the Empty exception if no item was available within that time.\n" +"If optional args \'block\' is true and \'timeout\' is None (the\n" +"default), block if necessary until an item is available. If\n" +"\'timeout\' is a non-negative number, it blocks at most \'timeout\'\n" +"seconds and raises the Empty exception if no item was available\n" +"within that time.\n" "Otherwise (\'block\' is false), return an item if one is immediately\n" "available, else raise the Empty exception (\'timeout\' is ignored\n" "in that case)."); @@ -388,4 +390,4 @@ _queue_SimpleQueue___sizeof__(PyObject *self, PyObject *Py_UNUSED(ignored)) exit: return return_value; } -/*[clinic end generated code: output=4af5d1b1ea31ac7d input=a9049054013a1b77]*/ +/*[clinic end generated code: output=8219fe2f2ed5f068 input=a9049054013a1b77]*/ diff --git a/Modules/clinic/_ssl.c.h b/Modules/clinic/_ssl.c.h index 8c35c8443b775a..e337ed2390a1fc 100644 --- a/Modules/clinic/_ssl.c.h +++ b/Modules/clinic/_ssl.c.h @@ -334,9 +334,10 @@ _ssl__SSLSocket_compression(PyObject *self, PyObject *Py_UNUSED(ignored)) PyDoc_STRVAR(_ssl__SSLSocket_context__doc__, "This changes the context associated with the SSLSocket.\n" "\n" -"This is typically used from within a callback function set by the sni_callback\n" -"on the SSLContext to change the certificate information associated with the\n" -"SSLSocket before the cryptographic exchange handshake messages."); +"This is typically used from within a callback function set by the\n" +"sni_callback on the SSLContext to change the certificate information\n" +"associated with the SSLSocket before the cryptographic exchange\n" +"handshake messages."); #if defined(_ssl__SSLSocket_context_DOCSTR) # undef _ssl__SSLSocket_context_DOCSTR #endif @@ -571,9 +572,9 @@ PyDoc_STRVAR(_ssl__SSLSocket_sendfile__doc__, "\n" "Write size bytes from offset in the file descriptor fd to the SSL connection.\n" "\n" -"This method uses the zero-copy technique and returns the number of bytes\n" -"written. It should be called only when Kernel TLS is used for sending data in\n" -"the connection.\n" +"This method uses the zero-copy technique and returns the number of\n" +"bytes written. It should be called only when Kernel TLS is used for\n" +"sending data in the connection.\n" "\n" "The meaning of flags is platform dependent."); @@ -762,8 +763,9 @@ PyDoc_STRVAR(_ssl__SSLSocket_get_channel_binding__doc__, "\n" "Get channel binding data for current connection.\n" "\n" -"Raise ValueError if the requested `cb_type` is not supported. Return bytes\n" -"of the data or None if the data is not available (e.g. before the handshake).\n" +"Raise ValueError if the requested `cb_type` is not supported.\n" +"Return bytes of the data or None if the data is not available (e.g.\n" +"before the handshake).\n" "Only \'tls-unique\' channel binding data from RFC 5929 is supported."); #define _SSL__SSLSOCKET_GET_CHANNEL_BINDING_METHODDEF \ @@ -2210,8 +2212,9 @@ _ssl__SSLContext_set_ecdh_curve(PyObject *self, PyObject *name) PyDoc_STRVAR(_ssl__SSLContext_sni_callback__doc__, "Set a callback that will be called when a server name is provided by the SSL/TLS client in the SNI extension.\n" "\n" -"If the argument is None then the callback is disabled. The method is called\n" -"with the SSLSocket, the server name as a string, and the SSLContext object.\n" +"If the argument is None then the callback is disabled. The method\n" +"is called with the SSLSocket, the server name as a string, and the\n" +"SSLContext object.\n" "\n" "See RFC 6066 for details of the SNI extension."); #if defined(_ssl__SSLContext_sni_callback_DOCSTR) @@ -2275,11 +2278,11 @@ PyDoc_STRVAR(_ssl__SSLContext_cert_store_stats__doc__, "\n" "Returns quantities of loaded X.509 certificates.\n" "\n" -"X.509 certificates with a CA extension and certificate revocation lists\n" -"inside the context\'s cert store.\n" +"X.509 certificates with a CA extension and certificate revocation\n" +"lists inside the context\'s cert store.\n" "\n" -"NOTE: Certificates in a capath directory aren\'t loaded unless they have\n" -"been used at least once."); +"NOTE: Certificates in a capath directory aren\'t loaded unless they\n" +"have been used at least once."); #define _SSL__SSLCONTEXT_CERT_STORE_STATS_METHODDEF \ {"cert_store_stats", (PyCFunction)_ssl__SSLContext_cert_store_stats, METH_NOARGS, _ssl__SSLContext_cert_store_stats__doc__}, @@ -2305,11 +2308,11 @@ PyDoc_STRVAR(_ssl__SSLContext_get_ca_certs__doc__, "\n" "Returns a list of dicts with information of loaded CA certs.\n" "\n" -"If the optional argument is True, returns a DER-encoded copy of the CA\n" -"certificate.\n" +"If the optional argument is True, returns a DER-encoded copy of the\n" +"CA certificate.\n" "\n" -"NOTE: Certificates in a capath directory aren\'t loaded unless they have\n" -"been used at least once."); +"NOTE: Certificates in a capath directory aren\'t loaded unless they\n" +"have been used at least once."); #define _SSL__SSLCONTEXT_GET_CA_CERTS_METHODDEF \ {"get_ca_certs", _PyCFunction_CAST(_ssl__SSLContext_get_ca_certs), METH_FASTCALL|METH_KEYWORDS, _ssl__SSLContext_get_ca_certs__doc__}, @@ -2970,8 +2973,8 @@ PyDoc_STRVAR(_ssl_RAND_status__doc__, "\n" "Returns True if the OpenSSL PRNG has been seeded with enough data and False if not.\n" "\n" -"It is necessary to seed the PRNG with RAND_add() on some platforms before\n" -"using the ssl() function."); +"It is necessary to seed the PRNG with RAND_add() on some platforms\n" +"before using the ssl() function."); #define _SSL_RAND_STATUS_METHODDEF \ {"RAND_status", (PyCFunction)_ssl_RAND_status, METH_NOARGS, _ssl_RAND_status__doc__}, @@ -3157,11 +3160,11 @@ PyDoc_STRVAR(_ssl_enum_certificates__doc__, "\n" "Retrieve certificates from Windows\' cert store.\n" "\n" -"store_name may be one of \'CA\', \'ROOT\' or \'MY\'. The system may provide\n" -"more cert storages, too. The function returns a list of (bytes,\n" -"encoding_type, trust) tuples. The encoding_type flag can be interpreted\n" -"with X509_ASN_ENCODING or PKCS_7_ASN_ENCODING. The trust setting is either\n" -"a set of OIDs or the boolean True."); +"store_name may be one of \'CA\', \'ROOT\' or \'MY\'. The system may\n" +"provide more cert storages, too. The function returns a list of\n" +"(bytes, encoding_type, trust) tuples. The encoding_type flag can be\n" +"interpreted with X509_ASN_ENCODING or PKCS_7_ASN_ENCODING. The\n" +"trust setting is either a set of OIDs or the boolean True."); #define _SSL_ENUM_CERTIFICATES_METHODDEF \ {"enum_certificates", _PyCFunction_CAST(_ssl_enum_certificates), METH_FASTCALL|METH_KEYWORDS, _ssl_enum_certificates__doc__}, @@ -3323,4 +3326,4 @@ _ssl_enum_crls(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObje #ifndef _SSL_ENUM_CRLS_METHODDEF #define _SSL_ENUM_CRLS_METHODDEF #endif /* !defined(_SSL_ENUM_CRLS_METHODDEF) */ -/*[clinic end generated code: output=e29d5ada294f97bb input=a9049054013a1b77]*/ +/*[clinic end generated code: output=aef2e74b706c6106 input=a9049054013a1b77]*/ diff --git a/Modules/clinic/_testmultiphase.c.h b/Modules/clinic/_testmultiphase.c.h index 311b6409476711..a0e4c66451101e 100644 --- a/Modules/clinic/_testmultiphase.c.h +++ b/Modules/clinic/_testmultiphase.c.h @@ -14,8 +14,8 @@ PyDoc_STRVAR(_testmultiphase_StateAccessType_get_defining_module__doc__, "\n" "Return the module of the defining class.\n" "\n" -"Also tests that result of PyType_GetModuleByDef matches defining_class\'s\n" -"module."); +"Also tests that result of PyType_GetModuleByDef matches\n" +"defining_class\'s module."); #define _TESTMULTIPHASE_STATEACCESSTYPE_GET_DEFINING_MODULE_METHODDEF \ {"get_defining_module", _PyCFunction_CAST(_testmultiphase_StateAccessType_get_defining_module), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _testmultiphase_StateAccessType_get_defining_module__doc__}, @@ -165,4 +165,4 @@ _testmultiphase_StateAccessType_get_count(PyObject *self, PyTypeObject *cls, PyO } return _testmultiphase_StateAccessType_get_count_impl((StateAccessTypeObject *)self, cls); } -/*[clinic end generated code: output=8eed2f14292ec986 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=aff91f6219a7baca input=a9049054013a1b77]*/ diff --git a/Modules/clinic/_threadmodule.c.h b/Modules/clinic/_threadmodule.c.h index 8455f9929babc1..926bea8e1e419a 100644 --- a/Modules/clinic/_threadmodule.c.h +++ b/Modules/clinic/_threadmodule.c.h @@ -14,8 +14,8 @@ PyDoc_STRVAR(_thread_lock_acquire__doc__, "\n" "Lock the lock.\n" "\n" -"Without argument, this blocks if the lock is already\n" -"locked (even by the same thread), waiting for another thread to release\n" +"Without argument, this blocks if the lock is already locked\n" +"(even by the same thread), waiting for another thread to release\n" "the lock, and return True once the lock is acquired.\n" "With an argument, this will only block if the argument is true,\n" "and the return value reflects whether the lock is acquired.\n" @@ -445,14 +445,14 @@ PyDoc_STRVAR(_thread_RLock_release__doc__, "\n" "Release the lock.\n" "\n" -"Allows another thread that is blocked waiting for\n" -"the lock to acquire the lock. The lock must be in the locked state,\n" +"Allows another thread that is blocked waiting for the lock\n" +"to acquire the lock. The lock must be in the locked state,\n" "and must be locked by the same thread that unlocks it; otherwise a\n" "`RuntimeError` is raised.\n" "\n" -"Do note that if the lock was acquire()d several times in a row by the\n" -"current thread, release() needs to be called as many times for the lock\n" -"to be available for other threads."); +"Do note that if the lock was acquire()d several times in a row by\n" +"the current thread, release() needs to be called as many times for\n" +"the lock to be available for other threads."); #define _THREAD_RLOCK_RELEASE_METHODDEF \ {"release", (PyCFunction)_thread_RLock_release, METH_NOARGS, _thread_RLock_release__doc__}, @@ -740,4 +740,4 @@ _thread_set_name(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyOb #ifndef _THREAD_SET_NAME_METHODDEF #define _THREAD_SET_NAME_METHODDEF #endif /* !defined(_THREAD_SET_NAME_METHODDEF) */ -/*[clinic end generated code: output=1255a1520f43f97a input=a9049054013a1b77]*/ +/*[clinic end generated code: output=0f1707cbafc0e8f2 input=a9049054013a1b77]*/ diff --git a/Modules/clinic/_tkinter.c.h b/Modules/clinic/_tkinter.c.h index 352c2b9e3d410c..3147cf7f9d2cff 100644 --- a/Modules/clinic/_tkinter.c.h +++ b/Modules/clinic/_tkinter.c.h @@ -907,7 +907,8 @@ PyDoc_STRVAR(_tkinter_setbusywaitinterval__doc__, "\n" "Set the busy-wait interval in milliseconds between successive calls to Tcl_DoOneEvent in a threaded Python interpreter.\n" "\n" -"It should be set to a divisor of the maximum time between frames in an animation."); +"It should be set to a divisor of the maximum time between frames in\n" +"an animation."); #define _TKINTER_SETBUSYWAITINTERVAL_METHODDEF \ {"setbusywaitinterval", (PyCFunction)_tkinter_setbusywaitinterval, METH_O, _tkinter_setbusywaitinterval__doc__}, @@ -966,4 +967,4 @@ _tkinter_getbusywaitinterval(PyObject *module, PyObject *Py_UNUSED(ignored)) #ifndef _TKINTER_TKAPP_DELETEFILEHANDLER_METHODDEF #define _TKINTER_TKAPP_DELETEFILEHANDLER_METHODDEF #endif /* !defined(_TKINTER_TKAPP_DELETEFILEHANDLER_METHODDEF) */ -/*[clinic end generated code: output=052c067aa69237be input=a9049054013a1b77]*/ +/*[clinic end generated code: output=c807adb73e305725 input=a9049054013a1b77]*/ diff --git a/Modules/clinic/arraymodule.c.h b/Modules/clinic/arraymodule.c.h index eec47ab2b1f9e1..1e9f317853d6c2 100644 --- a/Modules/clinic/arraymodule.c.h +++ b/Modules/clinic/arraymodule.c.h @@ -292,8 +292,8 @@ PyDoc_STRVAR(array_array_buffer_info__doc__, "\n" "Return a tuple (address, length) giving the current memory address and the length in items of the buffer used to hold array\'s contents.\n" "\n" -"The length should be multiplied by the itemsize attribute to calculate\n" -"the buffer length in bytes."); +"The length should be multiplied by the itemsize attribute to\n" +"calculate the buffer length in bytes."); #define ARRAY_ARRAY_BUFFER_INFO_METHODDEF \ {"buffer_info", (PyCFunction)array_array_buffer_info, METH_NOARGS, array_array_buffer_info__doc__}, @@ -335,8 +335,8 @@ PyDoc_STRVAR(array_array_byteswap__doc__, "\n" "Byteswap all items of the array.\n" "\n" -"If the items in the array are not 1, 2, 4, 8 or 16 bytes in size, RuntimeError\n" -"is raised. Note, that for complex types the order of\n" +"If the items in the array are not 1, 2, 4, 8 or 16 bytes in size,\n" +"RuntimeError is raised. Note, that for complex types the order of\n" "components (the real part, followed by imaginary part) is preserved."); #define ARRAY_ARRAY_BYTESWAP_METHODDEF \ @@ -572,9 +572,9 @@ PyDoc_STRVAR(array_array_fromunicode__doc__, "\n" "Extends this array with data from the unicode string ustr.\n" "\n" -"The array must be a unicode type array; otherwise a ValueError is raised.\n" -"Use array.frombytes(ustr.encode(...)) to append Unicode data to an array of\n" -"some other type."); +"The array must be a unicode type array; otherwise a ValueError is\n" +"raised. Use array.frombytes(ustr.encode(...)) to append Unicode\n" +"data to an array of some other type."); #define ARRAY_ARRAY_FROMUNICODE_METHODDEF \ {"fromunicode", (PyCFunction)array_array_fromunicode, METH_O, array_array_fromunicode__doc__}, @@ -605,9 +605,10 @@ PyDoc_STRVAR(array_array_tounicode__doc__, "\n" "Extends this array with data from the unicode string ustr.\n" "\n" -"Convert the array to a unicode string. The array must be a unicode type array;\n" -"otherwise a ValueError is raised. Use array.tobytes().decode() to obtain a\n" -"unicode string from an array of some other type."); +"Convert the array to a unicode string. The array must be a unicode\n" +"type array; otherwise a ValueError is raised. Use\n" +"array.tobytes().decode() to obtain a unicode string from an array of\n" +"some other type."); #define ARRAY_ARRAY_TOUNICODE_METHODDEF \ {"tounicode", (PyCFunction)array_array_tounicode, METH_NOARGS, array_array_tounicode__doc__}, @@ -780,4 +781,4 @@ array_arrayiterator___setstate__(PyObject *self, PyObject *state) return return_value; } -/*[clinic end generated code: output=8699475b51151247 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=32784678e77ac658 input=a9049054013a1b77]*/ diff --git a/Modules/clinic/cmathmodule.c.h b/Modules/clinic/cmathmodule.c.h index 7f9e65baf120ea..ecb5257cf6b240 100644 --- a/Modules/clinic/cmathmodule.c.h +++ b/Modules/clinic/cmathmodule.c.h @@ -644,7 +644,8 @@ PyDoc_STRVAR(cmath_log__doc__, "\n" "log(z[, base]) -> the logarithm of z to the given base.\n" "\n" -"If the base is not specified, returns the natural logarithm (base e) of z."); +"If the base is not specified, returns the natural logarithm (base e)\n" +"of z."); #define CMATH_LOG_METHODDEF \ {"log", _PyCFunction_CAST(cmath_log), METH_FASTCALL, cmath_log__doc__}, @@ -882,11 +883,12 @@ PyDoc_STRVAR(cmath_isclose__doc__, "\n" "Return True if a is close in value to b, and False otherwise.\n" "\n" -"For the values to be considered close, the difference between them must be\n" -"smaller than at least one of the tolerances.\n" +"For the values to be considered close, the difference between them must\n" +"be smaller than at least one of the tolerances.\n" "\n" -"-inf, inf and NaN behave similarly to the IEEE 754 Standard. That is, NaN is\n" -"not close to anything, even itself. inf and -inf are only close to themselves."); +"-inf, inf and NaN behave similarly to the IEEE 754 Standard. That is,\n" +"NaN is not close to anything, even itself. inf and -inf are only close\n" +"to themselves."); #define CMATH_ISCLOSE_METHODDEF \ {"isclose", _PyCFunction_CAST(cmath_isclose), METH_FASTCALL|METH_KEYWORDS, cmath_isclose__doc__}, @@ -985,4 +987,4 @@ cmath_isclose(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObjec exit: return return_value; } -/*[clinic end generated code: output=631db17fb1c79d66 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=7d5ad4cf258526cd input=a9049054013a1b77]*/ diff --git a/Modules/clinic/faulthandler.c.h b/Modules/clinic/faulthandler.c.h index e06cfdcfba2993..07a9dd7dc561e1 100644 --- a/Modules/clinic/faulthandler.c.h +++ b/Modules/clinic/faulthandler.c.h @@ -334,9 +334,9 @@ PyDoc_STRVAR(faulthandler_dump_traceback_later__doc__, "\n" "Dump the traceback of all threads in timeout seconds.\n" "\n" -"If repeat is true, the tracebacks of all threads are dumped every timeout\n" -"seconds. If exit is true, call _exit(1) which is not safe. max_threads\n" -"caps the number of threads dumped."); +"If repeat is true, the tracebacks of all threads are dumped every\n" +"timeout seconds. If exit is true, call _exit(1) which is not safe.\n" +"max_threads caps the number of threads dumped."); #define FAULTHANDLER_DUMP_TRACEBACK_LATER_METHODDEF \ {"dump_traceback_later", _PyCFunction_CAST(faulthandler_dump_traceback_later), METH_FASTCALL|METH_KEYWORDS, faulthandler_dump_traceback_later__doc__}, @@ -782,4 +782,4 @@ faulthandler__raise_exception(PyObject *module, PyObject *const *args, Py_ssize_ #ifndef FAULTHANDLER__RAISE_EXCEPTION_METHODDEF #define FAULTHANDLER__RAISE_EXCEPTION_METHODDEF #endif /* !defined(FAULTHANDLER__RAISE_EXCEPTION_METHODDEF) */ -/*[clinic end generated code: output=2452d767c85130a6 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=14815a5f8afe813f input=a9049054013a1b77]*/ diff --git a/Modules/clinic/gcmodule.c.h b/Modules/clinic/gcmodule.c.h index 08275e35413f66..aa743c8f40a565 100644 --- a/Modules/clinic/gcmodule.c.h +++ b/Modules/clinic/gcmodule.c.h @@ -376,8 +376,8 @@ PyDoc_STRVAR(gc_get_objects__doc__, " generation\n" " Generation to extract the objects from.\n" "\n" -"If generation is not None, return only the objects tracked by the collector\n" -"that are in that generation."); +"If generation is not None, return only the objects tracked by the\n" +"collector that are in that generation."); #define GC_GET_OBJECTS_METHODDEF \ {"get_objects", _PyCFunction_CAST(gc_get_objects), METH_FASTCALL|METH_KEYWORDS, gc_get_objects__doc__}, @@ -520,9 +520,10 @@ PyDoc_STRVAR(gc_freeze__doc__, "\n" "Freeze all current tracked objects and ignore them for future collections.\n" "\n" -"This can be used before a POSIX fork() call to make the gc copy-on-write friendly.\n" -"Note: collection before a POSIX fork() call may free pages for future allocation\n" -"which can cause copy-on-write."); +"This can be used before a POSIX fork() call to make the gc copy-on-write\n" +"friendly.\n" +"Note: collection before a POSIX fork() call may free pages for future\n" +"allocation which can cause copy-on-write."); #define GC_FREEZE_METHODDEF \ {"freeze", (PyCFunction)gc_freeze, METH_NOARGS, gc_freeze__doc__}, @@ -583,4 +584,4 @@ gc_get_freeze_count(PyObject *module, PyObject *Py_UNUSED(ignored)) exit: return return_value; } -/*[clinic end generated code: output=19738854607938db input=a9049054013a1b77]*/ +/*[clinic end generated code: output=756c0e7719b76971 input=a9049054013a1b77]*/ diff --git a/Modules/clinic/hmacmodule.c.h b/Modules/clinic/hmacmodule.c.h index 1ceb2d809e830a..a31d2ab7f04463 100644 --- a/Modules/clinic/hmacmodule.c.h +++ b/Modules/clinic/hmacmodule.c.h @@ -187,8 +187,8 @@ PyDoc_STRVAR(_hmac_HMAC_hexdigest__doc__, "\n" "Return hexadecimal digest of the bytes passed to the update() method so far.\n" "\n" -"This may be used to exchange the value safely in email or other non-binary\n" -"environments.\n" +"This may be used to exchange the value safely in email or other\n" +"non-binary environments.\n" "\n" "This method may raise a MemoryError."); @@ -670,4 +670,4 @@ _hmac_compute_blake2b_32(PyObject *module, PyObject *const *args, Py_ssize_t nar exit: return return_value; } -/*[clinic end generated code: output=30c0614482d963f5 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=6ec5948df1c5569a input=a9049054013a1b77]*/ diff --git a/Modules/clinic/itertoolsmodule.c.h b/Modules/clinic/itertoolsmodule.c.h index 49816bfcb42fec..d9917b47dc9037 100644 --- a/Modules/clinic/itertoolsmodule.c.h +++ b/Modules/clinic/itertoolsmodule.c.h @@ -814,8 +814,8 @@ PyDoc_STRVAR(itertools_compress__doc__, "\n" "Return data elements corresponding to true selector elements.\n" "\n" -"Forms a shorter iterator from selected data elements using the selectors to\n" -"choose the data elements."); +"Forms a shorter iterator from selected data elements using the selectors\n" +"to choose the data elements."); static PyObject * itertools_compress_impl(PyTypeObject *type, PyObject *seq1, PyObject *seq2); @@ -980,4 +980,4 @@ itertools_count(PyTypeObject *type, PyObject *args, PyObject *kwargs) exit: return return_value; } -/*[clinic end generated code: output=7f385837b13edbeb input=a9049054013a1b77]*/ +/*[clinic end generated code: output=a34a31f60100e0ff input=a9049054013a1b77]*/ diff --git a/Modules/clinic/mathmodule.c.h b/Modules/clinic/mathmodule.c.h index b023299dd9cb2d..6a1b1a45d1d93a 100644 --- a/Modules/clinic/mathmodule.c.h +++ b/Modules/clinic/mathmodule.c.h @@ -1043,8 +1043,8 @@ PyDoc_STRVAR(math_nextafter__doc__, "\n" "If steps is not specified or is None, it defaults to 1.\n" "\n" -"Raises a TypeError, if x or y is not a double, or if steps is not an integer.\n" -"Raises ValueError if steps is negative."); +"Raises a TypeError, if x or y is not a double, or if steps is not\n" +"an integer. Raises ValueError if steps is negative."); #define MATH_NEXTAFTER_METHODDEF \ {"nextafter", _PyCFunction_CAST(math_nextafter), METH_FASTCALL|METH_KEYWORDS, math_nextafter__doc__}, @@ -1163,4 +1163,4 @@ math_ulp(PyObject *module, PyObject *arg) exit: return return_value; } -/*[clinic end generated code: output=23b2453ba77453e5 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=80c666aef8d2df36 input=a9049054013a1b77]*/ diff --git a/Modules/clinic/overlapped.c.h b/Modules/clinic/overlapped.c.h index 7e2480bdace38d..ba41eab15650e8 100644 --- a/Modules/clinic/overlapped.c.h +++ b/Modules/clinic/overlapped.c.h @@ -529,8 +529,9 @@ PyDoc_STRVAR(_overlapped_Overlapped_getresult__doc__, "\n" "Retrieve result of operation.\n" "\n" -"If wait is true then it blocks until the operation is finished. If wait\n" -"is false and the operation is still pending then an error is raised."); +"If wait is true then it blocks until the operation is finished. If\n" +"wait is false and the operation is still pending then an error is\n" +"raised."); #define _OVERLAPPED_OVERLAPPED_GETRESULT_METHODDEF \ {"getresult", _PyCFunction_CAST(_overlapped_Overlapped_getresult), METH_FASTCALL, _overlapped_Overlapped_getresult__doc__}, @@ -1242,4 +1243,4 @@ _overlapped_Overlapped_WSARecvFromInto(PyObject *self, PyObject *const *args, Py return return_value; } -/*[clinic end generated code: output=3e4cb2b55342cd96 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=0ecaf45a09539599 input=a9049054013a1b77]*/ diff --git a/Modules/clinic/selectmodule.c.h b/Modules/clinic/selectmodule.c.h index 3952054e9e32bf..c1c8ad40e724f5 100644 --- a/Modules/clinic/selectmodule.c.h +++ b/Modules/clinic/selectmodule.c.h @@ -16,7 +16,8 @@ PyDoc_STRVAR(select_select__doc__, "\n" "Wait until one or more file descriptors are ready for some kind of I/O.\n" "\n" -"The first three arguments are iterables of file descriptors to be waited for:\n" +"The first three arguments are iterables of file descriptors to be waited\n" +"for:\n" "rlist -- wait until ready for reading\n" "wlist -- wait until ready for writing\n" "xlist -- wait for an \"exceptional condition\"\n" @@ -29,9 +30,9 @@ PyDoc_STRVAR(select_select__doc__, "a non-integer to specify fractions of seconds. If it is absent\n" "or None, the call will never time out.\n" "\n" -"The return value is a tuple of three lists corresponding to the first three\n" -"arguments; each contains the subset of the corresponding file descriptors\n" -"that are ready.\n" +"The return value is a tuple of three lists corresponding to the first\n" +"three arguments; each contains the subset of the corresponding file\n" +"descriptors that are ready.\n" "\n" "*** IMPORTANT NOTICE ***\n" "On Windows, only sockets are supported; on Unix, all file\n" @@ -214,8 +215,8 @@ PyDoc_STRVAR(select_poll_poll__doc__, " The maximum time to wait in milliseconds, or else None (or a negative\n" " value) to wait indefinitely.\n" "\n" -"Returns a list containing any descriptors that have events or errors to\n" -"report, as a list of (fd, event) 2-tuples."); +"Returns a list containing any descriptors that have events or errors\n" +"to report, as a list of (fd, event) 2-tuples."); #define SELECT_POLL_POLL_METHODDEF \ {"poll", _PyCFunction_CAST(select_poll_poll), METH_FASTCALL, select_poll_poll__doc__}, @@ -396,11 +397,11 @@ PyDoc_STRVAR(select_devpoll_poll__doc__, "Polls the set of registered file descriptors.\n" "\n" " timeout\n" -" The maximum time to wait in milliseconds, or else None (or a negative\n" -" value) to wait indefinitely.\n" +" The maximum time to wait in milliseconds, or else None (or\n" +" a negative value) to wait indefinitely.\n" "\n" -"Returns a list containing any descriptors that have events or errors to\n" -"report, as a list of (fd, event) 2-tuples."); +"Returns a list containing any descriptors that have events or errors\n" +"to report, as a list of (fd, event) 2-tuples."); #define SELECT_DEVPOLL_POLL_METHODDEF \ {"poll", _PyCFunction_CAST(select_devpoll_poll), METH_FASTCALL, select_devpoll_poll__doc__}, @@ -498,8 +499,8 @@ PyDoc_STRVAR(select_poll__doc__, "\n" "Returns a polling object.\n" "\n" -"This object supports registering and unregistering file descriptors, and then\n" -"polling them for I/O events."); +"This object supports registering and unregistering file descriptors, and\n" +"then polling them for I/O events."); #define SELECT_POLL_METHODDEF \ {"poll", (PyCFunction)select_poll, METH_NOARGS, select_poll__doc__}, @@ -523,8 +524,8 @@ PyDoc_STRVAR(select_devpoll__doc__, "\n" "Returns a polling object.\n" "\n" -"This object supports registering and unregistering file descriptors, and then\n" -"polling them for I/O events."); +"This object supports registering and unregistering file descriptors, and\n" +"then polling them for I/O events."); #define SELECT_DEVPOLL_METHODDEF \ {"devpoll", (PyCFunction)select_devpoll, METH_NOARGS, select_devpoll__doc__}, @@ -978,8 +979,8 @@ PyDoc_STRVAR(select_epoll_poll__doc__, " maxevents\n" " the maximum number of events returned; -1 means no limit\n" "\n" -"Returns a list containing any descriptors that have events to report,\n" -"as a list of (fd, events) 2-tuples."); +"Returns a list containing any descriptors that have events to\n" +"report, as a list of (fd, events) 2-tuples."); #define SELECT_EPOLL_POLL_METHODDEF \ {"poll", _PyCFunction_CAST(select_epoll_poll), METH_FASTCALL|METH_KEYWORDS, select_epoll_poll__doc__}, @@ -1399,4 +1400,4 @@ select_kqueue_control(PyObject *self, PyObject *const *args, Py_ssize_t nargs) #ifndef SELECT_KQUEUE_CONTROL_METHODDEF #define SELECT_KQUEUE_CONTROL_METHODDEF #endif /* !defined(SELECT_KQUEUE_CONTROL_METHODDEF) */ -/*[clinic end generated code: output=52e3be5cc66cf1b6 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=a1ac666294fd14bd input=a9049054013a1b77]*/ diff --git a/Modules/clinic/signalmodule.c.h b/Modules/clinic/signalmodule.c.h index 9fd24d15bf2500..ca47033446074c 100644 --- a/Modules/clinic/signalmodule.c.h +++ b/Modules/clinic/signalmodule.c.h @@ -138,11 +138,12 @@ PyDoc_STRVAR(signal_signal__doc__, "Set the action for the given signal.\n" "\n" "The action can be SIG_DFL, SIG_IGN, or a callable Python object.\n" -"The previous action is returned. See getsignal() for possible return values.\n" +"The previous action is returned. See getsignal() for possible return\n" +"values.\n" "\n" "*** IMPORTANT NOTICE ***\n" -"A signal handler function is called with two arguments:\n" -"the first is the signal number, the second is the interrupted stack frame."); +"A signal handler function is called with two arguments: the first is\n" +"the signal number, the second is the interrupted stack frame."); #define SIGNAL_SIGNAL_METHODDEF \ {"signal", _PyCFunction_CAST(signal_signal), METH_FASTCALL, signal_signal__doc__}, @@ -362,8 +363,8 @@ PyDoc_STRVAR(signal_setitimer__doc__, "\n" "Sets given itimer (one of ITIMER_REAL, ITIMER_VIRTUAL or ITIMER_PROF).\n" "\n" -"The timer will fire after value seconds and after that every interval seconds.\n" -"The itimer can be cleared by setting seconds to zero.\n" +"The timer will fire after value seconds and after that every interval\n" +"seconds. The itimer can be cleared by setting seconds to zero.\n" "\n" "Returns old values as a tuple: (delay, interval)."); @@ -508,8 +509,8 @@ PyDoc_STRVAR(signal_sigwait__doc__, "Wait for a signal.\n" "\n" "Suspend execution of the calling thread until the delivery of one of the\n" -"signals specified in the signal set sigset. The function accepts the signal\n" -"and returns the signal number."); +"signals specified in the signal set sigset. The function accepts the\n" +"signal and returns the signal number."); #define SIGNAL_SIGWAIT_METHODDEF \ {"sigwait", (PyCFunction)signal_sigwait, METH_O, signal_sigwait__doc__}, @@ -794,4 +795,4 @@ signal_pidfd_send_signal(PyObject *module, PyObject *const *args, Py_ssize_t nar #ifndef SIGNAL_PIDFD_SEND_SIGNAL_METHODDEF #define SIGNAL_PIDFD_SEND_SIGNAL_METHODDEF #endif /* !defined(SIGNAL_PIDFD_SEND_SIGNAL_METHODDEF) */ -/*[clinic end generated code: output=42e20d118435d7fa input=a9049054013a1b77]*/ +/*[clinic end generated code: output=0731d6f05c42c09a input=a9049054013a1b77]*/ diff --git a/Modules/clinic/socketmodule.c.h b/Modules/clinic/socketmodule.c.h index e0cc1c50dcbac3..b565e7516d50f3 100644 --- a/Modules/clinic/socketmodule.c.h +++ b/Modules/clinic/socketmodule.c.h @@ -36,7 +36,8 @@ PyDoc_STRVAR(_socket_socket_send__doc__, "Send a data string to the socket.\n" "\n" "For the optional flags argument, see the Unix manual.\n" -"Return the number of bytes sent; this may be less than len(data) if the network is busy."); +"Return the number of bytes sent; this may be less than len(data) if\n" +"the network is busy."); #define _SOCKET_SOCKET_SEND_METHODDEF \ {"send", _PyCFunction_CAST(_socket_socket_send), METH_FASTCALL, _socket_socket_send__doc__}, @@ -84,7 +85,8 @@ PyDoc_STRVAR(_socket_socket_sendall__doc__, "\n" "For the optional flags argument, see the Unix manual.\n" "This calls send() repeatedly until all data is sent.\n" -"If an error occurs, it\'s impossible to tell how much data has been sent."); +"If an error occurs, it\'s impossible to tell how much data has been\n" +"sent."); #define _SOCKET_SOCKET_SENDALL_METHODDEF \ {"sendall", _PyCFunction_CAST(_socket_socket_sendall), METH_FASTCALL, _socket_socket_sendall__doc__}, @@ -140,13 +142,13 @@ PyDoc_STRVAR(_socket_socket_sendmsg__doc__, "data as an iterable of bytes-like objects (e.g. bytes objects).\n" "The ancdata argument specifies the ancillary data (control messages)\n" "as an iterable of zero or more tuples (cmsg_level, cmsg_type,\n" -"cmsg_data), where cmsg_level and cmsg_type are integers specifying the\n" -"protocol level and protocol-specific type respectively, and cmsg_data\n" -"is a bytes-like object holding the associated data. The flags\n" -"argument defaults to 0 and has the same meaning as for send(). If\n" -"address is supplied and not None, it sets a destination address for\n" -"the message. The return value is the number of bytes of non-ancillary\n" -"data sent."); +"cmsg_data), where cmsg_level and cmsg_type are integers specifying\n" +"the protocol level and protocol-specific type respectively, and\n" +"cmsg_data is a bytes-like object holding the associated data. The\n" +"flags argument defaults to 0 and has the same meaning as for send().\n" +"If address is supplied and not None, it sets a destination address\n" +"for the message. The return value is the number of bytes of\n" +"non-ancillary data sent."); #define _SOCKET_SOCKET_SENDMSG_METHODDEF \ {"sendmsg", _PyCFunction_CAST(_socket_socket_sendmsg), METH_FASTCALL, _socket_socket_sendmsg__doc__}, @@ -541,4 +543,4 @@ _socket_if_indextoname(PyObject *module, PyObject *arg) #ifndef _SOCKET_IF_INDEXTONAME_METHODDEF #define _SOCKET_IF_INDEXTONAME_METHODDEF #endif /* !defined(_SOCKET_IF_INDEXTONAME_METHODDEF) */ -/*[clinic end generated code: output=36051ebf6ad1e6f8 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=0b1fa78ac6589353 input=a9049054013a1b77]*/ diff --git a/Modules/clinic/termios.c.h b/Modules/clinic/termios.c.h index 83f5a4f6e9f882..35522bef1dcae9 100644 --- a/Modules/clinic/termios.c.h +++ b/Modules/clinic/termios.c.h @@ -270,7 +270,8 @@ PyDoc_STRVAR(termios_tcsetwinsize__doc__, "Set the tty winsize for file descriptor fd.\n" "\n" "The winsize to be set is taken from the winsize argument, which\n" -"is a two-item tuple (ws_row, ws_col) like the one returned by tcgetwinsize()."); +"is a two-item tuple (ws_row, ws_col) like the one returned by\n" +"tcgetwinsize()."); #define TERMIOS_TCSETWINSIZE_METHODDEF \ {"tcsetwinsize", (PyCFunction)(void(*)(void))termios_tcsetwinsize, METH_FASTCALL, termios_tcsetwinsize__doc__}, @@ -299,4 +300,4 @@ termios_tcsetwinsize(PyObject *module, PyObject *const *args, Py_ssize_t nargs) exit: return return_value; } -/*[clinic end generated code: output=c6c6192583b0da36 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=d2176c4d9043d3cc input=a9049054013a1b77]*/ diff --git a/Modules/clinic/zlibmodule.c.h b/Modules/clinic/zlibmodule.c.h index f8fd111754a894..620e483d5a759a 100644 --- a/Modules/clinic/zlibmodule.c.h +++ b/Modules/clinic/zlibmodule.c.h @@ -503,8 +503,8 @@ PyDoc_STRVAR(zlib_Decompress_decompress__doc__, " Unconsumed input data will be stored in\n" " the unconsumed_tail attribute.\n" "\n" -"After calling this function, some of the input data may still be stored in\n" -"internal buffers for later processing.\n" +"After calling this function, some of the input data may still be\n" +"stored in internal buffers for later processing.\n" "Call the flush() method to clear these buffers."); #define ZLIB_DECOMPRESS_DECOMPRESS_METHODDEF \ @@ -914,18 +914,19 @@ PyDoc_STRVAR(zlib__ZlibDecompressor_decompress__doc__, "\n" "Decompress *data*, returning uncompressed data as bytes.\n" "\n" -"If *max_length* is nonnegative, returns at most *max_length* bytes of\n" -"decompressed data. If this limit is reached and further output can be\n" -"produced, *self.needs_input* will be set to ``False``. In this case, the next\n" -"call to *decompress()* may provide *data* as b\'\' to obtain more of the output.\n" +"If *max_length* is nonnegative, returns at most *max_length* bytes\n" +"of decompressed data. If this limit is reached and further output\n" +"can be produced, *self.needs_input* will be set to ``False``. In\n" +"this case, the next call to *decompress()* may provide *data* as b\'\'\n" +"to obtain more of the output.\n" "\n" -"If all of the input data was decompressed and returned (either because this\n" -"was less than *max_length* bytes, or because *max_length* was negative),\n" -"*self.needs_input* will be set to True.\n" +"If all of the input data was decompressed and returned (either\n" +"because this was less than *max_length* bytes, or because\n" +"*max_length* was negative), *self.needs_input* will be set to True.\n" "\n" -"Attempting to decompress data after the end of stream is reached raises an\n" -"EOFError. Any data found after the end of the stream is ignored and saved in\n" -"the unused_data attribute."); +"Attempting to decompress data after the end of stream is reached\n" +"raises an EOFError. Any data found after the end of the stream is\n" +"ignored and saved in the unused_data attribute."); #define ZLIB__ZLIBDECOMPRESSOR_DECOMPRESS_METHODDEF \ {"decompress", _PyCFunction_CAST(zlib__ZlibDecompressor_decompress), METH_FASTCALL|METH_KEYWORDS, zlib__ZlibDecompressor_decompress__doc__}, @@ -1402,4 +1403,4 @@ zlib_crc32_combine(PyObject *module, PyObject *const *args, Py_ssize_t nargs) #ifndef ZLIB_DECOMPRESS___DEEPCOPY___METHODDEF #define ZLIB_DECOMPRESS___DEEPCOPY___METHODDEF #endif /* !defined(ZLIB_DECOMPRESS___DEEPCOPY___METHODDEF) */ -/*[clinic end generated code: output=13627e14206d3552 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=c9a60fe6600a2e4d input=a9049054013a1b77]*/ diff --git a/Modules/cmathmodule.c b/Modules/cmathmodule.c index 1e9f9ae051a0b1..7c736f4610bb98 100644 --- a/Modules/cmathmodule.c +++ b/Modules/cmathmodule.c @@ -948,12 +948,13 @@ cmath.log log(z[, base]) -> the logarithm of z to the given base. -If the base is not specified, returns the natural logarithm (base e) of z. +If the base is not specified, returns the natural logarithm (base e) +of z. [clinic start generated code]*/ static PyObject * cmath_log_impl(PyObject *module, Py_complex x, PyObject *y_obj) -/*[clinic end generated code: output=4effdb7d258e0d94 input=e1f81d4fcfd26497]*/ +/*[clinic end generated code: output=4effdb7d258e0d94 input=eb25de0757baf4a0]*/ { Py_complex y; @@ -1162,7 +1163,6 @@ cmath_isinf_impl(PyObject *module, Py_complex z) } /*[clinic input] -@permit_long_docstring_body cmath.isclose -> bool a: Py_complex @@ -1179,17 +1179,18 @@ Determine whether two complex numbers are close in value. Return True if a is close in value to b, and False otherwise. -For the values to be considered close, the difference between them must be -smaller than at least one of the tolerances. +For the values to be considered close, the difference between them must +be smaller than at least one of the tolerances. --inf, inf and NaN behave similarly to the IEEE 754 Standard. That is, NaN is -not close to anything, even itself. inf and -inf are only close to themselves. +-inf, inf and NaN behave similarly to the IEEE 754 Standard. That is, +NaN is not close to anything, even itself. inf and -inf are only close +to themselves. [clinic start generated code]*/ static int cmath_isclose_impl(PyObject *module, Py_complex a, Py_complex b, double rel_tol, double abs_tol) -/*[clinic end generated code: output=8a2486cc6e0014d1 input=0d45feea7c626f47]*/ +/*[clinic end generated code: output=8a2486cc6e0014d1 input=301b56c90d9a79de]*/ { double diff; diff --git a/Modules/faulthandler.c b/Modules/faulthandler.c index fa7fb7085d7e8b..7c727d8c2d4ff0 100644 --- a/Modules/faulthandler.c +++ b/Modules/faulthandler.c @@ -795,9 +795,9 @@ faulthandler.dump_traceback_later Dump the traceback of all threads in timeout seconds. -If repeat is true, the tracebacks of all threads are dumped every timeout -seconds. If exit is true, call _exit(1) which is not safe. max_threads -caps the number of threads dumped. +If repeat is true, the tracebacks of all threads are dumped every +timeout seconds. If exit is true, call _exit(1) which is not safe. +max_threads caps the number of threads dumped. [clinic start generated code]*/ static PyObject * @@ -805,7 +805,7 @@ faulthandler_dump_traceback_later_impl(PyObject *module, PyObject *timeout_obj, int repeat, PyObject *file, int exit, Py_ssize_t max_threads) -/*[clinic end generated code: output=543a0f3807113394 input=6836555ee157ddb4]*/ +/*[clinic end generated code: output=543a0f3807113394 input=32aaf7437d0928db]*/ { PyTime_t timeout, timeout_us; int fd; diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c index 18bddf46a7466b..12f93ac0fdea14 100644 --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -326,13 +326,13 @@ gc.get_objects Return a list of objects tracked by the collector (excluding the list returned). -If generation is not None, return only the objects tracked by the collector -that are in that generation. +If generation is not None, return only the objects tracked by the +collector that are in that generation. [clinic start generated code]*/ static PyObject * gc_get_objects_impl(PyObject *module, Py_ssize_t generation) -/*[clinic end generated code: output=48b35fea4ba6cb0e input=a887f1d9924be7cf]*/ +/*[clinic end generated code: output=48b35fea4ba6cb0e input=89bca0d4a64e0135]*/ { if (PySys_Audit("gc.get_objects", "n", generation) < 0) { return NULL; @@ -440,19 +440,20 @@ gc_is_finalized_impl(PyObject *module, PyObject *obj) } /*[clinic input] -@permit_long_docstring_body +@permit_long_summary gc.freeze Freeze all current tracked objects and ignore them for future collections. -This can be used before a POSIX fork() call to make the gc copy-on-write friendly. -Note: collection before a POSIX fork() call may free pages for future allocation -which can cause copy-on-write. +This can be used before a POSIX fork() call to make the gc copy-on-write +friendly. +Note: collection before a POSIX fork() call may free pages for future +allocation which can cause copy-on-write. [clinic start generated code]*/ static PyObject * gc_freeze_impl(PyObject *module) -/*[clinic end generated code: output=502159d9cdc4c139 input=11fb59b0a75dcf3d]*/ +/*[clinic end generated code: output=502159d9cdc4c139 input=02674706fc9c0de6]*/ { PyInterpreterState *interp = _PyInterpreterState_GET(); _PyGC_Freeze(interp); diff --git a/Modules/hmacmodule.c b/Modules/hmacmodule.c index b39a8f99ed91e8..0f9eca2f73bd0c 100644 --- a/Modules/hmacmodule.c +++ b/Modules/hmacmodule.c @@ -942,20 +942,19 @@ _hmac_HMAC_digest_impl(HMACObject *self) /*[clinic input] @permit_long_summary -@permit_long_docstring_body _hmac.HMAC.hexdigest Return hexadecimal digest of the bytes passed to the update() method so far. -This may be used to exchange the value safely in email or other non-binary -environments. +This may be used to exchange the value safely in email or other +non-binary environments. This method may raise a MemoryError. [clinic start generated code]*/ static PyObject * _hmac_HMAC_hexdigest_impl(HMACObject *self) -/*[clinic end generated code: output=6659807a09ae14ec input=6e0e796e38d82fc8]*/ +/*[clinic end generated code: output=6659807a09ae14ec input=9097dce732ed808f]*/ { assert(self->digest_size <= Py_hmac_hash_max_digest_size); uint8_t digest[Py_hmac_hash_max_digest_size]; diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c index a6bfa78a461bb0..68ac810eaad237 100644 --- a/Modules/itertoolsmodule.c +++ b/Modules/itertoolsmodule.c @@ -107,6 +107,7 @@ typedef struct { #define batchedobject_CAST(op) ((batchedobject *)(op)) /*[clinic input] +@permit_long_summary @classmethod itertools.batched.__new__ as batched_new iterable: object @@ -136,7 +137,7 @@ than n. static PyObject * batched_new_impl(PyTypeObject *type, PyObject *iterable, Py_ssize_t n, int strict) -/*[clinic end generated code: output=c6de11b061529d3e input=7814b47e222f5467]*/ +/*[clinic end generated code: output=c6de11b061529d3e input=b31d8be8e8577a34]*/ { PyObject *it; batchedobject *bo; @@ -437,6 +438,7 @@ typedef struct { static PyObject *_grouper_create(groupbyobject *, PyObject *); /*[clinic input] +@permit_long_summary @classmethod itertools.groupby.__new__ @@ -452,7 +454,7 @@ make an iterator that returns consecutive keys and groups from the iterable static PyObject * itertools_groupby_impl(PyTypeObject *type, PyObject *it, PyObject *keyfunc) -/*[clinic end generated code: output=cbb1ae3a90fd4141 input=6b3d123e87ff65a1]*/ +/*[clinic end generated code: output=cbb1ae3a90fd4141 input=9f89fe625b20ef1a]*/ { groupbyobject *gbo; @@ -3163,13 +3165,13 @@ itertools.compress.__new__ selectors as seq2: object Return data elements corresponding to true selector elements. -Forms a shorter iterator from selected data elements using the selectors to -choose the data elements. +Forms a shorter iterator from selected data elements using the selectors +to choose the data elements. [clinic start generated code]*/ static PyObject * itertools_compress_impl(PyTypeObject *type, PyObject *seq1, PyObject *seq2) -/*[clinic end generated code: output=7e67157212ed09e0 input=79596d7cd20c77e5]*/ +/*[clinic end generated code: output=7e67157212ed09e0 input=32ca4347dbc46749]*/ { PyObject *data=NULL, *selectors=NULL; compressobject *lz; @@ -3427,6 +3429,7 @@ slow_mode: when cnt == PY_SSIZE_T_MAX, step is not int(1), or cnt is a float. */ /*[clinic input] +@permit_long_summary @classmethod itertools.count.__new__ start as long_cnt: object(c_default="NULL") = 0 @@ -3444,7 +3447,7 @@ Equivalent to: static PyObject * itertools_count_impl(PyTypeObject *type, PyObject *long_cnt, PyObject *long_step) -/*[clinic end generated code: output=09a9250aebd00b1c input=d7a85eec18bfcd94]*/ +/*[clinic end generated code: output=09a9250aebd00b1c input=91e4b12c0e88b9f4]*/ { countobject *lz; int fast_mode; diff --git a/Modules/mathmodule.c b/Modules/mathmodule.c index 6b7fc004d0d858..a7616ad70e4afe 100644 --- a/Modules/mathmodule.c +++ b/Modules/mathmodule.c @@ -2541,6 +2541,7 @@ math_isnan_impl(PyObject *module, double x) /*[clinic input] +@permit_long_summary math.isinf x: double @@ -2551,7 +2552,7 @@ Return True if x is a positive or negative infinity, and False otherwise. static PyObject * math_isinf_impl(PyObject *module, double x) -/*[clinic end generated code: output=9f00cbec4de7b06b input=32630e4212cf961f]*/ +/*[clinic end generated code: output=9f00cbec4de7b06b input=8584152a71a3aea9]*/ { return PyBool_FromLong((long)isinf(x)); } @@ -2831,7 +2832,7 @@ math_prod_impl(PyObject *module, PyObject *iterable, PyObject *start) /*[clinic input] -@permit_long_docstring_body +@permit_long_summary math.nextafter x: double @@ -2844,13 +2845,13 @@ Return the floating-point value the given number of steps after x towards y. If steps is not specified or is None, it defaults to 1. -Raises a TypeError, if x or y is not a double, or if steps is not an integer. -Raises ValueError if steps is negative. +Raises a TypeError, if x or y is not a double, or if steps is not +an integer. Raises ValueError if steps is negative. [clinic start generated code]*/ static PyObject * math_nextafter_impl(PyObject *module, double x, double y, PyObject *steps) -/*[clinic end generated code: output=cc6511f02afc099e input=cc8f0dad1b27a8a4]*/ +/*[clinic end generated code: output=cc6511f02afc099e input=3a9151e6b1e9f346]*/ { #if defined(_AIX) if (x == y) { diff --git a/Modules/overlapped.c b/Modules/overlapped.c index 51aee5afd35b6d..255576cc057cdd 100644 --- a/Modules/overlapped.c +++ b/Modules/overlapped.c @@ -885,13 +885,14 @@ _overlapped.Overlapped.getresult Retrieve result of operation. -If wait is true then it blocks until the operation is finished. If wait -is false and the operation is still pending then an error is raised. +If wait is true then it blocks until the operation is finished. If +wait is false and the operation is still pending then an error is +raised. [clinic start generated code]*/ static PyObject * _overlapped_Overlapped_getresult_impl(OverlappedObject *self, BOOL wait) -/*[clinic end generated code: output=8c9bd04d08994f6c input=aa5b03e9897ca074]*/ +/*[clinic end generated code: output=8c9bd04d08994f6c input=852fbd817cbd2b3d]*/ { DWORD transferred = 0; BOOL ret; diff --git a/Modules/readline.c b/Modules/readline.c index 488332f548e5fe..2cc3d40baa3aba 100644 --- a/Modules/readline.c +++ b/Modules/readline.c @@ -432,6 +432,7 @@ readline_append_history_file_impl(PyObject *module, int nelements, /* Set history length */ /*[clinic input] +@permit_long_summary readline.set_history_length length: int @@ -444,7 +445,7 @@ A negative length is used to inhibit history truncation. static PyObject * readline_set_history_length_impl(PyObject *module, int length) -/*[clinic end generated code: output=e161a53e45987dc7 input=b8901bf16488b760]*/ +/*[clinic end generated code: output=e161a53e45987dc7 input=8d02c81b38ef81ec]*/ { FT_ATOMIC_STORE_INT_RELAXED(_history_length, length); Py_RETURN_NONE; @@ -453,6 +454,7 @@ readline_set_history_length_impl(PyObject *module, int length) /* Get history length */ /*[clinic input] +@permit_long_summary readline.get_history_length Return the maximum number of lines that will be written to the history file. @@ -460,7 +462,7 @@ Return the maximum number of lines that will be written to the history file. static PyObject * readline_get_history_length_impl(PyObject *module) -/*[clinic end generated code: output=83a2eeae35b6d2b9 input=5dce2eeba4327817]*/ +/*[clinic end generated code: output=83a2eeae35b6d2b9 input=a65823e732ebfa9d]*/ { int history_length = FT_ATOMIC_LOAD_INT_RELAXED(_history_length); return PyLong_FromLong(history_length); diff --git a/Modules/selectmodule.c b/Modules/selectmodule.c index eb3148ef24631b..2c56dbc6a541f7 100644 --- a/Modules/selectmodule.c +++ b/Modules/selectmodule.c @@ -242,7 +242,6 @@ set2list(fd_set *set, pylist fd2obj[FD_SETSIZE + 1]) #endif /* FD_SETSIZE > 1024 */ /*[clinic input] -@permit_long_docstring_body select.select rlist: object @@ -253,7 +252,8 @@ select.select Wait until one or more file descriptors are ready for some kind of I/O. -The first three arguments are iterables of file descriptors to be waited for: +The first three arguments are iterables of file descriptors to be waited +for: rlist -- wait until ready for reading wlist -- wait until ready for writing xlist -- wait for an "exceptional condition" @@ -266,9 +266,9 @@ The optional 4th argument specifies a timeout in seconds; it may be a non-integer to specify fractions of seconds. If it is absent or None, the call will never time out. -The return value is a tuple of three lists corresponding to the first three -arguments; each contains the subset of the corresponding file descriptors -that are ready. +The return value is a tuple of three lists corresponding to the first +three arguments; each contains the subset of the corresponding file +descriptors that are ready. *** IMPORTANT NOTICE *** On Windows, only sockets are supported; on Unix, all file @@ -278,7 +278,7 @@ descriptors can be used. static PyObject * select_select_impl(PyObject *module, PyObject *rlist, PyObject *wlist, PyObject *xlist, PyObject *timeout_obj) -/*[clinic end generated code: output=2b3cfa824f7ae4cf input=b0403de75cd11cc1]*/ +/*[clinic end generated code: output=2b3cfa824f7ae4cf input=cc93e9bb9ffacbaf]*/ { #ifdef SELECT_USES_HEAP pylist *rfd2obj, *wfd2obj, *efd2obj; @@ -616,13 +616,13 @@ select.poll.poll Polls the set of registered file descriptors. -Returns a list containing any descriptors that have events or errors to -report, as a list of (fd, event) 2-tuples. +Returns a list containing any descriptors that have events or errors +to report, as a list of (fd, event) 2-tuples. [clinic start generated code]*/ static PyObject * select_poll_poll_impl(pollObject *self, PyObject *timeout_obj) -/*[clinic end generated code: output=876e837d193ed7e4 input=54310631457efdec]*/ +/*[clinic end generated code: output=876e837d193ed7e4 input=e0a9c0aa283de8c8]*/ { PyObject *result_list = NULL; int poll_result, i, j; @@ -975,19 +975,19 @@ select_devpoll_unregister_impl(devpollObject *self, int fd) @critical_section select.devpoll.poll timeout as timeout_obj: object = None - The maximum time to wait in milliseconds, or else None (or a negative - value) to wait indefinitely. + The maximum time to wait in milliseconds, or else None (or + a negative value) to wait indefinitely. / Polls the set of registered file descriptors. -Returns a list containing any descriptors that have events or errors to -report, as a list of (fd, event) 2-tuples. +Returns a list containing any descriptors that have events or errors +to report, as a list of (fd, event) 2-tuples. [clinic start generated code]*/ static PyObject * select_devpoll_poll_impl(devpollObject *self, PyObject *timeout_obj) -/*[clinic end generated code: output=2654e5457cca0b3c input=fe7a3f6dcbc118c5]*/ +/*[clinic end generated code: output=2654e5457cca0b3c input=9e1672658d728539]*/ { struct dvpoll dvp; PyObject *result_list = NULL; @@ -1233,18 +1233,17 @@ static PyType_Spec devpoll_Type_spec = { /*[clinic input] -@permit_long_docstring_body select.poll Returns a polling object. -This object supports registering and unregistering file descriptors, and then -polling them for I/O events. +This object supports registering and unregistering file descriptors, and +then polling them for I/O events. [clinic start generated code]*/ static PyObject * select_poll_impl(PyObject *module) -/*[clinic end generated code: output=16a665a4e1d228c5 input=5e07eea8ad564e7f]*/ +/*[clinic end generated code: output=16a665a4e1d228c5 input=0aefd4527e99e0aa]*/ { return (PyObject *)newPollObject(module); } @@ -1252,18 +1251,17 @@ select_poll_impl(PyObject *module) #ifdef HAVE_SYS_DEVPOLL_H /*[clinic input] -@permit_long_docstring_body select.devpoll Returns a polling object. -This object supports registering and unregistering file descriptors, and then -polling them for I/O events. +This object supports registering and unregistering file descriptors, and +then polling them for I/O events. [clinic start generated code]*/ static PyObject * select_devpoll_impl(PyObject *module) -/*[clinic end generated code: output=ea9213cc87fd9581 input=048506faef19d947]*/ +/*[clinic end generated code: output=ea9213cc87fd9581 input=4c2ac27d10248526]*/ { return (PyObject *)newDevPollObject(module); } @@ -1540,6 +1538,7 @@ pyepoll_internal_ctl(int epfd, int op, int fd, unsigned int events) } /*[clinic input] +@permit_long_summary select.epoll.register fd: fildes @@ -1555,7 +1554,7 @@ The epoll interface supports all file descriptors that support poll. static PyObject * select_epoll_register_impl(pyEpoll_Object *self, int fd, unsigned int eventmask) -/*[clinic end generated code: output=318e5e6386520599 input=a5071b71edfe3578]*/ +/*[clinic end generated code: output=318e5e6386520599 input=9f0c9ebb25a4fc8f]*/ { return pyepoll_internal_ctl(self->epfd, EPOLL_CTL_ADD, fd, eventmask); } @@ -1606,14 +1605,14 @@ select.epoll.poll Wait for events on the epoll file descriptor. -Returns a list containing any descriptors that have events to report, -as a list of (fd, events) 2-tuples. +Returns a list containing any descriptors that have events to +report, as a list of (fd, events) 2-tuples. [clinic start generated code]*/ static PyObject * select_epoll_poll_impl(pyEpoll_Object *self, PyObject *timeout_obj, int maxevents) -/*[clinic end generated code: output=e02d121a20246c6c input=deafa7f04a60ebe0]*/ +/*[clinic end generated code: output=e02d121a20246c6c input=911ddc16978a9159]*/ { int nfds, i; PyObject *elist = NULL, *etuple = NULL; diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c index fb548b8ca00f24..8456239dee202d 100644 --- a/Modules/signalmodule.c +++ b/Modules/signalmodule.c @@ -450,7 +450,6 @@ signal_raise_signal_impl(PyObject *module, int signalnum) } /*[clinic input] -@permit_long_docstring_body signal.signal signalnum: int @@ -460,16 +459,17 @@ signal.signal Set the action for the given signal. The action can be SIG_DFL, SIG_IGN, or a callable Python object. -The previous action is returned. See getsignal() for possible return values. +The previous action is returned. See getsignal() for possible return +values. *** IMPORTANT NOTICE *** -A signal handler function is called with two arguments: -the first is the signal number, the second is the interrupted stack frame. +A signal handler function is called with two arguments: the first is +the signal number, the second is the interrupted stack frame. [clinic start generated code]*/ static PyObject * signal_signal_impl(PyObject *module, int signalnum, PyObject *handler) -/*[clinic end generated code: output=b44cfda43780f3a1 input=7608656f34fa378b]*/ +/*[clinic end generated code: output=b44cfda43780f3a1 input=99ce4035ec56ffc1]*/ { _signal_module_state *modstate = get_signal_state(module); PyObject *old_handler; @@ -839,7 +839,6 @@ PySignal_SetWakeupFd(int fd) #ifdef HAVE_SETITIMER /*[clinic input] -@permit_long_docstring_body signal.setitimer which: int @@ -849,8 +848,8 @@ signal.setitimer Sets given itimer (one of ITIMER_REAL, ITIMER_VIRTUAL or ITIMER_PROF). -The timer will fire after value seconds and after that every interval seconds. -The itimer can be cleared by setting seconds to zero. +The timer will fire after value seconds and after that every interval +seconds. The itimer can be cleared by setting seconds to zero. Returns old values as a tuple: (delay, interval). [clinic start generated code]*/ @@ -858,7 +857,7 @@ Returns old values as a tuple: (delay, interval). static PyObject * signal_setitimer_impl(PyObject *module, int which, PyObject *seconds, PyObject *interval) -/*[clinic end generated code: output=65f9dcbddc35527b input=ab5bf2b8f5cff3f4]*/ +/*[clinic end generated code: output=65f9dcbddc35527b input=bd9f0d2ed8614193]*/ { _signal_module_state *modstate = get_signal_state(module); @@ -1019,13 +1018,13 @@ signal.sigwait Wait for a signal. Suspend execution of the calling thread until the delivery of one of the -signals specified in the signal set sigset. The function accepts the signal -and returns the signal number. +signals specified in the signal set sigset. The function accepts the +signal and returns the signal number. [clinic start generated code]*/ static PyObject * signal_sigwait_impl(PyObject *module, sigset_t sigset) -/*[clinic end generated code: output=f43770699d682f96 input=a6fbd47b1086d119]*/ +/*[clinic end generated code: output=f43770699d682f96 input=91773742dd416a3e]*/ { int err, signum; diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c index f5993fc8fdaab2..722287fbb134c3 100644 --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -4620,7 +4620,6 @@ sock_send_impl(PySocketSockObject *s, void *data) } /*[clinic input] -@permit_long_docstring_body _socket.socket.send self as s: self(type="PySocketSockObject *") data as pbuf: Py_buffer @@ -4630,12 +4629,13 @@ _socket.socket.send Send a data string to the socket. For the optional flags argument, see the Unix manual. -Return the number of bytes sent; this may be less than len(data) if the network is busy. +Return the number of bytes sent; this may be less than len(data) if +the network is busy. [clinic start generated code]*/ static PyObject * _socket_socket_send_impl(PySocketSockObject *s, Py_buffer *pbuf, int flags) -/*[clinic end generated code: output=3ddf83f17d0c875b input=e776a48af2e3d615]*/ +/*[clinic end generated code: output=3ddf83f17d0c875b input=d2b8af9bf99cfafb]*/ { struct sock_send ctx; @@ -4665,13 +4665,14 @@ Send a data string to the socket. For the optional flags argument, see the Unix manual. This calls send() repeatedly until all data is sent. -If an error occurs, it's impossible to tell how much data has been sent. +If an error occurs, it's impossible to tell how much data has been +sent. [clinic start generated code]*/ static PyObject * _socket_socket_sendall_impl(PySocketSockObject *s, Py_buffer *pbuf, int flags) -/*[clinic end generated code: output=ec92861424d3faa8 input=732b15b9ca64dce6]*/ +/*[clinic end generated code: output=ec92861424d3faa8 input=2600de13b4614893]*/ { char *buf; @@ -4921,20 +4922,20 @@ The buffers argument specifies the non-ancillary data as an iterable of bytes-like objects (e.g. bytes objects). The ancdata argument specifies the ancillary data (control messages) as an iterable of zero or more tuples (cmsg_level, cmsg_type, -cmsg_data), where cmsg_level and cmsg_type are integers specifying the -protocol level and protocol-specific type respectively, and cmsg_data -is a bytes-like object holding the associated data. The flags -argument defaults to 0 and has the same meaning as for send(). If -address is supplied and not None, it sets a destination address for -the message. The return value is the number of bytes of non-ancillary -data sent. +cmsg_data), where cmsg_level and cmsg_type are integers specifying +the protocol level and protocol-specific type respectively, and +cmsg_data is a bytes-like object holding the associated data. The +flags argument defaults to 0 and has the same meaning as for send(). +If address is supplied and not None, it sets a destination address +for the message. The return value is the number of bytes of +non-ancillary data sent. [clinic start generated code]*/ static PyObject * _socket_socket_sendmsg_impl(PySocketSockObject *s, PyObject *data_arg, PyObject *cmsg_arg, int flags, PyObject *addr_arg) -/*[clinic end generated code: output=3b4cb1110644ce39 input=479c13d90bd2f88b]*/ +/*[clinic end generated code: output=3b4cb1110644ce39 input=8ae408971a3aa329]*/ { Py_ssize_t i, ndatabufs = 0, ncmsgs, ncmsgbufs = 0; @@ -7310,6 +7311,7 @@ _socket_if_nametoindex_impl(PyObject *module, PyObject *oname) /*[clinic input] +@permit_long_summary _socket.if_indextoname if_index as index: NET_IFINDEX / @@ -7319,7 +7321,7 @@ Returns the interface name corresponding to the interface index if_index. static PyObject * _socket_if_indextoname_impl(PyObject *module, NET_IFINDEX index) -/*[clinic end generated code: output=e48bc324993052e0 input=c93f753d0cf6d7d1]*/ +/*[clinic end generated code: output=e48bc324993052e0 input=2a0026b271cd43ae]*/ { errno = ENXIO; // in case 'if_indextoname' does not set errno char name[IF_NAMESIZE + 1]; diff --git a/Modules/termios.c b/Modules/termios.c index 95b9c920f39c12..38743e176f0bf6 100644 --- a/Modules/termios.c +++ b/Modules/termios.c @@ -312,6 +312,7 @@ termios_tcsendbreak_impl(PyObject *module, int fd, int duration) } /*[clinic input] +@permit_long_summary termios.tcdrain fd: fildes @@ -322,7 +323,7 @@ Wait until all output written to file descriptor fd has been transmitted. static PyObject * termios_tcdrain_impl(PyObject *module, int fd) -/*[clinic end generated code: output=5fd86944c6255955 input=c99241b140b32447]*/ +/*[clinic end generated code: output=5fd86944c6255955 input=d1557e60b5ec66c5]*/ { termiosmodulestate *state = PyModule_GetState(module); int r; @@ -474,7 +475,6 @@ termios_tcgetwinsize_impl(PyObject *module, int fd) } /*[clinic input] -@permit_long_docstring_body termios.tcsetwinsize fd: fildes @@ -484,12 +484,13 @@ termios.tcsetwinsize Set the tty winsize for file descriptor fd. The winsize to be set is taken from the winsize argument, which -is a two-item tuple (ws_row, ws_col) like the one returned by tcgetwinsize(). +is a two-item tuple (ws_row, ws_col) like the one returned by +tcgetwinsize(). [clinic start generated code]*/ static PyObject * termios_tcsetwinsize_impl(PyObject *module, int fd, PyObject *winsz) -/*[clinic end generated code: output=2ac3c9bb6eda83e1 input=9a163c4e06fc4a41]*/ +/*[clinic end generated code: output=2ac3c9bb6eda83e1 input=efc9beb16d06382a]*/ { if (!PySequence_Check(winsz) || PySequence_Size(winsz) != 2) { PyErr_SetString(PyExc_TypeError, diff --git a/Modules/unicodedata.c b/Modules/unicodedata.c index 55b33a76e7af8a..31ad916b2c5c26 100644 --- a/Modules/unicodedata.c +++ b/Modules/unicodedata.c @@ -291,6 +291,7 @@ unicodedata_UCD_numeric_impl(PyObject *self, int chr, } /*[clinic input] +@permit_long_summary unicodedata.UCD.category self: self @@ -302,7 +303,7 @@ Returns the general category assigned to the character chr as string. static PyObject * unicodedata_UCD_category_impl(PyObject *self, int chr) -/*[clinic end generated code: output=8571539ee2e6783a input=27d6f3d85050bc06]*/ +/*[clinic end generated code: output=8571539ee2e6783a input=1d729c67299e8a31]*/ { int index; Py_UCS4 c = (Py_UCS4)chr; @@ -316,6 +317,7 @@ unicodedata_UCD_category_impl(PyObject *self, int chr) } /*[clinic input] +@permit_long_summary unicodedata.UCD.bidirectional self: self @@ -329,7 +331,7 @@ If no such value is defined, an empty string is returned. static PyObject * unicodedata_UCD_bidirectional_impl(PyObject *self, int chr) -/*[clinic end generated code: output=d36310ce2039bb92 input=b3d8f42cebfcf475]*/ +/*[clinic end generated code: output=d36310ce2039bb92 input=838f8a2203bd2990]*/ { int index; Py_UCS4 c = (Py_UCS4)chr; @@ -373,6 +375,7 @@ unicodedata_UCD_combining_impl(PyObject *self, int chr) } /*[clinic input] +@permit_long_summary unicodedata.UCD.mirrored -> int self: self @@ -387,7 +390,7 @@ character in bidirectional text, 0 otherwise. static int unicodedata_UCD_mirrored_impl(PyObject *self, int chr) -/*[clinic end generated code: output=2532dbf8121b50e6 input=5dd400d351ae6f3b]*/ +/*[clinic end generated code: output=2532dbf8121b50e6 input=6db28989e49cd9c8]*/ { int index; Py_UCS4 c = (Py_UCS4)chr; @@ -403,6 +406,7 @@ unicodedata_UCD_mirrored_impl(PyObject *self, int chr) } /*[clinic input] +@permit_long_summary unicodedata.UCD.east_asian_width self: self @@ -414,7 +418,7 @@ Returns the east asian width assigned to the character chr as string. static PyObject * unicodedata_UCD_east_asian_width_impl(PyObject *self, int chr) -/*[clinic end generated code: output=484e8537d9ee8197 input=c4854798aab026e0]*/ +/*[clinic end generated code: output=484e8537d9ee8197 input=207c5f68fa475516]*/ { int index; Py_UCS4 c = (Py_UCS4)chr; @@ -911,6 +915,7 @@ is_normalized_quickcheck(PyObject *self, PyObject *input, bool nfc, bool k, } /*[clinic input] +@permit_long_summary unicodedata.UCD.is_normalized self: self @@ -926,7 +931,7 @@ Valid values for form are 'NFC', 'NFKC', 'NFD', and 'NFKD'. static PyObject * unicodedata_UCD_is_normalized_impl(PyObject *self, PyObject *form, PyObject *input) -/*[clinic end generated code: output=11e5a3694e723ca5 input=a544f14cea79e508]*/ +/*[clinic end generated code: output=11e5a3694e723ca5 input=de66aa679265300b]*/ { if (PyUnicode_GET_LENGTH(input) == 0) { /* special case empty input strings. */ diff --git a/Modules/zlibmodule.c b/Modules/zlibmodule.c index 9c5820fbe97a6b..0a6732835eb51f 100644 --- a/Modules/zlibmodule.c +++ b/Modules/zlibmodule.c @@ -858,7 +858,7 @@ save_unconsumed_input(compobject *self, Py_buffer *data, int err) } /*[clinic input] -@permit_long_docstring_body +@permit_long_summary zlib.Decompress.decompress cls: defining_class @@ -872,15 +872,15 @@ zlib.Decompress.decompress Return a bytes object containing the decompressed version of the data. -After calling this function, some of the input data may still be stored in -internal buffers for later processing. +After calling this function, some of the input data may still be +stored in internal buffers for later processing. Call the flush() method to clear these buffers. [clinic start generated code]*/ static PyObject * zlib_Decompress_decompress_impl(compobject *self, PyTypeObject *cls, Py_buffer *data, Py_ssize_t max_length) -/*[clinic end generated code: output=b024a93c2c922d57 input=77de124bd2a2ecc0]*/ +/*[clinic end generated code: output=b024a93c2c922d57 input=9035027c9e4be7fd]*/ { int err = Z_OK; Py_ssize_t ibuflen; @@ -1675,7 +1675,6 @@ decompress(ZlibDecompressor *self, uint8_t *data, } /*[clinic input] -@permit_long_docstring_body zlib._ZlibDecompressor.decompress data: Py_buffer @@ -1683,25 +1682,26 @@ zlib._ZlibDecompressor.decompress Decompress *data*, returning uncompressed data as bytes. -If *max_length* is nonnegative, returns at most *max_length* bytes of -decompressed data. If this limit is reached and further output can be -produced, *self.needs_input* will be set to ``False``. In this case, the next -call to *decompress()* may provide *data* as b'' to obtain more of the output. +If *max_length* is nonnegative, returns at most *max_length* bytes +of decompressed data. If this limit is reached and further output +can be produced, *self.needs_input* will be set to ``False``. In +this case, the next call to *decompress()* may provide *data* as b'' +to obtain more of the output. -If all of the input data was decompressed and returned (either because this -was less than *max_length* bytes, or because *max_length* was negative), -*self.needs_input* will be set to True. +If all of the input data was decompressed and returned (either +because this was less than *max_length* bytes, or because +*max_length* was negative), *self.needs_input* will be set to True. -Attempting to decompress data after the end of stream is reached raises an -EOFError. Any data found after the end of the stream is ignored and saved in -the unused_data attribute. +Attempting to decompress data after the end of stream is reached +raises an EOFError. Any data found after the end of the stream is +ignored and saved in the unused_data attribute. [clinic start generated code]*/ static PyObject * zlib__ZlibDecompressor_decompress_impl(ZlibDecompressor *self, Py_buffer *data, Py_ssize_t max_length) -/*[clinic end generated code: output=ac00dcf73e843e99 input=c9278e791be1152b]*/ +/*[clinic end generated code: output=ac00dcf73e843e99 input=d7862eade3f29d56]*/ { PyObject *result = NULL; diff --git a/Python/clinic/context.c.h b/Python/clinic/context.c.h index 5ed74e6e6ddb6b..ece7341d65d5fb 100644 --- a/Python/clinic/context.c.h +++ b/Python/clinic/context.c.h @@ -10,8 +10,8 @@ PyDoc_STRVAR(_contextvars_Context_get__doc__, "\n" "Return the value for `key` if `key` has the value in the context object.\n" "\n" -"If `key` does not exist, return `default`. If `default` is not given,\n" -"return None."); +"If `key` does not exist, return `default`. If `default` is not\n" +"given, return None."); #define _CONTEXTVARS_CONTEXT_GET_METHODDEF \ {"get", _PyCFunction_CAST(_contextvars_Context_get), METH_FASTCALL, _contextvars_Context_get__doc__}, @@ -122,10 +122,12 @@ PyDoc_STRVAR(_contextvars_ContextVar_get__doc__, "\n" "Return a value for the context variable for the current context.\n" "\n" -"If there is no value for the variable in the current context, the method will:\n" -" * return the value of the default argument of the method, if provided; or\n" -" * return the default value for the context variable, if it was created\n" -" with one; or\n" +"If there is no value for the variable in the current context, the\n" +"method will:\n" +" * return the value of the default argument of the method, if\n" +" provided; or\n" +" * return the default value for the context variable, if it was\n" +" created with one; or\n" " * raise a LookupError."); #define _CONTEXTVARS_CONTEXTVAR_GET_METHODDEF \ @@ -160,10 +162,11 @@ PyDoc_STRVAR(_contextvars_ContextVar_set__doc__, "\n" "Call to set a new value for the context variable in the current context.\n" "\n" -"The required value argument is the new value for the context variable.\n" +"The required value argument is the new value for the context\n" +"variable.\n" "\n" -"Returns a Token object that can be used to restore the variable to its previous\n" -"value via the `ContextVar.reset()` method."); +"Returns a Token object that can be used to restore the variable to\n" +"its previous value via the `ContextVar.reset()` method."); #define _CONTEXTVARS_CONTEXTVAR_SET_METHODDEF \ {"set", (PyCFunction)_contextvars_ContextVar_set, METH_O, _contextvars_ContextVar_set__doc__}, @@ -187,8 +190,8 @@ PyDoc_STRVAR(_contextvars_ContextVar_reset__doc__, "\n" "Reset the context variable.\n" "\n" -"The variable is reset to the value it had before the `ContextVar.set()` that\n" -"created the token was used."); +"The variable is reset to the value it had before the\n" +"`ContextVar.set()` that created the token was used."); #define _CONTEXTVARS_CONTEXTVAR_RESET_METHODDEF \ {"reset", (PyCFunction)_contextvars_ContextVar_reset, METH_O, _contextvars_ContextVar_reset__doc__}, @@ -256,4 +259,4 @@ token_exit(PyObject *self, PyObject *const *args, Py_ssize_t nargs) exit: return return_value; } -/*[clinic end generated code: output=3a04b2fddf24c3e9 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=90ec3e4375804e9b input=a9049054013a1b77]*/ diff --git a/Python/clinic/import.c.h b/Python/clinic/import.c.h index de62714ebddafa..2e4e178b308406 100644 --- a/Python/clinic/import.c.h +++ b/Python/clinic/import.c.h @@ -34,8 +34,9 @@ PyDoc_STRVAR(_imp_acquire_lock__doc__, "\n" "Acquires the interpreter\'s import lock for the current thread.\n" "\n" -"This lock should be used by import hooks to ensure thread-safety when importing\n" -"modules. On platforms without threads, this function does nothing."); +"This lock should be used by import hooks to ensure thread-safety when\n" +"importing modules. On platforms without threads, this function does\n" +"nothing."); #define _IMP_ACQUIRE_LOCK_METHODDEF \ {"acquire_lock", (PyCFunction)_imp_acquire_lock, METH_NOARGS, _imp_acquire_lock__doc__}, @@ -664,4 +665,4 @@ _imp__set_lazy_attributes(PyObject *module, PyObject *const *args, Py_ssize_t na #ifndef _IMP_EXEC_DYNAMIC_METHODDEF #define _IMP_EXEC_DYNAMIC_METHODDEF #endif /* !defined(_IMP_EXEC_DYNAMIC_METHODDEF) */ -/*[clinic end generated code: output=5fa42f580441b3fa input=a9049054013a1b77]*/ +/*[clinic end generated code: output=0974db098d601372 input=a9049054013a1b77]*/ diff --git a/Python/clinic/marshal.c.h b/Python/clinic/marshal.c.h index 6c00b2b31b007f..ec0d2eb8a2af54 100644 --- a/Python/clinic/marshal.c.h +++ b/Python/clinic/marshal.c.h @@ -195,8 +195,8 @@ PyDoc_STRVAR(marshal_dumps__doc__, " allow_code\n" " Allow to write code objects.\n" "\n" -"Raise a ValueError exception if value has (or contains an object that has) an\n" -"unsupported type."); +"Raise a ValueError exception if value has (or contains an object that\n" +"has) an unsupported type."); #define MARSHAL_DUMPS_METHODDEF \ {"dumps", _PyCFunction_CAST(marshal_dumps), METH_FASTCALL|METH_KEYWORDS, marshal_dumps__doc__}, @@ -280,8 +280,8 @@ PyDoc_STRVAR(marshal_loads__doc__, " allow_code\n" " Allow to load code objects.\n" "\n" -"If no valid value is found, raise EOFError, ValueError or TypeError. Extra\n" -"bytes in the input are ignored."); +"If no valid value is found, raise EOFError, ValueError or TypeError.\n" +"Extra bytes in the input are ignored."); #define MARSHAL_LOADS_METHODDEF \ {"loads", _PyCFunction_CAST(marshal_loads), METH_FASTCALL|METH_KEYWORDS, marshal_loads__doc__}, @@ -351,4 +351,4 @@ marshal_loads(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObjec return return_value; } -/*[clinic end generated code: output=3e4bfc070a3c78ac input=a9049054013a1b77]*/ +/*[clinic end generated code: output=a574570c3717f60e input=a9049054013a1b77]*/ diff --git a/Python/clinic/sysmodule.c.h b/Python/clinic/sysmodule.c.h index 86e942ec2b8afb..75ce493f8688d6 100644 --- a/Python/clinic/sysmodule.c.h +++ b/Python/clinic/sysmodule.c.h @@ -1395,7 +1395,8 @@ PyDoc_STRVAR(sys__stats_dump__doc__, "\n" "Dump stats to file, and clears the stats.\n" "\n" -"Return False if no statistics were not dumped because stats gathering was off."); +"Return False if no statistics were not dumped because stats gathering\n" +"was off."); #define SYS__STATS_DUMP_METHODDEF \ {"_stats_dump", (PyCFunction)sys__stats_dump, METH_NOARGS, sys__stats_dump__doc__}, @@ -1543,16 +1544,16 @@ PyDoc_STRVAR(sys_remote_exec__doc__, "Executes a file containing Python code in a given remote Python process.\n" "\n" "This function returns immediately, and the code will be executed by the\n" -"target process\'s main thread at the next available opportunity, similarly\n" -"to how signals are handled. There is no interface to determine when the\n" -"code has been executed. The caller is responsible for making sure that\n" -"the file still exists whenever the remote process tries to read it and that\n" -"it hasn\'t been overwritten.\n" +"target process\'s main thread at the next available opportunity,\n" +"similarly to how signals are handled. There is no interface to\n" +"determine when the code has been executed. The caller is responsible\n" +"for making sure that the file still exists whenever the remote process\n" +"tries to read it and that it hasn\'t been overwritten.\n" "\n" -"The remote process must be running a CPython interpreter of the same major\n" -"and minor version as the local process. If either the local or remote\n" -"interpreter is pre-release (alpha, beta, or release candidate) then the\n" -"local and remote interpreters must be the same exact version.\n" +"The remote process must be running a CPython interpreter of the same\n" +"major and minor version as the local process. If either the local or\n" +"remote interpreter is pre-release (alpha, beta, or release candidate)\n" +"then the local and remote interpreters must be the same exact version.\n" "\n" "Args:\n" " pid (int): The process ID of the target Python process.\n" @@ -1915,7 +1916,8 @@ PyDoc_STRVAR(sys_set_lazy_imports__doc__, "The mode parameter must be one of the following strings:\n" "- \"all\": All top-level imports become potentially lazy\n" "- \"none\": All lazy imports are suppressed (even explicitly marked ones)\n" -"- \"normal\": Only explicitly marked imports (with \'lazy\' keyword) are lazy\n" +"- \"normal\": Only explicitly marked imports (with \'lazy\' keyword) are\n" +" lazy\n" "\n" "In addition to the mode, lazy imports can be controlled via the filter\n" "provided to sys.set_lazy_imports_filter"); @@ -2121,4 +2123,4 @@ _jit_is_active(PyObject *module, PyObject *Py_UNUSED(ignored)) #ifndef SYS_GETANDROIDAPILEVEL_METHODDEF #define SYS_GETANDROIDAPILEVEL_METHODDEF #endif /* !defined(SYS_GETANDROIDAPILEVEL_METHODDEF) */ -/*[clinic end generated code: output=e8333fe10c01ae66 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=94838be2d96b4522 input=a9049054013a1b77]*/ diff --git a/Python/context.c b/Python/context.c index 62b582f271ffe5..3170018da8c1c9 100644 --- a/Python/context.c +++ b/Python/context.c @@ -618,6 +618,7 @@ context_tp_contains(PyObject *op, PyObject *key) /*[clinic input] +@permit_long_summary _contextvars.Context.get key: object default: object = None @@ -625,14 +626,14 @@ _contextvars.Context.get Return the value for `key` if `key` has the value in the context object. -If `key` does not exist, return `default`. If `default` is not given, -return None. +If `key` does not exist, return `default`. If `default` is not +given, return None. [clinic start generated code]*/ static PyObject * _contextvars_Context_get_impl(PyContext *self, PyObject *key, PyObject *default_value) -/*[clinic end generated code: output=0c54aa7664268189 input=c8eeb81505023995]*/ +/*[clinic end generated code: output=0c54aa7664268189 input=d669a0d56fabb0a5]*/ { if (context_check_key_type(key)) { return NULL; @@ -1006,23 +1007,24 @@ contextvar_tp_repr(PyObject *op) /*[clinic input] -@permit_long_docstring_body _contextvars.ContextVar.get default: object = NULL / Return a value for the context variable for the current context. -If there is no value for the variable in the current context, the method will: - * return the value of the default argument of the method, if provided; or - * return the default value for the context variable, if it was created - with one; or +If there is no value for the variable in the current context, the +method will: + * return the value of the default argument of the method, if + provided; or + * return the default value for the context variable, if it was + created with one; or * raise a LookupError. [clinic start generated code]*/ static PyObject * _contextvars_ContextVar_get_impl(PyContextVar *self, PyObject *default_value) -/*[clinic end generated code: output=0746bd0aa2ced7bf input=da66664d5d0af4ad]*/ +/*[clinic end generated code: output=0746bd0aa2ced7bf input=83814c6aef4a9fe3]*/ { PyObject *val; if (PyContextVar_Get((PyObject *)self, default_value, &val) < 0) { @@ -1038,41 +1040,41 @@ _contextvars_ContextVar_get_impl(PyContextVar *self, PyObject *default_value) } /*[clinic input] -@permit_long_docstring_body +@permit_long_summary _contextvars.ContextVar.set value: object / Call to set a new value for the context variable in the current context. -The required value argument is the new value for the context variable. +The required value argument is the new value for the context +variable. -Returns a Token object that can be used to restore the variable to its previous -value via the `ContextVar.reset()` method. +Returns a Token object that can be used to restore the variable to +its previous value via the `ContextVar.reset()` method. [clinic start generated code]*/ static PyObject * _contextvars_ContextVar_set_impl(PyContextVar *self, PyObject *value) -/*[clinic end generated code: output=1b562d35cc79c806 input=73ebbbfc7c98f6cd]*/ +/*[clinic end generated code: output=1b562d35cc79c806 input=04ef8dcd810f5be6]*/ { return PyContextVar_Set((PyObject *)self, value); } /*[clinic input] -@permit_long_docstring_body _contextvars.ContextVar.reset token: object / Reset the context variable. -The variable is reset to the value it had before the `ContextVar.set()` that -created the token was used. +The variable is reset to the value it had before the +`ContextVar.set()` that created the token was used. [clinic start generated code]*/ static PyObject * _contextvars_ContextVar_reset_impl(PyContextVar *self, PyObject *token) -/*[clinic end generated code: output=3205d2bdff568521 input=b8bc514a9245242a]*/ +/*[clinic end generated code: output=3205d2bdff568521 input=dd33cfcb18c00e37]*/ { if (!PyContextToken_CheckExact(token)) { PyErr_Format(PyExc_TypeError, diff --git a/Python/import.c b/Python/import.c index 352941a836ef21..aa4ee660fa75da 100644 --- a/Python/import.c +++ b/Python/import.c @@ -5025,18 +5025,18 @@ _imp_lock_held_impl(PyObject *module) } /*[clinic input] -@permit_long_docstring_body _imp.acquire_lock Acquires the interpreter's import lock for the current thread. -This lock should be used by import hooks to ensure thread-safety when importing -modules. On platforms without threads, this function does nothing. +This lock should be used by import hooks to ensure thread-safety when +importing modules. On platforms without threads, this function does +nothing. [clinic start generated code]*/ static PyObject * _imp_acquire_lock_impl(PyObject *module) -/*[clinic end generated code: output=1aff58cb0ee1b026 input=e1a4ef049d34e7dd]*/ +/*[clinic end generated code: output=1aff58cb0ee1b026 input=60e9c1b4ab471ead]*/ { PyInterpreterState *interp = _PyInterpreterState_GET(); _PyImport_AcquireLock(interp); @@ -5194,6 +5194,7 @@ _imp_init_frozen_impl(PyObject *module, PyObject *name) } /*[clinic input] +@permit_long_summary _imp.find_frozen name: unicode @@ -5214,7 +5215,7 @@ The returned info (a 2-tuple): static PyObject * _imp_find_frozen_impl(PyObject *module, PyObject *name, int withdata) -/*[clinic end generated code: output=8c1c3c7f925397a5 input=22a8847c201542fd]*/ +/*[clinic end generated code: output=8c1c3c7f925397a5 input=30a7a50da49eca97]*/ { struct frozen_info info; frozen_status status = find_frozen(name, &info); @@ -5401,6 +5402,7 @@ _imp__override_frozen_modules_for_tests_impl(PyObject *module, int override) } /*[clinic input] +@permit_long_summary _imp._override_multi_interp_extensions_check override: int @@ -5414,7 +5416,7 @@ _imp._override_multi_interp_extensions_check static PyObject * _imp__override_multi_interp_extensions_check_impl(PyObject *module, int override) -/*[clinic end generated code: output=3ff043af52bbf280 input=e086a2ea181f92ae]*/ +/*[clinic end generated code: output=3ff043af52bbf280 input=24f23f8510a7f6e7]*/ { PyInterpreterState *interp = _PyInterpreterState_GET(); if (_Py_IsMainInterpreter(interp)) { diff --git a/Python/marshal.c b/Python/marshal.c index 990afefe0d3b41..9688d426419c2f 100644 --- a/Python/marshal.c +++ b/Python/marshal.c @@ -2061,7 +2061,6 @@ marshal_load_impl(PyObject *module, PyObject *file, int allow_code) /*[clinic input] @permit_long_summary -@permit_long_docstring_body marshal.dumps value: object @@ -2075,14 +2074,14 @@ marshal.dumps Return the bytes object that would be written to a file by dump(value, file). -Raise a ValueError exception if value has (or contains an object that has) an -unsupported type. +Raise a ValueError exception if value has (or contains an object that +has) an unsupported type. [clinic start generated code]*/ static PyObject * marshal_dumps_impl(PyObject *module, PyObject *value, int version, int allow_code) -/*[clinic end generated code: output=115f90da518d1d49 input=80cd3f30c1637ade]*/ +/*[clinic end generated code: output=115f90da518d1d49 input=dc1edcafd43124c5]*/ { return _PyMarshal_WriteObjectToString(value, version, allow_code); } @@ -2098,13 +2097,13 @@ marshal.loads Convert the bytes-like object to a value. -If no valid value is found, raise EOFError, ValueError or TypeError. Extra -bytes in the input are ignored. +If no valid value is found, raise EOFError, ValueError or TypeError. +Extra bytes in the input are ignored. [clinic start generated code]*/ static PyObject * marshal_loads_impl(PyObject *module, Py_buffer *bytes, int allow_code) -/*[clinic end generated code: output=62c0c538d3edc31f input=14de68965b45aaa7]*/ +/*[clinic end generated code: output=62c0c538d3edc31f input=286f1dbd6811d2ad]*/ { RFILE rf; char *s = bytes->buf; diff --git a/Python/sysmodule.c b/Python/sysmodule.c index c6447d03369a94..b2f33d4e809d26 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -1893,6 +1893,7 @@ sys_mdebug_impl(PyObject *module, int flag) /*[clinic input] +@permit_long_summary sys.get_int_max_str_digits Return the maximum string digits limit for non-binary int<->str conversions. @@ -1900,7 +1901,7 @@ Return the maximum string digits limit for non-binary int<->str conversions. static PyObject * sys_get_int_max_str_digits_impl(PyObject *module) -/*[clinic end generated code: output=0042f5e8ae0e8631 input=61bf9f99bc8b112d]*/ +/*[clinic end generated code: output=0042f5e8ae0e8631 input=77fb74e987ba7ecb]*/ { PyInterpreterState *interp = _PyInterpreterState_GET(); return PyLong_FromLong(interp->long_state.max_str_digits); @@ -1908,6 +1909,7 @@ sys_get_int_max_str_digits_impl(PyObject *module) /*[clinic input] +@permit_long_summary sys.set_int_max_str_digits maxdigits: int @@ -1917,7 +1919,7 @@ Set the maximum string digits limit for non-binary int<->str conversions. static PyObject * sys_set_int_max_str_digits_impl(PyObject *module, int maxdigits) -/*[clinic end generated code: output=734d4c2511f2a56d input=d7e3f325db6910c5]*/ +/*[clinic end generated code: output=734d4c2511f2a56d input=d4c0bf50c466d57a]*/ { if (_PySys_SetIntMaxStrDigits(maxdigits) < 0) { return NULL; @@ -2129,6 +2131,7 @@ sys__getframe_impl(PyObject *module, int depth) } /*[clinic input] +@permit_long_summary sys._current_frames Return a dict mapping each thread's thread id to its current stack frame. @@ -2138,7 +2141,7 @@ This function should be used for specialized purposes only. static PyObject * sys__current_frames_impl(PyObject *module) -/*[clinic end generated code: output=d2a41ac0a0a3809a input=2a9049c5f5033691]*/ +/*[clinic end generated code: output=d2a41ac0a0a3809a input=e1ce34f43501e0d6]*/ { return _PyThread_CurrentFrames(); } @@ -2317,17 +2320,17 @@ sys__stats_clear_impl(PyObject *module) } /*[clinic input] -@permit_long_docstring_body sys._stats_dump -> bool Dump stats to file, and clears the stats. -Return False if no statistics were not dumped because stats gathering was off. +Return False if no statistics were not dumped because stats gathering +was off. [clinic start generated code]*/ static int sys__stats_dump_impl(PyObject *module) -/*[clinic end generated code: output=6e346b4ba0de4489 input=5a3ab40d2fb5af47]*/ +/*[clinic end generated code: output=6e346b4ba0de4489 input=7f3b7758cb59d2ff]*/ { int res = _Py_PrintSpecializationStats(1); _Py_StatsClear(); @@ -2471,16 +2474,16 @@ sys.remote_exec Executes a file containing Python code in a given remote Python process. This function returns immediately, and the code will be executed by the -target process's main thread at the next available opportunity, similarly -to how signals are handled. There is no interface to determine when the -code has been executed. The caller is responsible for making sure that -the file still exists whenever the remote process tries to read it and that -it hasn't been overwritten. +target process's main thread at the next available opportunity, +similarly to how signals are handled. There is no interface to +determine when the code has been executed. The caller is responsible +for making sure that the file still exists whenever the remote process +tries to read it and that it hasn't been overwritten. -The remote process must be running a CPython interpreter of the same major -and minor version as the local process. If either the local or remote -interpreter is pre-release (alpha, beta, or release candidate) then the -local and remote interpreters must be the same exact version. +The remote process must be running a CPython interpreter of the same +major and minor version as the local process. If either the local or +remote interpreter is pre-release (alpha, beta, or release candidate) +then the local and remote interpreters must be the same exact version. Args: pid (int): The process ID of the target Python process. @@ -2490,7 +2493,7 @@ local and remote interpreters must be the same exact version. static PyObject * sys_remote_exec_impl(PyObject *module, int pid, PyObject *script) -/*[clinic end generated code: output=7d94c56afe4a52c0 input=39908ca2c5fe1eb0]*/ +/*[clinic end generated code: output=7d94c56afe4a52c0 input=7bd58f8da20cb74c]*/ { PyObject *path; const char *debugger_script_path; @@ -2843,7 +2846,8 @@ Sets the global lazy imports mode. The mode parameter must be one of the following strings: - "all": All top-level imports become potentially lazy - "none": All lazy imports are suppressed (even explicitly marked ones) -- "normal": Only explicitly marked imports (with 'lazy' keyword) are lazy +- "normal": Only explicitly marked imports (with 'lazy' keyword) are + lazy In addition to the mode, lazy imports can be controlled via the filter provided to sys.set_lazy_imports_filter @@ -2852,7 +2856,7 @@ provided to sys.set_lazy_imports_filter static PyObject * sys_set_lazy_imports_impl(PyObject *module, PyObject *mode) -/*[clinic end generated code: output=1ff34ba6c4feaf73 input=f04e70d8bf9fe4f6]*/ +/*[clinic end generated code: output=1ff34ba6c4feaf73 input=cb6df28a51844a31]*/ { PyImport_LazyImportsMode lazy_mode; if (!PyUnicode_Check(mode)) { diff --git a/Tools/clinic/libclinic/function.py b/Tools/clinic/libclinic/function.py index f981f0bcaf89f0..1c643caea98e3b 100644 --- a/Tools/clinic/libclinic/function.py +++ b/Tools/clinic/libclinic/function.py @@ -173,12 +173,12 @@ def docstring_line_width(self) -> int: Pydoc adds indentation when displaying functions and methods. To keep the total width of within 80 characters, we use a - maximum of 76 characters for global functions and classes, - and 72 characters for methods. + maximum of 72 characters for global functions and classes, + and 68 characters for methods. """ if self.cls is not None and not self.kind.new_or_init: - return 72 - return 76 + return 68 + return 72 def __repr__(self) -> str: return f'' From c95aa3aeb1a86e8f2e08da8868a0e622790ee98b Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 25 May 2026 09:05:24 +0200 Subject: [PATCH 138/818] [3.15] gh-149449: Fix use-after-free in `_PyUnicode_GetNameCAPI` (GH-150323) (#150352) gh-149449: Fix use-after-free in `_PyUnicode_GetNameCAPI` (GH-150323) (cherry picked from commit 43c60ec2fddd316a4a6b7b6c68eae7cb66df0850) Co-authored-by: Pieter Eendebak Co-authored-by: Kumar Aditya --- Lib/test/test_unicodedata.py | 16 ++++++++++ ...-05-23-22-08-01.gh-issue-149449.2lhQFF.rst | 3 ++ Modules/unicodedata.c | 31 +++++-------------- Tools/c-analyzer/cpython/ignored.tsv | 1 + 4 files changed, 28 insertions(+), 23 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-05-23-22-08-01.gh-issue-149449.2lhQFF.rst diff --git a/Lib/test/test_unicodedata.py b/Lib/test/test_unicodedata.py index 8ecb0df2f8e5dd..060d81415aa1f1 100644 --- a/Lib/test/test_unicodedata.py +++ b/Lib/test/test_unicodedata.py @@ -1106,6 +1106,22 @@ def test_failed_import_during_compiling(self): "(can't load unicodedata module)" self.assertIn(error, result.err.decode("ascii")) + def test_unicodedata_unload_reload(self): + # gh-149449: dropping unicodedata and running gc must not leave the + # cached _ucnhash_CAPI pointer dangling. + code = ( + "import gc, sys\n" + "assert '\\N{GRINNING FACE}'.encode(" + " 'ascii', errors='namereplace') == b'\\\\N{GRINNING FACE}'\n" + "compile(r\"x = '\\\\N{LATIN CAPITAL LETTER A}'\", '', 'exec')\n" + "del sys.modules['unicodedata']\n" + "gc.collect()\n" + "assert '\\N{WINKING FACE}'.encode(" + " 'ascii', errors='namereplace') == b'\\\\N{WINKING FACE}'\n" + "compile(r\"x = '\\\\N{LATIN CAPITAL LETTER B}'\", '', 'exec')\n" + ) + script_helper.assert_python_ok("-c", code) + def test_decimal_numeric_consistent(self): # Test that decimal and numeric are consistent, # i.e. if a character has a decimal value, diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-23-22-08-01.gh-issue-149449.2lhQFF.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-23-22-08-01.gh-issue-149449.2lhQFF.rst new file mode 100644 index 00000000000000..7d11442468d207 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-23-22-08-01.gh-issue-149449.2lhQFF.rst @@ -0,0 +1,3 @@ +Fix a use-after-free crash when the :mod:`unicodedata` module was removed +from :data:`sys.modules` and garbage-collected between calls that decode +``\N{...}`` escapes or use the ``namereplace`` codec error handler. diff --git a/Modules/unicodedata.c b/Modules/unicodedata.c index 31ad916b2c5c26..6bb25fc0b63781 100644 --- a/Modules/unicodedata.c +++ b/Modules/unicodedata.c @@ -1548,32 +1548,17 @@ capi_getcode(const char* name, int namelen, Py_UCS4* code, return _check_alias_and_seq(code, with_named_seq); } -static void -unicodedata_destroy_capi(PyObject *capsule) -{ - void *capi = PyCapsule_GetPointer(capsule, PyUnicodeData_CAPSULE_NAME); - PyMem_Free(capi); -} - static PyObject * unicodedata_create_capi(void) { - _PyUnicode_Name_CAPI *capi = PyMem_Malloc(sizeof(_PyUnicode_Name_CAPI)); - if (capi == NULL) { - PyErr_NoMemory(); - return NULL; - } - capi->getname = capi_getucname; - capi->getcode = capi_getcode; - - PyObject *capsule = PyCapsule_New(capi, - PyUnicodeData_CAPSULE_NAME, - unicodedata_destroy_capi); - if (capsule == NULL) { - PyMem_Free(capi); - } - return capsule; -}; + // Statically allocated so that any cached pointers stay valid after unicodedata + // is removed from sys.modules and the capsule is gc'd (gh-149449). + static _PyUnicode_Name_CAPI capi = { + .getname = capi_getucname, + .getcode = capi_getcode, + }; + return PyCapsule_New(&capi, PyUnicodeData_CAPSULE_NAME, NULL); +} /* -------------------------------------------------------------------- */ diff --git a/Tools/c-analyzer/cpython/ignored.tsv b/Tools/c-analyzer/cpython/ignored.tsv index ddfb93a424c018..bf08e5568205e7 100644 --- a/Tools/c-analyzer/cpython/ignored.tsv +++ b/Tools/c-analyzer/cpython/ignored.tsv @@ -327,6 +327,7 @@ Modules/pyexpat.c - error_info_of - Modules/pyexpat.c - handler_info - Modules/termios.c - termios_constants - Modules/timemodule.c init_timezone YEAR - +Modules/unicodedata.c unicodedata_create_capi capi - Objects/bytearrayobject.c - _PyByteArray_empty_string - Objects/complexobject.c - c_1 - Objects/exceptions.c - static_exceptions - From 5292bb45d95dd27e92229d94ab3471264ddf0121 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 25 May 2026 10:19:05 +0200 Subject: [PATCH 139/818] [3.15] gh-150285: Fix too long docstrings in _wmi.exec_query (GH-150373) (GH-150377) (cherry picked from commit fbeafc062e55a52ba7369c36be0b3eb34eabb560) Co-authored-by: Serhiy Storchaka --- PC/_wmimodule.cpp | 7 +++---- PC/clinic/_wmimodule.cpp.h | 6 +++--- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/PC/_wmimodule.cpp b/PC/_wmimodule.cpp index 86df2c7183c30d..b9a229b1398ec8 100644 --- a/PC/_wmimodule.cpp +++ b/PC/_wmimodule.cpp @@ -224,20 +224,19 @@ wait_event(HANDLE event, DWORD timeout) /*[clinic input] -@permit_long_docstring_body _wmi.exec_query query: unicode Runs a WMI query against the local machine. -This returns a single string with 'name=value' pairs in a flat array separated -by null characters. +This returns a single string with 'name=value' pairs in a flat array +separated by null characters. [clinic start generated code]*/ static PyObject * _wmi_exec_query_impl(PyObject *module, PyObject *query) -/*[clinic end generated code: output=a62303d5bb5e003f input=621f5c50c56d06d0]*/ +/*[clinic end generated code: output=a62303d5bb5e003f input=a8d5710acdfbf515]*/ /*[clinic end generated code]*/ { diff --git a/PC/clinic/_wmimodule.cpp.h b/PC/clinic/_wmimodule.cpp.h index 38d52d0329dcc0..6c18990f056b5f 100644 --- a/PC/clinic/_wmimodule.cpp.h +++ b/PC/clinic/_wmimodule.cpp.h @@ -14,8 +14,8 @@ PyDoc_STRVAR(_wmi_exec_query__doc__, "\n" "Runs a WMI query against the local machine.\n" "\n" -"This returns a single string with \'name=value\' pairs in a flat array separated\n" -"by null characters."); +"This returns a single string with \'name=value\' pairs in a flat array\n" +"separated by null characters."); #define _WMI_EXEC_QUERY_METHODDEF \ {"exec_query", _PyCFunction_CAST(_wmi_exec_query), METH_FASTCALL|METH_KEYWORDS, _wmi_exec_query__doc__}, @@ -72,4 +72,4 @@ _wmi_exec_query(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObj exit: return return_value; } -/*[clinic end generated code: output=802bcbcba69e8d0e input=a9049054013a1b77]*/ +/*[clinic end generated code: output=f246d0e568cc2d2c input=a9049054013a1b77]*/ From 03244b9f043a31eaa9243d90d01139294155e1f3 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 25 May 2026 10:19:36 +0200 Subject: [PATCH 140/818] [3.15] gh-150285: Fix too long docstrings in some Python modules (GH-150366) (GH-150375) (cherry picked from commit 01c6d3d76bf222d8b847c97e0a3d3fad0c1b1fe3) Co-authored-by: Serhiy Storchaka --- Lib/_collections_abc.py | 29 +++++++----- Lib/enum.py | 25 +++++----- Lib/functools.py | 12 ++--- Lib/glob.py | 34 +++++++------- Lib/gzip.py | 65 +++++++++++++------------- Lib/json/__init__.py | 26 ++++++----- Lib/ntpath.py | 16 ++++--- Lib/tarfile.py | 33 +++++++------ Lib/test/test_enum.py | 4 +- Lib/types.py | 25 +++++----- Lib/xml/etree/ElementTree.py | 89 +++++++++++++++++++++--------------- Lib/zipfile/__init__.py | 47 +++++++++---------- 12 files changed, 220 insertions(+), 185 deletions(-) diff --git a/Lib/_collections_abc.py b/Lib/_collections_abc.py index 23cc6d8faae2da..0e1d8ccf44a435 100644 --- a/Lib/_collections_abc.py +++ b/Lib/_collections_abc.py @@ -461,8 +461,8 @@ def __subclasshook__(cls, C): class _CallableGenericAlias(GenericAlias): """ Represent `Callable[argtypes, resulttype]`. - This sets ``__args__`` to a tuple containing the flattened ``argtypes`` - followed by ``resulttype``. + This sets ``__args__`` to a tuple containing the flattened + ``argtypes`` followed by ``resulttype``. Example: ``Callable[[int, str], float]`` sets ``__args__`` to ``(int, str, float)``. @@ -928,8 +928,9 @@ def __delitem__(self, key): __marker = object() def pop(self, key, default=__marker): - '''D.pop(k[,d]) -> v, remove specified key and return the corresponding value. - If key is not found, d is returned if given, otherwise KeyError is raised. + '''D.pop(k[,d]) -> v, remove specified key and return the corresponding + value. If key is not found, d is returned if given, otherwise + KeyError is raised. ''' try: value = self[key] @@ -963,9 +964,12 @@ def clear(self): def update(self, other=(), /, **kwds): ''' D.update([E, ]**F) -> None. Update D from mapping/iterable E and F. - If E present and has a .keys() method, does: for k in E.keys(): D[k] = E[k] - If E present and lacks .keys() method, does: for (k, v) in E: D[k] = v - In either case, this is followed by: for k, v in F.items(): D[k] = v + If E present and has a .keys() method, does: + for k in E.keys(): D[k] = E[k] + If E present and lacks .keys() method, does: + for (k, v) in E: D[k] = v + In either case, this is followed by: + for k, v in F.items(): D[k] = v ''' if isinstance(other, Mapping): for key in other: @@ -1030,8 +1034,8 @@ def __reversed__(self): yield self[i] def index(self, value, start=0, stop=None): - '''S.index(value, [start, [stop]]) -> integer -- return first index of value. - Raises ValueError if the value is not present. + '''S.index(value, [start, [stop]]) -> integer -- return first index of + value. Raises ValueError if the value is not present. Supporting start and stop arguments is optional, but recommended. @@ -1139,15 +1143,16 @@ def reverse(self): self[i], self[n-i-1] = self[n-i-1], self[i] def extend(self, values): - 'S.extend(iterable) -- extend sequence by appending elements from the iterable' + """S.extend(iterable) -- extend sequence by appending elements from the + iterable""" if values is self: values = list(values) for v in values: self.append(v) def pop(self, index=-1): - '''S.pop([index]) -> item -- remove and return item at index (default last). - Raise IndexError if list is empty or index is out of range. + '''S.pop([index]) -> item -- remove and return item at index (default + last). Raise IndexError if list is empty or index is out of range. ''' v = self[index] del self[index] diff --git a/Lib/enum.py b/Lib/enum.py index 025e973446d88d..f536a3eae2b6e3 100644 --- a/Lib/enum.py +++ b/Lib/enum.py @@ -702,9 +702,9 @@ def __call__(cls, value, names=_not_given, *values, module=None, qualname=None, """ Either returns an existing member, or creates a new enum class. - This method is used both when an enum class is given a value to match - to an enumeration member (i.e. Color(3)) and for the functional API - (i.e. Color = Enum('Color', names='RED GREEN BLUE')). + This method is used both when an enum class is given a value to + match to an enumeration member (i.e. Color(3)) and for the + functional API (i.e. Color = Enum('Color', names='RED GREEN BLUE')). The value lookup branch is chosen if the enum is final. @@ -712,16 +712,17 @@ def __call__(cls, value, names=_not_given, *values, module=None, qualname=None, `value` will be the name of the new class. - `names` should be either a string of white-space/comma delimited names - (values will start at `start`), or an iterator/mapping of name, value pairs. + `names` should be either a string of white-space/comma delimited + names (values will start at `start`), or an iterator/mapping of + name, value pairs. `module` should be set to the module this class is being created in; - if it is not set, an attempt to find that module will be made, but if - it fails the class will not be picklable. + if it is not set, an attempt to find that module will be made, but + if it fails the class will not be picklable. - `qualname` should be set to the actual location this class can be found - at in its module; by default it is set to the global scope. If this is - not correct, unpickling will fail in some circumstances. + `qualname` should be set to the actual location this class can be + found at in its module; by default it is set to the global scope. + If this is not correct, unpickling will fail in some circumstances. `type`, if set, will be mixed in as the first base class. """ @@ -819,8 +820,8 @@ def __members__(cls): """ Returns a mapping of member name->value. - This mapping lists all enum members, including aliases. Note that this - is a read-only view of the internal mapping. + This mapping lists all enum members, including aliases. Note that + this is a read-only view of the internal mapping. """ return MappingProxyType(cls._member_map_) diff --git a/Lib/functools.py b/Lib/functools.py index e03a77f204b544..c5aaa15f3d5e33 100644 --- a/Lib/functools.py +++ b/Lib/functools.py @@ -558,16 +558,16 @@ def lru_cache(maxsize=128, typed=False): If *maxsize* is set to None, the LRU features are disabled and the cache can grow without bound. - If *typed* is True, arguments of different types will be cached separately. - For example, f(decimal.Decimal("3.0")) and f(3.0) will be treated as - distinct calls with distinct results. Some types such as str and int may - be cached separately even when typed is false. + If *typed* is True, arguments of different types will be cached + separately. For example, f(decimal.Decimal("3.0")) and f(3.0) will be + treated as distinct calls with distinct results. Some types such as + str and int may be cached separately even when typed is false. Arguments to the cached function must be hashable. View the cache statistics named tuple (hits, misses, maxsize, currsize) - with f.cache_info(). Clear the cache and statistics with f.cache_clear(). - Access the underlying function with f.__wrapped__. + with f.cache_info(). Clear the cache and statistics with + f.cache_clear(). Access the underlying function with f.__wrapped__. See: https://en.wikipedia.org/wiki/Cache_replacement_policies#Least_recently_used_(LRU) diff --git a/Lib/glob.py b/Lib/glob.py index 575e4bcba5be0d..5a8ff46137ba5e 100644 --- a/Lib/glob.py +++ b/Lib/glob.py @@ -25,17 +25,17 @@ def glob(pathname, *, root_dir=None, dir_fd=None, recursive=False, The order of the returned list is undefined. Sort it if you need a particular order. - If `root_dir` is not None, it should be a path-like object specifying the - root directory for searching. It has the same effect as changing the - current directory before calling it (without actually - changing it). If pathname is relative, the result will contain - paths relative to `root_dir`. + If `root_dir` is not None, it should be a path-like object specifying + the root directory for searching. It has the same effect as changing + the current directory before calling it (without actually changing it). + If pathname is relative, the result will contain paths relative to + `root_dir`. If `dir_fd` is not None, it should be a file descriptor referring to a directory, and paths will then be relative to that directory. - If `include_hidden` is true, the patterns '*', '?', '**' will match hidden - directories. + If `include_hidden` is true, the patterns '*', '?', '**' will match + hidden directories. If `recursive` is true, the pattern '**' will match any files and zero or more directories and subdirectories. @@ -56,16 +56,16 @@ def iglob(pathname, *, root_dir=None, dir_fd=None, recursive=False, particular order. If `root_dir` is not None, it should be a path-like object specifying - the root directory for searching. It has the same effect as changing - the current directory before calling it (without actually - changing it). If pathname is relative, the result will contain - paths relative to `root_dir`. + the root directory for searching. It has the same effect as changing + the current directory before calling it (without actually changing it). + If pathname is relative, the result will contain paths relative to + `root_dir`. If `dir_fd` is not None, it should be a file descriptor referring to a directory, and paths will then be relative to that directory. - If `include_hidden` is true, the patterns '*', '?', '**' will match hidden - directories. + If `include_hidden` is true, the patterns '*', '?', '**' will match + hidden directories. If `recursive` is true, the pattern '**' will match any files and zero or more directories and subdirectories. @@ -279,15 +279,15 @@ def escape(pathname): def translate(pat, *, recursive=False, include_hidden=False, seps=None): """Translate a pathname with shell wildcards to a regular expression. - If `recursive` is true, the pattern segment '**' will match any number of - path segments. + If `recursive` is true, the pattern segment '**' will match any number + of path segments. If `include_hidden` is true, wildcards can match path segments beginning with a dot ('.'). If a sequence of separator characters is given to `seps`, they will be - used to split the pattern into segments and match path separators. If not - given, os.path.sep and os.path.altsep (where available) are used. + used to split the pattern into segments and match path separators. If + not given, os.path.sep and os.path.altsep (where available) are used. """ if not seps: if os.path.altsep: diff --git a/Lib/gzip.py b/Lib/gzip.py index 0713b922522ee1..c7b4563fdfe991 100644 --- a/Lib/gzip.py +++ b/Lib/gzip.py @@ -34,16 +34,16 @@ def open(filename, mode="rb", compresslevel=_COMPRESS_LEVEL_TRADEOFF, encoding=None, errors=None, newline=None): """Open a gzip-compressed file in binary or text mode. - The filename argument can be an actual filename (a str or bytes object), or - an existing file object to read from or write to. + The filename argument can be an actual filename (a str or bytes object), + or an existing file object to read from or write to. - The mode argument can be "r", "rb", "w", "wb", "x", "xb", "a" or "ab" for - binary mode, or "rt", "wt", "xt" or "at" for text mode. The default mode is - "rb", and the default compresslevel is 9. + The mode argument can be "r", "rb", "w", "wb", "x", "xb", "a" or "ab" + for binary mode, or "rt", "wt", "xt" or "at" for text mode. The default + mode is "rb", and the default compresslevel is 9. - For binary mode, this function is equivalent to the GzipFile constructor: - GzipFile(filename, mode, compresslevel). In this case, the encoding, errors - and newline arguments must not be provided. + For binary mode, this function is equivalent to the GzipFile + constructor: GzipFile(filename, mode, compresslevel). In this case, + the encoding, errors and newline arguments must not be provided. For text mode, a GzipFile object is created, and wrapped in an io.TextIOWrapper instance with the specified encoding, error handling @@ -148,8 +148,8 @@ class GzipFile(_streams.BaseStream): """The GzipFile class simulates most of the methods of a file object with the exception of the truncate() method. - This class only supports opening files in binary mode. If you need to open a - compressed file in text mode, use the gzip.open() function. + This class only supports opening files in binary mode. If you need to + open a compressed file in text mode, use the gzip.open() function. """ @@ -165,33 +165,34 @@ def __init__(self, filename=None, mode=None, non-trivial value. The new class instance is based on fileobj, which can be a regular - file, an io.BytesIO object, or any other object which simulates a file. - It defaults to None, in which case filename is opened to provide - a file object. + file, an io.BytesIO object, or any other object which simulates + a file. It defaults to None, in which case filename is opened to + provide a file object. When fileobj is not None, the filename argument is only used to be included in the gzip file header, which may include the original filename of the uncompressed file. It defaults to the filename of fileobj, if discernible; otherwise, it defaults to the empty string, - and in this case the original filename is not included in the header. - - The mode argument can be any of 'r', 'rb', 'a', 'ab', 'w', 'wb', 'x', or - 'xb' depending on whether the file will be read or written. The default - is the mode of fileobj if discernible; otherwise, the default is 'rb'. - A mode of 'r' is equivalent to one of 'rb', and similarly for 'w' and - 'wb', 'a' and 'ab', and 'x' and 'xb'. - - The compresslevel argument is an integer from 0 to 9 controlling the - level of compression; 1 is fastest and produces the least compression, - and 9 is slowest and produces the most compression. 0 is no compression - at all. The default is 9. - - The optional mtime argument is the timestamp requested by gzip. The time - is in Unix format, i.e., seconds since 00:00:00 UTC, January 1, 1970. - Set mtime to 0 to generate a compressed stream that does not depend on - creation time. If mtime is omitted or None, the current time is used. - If the resulting mtime is outside the range 0 to 2**32-1, then the - value 0 is used instead. + and in this case the original filename is not included in the + header. + + The mode argument can be any of 'r', 'rb', 'a', 'ab', 'w', 'wb', + 'x', or 'xb' depending on whether the file will be read or written. + The default is the mode of fileobj if discernible; otherwise, the + default is 'rb'. A mode of 'r' is equivalent to one of 'rb', and + similarly for 'w' and 'wb', 'a' and 'ab', and 'x' and 'xb'. + + The compresslevel argument is an integer from 0 to 9 controlling + the level of compression; 1 is fastest and produces the least + compression, and 9 is slowest and produces the most compression. + 0 is no compression at all. The default is 9. + + The optional mtime argument is the timestamp requested by gzip. + The time is in Unix format, i.e., seconds since 00:00:00 UTC, + January 1, 1970. Set mtime to 0 to generate a compressed stream + that does not depend on creation time. If mtime is omitted or None, + the current time is used. If the resulting mtime is outside the + range 0 to 2**32-1, then the value 0 is used instead. """ diff --git a/Lib/json/__init__.py b/Lib/json/__init__.py index 94c177cafa0294..9681a8fe53ec48 100644 --- a/Lib/json/__init__.py +++ b/Lib/json/__init__.py @@ -292,12 +292,13 @@ def load(fp, *, cls=None, object_hook=None, parse_float=None, ``object_hook`` is also defined, the ``object_pairs_hook`` takes priority. - ``array_hook`` is an optional function that will be called with the result - of any literal array decode (a ``list``). The return value of this function will - be used instead of the ``list``. This feature can be used along - ``object_pairs_hook`` to customize the resulting data structure - for example, - by setting that to ``frozendict`` and ``array_hook`` to ``tuple``, one can get - a deep immutable data structute from any JSON data. + ``array_hook`` is an optional function that will be called with the + result of any literal array decode (a ``list``). The return value of + this function will be used instead of the ``list``. This feature can + be used along ``object_pairs_hook`` to customize the resulting data + structure - for example, by setting that to ``frozendict`` and + ``array_hook`` to ``tuple``, one can get a deep immutable data structure + from any JSON data. To use a custom ``JSONDecoder`` subclass, specify it with the ``cls`` kwarg; otherwise ``JSONDecoder`` is used. @@ -327,12 +328,13 @@ def loads(s, *, cls=None, object_hook=None, parse_float=None, ``object_hook`` is also defined, the ``object_pairs_hook`` takes priority. - ``array_hook`` is an optional function that will be called with the result - of any literal array decode (a ``list``). The return value of this function will - be used instead of the ``list``. This feature can be used along - ``object_pairs_hook`` to customize the resulting data structure - for example, - by setting that to ``frozendict`` and ``array_hook`` to ``tuple``, one can get - a deep immutable data structute from any JSON data. + ``array_hook`` is an optional function that will be called with the + result of any literal array decode (a ``list``). The return value of + this function will be used instead of the ``list``. This feature can + be used along ``object_pairs_hook`` to customize the resulting data + structure - for example, by setting that to ``frozendict`` and + ``array_hook`` to ``tuple``, one can get a deep immutable data structure + from any JSON data. ``parse_float``, if specified, will be called with the string of every JSON float to be decoded. By default this is equivalent to diff --git a/Lib/ntpath.py b/Lib/ntpath.py index 7d637325240f1c..811e796f7766e9 100644 --- a/Lib/ntpath.py +++ b/Lib/ntpath.py @@ -152,12 +152,14 @@ def splitdrive(p, /): It is always true that: result[0] + result[1] == p - If the path contained a drive letter, drive_or_unc will contain everything - up to and including the colon. e.g. splitdrive("c:/dir") returns ("c:", "/dir") + If the path contained a drive letter, drive_or_unc will contain + everything up to and including the colon. e.g. splitdrive("c:/dir") + returns ("c:", "/dir") - If the path contained a UNC path, the drive_or_unc will contain the host name - and share up to but not including the fourth directory separator character. - e.g. splitdrive("//host/computer/dir") returns ("//host/computer", "/dir") + If the path contained a UNC path, the drive_or_unc will contain the + host name and share up to but not including the fourth directory + separator character. e.g. splitdrive("//host/computer/dir") returns + ("//host/computer", "/dir") Paths cannot contain both a drive letter and a UNC path. @@ -222,8 +224,8 @@ def splitroot(p, /): def split(p, /): """Split a pathname. - Return tuple (head, tail) where tail is everything after the final slash. - Either part may be empty.""" + Return tuple (head, tail) where tail is everything after the final + slash. Either part may be empty.""" p = os.fspath(p) seps = _get_bothseps(p) d, r, p = splitroot(p) diff --git a/Lib/tarfile.py b/Lib/tarfile.py index 5e43b4c19c0a8a..5bf2ede090100a 100644 --- a/Lib/tarfile.py +++ b/Lib/tarfile.py @@ -899,11 +899,14 @@ class TarInfo(object): size = 'Size in bytes.', mtime = 'Time of last modification.', chksum = 'Header checksum.', - type = ('File type. type is usually one of these constants: ' - 'REGTYPE, AREGTYPE, LNKTYPE, SYMTYPE, DIRTYPE, FIFOTYPE, ' - 'CONTTYPE, CHRTYPE, BLKTYPE, GNUTYPE_SPARSE.'), + type = ('File type. type is usually one of these constants: ' + 'REGTYPE,\n' + 'AREGTYPE, LNKTYPE, SYMTYPE, DIRTYPE, FIFOTYPE, ' + 'CONTTYPE, CHRTYPE,\n' + 'BLKTYPE, GNUTYPE_SPARSE.'), linkname = ('Name of the target file name, which is only present ' - 'in TarInfo objects of type LNKTYPE and SYMTYPE.'), + 'in TarInfo\n' + 'objects of type LNKTYPE and SYMTYPE.'), uname = 'User name.', gname = 'Group name.', devmajor = 'Device major number.', @@ -911,7 +914,8 @@ class TarInfo(object): offset = 'The tar header starts here.', offset_data = "The file's data starts here.", pax_headers = ('A dictionary containing key-value pairs of an ' - 'associated pax extended header.'), + 'associated pax\n' + 'extended header.'), sparse = 'Sparse member information.', _tarfile = None, _sparse_structs = None, @@ -2275,10 +2279,11 @@ def gettarinfo(self, name=None, arcname=None, fileobj=None): return tarinfo def list(self, verbose=True, *, members=None): - """Print a table of contents to sys.stdout. If 'verbose' is False, only - the names of the members are printed. If it is True, an 'ls -l'-like - output is produced. 'members' is optional and must be a subset of the - list returned by getmembers(). + """Print a table of contents to sys.stdout. + + If 'verbose' is False, only the names of the members are printed. + If it is True, an 'ls -l'-like output is produced. 'members' is + optional and must be a subset of the list returned by getmembers(). """ # Convert tarinfo type to stat type. type2mode = {REGTYPE: stat.S_IFREG, SYMTYPE: stat.S_IFLNK, @@ -2369,10 +2374,12 @@ def add(self, name, arcname=None, recursive=True, *, filter=None): self.addfile(tarinfo) def addfile(self, tarinfo, fileobj=None): - """Add the TarInfo object 'tarinfo' to the archive. If 'tarinfo' represents - a non zero-size regular file, the 'fileobj' argument should be a binary file, - and tarinfo.size bytes are read from it and added to the archive. - You can create TarInfo objects directly, or by using gettarinfo(). + """Add the TarInfo object 'tarinfo' to the archive. + + If 'tarinfo' represents a non zero-size regular file, the 'fileobj' + argument should be a binary file, and tarinfo.size bytes are read + from it and added to the archive. You can create TarInfo objects + directly, or by using gettarinfo(). """ self._check("awx") diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py index 779457119e8f0e..e0dcc6b8a519e7 100644 --- a/Lib/test/test_enum.py +++ b/Lib/test/test_enum.py @@ -5021,8 +5021,8 @@ class Color(enum.Enum) | __members__ | Returns a mapping of member name->value. | - | This mapping lists all enum members, including aliases. Note that this - | is a read-only view of the internal mapping.""" + | This mapping lists all enum members, including aliases. Note that + | this is a read-only view of the internal mapping.""" expected_help_output_without_docs = """\ Help on class Color in module %s: diff --git a/Lib/types.py b/Lib/types.py index b4f9a5c5140860..6c069591ab26ef 100644 --- a/Lib/types.py +++ b/Lib/types.py @@ -195,18 +195,19 @@ class Baz(list[str]): ... class DynamicClassAttribute: """Route attribute access on a class to __getattr__. - This is a descriptor, used to define attributes that act differently when - accessed through an instance and through a class. Instance access remains - normal, but access to an attribute through a class will be routed to the - class's __getattr__ method; this is done by raising AttributeError. - - This allows one to have properties active on an instance, and have virtual - attributes on the class with the same name. (Enum used this between Python - versions 3.4 - 3.9 .) - - Subclass from this to use a different method of accessing virtual attributes - and still be treated properly by the inspect module. (Enum uses this since - Python 3.10 .) + This is a descriptor, used to define attributes that act differently + when accessed through an instance and through a class. Instance access + remains normal, but access to an attribute through a class will be + routed to the class's __getattr__ method; this is done by raising + AttributeError. + + This allows one to have properties active on an instance, and have + virtual attributes on the class with the same name. (Enum used this + between Python versions 3.4 - 3.9 .) + + Subclass from this to use a different method of accessing virtual + attributes and still be treated properly by the inspect module. (Enum + uses this since Python 3.10 .) """ def __init__(self, fget=None, fset=None, fdel=None, doc=None): diff --git a/Lib/xml/etree/ElementTree.py b/Lib/xml/etree/ElementTree.py index 85766e02b531ce..75bebc0b1668ab 100644 --- a/Lib/xml/etree/ElementTree.py +++ b/Lib/xml/etree/ElementTree.py @@ -8,8 +8,8 @@ 2. Element represents a single node in this tree. Interactions with the whole document (reading and writing to/from files) are - usually done on the ElementTree level. Interactions with a single XML element - and its sub-elements are done on the Element level. + usually done on the ElementTree level. Interactions with a single XML + element and its sub-elements are done on the Element level. Element is a flexible container object designed to store hierarchical data structures in memory. It can be described as a cross between a list and a @@ -277,7 +277,8 @@ def find(self, path, namespaces=None): """Find first matching element by tag name or path. *path* is a string having either an element tag or an XPath, - *namespaces* is an optional mapping from namespace prefix to full name. + *namespaces* is an optional mapping from namespace prefix to full + name. Return the first matching element, or None if no element was found. @@ -289,7 +290,8 @@ def findtext(self, path, default=None, namespaces=None): *path* is a string having either an element tag or an XPath, *default* is the value to return if the element was not found, - *namespaces* is an optional mapping from namespace prefix to full name. + *namespaces* is an optional mapping from namespace prefix to full + name. Return text content of first matching element, or default value if none was found. Note that if an element is found having no text @@ -302,7 +304,8 @@ def findall(self, path, namespaces=None): """Find all matching subelements by tag name or path. *path* is a string having either an element tag or an XPath, - *namespaces* is an optional mapping from namespace prefix to full name. + *namespaces* is an optional mapping from namespace prefix to full + name. Returns list containing all matching elements in document order. @@ -313,7 +316,8 @@ def iterfind(self, path, namespaces=None): """Find all matching subelements by tag name or path. *path* is a string having either an element tag or an XPath, - *namespaces* is an optional mapping from namespace prefix to full name. + *namespaces* is an optional mapping from namespace prefix to full + name. Return an iterable yielding all matching elements in document order. @@ -553,8 +557,8 @@ def _setroot(self, element): def parse(self, source, parser=None): """Load external XML document into element tree. - *source* is a file name or file object, *parser* is an optional parser - instance that defaults to XMLParser. + *source* is a file name or file object, *parser* is an optional + parser instance that defaults to XMLParser. ParseError is raised if the parser fails to parse the document. @@ -587,7 +591,8 @@ def parse(self, source, parser=None): def iter(self, tag=None): """Create and return tree iterator for the root element. - The iterator loops over all elements in this tree, in document order. + The iterator loops over all elements in this tree, in document + order. *tag* is a string with the tag name to iterate over (default is to return all elements). @@ -602,7 +607,8 @@ def find(self, path, namespaces=None): Same as getroot().find(path), which is Element.find() *path* is a string having either an element tag or an XPath, - *namespaces* is an optional mapping from namespace prefix to full name. + *namespaces* is an optional mapping from namespace prefix to full + name. Return the first matching element, or None if no element was found. @@ -624,7 +630,8 @@ def findtext(self, path, default=None, namespaces=None): Same as getroot().findtext(path), which is Element.findtext() *path* is a string having either an element tag or an XPath, - *namespaces* is an optional mapping from namespace prefix to full name. + *namespaces* is an optional mapping from namespace prefix to full + name. Return the first matching element, or None if no element was found. @@ -646,7 +653,8 @@ def findall(self, path, namespaces=None): Same as getroot().findall(path), which is Element.findall(). *path* is a string having either an element tag or an XPath, - *namespaces* is an optional mapping from namespace prefix to full name. + *namespaces* is an optional mapping from namespace prefix to full + name. Return list containing all matching elements in document order. @@ -693,24 +701,26 @@ def write(self, file_or_filename, """Write element tree to a file as XML. Arguments: - *file_or_filename* -- file name or a file object opened for writing + *file_or_filename* -- file name or a file object opened for + writing *encoding* -- the output encoding (default: US-ASCII) - *xml_declaration* -- bool indicating if an XML declaration should be - added to the output. If None, an XML declaration - is added if encoding IS NOT either of: - US-ASCII, UTF-8, or Unicode + *xml_declaration* -- bool indicating if an XML declaration should + be added to the output. If None, an XML + declaration is added if encoding IS NOT + either of: US-ASCII, UTF-8, or Unicode - *default_namespace* -- sets the default XML namespace (for "xmlns") + *default_namespace* -- sets the default XML namespace (for + "xmlns") *method* -- either "xml" (default), "html, "text", or "c14n" *short_empty_elements* -- controls the formatting of elements - that contain no content. If True (default) - they are emitted as a single self-closed - tag, otherwise they are emitted as a pair - of start/end tags + that contain no content. If True + (default) they are emitted as a single + self-closed tag, otherwise they are + emitted as a pair of start/end tags """ if self._root is None: @@ -1083,9 +1093,9 @@ def tostring(element, encoding=None, method=None, *, is returned. Otherwise a bytestring is returned. *element* is an Element instance, *encoding* is an optional output - encoding defaulting to US-ASCII, *method* is an optional output which can - be one of "xml" (default), "html", "text" or "c14n", *default_namespace* - sets the default XML namespace (for "xmlns"). + encoding defaulting to US-ASCII, *method* is an optional output which + can be one of "xml" (default), "html", "text" or "c14n", + *default_namespace* sets the default XML namespace (for "xmlns"). Returns an (optionally) encoded string containing the XML data. @@ -1225,7 +1235,8 @@ def iterparse(source, events=None, parser=None): "end" events are reported. *source* is a filename or file object containing XML data, *events* is - a list of events to report back, *parser* is an optional parser instance. + a list of events to report back, *parser* is an optional parser + instance. Returns an iterator providing (event, elem) pairs. @@ -1761,10 +1772,11 @@ def flush(self): def canonicalize(xml_data=None, *, out=None, from_file=None, **options): """Convert XML to its C14N 2.0 serialised form. - If *out* is provided, it must be a file or file-like object that receives - the serialised canonical XML output (text, not bytes) through its ``.write()`` - method. To write to a file, open it in text mode with encoding "utf-8". - If *out* is not provided, this function returns the output as text string. + If *out* is provided, it must be a file or file-like object that + receives the serialised canonical XML output (text, not bytes) through + its ``.write()`` method. To write to a file, open it in text mode with + encoding "utf-8". If *out* is not provided, this function returns the + output as text string. Either *xml_data* (an XML string) or *from_file* (a file path or file-like object) must be provided as input. @@ -1798,19 +1810,22 @@ class C14NWriterTarget: Serialises parse events to XML C14N 2.0. The *write* function is used for writing out the resulting data stream - as text (not bytes). To write to a file, open it in text mode with encoding - "utf-8" and pass its ``.write`` method. + as text (not bytes). To write to a file, open it in text mode with + encoding "utf-8" and pass its ``.write`` method. Configuration options: - *with_comments*: set to true to include comments - - *strip_text*: set to true to strip whitespace before and after text content - - *rewrite_prefixes*: set to true to replace namespace prefixes by "n{number}" + - *strip_text*: set to true to strip whitespace before and after text + content + - *rewrite_prefixes*: set to true to replace namespace prefixes by + "n{number}" - *qname_aware_tags*: a set of qname aware tag names in which prefixes should be replaced in text content - - *qname_aware_attrs*: a set of qname aware attribute names in which prefixes - should be replaced in text content - - *exclude_attrs*: a set of attribute names that should not be serialised + - *qname_aware_attrs*: a set of qname aware attribute names in which + prefixes should be replaced in text content + - *exclude_attrs*: a set of attribute names that should not be + serialised - *exclude_tags*: a set of tag names that should not be serialised """ def __init__(self, write, *, diff --git a/Lib/zipfile/__init__.py b/Lib/zipfile/__init__.py index c5c6ac03fb7b8c..d91cb509a6ff4f 100644 --- a/Lib/zipfile/__init__.py +++ b/Lib/zipfile/__init__.py @@ -620,11 +620,12 @@ def _decodeExtra(self, filename_crc): def from_file(cls, filename, arcname=None, *, strict_timestamps=True): """Construct an appropriate ZipInfo for a file on the filesystem. - filename should be the path to a file or directory on the filesystem. + filename should be the path to a file or directory on the + filesystem. - arcname is the name which it will have within the archive (by default, - this will be the same as filename, but without a drive letter and with - leading path separators removed). + arcname is the name which it will have within the archive (by + default, this will be the same as filename, but without a drive + letter and with leading path separators removed). """ if isinstance(filename, os.PathLike): filename = os.fspath(filename) @@ -1395,19 +1396,19 @@ class ZipFile: mode: The mode can be either read 'r', write 'w', exclusive create 'x', or append 'a'. compression: ZIP_STORED (no compression), ZIP_DEFLATED (requires zlib), - ZIP_BZIP2 (requires bz2), ZIP_LZMA (requires lzma), or - ZIP_ZSTANDARD (requires compression.zstd). - allowZip64: if True ZipFile will create files with ZIP64 extensions when - needed, otherwise it will raise an exception when this would - be necessary. - compresslevel: None (default for the given compression type) or an integer - specifying the level to pass to the compressor. - When using ZIP_STORED or ZIP_LZMA this keyword has no effect. - When using ZIP_DEFLATED integers 0 through 9 are accepted. - When using ZIP_BZIP2 integers 1 through 9 are accepted. - When using ZIP_ZSTANDARD integers -7 though 22 are common, - see the CompressionParameter enum in compression.zstd for - details. + ZIP_BZIP2 (requires bz2), ZIP_LZMA (requires lzma), or + ZIP_ZSTANDARD (requires compression.zstd). + allowZip64: if True ZipFile will create files with ZIP64 extensions + when needed, otherwise it will raise an exception when this + would be necessary. + compresslevel: None (default for the given compression type) or + an integer specifying the level to pass to the compressor. + When using ZIP_STORED or ZIP_LZMA this keyword has no effect. + When using ZIP_DEFLATED integers 0 through 9 are accepted. + When using ZIP_BZIP2 integers 1 through 9 are accepted. + When using ZIP_ZSTANDARD integers -7 though 22 are common, + see the CompressionParameter enum in compression.zstd for + details. """ @@ -1417,8 +1418,8 @@ class ZipFile: def __init__(self, file, mode="r", compression=ZIP_STORED, allowZip64=True, compresslevel=None, *, strict_timestamps=True, metadata_encoding=None): - """Open the ZIP file with mode read 'r', write 'w', exclusive create 'x', - or append 'a'.""" + """Open the ZIP file with mode read 'r', write 'w', exclusive create + 'x', or append 'a'.""" if mode not in ('r', 'w', 'x', 'a'): raise ValueError("ZipFile requires mode 'r', 'w', 'x', or 'a'") @@ -1696,10 +1697,10 @@ def open(self, name, mode="r", pwd=None, *, force_zip64=False): pwd is the password to decrypt files (only used for reading). - When writing, if the file size is not known in advance but may exceed - 2 GiB, pass force_zip64 to use the ZIP64 format, which can handle large - files. If the size is known in advance, it is best to pass a ZipInfo - instance for name, with zinfo.file_size set. + When writing, if the file size is not known in advance but may + exceed 2 GiB, pass force_zip64 to use the ZIP64 format, which can + handle large files. If the size is known in advance, it is best to + pass a ZipInfo instance for name, with zinfo.file_size set. """ if mode not in {"r", "w"}: raise ValueError('open() requires mode "r" or "w"') From acd402ecdb7d04d8730d2d10352fa22823b0bd1c Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 25 May 2026 11:36:22 +0200 Subject: [PATCH 141/818] [3.15] gh-150374: Fix double release of import lock in lazy import reification (GH-150376) (#150378) gh-150374: Fix double release of import lock in lazy import reification (GH-150376) (cherry picked from commit 5498eba545e950c7550c924f2e458c740a689c69) Co-authored-by: pengyu lee --- .../2026-05-25-16-00-22.gh-issue-150374.Emu6d8.rst | 1 + Python/import.c | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-05-25-16-00-22.gh-issue-150374.Emu6d8.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-25-16-00-22.gh-issue-150374.Emu6d8.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-25-16-00-22.gh-issue-150374.Emu6d8.rst new file mode 100644 index 00000000000000..7189ca186d2b7e --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-25-16-00-22.gh-issue-150374.Emu6d8.rst @@ -0,0 +1 @@ +Fix double release of the import lock on lazy import reification errors. diff --git a/Python/import.c b/Python/import.c index aa4ee660fa75da..fc1b3f1acbe063 100644 --- a/Python/import.c +++ b/Python/import.c @@ -3934,7 +3934,6 @@ _PyImport_LoadLazyImportTstate(PyThreadState *tstate, PyObject *lazy_import) return NULL; } else if (PySet_Add(importing, lazy_import) < 0) { - _PyImport_ReleaseLock(interp); goto error; } From 28037c2d11be131588efcd22c17c6bafa824cc8d Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 25 May 2026 12:13:01 +0200 Subject: [PATCH 142/818] [3.15] gh-145896: Fix typos and stale docstrings in the traceback module (GH-145897) (GH-150383) (cherry picked from commit 832afeddcea78e40d39c47cd1893f8137e588e72) Co-authored-by: devdanzin <74280297+devdanzin@users.noreply.github.com> --- Doc/library/traceback.rst | 10 ++++------ Lib/traceback.py | 19 +++++++++---------- 2 files changed, 13 insertions(+), 16 deletions(-) diff --git a/Doc/library/traceback.rst b/Doc/library/traceback.rst index b5464ac55ddfa9..aa48cea357cfd3 100644 --- a/Doc/library/traceback.rst +++ b/Doc/library/traceback.rst @@ -147,9 +147,7 @@ Module-Level Functions :ref:`traceback object ` *tb*. It is useful for alternate formatting of stack traces. The optional *limit* argument has the same meaning as for :func:`print_tb`. A "pre-processed" stack trace - entry is a :class:`FrameSummary` object containing attributes - :attr:`~FrameSummary.filename`, :attr:`~FrameSummary.lineno`, - :attr:`~FrameSummary.name`, and :attr:`~FrameSummary.line` representing the + entry is a :class:`FrameSummary` object with attributes representing the information that is usually printed for a stack trace. @@ -181,7 +179,7 @@ Module-Level Functions .. function:: format_exception_only(exc, /[, value], *, show_group=False) Format the exception part of a traceback using an exception value such as - given by :data:`sys.last_value`. The return value is a list of strings, each + given by :data:`sys.last_exc`. The return value is a list of strings, each ending in a newline. The list contains the exception's message, which is normally a single string; however, for :exc:`SyntaxError` exceptions, it contains several lines that (when printed) display detailed information @@ -347,7 +345,7 @@ the module-level functions described above. .. attribute:: exc_type - The class of the original traceback. + The class of the original exception. .. deprecated:: 3.13 @@ -391,7 +389,7 @@ the module-level functions described above. For syntax errors - the compiler error message. - .. classmethod:: from_exception(exc, *, limit=None, lookup_lines=True, capture_locals=False) + .. classmethod:: from_exception(exc, *, limit=None, lookup_lines=True, capture_locals=False, compact=False, max_group_width=15, max_group_depth=10) Capture an exception for later rendering. *limit*, *lookup_lines* and *capture_locals* are as for the :class:`StackSummary` class. diff --git a/Lib/traceback.py b/Lib/traceback.py index 88529e1c259a29..d16ab468db9962 100644 --- a/Lib/traceback.py +++ b/Lib/traceback.py @@ -115,10 +115,10 @@ def extract_tb(tb, limit=None): This is useful for alternate formatting of stack traces. If 'limit' is omitted or None, all entries are extracted. A pre-processed stack trace entry is a FrameSummary object - containing attributes filename, lineno, name, and line - representing the information that is usually printed for a stack - trace. The line is a string with leading and trailing - whitespace stripped; if the source is not available it is None. + representing the information that is usually printed for a + stack trace. The line attribute is a string with + leading and trailing whitespace stripped; if the source is not + available the corresponding attribute is None. """ return StackSummary._extract_from_extended_frame_gen( _walk_tb_with_full_positions(tb), limit=limit) @@ -295,9 +295,8 @@ def extract_stack(f=None, limit=None): The return value has the same format as for extract_tb(). The optional 'f' and 'limit' arguments have the same meaning as for - print_stack(). Each item in the list is a quadruple (filename, - line number, function name, text), and the entries are in order - from oldest to newest stack frame. + print_stack(). Each item in the list is a FrameSummary object, + and the entries are in order from oldest to newest stack frame. """ if f is None: f = sys._getframe().f_back @@ -325,7 +324,7 @@ class FrameSummary: active when the frame was captured. - :attr:`name` The name of the function or method that was executing when the frame was captured. - - :attr:`line` The text from the linecache module for the + - :attr:`line` The text from the linecache module for the line of code that was running when the frame was captured. - :attr:`locals` Either None if locals were not supplied, or a dict mapping the name to the repr() of the variable. @@ -1053,7 +1052,7 @@ def _wlen(s: str) -> int: def _display_width(line, offset=None): - """Calculate the extra amount of width space the given source + """Calculate the amount of width space the given source code segment might take if it were to be displayed on a fixed width output device. Supports wide unicode characters and emojis.""" @@ -1134,7 +1133,7 @@ class TracebackException: def __init__(self, exc_type, exc_value, exc_traceback, *, limit=None, lookup_lines=True, capture_locals=False, compact=False, max_group_width=15, max_group_depth=10, save_exc_type=True, _seen=None): - # NB: we need to accept exc_traceback, exc_value, exc_traceback to + # NB: we need to accept exc_type, exc_value, exc_traceback to # permit backwards compat with the existing API, otherwise we # need stub thunk objects just to glue it together. # Handle loops in __cause__ or __context__. From e2362aac3470a23ea048384024ec16f2bf866a6b Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 25 May 2026 20:19:22 +0200 Subject: [PATCH 143/818] [3.15] gh-149156: Fix perf trampoline crash after fork (GH-150347) (#150394) --- ...26-05-24-14-45-00.gh-issue-149156.NP73rB.rst | 3 +++ Python/perf_trampoline.c | 17 ++++++++++++----- 2 files changed, 15 insertions(+), 5 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-05-24-14-45-00.gh-issue-149156.NP73rB.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-24-14-45-00.gh-issue-149156.NP73rB.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-24-14-45-00.gh-issue-149156.NP73rB.rst new file mode 100644 index 00000000000000..2cb091e2b162f6 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-24-14-45-00.gh-issue-149156.NP73rB.rst @@ -0,0 +1,3 @@ +Fix an intermittent crash after :func:`os.fork` when perf trampoline +profiling is enabled and the child returns through trampoline frames +inherited from the parent process. diff --git a/Python/perf_trampoline.c b/Python/perf_trampoline.c index 58c61e64bfc4e9..d90b789c2b5712 100644 --- a/Python/perf_trampoline.c +++ b/Python/perf_trampoline.c @@ -210,9 +210,8 @@ enum perf_trampoline_type { static void free_code_arenas(void); static void -perf_trampoline_reset_state(void) +perf_trampoline_clear_code_watcher(void) { - free_code_arenas(); if (code_watcher_id >= 0) { PyCode_ClearWatcher(code_watcher_id); code_watcher_id = -1; @@ -220,6 +219,13 @@ perf_trampoline_reset_state(void) extra_code_index = -1; } +static void +perf_trampoline_reset_state(void) +{ + free_code_arenas(); + perf_trampoline_clear_code_watcher(); +} + static int perf_trampoline_code_watcher(PyCodeEvent event, PyCodeObject *co) { @@ -621,9 +627,10 @@ _PyPerfTrampoline_AfterFork_Child(void) // After fork, Fini may leave the old code watcher registered // if trampolined code objects from the parent still exist // (trampoline_refcount > 0). Clear it unconditionally before - // Init registers a new one, to prevent two watchers sharing - // the same globals and double-decrementing trampoline_refcount. - perf_trampoline_reset_state(); + // Init registers a new one, but keep the old arenas mapped: the + // child may still need to return through trampoline frames that + // were on the C stack at fork(). + perf_trampoline_clear_code_watcher(); _PyPerfTrampoline_Init(1); } } From 4bdff2cc89dad8f3fa63b98dd12ba22a8b3eb6e0 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Mon, 25 May 2026 21:43:23 +0300 Subject: [PATCH 144/818] [3.15] gh-80198: Improve test_pwd and test_grp (GH-150380) (GH-150398) Fix tests for non-existing names and ids when getpwall()/getgrall() don't return all users/groups. Add tests for out-of-range uids, integer float ids, bytes names, null-terminated names, names with surrogates, empty names, excessive arguments. (cherry picked from commit 46e8f7a9e794bfb0fdc5ee82348623eb2b91a0b5) --- Lib/test/test_grp.py | 90 +++++++++++++++++++----------------------- Lib/test/test_pwd.py | 94 ++++++++++++++++++++++---------------------- 2 files changed, 88 insertions(+), 96 deletions(-) diff --git a/Lib/test/test_grp.py b/Lib/test/test_grp.py index e52e17b8dc7366..ed86802f069e0f 100644 --- a/Lib/test/test_grp.py +++ b/Lib/test/test_grp.py @@ -1,5 +1,7 @@ """Test script for the grp module.""" +import random +import string import unittest from test.support import import_helper @@ -50,61 +52,51 @@ def test_values_extended(self): def test_errors(self): self.assertRaises(TypeError, grp.getgrgid) self.assertRaises(TypeError, grp.getgrgid, 3.14) + self.assertRaises(TypeError, grp.getgrgid, 0.0) + self.assertRaises(TypeError, grp.getgrgid, 0, 0) + # should be out of gid_t range + self.assertRaises(OverflowError, grp.getgrgid, 2**128) + self.assertRaises(OverflowError, grp.getgrgid, -2**128) self.assertRaises(TypeError, grp.getgrnam) self.assertRaises(TypeError, grp.getgrnam, 42) - self.assertRaises(TypeError, grp.getgrall, 42) + self.assertRaises(TypeError, grp.getgrnam, b'root') + self.assertRaises(TypeError, grp.getgrnam, 'root', 0) # embedded null character self.assertRaisesRegex(ValueError, 'null', grp.getgrnam, 'a\x00b') + self.assertRaisesRegex(ValueError, 'null', grp.getgrnam, 'root\x00') + self.assertRaises(UnicodeEncodeError, grp.getgrnam, 'roo\udc74') + self.assertRaises(KeyError, grp.getgrnam, '') + self.assertRaises(TypeError, grp.getgrall, 42) - # try to get some errors - bynames = {} - bygids = {} - for (n, p, g, mem) in grp.getgrall(): - if not n or n == '+': - continue # skip NIS entries etc. - bynames[n] = g - bygids[g] = n - - allnames = list(bynames.keys()) - namei = 0 - fakename = allnames[namei] - while fakename in bynames: - chars = list(fakename) - for i in range(len(chars)): - if chars[i] == 'z': - chars[i] = 'A' - break - elif chars[i] == 'Z': - continue + # Find a non-existent group name. + # getgrall() will not necessarily report all existing groups + # (typical for LDAP based directories in big organizations). + for _ in range(30): + fakename = ''.join(random.choices(string.ascii_lowercase, k=6)) + try: + grp.getgrnam(fakename) + except KeyError: + break + else: + self.fail('Cannot find non-existent group name') + + # Find a non-existent gid. + maxgid = 2**31 + for _ in range(30): + fakegid = random.randrange(maxgid) + try: + grp.getgrgid(fakegid) + except KeyError: + break + except OverflowError: + if maxgid == 2**31: + maxgid = 2**16-1 + elif maxgid == 2**16-1: + maxgid = 2**15 else: - chars[i] = chr(ord(chars[i]) + 1) - break - else: - namei = namei + 1 - try: - fakename = allnames[namei] - except IndexError: - # should never happen... if so, just forget it - break - fakename = ''.join(chars) - - self.assertRaises(KeyError, grp.getgrnam, fakename) - - # Choose a non-existent gid. - fakegid = 4127 - while fakegid in bygids: - fakegid = (fakegid * 3) % 0x10000 - - self.assertRaises(KeyError, grp.getgrgid, fakegid) - - def test_noninteger_gid(self): - entries = grp.getgrall() - if not entries: - self.skipTest('no groups') - # Choose an existent gid. - gid = entries[0][2] - self.assertRaises(TypeError, grp.getgrgid, float(gid)) - self.assertRaises(TypeError, grp.getgrgid, str(gid)) + raise + else: + self.fail('Cannot find non-existent gid') if __name__ == "__main__": diff --git a/Lib/test/test_pwd.py b/Lib/test/test_pwd.py index aa090b464a7222..bdf57776c82be1 100644 --- a/Lib/test/test_pwd.py +++ b/Lib/test/test_pwd.py @@ -1,3 +1,5 @@ +import random +import string import sys import unittest from test.support import import_helper @@ -56,59 +58,57 @@ def test_values_extended(self): def test_errors(self): self.assertRaises(TypeError, pwd.getpwuid) self.assertRaises(TypeError, pwd.getpwuid, 3.14) + self.assertRaises(TypeError, pwd.getpwuid, 0.0) + self.assertRaises(TypeError, pwd.getpwuid, 0, 0) + # should be out of uid_t range + self.assertRaises(KeyError, pwd.getpwuid, 2**128) + self.assertRaises(KeyError, pwd.getpwuid, -2**128) self.assertRaises(TypeError, pwd.getpwnam) self.assertRaises(TypeError, pwd.getpwnam, 42) - self.assertRaises(TypeError, pwd.getpwall, 42) + self.assertRaises(TypeError, pwd.getpwnam, b'root') + self.assertRaises(TypeError, pwd.getpwnam, 'root', 0) # embedded null character self.assertRaisesRegex(ValueError, 'null', pwd.getpwnam, 'a\x00b') + self.assertRaisesRegex(ValueError, 'null', pwd.getpwnam, 'root\x00') + self.assertRaises(UnicodeEncodeError, pwd.getpwnam, 'roo\udc74') + self.assertRaises(KeyError, pwd.getpwnam, '') + self.assertRaises(TypeError, pwd.getpwall, 42) - # try to get some errors - bynames = {} - byuids = {} - for (n, p, u, g, gecos, d, s) in pwd.getpwall(): - bynames[n] = u - byuids[u] = n - - allnames = list(bynames.keys()) - namei = 0 - fakename = allnames[namei] if allnames else "invaliduser" - while fakename in bynames: - chars = list(fakename) - for i in range(len(chars)): - if chars[i] == 'z': - chars[i] = 'A' - break - elif chars[i] == 'Z': - continue - else: - chars[i] = chr(ord(chars[i]) + 1) - break - else: - namei = namei + 1 - try: - fakename = allnames[namei] - except IndexError: - # should never happen... if so, just forget it - break - fakename = ''.join(chars) - - self.assertRaises(KeyError, pwd.getpwnam, fakename) - - # In some cases, byuids isn't a complete list of all users in the - # system, so if we try to pick a value not in byuids (via a perturbing - # loop, say), pwd.getpwuid() might still be able to find data for that - # uid. Using sys.maxint may provoke the same problems, but hopefully - # it will be a more repeatable failure. - fakeuid = sys.maxsize - self.assertNotIn(fakeuid, byuids) - self.assertRaises(KeyError, pwd.getpwuid, fakeuid) + # Find a non-existent user name. + # getpwall() will not necessarily report all existing users + # (typical for LDAP based directories in big organizations). + for _ in range(30): + fakename = ''.join(random.choices(string.ascii_lowercase, k=6)) + try: + pwd.getpwnam(fakename) + except KeyError: + break + else: + self.fail('Cannot find non-existent user name') + + # Find a non-existent uid. + maxuid = max(e.pw_uid for e in pwd.getpwall()) + if maxuid < 2**15: + maxuid = 2**15 + elif maxuid < 2**16: + maxuid = 2**16-1 + else: + maxuid = 2**31 + for _ in range(30): + fakeuid = random.randrange(maxuid) + try: + pwd.getpwuid(fakeuid) + except KeyError: + break + else: + self.fail('Cannot find non-existent uid') + + # On Cygwin, getpwuid(-1) returns 'Unknown+User' user + if sys.platform != 'cygwin': + # -1 shouldn't be a valid uid because it has a special meaning in many + # uid-related functions + self.assertRaises(KeyError, pwd.getpwuid, -1) - # -1 shouldn't be a valid uid because it has a special meaning in many - # uid-related functions - self.assertRaises(KeyError, pwd.getpwuid, -1) - # should be out of uid_t range - self.assertRaises(KeyError, pwd.getpwuid, 2**128) - self.assertRaises(KeyError, pwd.getpwuid, -2**128) if __name__ == "__main__": unittest.main() From d23b06b2a8becc6619e3112468f8c94500d7e470 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 25 May 2026 20:46:19 +0200 Subject: [PATCH 145/818] [3.15] gh-150387: Fix hang in test_run_failed_script_live on slow buildbots (GH-150405) (#150420) --- .../test_sampling_profiler/test_live_collector_ui.py | 3 +-- .../Tests/2026-05-25-15-39-53.gh-issue-150387.yzZ7jq.rst | 5 +++++ 2 files changed, 6 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Tests/2026-05-25-15-39-53.gh-issue-150387.yzZ7jq.rst diff --git a/Lib/test/test_profiling/test_sampling_profiler/test_live_collector_ui.py b/Lib/test/test_profiling/test_sampling_profiler/test_live_collector_ui.py index c0d39f487c8cbd..59373a8d00c03c 100644 --- a/Lib/test/test_profiling/test_sampling_profiler/test_live_collector_ui.py +++ b/Lib/test/test_profiling/test_sampling_profiler/test_live_collector_ui.py @@ -835,8 +835,7 @@ def mock_init_curses_side_effect(self, n_times, mock_self, stdscr): # still failing for _ in range(n_times): mock_self.display.simulate_input(-1) - if n_times >= 500: - mock_self.display.simulate_input(ord('q')) + mock_self.display.simulate_input(ord('q')) def test_run_failed_module_live(self): """Test that running a existing module that fails exits with clean error.""" diff --git a/Misc/NEWS.d/next/Tests/2026-05-25-15-39-53.gh-issue-150387.yzZ7jq.rst b/Misc/NEWS.d/next/Tests/2026-05-25-15-39-53.gh-issue-150387.yzZ7jq.rst new file mode 100644 index 00000000000000..663a357a179204 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2026-05-25-15-39-53.gh-issue-150387.yzZ7jq.rst @@ -0,0 +1,5 @@ +Fix hang in +``test.test_profiling.test_sampling_profiler.test_live_collector_ui.TestLiveModeErrors.test_run_failed_script_live`` +on slow buildbots. The test now always queues a final ``q`` keystroke so the +live TUI loop exits even when the profiler collects enough samples to enter +the post-finished input loop. From d5381e18b85c6781e4961e5d98e2ef23781f654c Mon Sep 17 00:00:00 2001 From: Pablo Galindo Salgado Date: Tue, 26 May 2026 00:02:37 +0100 Subject: [PATCH 146/818] [3.15] gh-149619: Harden _remote_debugging error paths (GH-150349) (#150435) (cherry picked from commit a5be25d3bdc1b3cbc9638a3249c0e3db5a97ebc6) --- .../test_binary_format.py | 41 ++ Modules/_remote_debugging/_remote_debugging.h | 2 +- Modules/_remote_debugging/asyncio.c | 41 +- Modules/_remote_debugging/binary_io_reader.c | 72 +++- Modules/_remote_debugging/binary_io_writer.c | 42 +- Modules/_remote_debugging/code_objects.c | 2 - Modules/_remote_debugging/module.c | 3 + Modules/_remote_debugging/object_reading.c | 58 +-- Modules/_remote_debugging/subprocess.c | 51 ++- Modules/_remote_debugging/threads.c | 91 ++-- Python/remote_debug.h | 390 +++++++++++++----- 11 files changed, 597 insertions(+), 196 deletions(-) diff --git a/Lib/test/test_profiling/test_sampling_profiler/test_binary_format.py b/Lib/test/test_profiling/test_sampling_profiler/test_binary_format.py index 1fbb4e2d6c6fbb..5efc60a9211175 100644 --- a/Lib/test/test_profiling/test_sampling_profiler/test_binary_format.py +++ b/Lib/test/test_profiling/test_sampling_profiler/test_binary_format.py @@ -975,7 +975,11 @@ def test_writer_total_samples_after_close_returns_zero(self): class TestBinaryFormatValidation(BinaryFormatTestBase): """Tests for malformed binary files.""" + HDR_OFF_SAMPLES = 28 HDR_OFF_THREADS = 32 + HDR_OFF_STR_TABLE = 36 + HDR_OFF_FRAME_TABLE = 44 + FILE_HEADER_PLACEHOLDER_SIZE = 64 def test_replay_rejects_more_threads_than_declared(self): """Replay rejects files with more unique threads than the header declares.""" @@ -1000,6 +1004,43 @@ def test_replay_rejects_more_threads_than_declared(self): "threads than declared in header (declared 1, found at least 2)", ) + def test_replay_rejects_sample_count_mismatch(self): + """Replay rejects files whose decoded samples disagree with the header.""" + samples = [[make_interpreter(0, [ + make_thread(1, [make_frame("sample.py", 10, "sample")]) + ])]] + filename = self.create_binary_file(samples, compression="none") + + with open(filename, "r+b") as raw: + raw.seek(self.HDR_OFF_SAMPLES) + raw.write(struct.pack("=I", 2)) + + with BinaryReader(filename) as reader: + self.assertEqual(reader.get_info()["sample_count"], 2) + with self.assertRaises(ValueError) as cm: + reader.replay_samples(RawCollector()) + self.assertEqual( + str(cm.exception), + "Sample count mismatch: header declares 2 samples " + "but replay decoded 1", + ) + + def test_replay_rejects_trailing_partial_sample_header(self): + """Replay rejects partial sample bytes instead of silently stopping.""" + filename = self.create_binary_file([], compression="none") + sample_data_end = self.FILE_HEADER_PLACEHOLDER_SIZE + 1 + + with open(filename, "r+b") as raw: + raw.seek(self.HDR_OFF_STR_TABLE) + raw.write(struct.pack("=Q", sample_data_end)) + raw.seek(self.HDR_OFF_FRAME_TABLE) + raw.write(struct.pack("=Q", sample_data_end)) + + with BinaryReader(filename) as reader: + with self.assertRaises(ValueError) as cm: + reader.replay_samples(RawCollector()) + self.assertEqual(str(cm.exception), "Truncated sample data: 1 trailing bytes") + class TestBinaryEncodings(BinaryFormatTestBase): """Tests specifically targeting different stack encodings.""" diff --git a/Modules/_remote_debugging/_remote_debugging.h b/Modules/_remote_debugging/_remote_debugging.h index d91ce54a18c813..635e6e208902af 100644 --- a/Modules/_remote_debugging/_remote_debugging.h +++ b/Modules/_remote_debugging/_remote_debugging.h @@ -180,7 +180,7 @@ typedef enum _WIN32_THREADSTATE { #define set_exception_cause(unwinder, exc_type, message) \ do { \ assert(PyErr_Occurred() && "function returned -1 without setting exception"); \ - if (unwinder->debug) { \ + if (unwinder->debug && !_Py_RemoteDebug_HasPermissionError()) { \ _set_debug_exception_cause(exc_type, message); \ } \ } while (0) diff --git a/Modules/_remote_debugging/asyncio.c b/Modules/_remote_debugging/asyncio.c index fc7487d4044bfb..44a9a3cbce0061 100644 --- a/Modules/_remote_debugging/asyncio.c +++ b/Modules/_remote_debugging/asyncio.c @@ -22,35 +22,38 @@ _Py_RemoteDebug_GetAsyncioDebugAddress(proc_handle_t* handle) address = search_windows_map_for_section(handle, "AsyncioD", L"_asyncio", NULL); if (address == 0) { - // Error out: 'python' substring covers both executable and DLL - PyObject *exc = PyErr_GetRaisedException(); - PyErr_SetString(PyExc_RuntimeError, "Failed to find the AsyncioDebug section in the process."); - _PyErr_ChainExceptions1(exc); + if (!_Py_RemoteDebug_HasPermissionError()) { + PyObject *exc = PyErr_GetRaisedException(); + PyErr_SetString(PyExc_RuntimeError, "Failed to find the AsyncioDebug section in the process."); + _PyErr_ChainExceptions1(exc); + } } #elif defined(__linux__) && HAVE_PROCESS_VM_READV // On Linux, search for asyncio debug in executable or DLL address = search_linux_map_for_section(handle, "AsyncioDebug", "python", NULL); if (address == 0) { - // Error out: 'python' substring covers both executable and DLL - PyObject *exc = PyErr_GetRaisedException(); - PyErr_SetString(PyExc_RuntimeError, "Failed to find the AsyncioDebug section in the process."); - _PyErr_ChainExceptions1(exc); + if (!_Py_RemoteDebug_HasPermissionError()) { + PyObject *exc = PyErr_GetRaisedException(); + PyErr_SetString(PyExc_RuntimeError, "Failed to find the AsyncioDebug section in the process."); + _PyErr_ChainExceptions1(exc); + } } #elif defined(__APPLE__) && TARGET_OS_OSX // On macOS, try libpython first, then fall back to python address = search_map_for_section(handle, "AsyncioDebug", "libpython", NULL); - if (address == 0) { + if (address == 0 && !_Py_RemoteDebug_HasPermissionError()) { PyErr_Clear(); address = search_map_for_section(handle, "AsyncioDebug", "python", NULL); } if (address == 0) { - // Error out: 'python' substring covers both executable and DLL - PyObject *exc = PyErr_GetRaisedException(); - PyErr_SetString(PyExc_RuntimeError, "Failed to find the AsyncioDebug section in the process."); - _PyErr_ChainExceptions1(exc); + if (!_Py_RemoteDebug_HasPermissionError()) { + PyObject *exc = PyErr_GetRaisedException(); + PyErr_SetString(PyExc_RuntimeError, "Failed to find the AsyncioDebug section in the process."); + _PyErr_ChainExceptions1(exc); + } } #else Py_UNREACHABLE(); @@ -96,10 +99,12 @@ ensure_async_debug_offsets(RemoteUnwinderObject *unwinder) return -1; } if (result < 0) { - PyErr_Clear(); - PyErr_SetString(PyExc_RuntimeError, "AsyncioDebug section not available"); - set_exception_cause(unwinder, PyExc_RuntimeError, - "AsyncioDebug section unavailable - asyncio module may not be loaded in target process"); + if (!_Py_RemoteDebug_HasPermissionError()) { + PyErr_Clear(); + PyErr_SetString(PyExc_RuntimeError, "AsyncioDebug section not available"); + set_exception_cause(unwinder, PyExc_RuntimeError, + "AsyncioDebug section unavailable - asyncio module may not be loaded in target process"); + } return -1; } @@ -218,7 +223,7 @@ parse_task_name( if ((GET_MEMBER(unsigned long, type_obj, unwinder->debug_offsets.type_object.tp_flags) & Py_TPFLAGS_LONG_SUBCLASS)) { long res = read_py_long(unwinder, task_name_addr); - if (res == -1) { + if (res == -1 && PyErr_Occurred()) { set_exception_cause(unwinder, PyExc_RuntimeError, "Task name PyLong parsing failed"); return NULL; } diff --git a/Modules/_remote_debugging/binary_io_reader.c b/Modules/_remote_debugging/binary_io_reader.c index 972b197cfbad86..ce1c3d232c94e0 100644 --- a/Modules/_remote_debugging/binary_io_reader.c +++ b/Modules/_remote_debugging/binary_io_reader.c @@ -380,7 +380,22 @@ binary_reader_open(PyObject *path) Py_fclose(fp); goto error; } + if (st.st_size < 0) { + PyErr_SetString(PyExc_IOError, "Invalid negative file size"); + Py_fclose(fp); + goto error; + } + if ((uintmax_t)st.st_size > SIZE_MAX) { + PyErr_SetString(PyExc_OverflowError, "File is too large to map"); + Py_fclose(fp); + goto error; + } reader->mapped_size = st.st_size; + if (reader->mapped_size == 0) { + PyErr_SetString(PyExc_ValueError, "File too small for header"); + Py_fclose(fp); + goto error; + } /* Map the file into memory. * MAP_POPULATE (Linux-only) pre-faults all pages at mmap time, which: @@ -424,7 +439,10 @@ binary_reader_open(PyObject *path) } #endif - (void)Py_fclose(fp); + if (Py_fclose(fp) != 0) { + PyErr_SetFromErrno(PyExc_IOError); + goto error; + } uint8_t *data = reader->mapped_data; size_t file_size = reader->mapped_size; @@ -444,7 +462,15 @@ binary_reader_open(PyObject *path) PyErr_SetFromErrno(PyExc_IOError); goto error; } + if ((uint64_t)file_size_off > SIZE_MAX) { + PyErr_SetString(PyExc_OverflowError, "File is too large to read"); + goto error; + } reader->file_size = (size_t)file_size_off; + if (reader->file_size == 0) { + PyErr_SetString(PyExc_ValueError, "File too small for header"); + goto error; + } if (FSEEK64(reader->fp, 0, SEEK_SET) != 0) { PyErr_SetFromErrno(PyExc_IOError); goto error; @@ -456,8 +482,18 @@ binary_reader_open(PyObject *path) goto error; } - if (fread(reader->file_data, 1, reader->file_size, reader->fp) != reader->file_size) { - PyErr_SetFromErrno(PyExc_IOError); + size_t nread = fread(reader->file_data, 1, reader->file_size, reader->fp); + if (nread != reader->file_size) { + int err = errno; + if (ferror(reader->fp) && err != 0) { + errno = err; + PyErr_SetFromErrno(PyExc_IOError); + } + else { + PyErr_Format(PyExc_ValueError, + "Unexpected end of file: read %zu of %zu bytes", + nread, reader->file_size); + } goto error; } @@ -944,10 +980,16 @@ invoke_progress_callback(PyObject *callback, Py_ssize_t current, uint32_t total) Py_ssize_t binary_reader_replay(BinaryReader *reader, PyObject *collector, PyObject *progress_callback) { - if (!PyObject_HasAttrString(collector, "collect")) { + PyObject *collect_method; + int has_collect = PyObject_GetOptionalAttrString(collector, "collect", &collect_method); + if (has_collect < 0) { + return -1; + } + if (has_collect == 0) { PyErr_SetString(PyExc_TypeError, "Collector must have a collect() method"); return -1; } + Py_DECREF(collect_method); /* Get module state for struct sequence types */ PyObject *module = PyImport_ImportModule("_remote_debugging"); @@ -973,7 +1015,10 @@ binary_reader_replay(BinaryReader *reader, PyObject *collector, PyObject *progre while (offset < reader->sample_data_size) { /* Read thread_id (8 bytes) + interpreter_id (4 bytes) + encoding byte */ if (reader->sample_data_size - offset < SAMPLE_HEADER_FIXED_SIZE) { - break; /* End of data */ + PyErr_Format(PyExc_ValueError, + "Truncated sample data: %zu trailing bytes", + reader->sample_data_size - offset); + return -1; } /* Use memcpy to avoid strict aliasing violations, then byte-swap if needed */ @@ -1019,6 +1064,11 @@ binary_reader_replay(BinaryReader *reader, PyObject *collector, PyObject *progre count, max_possible_samples); return -1; } + if ((uint64_t)count > (uint64_t)PY_SSIZE_T_MAX - (uint64_t)replayed) { + PyErr_SetString(PyExc_OverflowError, + "Sample count exceeds Py_ssize_t maximum"); + return -1; + } reader->stats.repeat_records++; reader->stats.repeat_samples += count; @@ -1149,6 +1199,11 @@ binary_reader_replay(BinaryReader *reader, PyObject *collector, PyObject *progre return -1; } Py_DECREF(timestamps_list); + if (replayed == PY_SSIZE_T_MAX) { + PyErr_SetString(PyExc_OverflowError, + "Sample count exceeds Py_ssize_t maximum"); + return -1; + } replayed++; reader->stats.total_samples++; break; @@ -1167,6 +1222,13 @@ binary_reader_replay(BinaryReader *reader, PyObject *collector, PyObject *progre } } + if ((uint64_t)replayed != reader->sample_count) { + PyErr_Format(PyExc_ValueError, + "Sample count mismatch: header declares %u samples but replay decoded %zd", + reader->sample_count, replayed); + return -1; + } + /* Final progress callback at 100% */ if (invoke_progress_callback(progress_callback, replayed, reader->sample_count) < 0) { return -1; diff --git a/Modules/_remote_debugging/binary_io_writer.c b/Modules/_remote_debugging/binary_io_writer.c index c31ed7d746466f..341f9f7dc8ac45 100644 --- a/Modules/_remote_debugging/binary_io_writer.c +++ b/Modules/_remote_debugging/binary_io_writer.c @@ -108,7 +108,15 @@ fwrite_checked_allow_threads(const void *data, size_t size, FILE *fp) written = fwrite(data, 1, size, fp); Py_END_ALLOW_THREADS if (written != size) { - PyErr_SetFromErrno(PyExc_IOError); + int err = errno; + if (ferror(fp) && err != 0) { + errno = err; + PyErr_SetFromErrno(PyExc_IOError); + } + else { + PyErr_Format(PyExc_IOError, + "short write: wrote %zu of %zu bytes", written, size); + } return -1; } return 0; @@ -366,6 +374,11 @@ writer_intern_string(BinaryWriter *writer, PyObject *string, uint32_t *index) return 0; } + if (writer->string_count >= UINT32_MAX) { + PyErr_SetString(PyExc_OverflowError, + "too many strings for binary format"); + return -1; + } if (writer->string_count >= writer->string_capacity) { if (grow_parallel_arrays((void **)&writer->strings, (void **)&writer->string_lengths, @@ -380,6 +393,12 @@ writer_intern_string(BinaryWriter *writer, PyObject *string, uint32_t *index) if (!str_data) { return -1; } + if ((uintmax_t)str_len > UINT32_MAX) { + PyErr_Format(PyExc_OverflowError, + "string length %zd exceeds binary format maximum %u", + str_len, UINT32_MAX); + return -1; + } char *str_copy = PyMem_Malloc(str_len + 1); if (!str_copy) { @@ -422,6 +441,11 @@ writer_intern_frame(BinaryWriter *writer, const FrameEntry *entry, uint32_t *ind return 0; } + if (writer->frame_count >= UINT32_MAX) { + PyErr_SetString(PyExc_OverflowError, + "too many frames for binary format"); + return -1; + } if (GROW_ARRAY(writer->frame_entries, writer->frame_count, writer->frame_capacity, FrameEntry) < 0) { return -1; @@ -466,6 +490,11 @@ writer_get_or_create_thread_entry(BinaryWriter *writer, uint64_t thread_id, } } + if (writer->thread_count >= UINT32_MAX) { + PyErr_SetString(PyExc_OverflowError, + "too many threads for binary format"); + return NULL; + } if (writer->thread_count >= writer->thread_capacity) { ThreadEntry *new_entries = grow_array(writer->thread_entries, &writer->thread_capacity, @@ -600,6 +629,11 @@ flush_pending_rle(BinaryWriter *writer, ThreadEntry *entry) if (!entry->has_pending_rle || entry->pending_rle_count == 0) { return 0; } + if (entry->pending_rle_count > UINT32_MAX - writer->total_samples) { + PyErr_SetString(PyExc_OverflowError, + "too many samples for binary format"); + return -1; + } /* Write RLE record: * [thread_id: 8] [interpreter_id: 4] [STACK_REPEAT: 1] [count: varint] @@ -644,6 +678,12 @@ write_sample_with_encoding(BinaryWriter *writer, ThreadEntry *entry, const uint32_t *frame_indices, size_t stack_depth, size_t shared_count, size_t pop_count, size_t push_count) { + if (writer->total_samples == UINT32_MAX) { + PyErr_SetString(PyExc_OverflowError, + "too many samples for binary format"); + return -1; + } + /* Header: thread_id(8) + interpreter_id(4) + encoding(1) + delta(varint) + status(1) */ uint8_t header_buf[SAMPLE_HEADER_MAX_SIZE]; memcpy(header_buf + SMP_OFF_THREAD_ID, &entry->thread_id, SMP_SIZE_THREAD_ID); diff --git a/Modules/_remote_debugging/code_objects.c b/Modules/_remote_debugging/code_objects.c index 3af58f2b3c379e..ab889a130ee4e7 100644 --- a/Modules/_remote_debugging/code_objects.c +++ b/Modules/_remote_debugging/code_objects.c @@ -47,7 +47,6 @@ cache_tlbc_array(RemoteUnwinderObject *unwinder, uintptr_t code_addr, uintptr_t // Read the TLBC array pointer if (read_ptr(unwinder, tlbc_array_addr, &tlbc_array_ptr) != 0) { - PyErr_SetString(PyExc_RuntimeError, "Failed to read TLBC array pointer"); set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read TLBC array pointer"); return 0; // Read error } @@ -61,7 +60,6 @@ cache_tlbc_array(RemoteUnwinderObject *unwinder, uintptr_t code_addr, uintptr_t // Read the TLBC array size Py_ssize_t tlbc_size; if (_Py_RemoteDebug_PagedReadRemoteMemory(&unwinder->handle, tlbc_array_ptr, sizeof(tlbc_size), &tlbc_size) != 0) { - PyErr_SetString(PyExc_RuntimeError, "Failed to read TLBC array size"); set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read TLBC array size"); return 0; // Read error } diff --git a/Modules/_remote_debugging/module.c b/Modules/_remote_debugging/module.c index 3e60a7c2f794ad..984213d1881752 100644 --- a/Modules/_remote_debugging/module.c +++ b/Modules/_remote_debugging/module.c @@ -411,6 +411,9 @@ _remote_debugging_RemoteUnwinder___init___impl(RemoteUnwinderObject *self, return -1; } if (async_debug_result < 0) { + if (_Py_RemoteDebug_HasPermissionError()) { + return -1; + } PyErr_Clear(); memset(&self->async_debug_offsets, 0, sizeof(self->async_debug_offsets)); self->async_debug_offsets_available = 0; diff --git a/Modules/_remote_debugging/object_reading.c b/Modules/_remote_debugging/object_reading.c index b63b103a2617ac..1cea96a2151fcc 100644 --- a/Modules/_remote_debugging/object_reading.c +++ b/Modules/_remote_debugging/object_reading.c @@ -6,6 +6,7 @@ ******************************************************************************/ #include "_remote_debugging.h" +#include /* ============================================================================ * MEMORY READING FUNCTIONS @@ -264,26 +265,16 @@ read_py_long( Py_ssize_t inline_digits_space = SIZEOF_LONG_OBJ - ob_digit_offset; Py_ssize_t max_inline_digits = inline_digits_space / (Py_ssize_t)sizeof(digit); - // If the long object has inline digits that fit in our buffer, use them directly - digit *digits; + digit *digits = (digit *)PyMem_RawMalloc(size * sizeof(digit)); + if (!digits) { + PyErr_NoMemory(); + set_exception_cause(unwinder, PyExc_MemoryError, "Failed to allocate digits for PyLong"); + return -1; + } + if (size <= max_inline_digits && size <= _PY_NSMALLNEGINTS + _PY_NSMALLPOSINTS) { - // For small integers, digits are inline in the long_value.ob_digit array - digits = (digit *)PyMem_RawMalloc(size * sizeof(digit)); - if (!digits) { - PyErr_NoMemory(); - set_exception_cause(unwinder, PyExc_MemoryError, "Failed to allocate digits for small PyLong"); - return -1; - } memcpy(digits, long_obj + ob_digit_offset, size * sizeof(digit)); } else { - // For larger integers, we need to read the digits separately - digits = (digit *)PyMem_RawMalloc(size * sizeof(digit)); - if (!digits) { - PyErr_NoMemory(); - set_exception_cause(unwinder, PyExc_MemoryError, "Failed to allocate digits for large PyLong"); - return -1; - } - bytes_read = _Py_RemoteDebug_PagedReadRemoteMemory( &unwinder->handle, address + (uintptr_t)unwinder->debug_offsets.long_object.ob_digit, @@ -296,19 +287,34 @@ read_py_long( } } - long long value = 0; + unsigned long limit = negative + ? (unsigned long)LONG_MAX + 1UL + : (unsigned long)LONG_MAX; + unsigned long value = 0; - // In theory this can overflow, but because of llvm/llvm-project#16778 - // we can't use __builtin_mul_overflow because it fails to link with - // __muloti4 on aarch64. In practice this is fine because all we're - // testing here are task numbers that would fit in a single byte. - for (Py_ssize_t i = 0; i < size; ++i) { - long long factor = digits[i] * (1UL << (Py_ssize_t)(shift * i)); - value += factor; + for (Py_ssize_t i = size; i-- > 0;) { + if (digits[i] >= PyLong_BASE) { + PyErr_Format(PyExc_RuntimeError, + "Invalid PyLong digit: %u (base %u)", digits[i], PyLong_BASE); + set_exception_cause(unwinder, PyExc_RuntimeError, + "Invalid PyLong digit (corrupted remote memory)"); + goto error; + } + if (value > ((limit - (unsigned long)digits[i]) >> shift)) { + PyErr_SetString(PyExc_OverflowError, + "Remote PyLong value does not fit in C long"); + set_exception_cause(unwinder, PyExc_OverflowError, + "Remote PyLong value is too large"); + goto error; + } + value = (value << shift) | (unsigned long)digits[i]; } PyMem_RawFree(digits); if (negative) { - value *= -1; + if (value == (unsigned long)LONG_MAX + 1UL) { + return LONG_MIN; + } + return -(long)value; } return (long)value; error: diff --git a/Modules/_remote_debugging/subprocess.c b/Modules/_remote_debugging/subprocess.c index 1b16dd8343f2a5..cdad75e318be91 100644 --- a/Modules/_remote_debugging/subprocess.c +++ b/Modules/_remote_debugging/subprocess.c @@ -223,8 +223,19 @@ get_child_pids_platform(pid_t target_pid, int recursive, pid_array_t *result) } /* Single pass: collect PIDs and their PPIDs together */ - struct dirent *entry; - while ((entry = readdir(proc_dir)) != NULL) { + for (;;) { + errno = 0; + struct dirent *entry = readdir(proc_dir); + if (entry == NULL) { + if (errno != 0) { + int err = errno; + _set_debug_oserror_from_errno_with_filename(err, "/proc", + "Failed to read process directory '/proc': %s", + strerror(err)); + goto done; + } + break; + } /* Skip non-numeric entries (also skips . and ..) */ if (entry->d_name[0] < '1' || entry->d_name[0] > '9') { continue; @@ -245,7 +256,14 @@ get_child_pids_platform(pid_t target_pid, int recursive, pid_array_t *result) } } - closedir(proc_dir); + if (closedir(proc_dir) != 0) { + int err = errno; + proc_dir = NULL; + _set_debug_oserror_from_errno_with_filename(err, "/proc", + "Failed to close process directory '/proc': %s", + strerror(err)); + goto done; + } proc_dir = NULL; if (find_children_bfs(target_pid, recursive, @@ -358,7 +376,8 @@ get_child_pids_platform(pid_t target_pid, int recursive, pid_array_t *result) snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (snapshot == INVALID_HANDLE_VALUE) { - PyErr_SetFromWindowsErr(0); + DWORD error = GetLastError(); + PyErr_SetFromWindowsErr(error); goto done; } @@ -373,13 +392,23 @@ get_child_pids_platform(pid_t target_pid, int recursive, pid_array_t *result) /* Single pass: collect PIDs and PPIDs together */ PROCESSENTRY32 pe; pe.dwSize = sizeof(PROCESSENTRY32); - if (Process32First(snapshot, &pe)) { - do { - if (pid_array_append(&all_pids, (pid_t)pe.th32ProcessID) < 0 || - pid_array_append(&ppids, (pid_t)pe.th32ParentProcessID) < 0) { - goto done; - } - } while (Process32Next(snapshot, &pe)); + if (!Process32First(snapshot, &pe)) { + DWORD error = GetLastError(); + PyErr_SetFromWindowsErr(error); + goto done; + } + + do { + if (pid_array_append(&all_pids, (pid_t)pe.th32ProcessID) < 0 || + pid_array_append(&ppids, (pid_t)pe.th32ParentProcessID) < 0) { + goto done; + } + } while (Process32Next(snapshot, &pe)); + + DWORD error = GetLastError(); + if (error != ERROR_NO_MORE_FILES) { + PyErr_SetFromWindowsErr(error); + goto done; } CloseHandle(snapshot); diff --git a/Modules/_remote_debugging/threads.c b/Modules/_remote_debugging/threads.c index ae120a26d5f4ec..5176c4cf0671bb 100644 --- a/Modules/_remote_debugging/threads.c +++ b/Modules/_remote_debugging/threads.c @@ -658,8 +658,7 @@ read_thread_ids(RemoteUnwinderObject *unwinder, _Py_RemoteDebug_ThreadsState *st DIR *dir = opendir(task_path); if (dir == NULL) { - st->tids = NULL; - st->count = 0; + _Py_RemoteDebug_InitThreadsState(unwinder, st); if (errno == ENOENT || errno == ESRCH) { PyErr_Format(PyExc_ProcessLookupError, "Process %d has terminated", unwinder->handle.pid); @@ -671,8 +670,21 @@ read_thread_ids(RemoteUnwinderObject *unwinder, _Py_RemoteDebug_ThreadsState *st st->count = 0; - struct dirent *entry; - while ((entry = readdir(dir)) != NULL) { + for (;;) { + errno = 0; + struct dirent *entry = readdir(dir); + if (entry == NULL) { + if (errno != 0) { + int err = errno; + closedir(dir); + _Py_RemoteDebug_InitThreadsState(unwinder, st); + _set_debug_oserror_from_errno_with_filename(err, task_path, + "Failed to read process task directory '%s': %s", + task_path, strerror(err)); + return -1; + } + break; + } if (entry->d_name[0] < '1' || entry->d_name[0] > '9') { continue; } @@ -686,8 +698,7 @@ read_thread_ids(RemoteUnwinderObject *unwinder, _Py_RemoteDebug_ThreadsState *st pid_t *new_tids = PyMem_RawRealloc(unwinder->thread_tids, new_cap * sizeof(pid_t)); if (new_tids == NULL) { closedir(dir); - st->tids = NULL; - st->count = 0; + _Py_RemoteDebug_InitThreadsState(unwinder, st); PyErr_NoMemory(); return -1; } @@ -697,8 +708,15 @@ read_thread_ids(RemoteUnwinderObject *unwinder, _Py_RemoteDebug_ThreadsState *st unwinder->thread_tids[st->count++] = (pid_t)tid; } + if (closedir(dir) != 0) { + int err = errno; + _Py_RemoteDebug_InitThreadsState(unwinder, st); + _set_debug_oserror_from_errno_with_filename(err, task_path, + "Failed to close process task directory '%s': %s", + task_path, strerror(err)); + return -1; + } st->tids = unwinder->thread_tids; - closedir(dir); return 0; } @@ -711,28 +729,30 @@ detach_threads(_Py_RemoteDebug_ThreadsState *st, size_t up_to) } static int -seize_thread(pid_t tid) +seize_thread(pid_t tid, int *err) { if (ptrace(PTRACE_SEIZE, tid, NULL, 0) == 0) { return 0; } - if (errno == ESRCH) { + *err = errno; + if (*err == ESRCH) { return 1; // Thread gone, skip } - if (errno == EPERM) { + if (*err == EPERM) { // Thread may have exited, be in a special state, or already be traced. // Skip rather than fail - this avoids endless retry loops when // threads transiently become inaccessible. return 1; } - if (errno == EINVAL || errno == EIO) { + if (*err == EINVAL || *err == EIO) { // Fallback for older kernels if (ptrace(PTRACE_ATTACH, tid, NULL, NULL) == 0) { int status; waitpid(tid, &status, __WALL); return 0; } - if (errno == ESRCH || errno == EPERM) { + *err = errno; + if (*err == ESRCH || *err == EPERM) { return 1; // Thread gone or inaccessible } } @@ -746,39 +766,50 @@ _Py_RemoteDebug_StopAllThreads(RemoteUnwinderObject *unwinder, _Py_RemoteDebug_T return -1; } - for (size_t i = 0; i < st->count; i++) { + size_t n_tids = st->count; + size_t seized = 0; + for (size_t i = 0; i < n_tids; i++) { pid_t tid = st->tids[i]; - int ret = seize_thread(tid); + int err = 0; + int ret = seize_thread(tid, &err); if (ret == 1) { continue; // Thread gone, skip } if (ret < 0) { - detach_threads(st, i); - PyErr_Format(PyExc_RuntimeError, "Failed to seize thread %d: %s", tid, strerror(errno)); - st->tids = NULL; - st->count = 0; + detach_threads(st, seized); + _set_debug_oserror_from_errno(err, + "Failed to seize thread %d: %s", tid, strerror(err)); + _Py_RemoteDebug_InitThreadsState(unwinder, st); return -1; } + st->tids[seized++] = tid; - if (ptrace(PTRACE_INTERRUPT, tid, NULL, NULL) == -1 && errno != ESRCH) { - detach_threads(st, i + 1); - PyErr_Format(PyExc_RuntimeError, "Failed to interrupt thread %d: %s", tid, strerror(errno)); - st->tids = NULL; - st->count = 0; - return -1; + if (ptrace(PTRACE_INTERRUPT, tid, NULL, NULL) == -1) { + err = errno; + if (err != ESRCH) { + detach_threads(st, seized); + _set_debug_oserror_from_errno(err, + "Failed to interrupt thread %d: %s", tid, strerror(err)); + _Py_RemoteDebug_InitThreadsState(unwinder, st); + return -1; + } } int status; - if (waitpid(tid, &status, __WALL) == -1 && errno != ECHILD && errno != ESRCH) { - detach_threads(st, i + 1); - PyErr_Format(PyExc_RuntimeError, "waitpid failed for thread %d: %s", tid, strerror(errno)); - st->tids = NULL; - st->count = 0; - return -1; + if (waitpid(tid, &status, __WALL) == -1) { + err = errno; + if (err != ECHILD && err != ESRCH) { + detach_threads(st, seized); + _set_debug_oserror_from_errno(err, + "waitpid failed for thread %d: %s", tid, strerror(err)); + _Py_RemoteDebug_InitThreadsState(unwinder, st); + return -1; + } } } + st->count = seized; return 0; } diff --git a/Python/remote_debug.h b/Python/remote_debug.h index 53bbd571ad3cef..6fecc23502b46e 100644 --- a/Python/remote_debug.h +++ b/Python/remote_debug.h @@ -100,9 +100,16 @@ extern "C" { # define HAVE_PROCESS_VM_READV 0 #endif +static inline int +_Py_RemoteDebug_HasPermissionError(void) +{ + return PyErr_Occurred() + && PyErr_ExceptionMatches(PyExc_PermissionError); +} + #define _set_debug_exception_cause(exception, format, ...) \ do { \ - if (!PyErr_ExceptionMatches(PyExc_PermissionError)) { \ + if (!_Py_RemoteDebug_HasPermissionError()) { \ PyThreadState *tstate = _PyThreadState_GET(); \ if (!_PyErr_Occurred(tstate)) { \ _PyErr_Format(tstate, exception, format, ##__VA_ARGS__); \ @@ -112,6 +119,20 @@ extern "C" { } \ } while (0) +#define _set_debug_oserror_from_errno(err, format, ...) \ + do { \ + errno = (err); \ + PyErr_SetFromErrno(PyExc_OSError); \ + _set_debug_exception_cause(PyExc_OSError, format, ##__VA_ARGS__); \ + } while (0) + +#define _set_debug_oserror_from_errno_with_filename(err, filename, format, ...) \ + do { \ + errno = (err); \ + PyErr_SetFromErrnoWithFilename(PyExc_OSError, filename); \ + _set_debug_exception_cause(PyExc_OSError, format, ##__VA_ARGS__); \ + } while (0) + static inline size_t get_page_size(void) { size_t page_size = 0; @@ -170,7 +191,7 @@ _Py_RemoteDebug_ValidatePyRuntimeCookie(proc_handle_t *handle, uintptr_t address } char buf[sizeof(_Py_Debug_Cookie) - 1]; if (_Py_RemoteDebug_ReadRemoteMemory(handle, address, sizeof(buf), buf) != 0) { - if (!PyErr_ExceptionMatches(PyExc_PermissionError)) { + if (!_Py_RemoteDebug_HasPermissionError()) { PyErr_Clear(); } return 0; @@ -207,6 +228,21 @@ static mach_port_t pid_to_task(pid_t pid); // Initialize the process handle UNUSED static int _Py_RemoteDebug_InitProcHandle(proc_handle_t *handle, pid_t pid) { + handle->pid = 0; +#if defined(__APPLE__) && defined(TARGET_OS_OSX) && TARGET_OS_OSX + handle->task = 0; +#elif defined(MS_WINDOWS) + handle->hProcess = NULL; +#elif defined(__linux__) + handle->memfd = -1; +#endif + handle->page_size = get_page_size(); + handle->page_cache_count = 0; + for (int i = 0; i < MAX_PAGES; i++) { + handle->pages[i].data = NULL; + handle->pages[i].valid = 0; + } + handle->pid = pid; #if defined(__APPLE__) && defined(TARGET_OS_OSX) && TARGET_OS_OSX handle->task = pid_to_task(handle->pid); @@ -219,19 +255,12 @@ _Py_RemoteDebug_InitProcHandle(proc_handle_t *handle, pid_t pid) { PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION | PROCESS_QUERY_INFORMATION | PROCESS_SUSPEND_RESUME, FALSE, pid); if (handle->hProcess == NULL) { - PyErr_SetFromWindowsErr(0); + DWORD error = GetLastError(); + PyErr_SetFromWindowsErr(error); _set_debug_exception_cause(PyExc_RuntimeError, "Failed to initialize Windows process handle"); return -1; } -#elif defined(__linux__) - handle->memfd = -1; #endif - handle->page_size = get_page_size(); - handle->page_cache_count = 0; - for (int i = 0; i < MAX_PAGES; i++) { - handle->pages[i].data = NULL; - handle->pages[i].valid = 0; - } return 0; } @@ -396,17 +425,19 @@ return_section_address_fat( size_t cpu_size = sizeof(cpu), abi64_size = sizeof(is_abi64); if (sysctlbyname("hw.cputype", &cpu, &cpu_size, NULL, 0) != 0) { - PyErr_Format(PyExc_OSError, + int err = errno; + _set_debug_oserror_from_errno(err, "Failed to determine CPU type via sysctlbyname " "for fat binary analysis at 0x%lx: %s", - base, strerror(errno)); + base, strerror(err)); return 0; } if (sysctlbyname("hw.cpu64bit_capable", &is_abi64, &abi64_size, NULL, 0) != 0) { - PyErr_Format(PyExc_OSError, + int err = errno; + _set_debug_oserror_from_errno(err, "Failed to determine CPU ABI capability via sysctlbyname " "for fat binary analysis at 0x%lx: %s", - base, strerror(errno)); + base, strerror(err)); return 0; } @@ -459,26 +490,29 @@ search_section_in_file(const char* secname, char* path, uintptr_t base, mach_vm_ { int fd = open(path, O_RDONLY); if (fd == -1) { - PyErr_Format(PyExc_OSError, + int err = errno; + _set_debug_oserror_from_errno_with_filename(err, path, "Cannot open binary file '%s' for section '%s' search: %s", - path, secname, strerror(errno)); + path, secname, strerror(err)); return 0; } struct stat fs; if (fstat(fd, &fs) == -1) { - PyErr_Format(PyExc_OSError, + int err = errno; + _set_debug_oserror_from_errno_with_filename(err, path, "Cannot get file size for binary '%s' during section '%s' search: %s", - path, secname, strerror(errno)); + path, secname, strerror(err)); close(fd); return 0; } void* map = mmap(0, fs.st_size, PROT_READ, MAP_SHARED, fd, 0); if (map == MAP_FAILED) { - PyErr_Format(PyExc_OSError, + int err = errno; + _set_debug_oserror_from_errno_with_filename(err, path, "Cannot memory map binary file '%s' (size: %lld bytes) for section '%s' search: %s", - path, (long long)fs.st_size, secname, strerror(errno)); + path, (long long)fs.st_size, secname, strerror(err)); close(fd); return 0; } @@ -507,15 +541,21 @@ search_section_in_file(const char* secname, char* path, uintptr_t base, mach_vm_ } if (munmap(map, fs.st_size) != 0) { - PyErr_Format(PyExc_OSError, - "Failed to unmap binary file '%s' (size: %lld bytes): %s", - path, (long long)fs.st_size, strerror(errno)); + if (!PyErr_Occurred()) { + int err = errno; + _set_debug_oserror_from_errno_with_filename(err, path, + "Failed to unmap binary file '%s' (size: %lld bytes): %s", + path, (long long)fs.st_size, strerror(err)); + } result = 0; } if (close(fd) != 0) { - PyErr_Format(PyExc_OSError, - "Failed to close binary file '%s': %s", - path, strerror(errno)); + if (!PyErr_Occurred()) { + int err = errno; + _set_debug_oserror_from_errno_with_filename(err, path, + "Failed to close binary file '%s': %s", + path, strerror(err)); + } result = 0; } return result; @@ -560,14 +600,15 @@ search_map_for_section(proc_handle_t *handle, const char* secname, const char* s char map_filename[MAXPATHLEN + 1]; - while (mach_vm_region( - proc_ref, - &address, - &size, - VM_REGION_BASIC_INFO_64, - (vm_region_info_t)®ion_info, - &count, - &object_name) == KERN_SUCCESS) + kern_return_t kr; + while ((kr = mach_vm_region( + proc_ref, + &address, + &size, + VM_REGION_BASIC_INFO_64, + (vm_region_info_t)®ion_info, + &count, + &object_name)) == KERN_SUCCESS) { if ((region_info.protection & VM_PROT_READ) == 0 @@ -591,18 +632,32 @@ search_map_for_section(proc_handle_t *handle, const char* secname, const char* s } if (strncmp(filename, substr, strlen(substr)) == 0) { + PyErr_Clear(); uintptr_t result = search_section_in_file( secname, map_filename, address, size, proc_ref); - if (result != 0 - && (validator == NULL || validator(handle, result))) - { - return result; + if (result != 0) { + if (validator == NULL || validator(handle, result)) { + return result; + } + if (_Py_RemoteDebug_HasPermissionError()) { + return 0; + } + } + else if (_Py_RemoteDebug_HasPermissionError()) { + return 0; } } address += size; } + if (kr != KERN_INVALID_ADDRESS && !PyErr_Occurred()) { + PyErr_Format(PyExc_RuntimeError, + "mach_vm_region failed while searching PID %d for section '%s' " + "(kern_return_t: %d)", + handle->pid, secname, kr); + } + return 0; } @@ -625,25 +680,29 @@ search_elf_file_for_section( int fd = open(elf_file, O_RDONLY); if (fd < 0) { - PyErr_Format(PyExc_OSError, + int err = errno; + _set_debug_oserror_from_errno_with_filename(err, elf_file, "Cannot open ELF file '%s' for section '%s' search: %s", - elf_file, secname, strerror(errno)); + elf_file, secname, strerror(err)); goto exit; } struct stat file_stats; if (fstat(fd, &file_stats) != 0) { - PyErr_Format(PyExc_OSError, + int err = errno; + _set_debug_oserror_from_errno_with_filename(err, elf_file, "Cannot get file size for ELF file '%s' during section '%s' search: %s", - elf_file, secname, strerror(errno)); + elf_file, secname, strerror(err)); goto exit; } file_memory = mmap(NULL, file_stats.st_size, PROT_READ, MAP_PRIVATE, fd, 0); if (file_memory == MAP_FAILED) { - PyErr_Format(PyExc_OSError, + int err = errno; + _set_debug_oserror_from_errno_with_filename(err, elf_file, "Cannot memory map ELF file '%s' (size: %lld bytes) for section '%s' search: %s", - elf_file, (long long)file_stats.st_size, secname, strerror(errno)); + elf_file, (long long)file_stats.st_size, secname, strerror(err)); + file_memory = NULL; goto exit; } @@ -700,12 +759,23 @@ search_elf_file_for_section( exit: if (file_memory != NULL) { - munmap(file_memory, file_stats.st_size); + if (munmap(file_memory, file_stats.st_size) != 0) { + if (!PyErr_Occurred()) { + int err = errno; + _set_debug_oserror_from_errno_with_filename(err, elf_file, + "Failed to unmap ELF file '%s' (size: %lld bytes): %s", + elf_file, (long long)file_stats.st_size, strerror(err)); + } + result = 0; + } } if (fd >= 0 && close(fd) != 0) { - PyErr_Format(PyExc_OSError, - "Failed to close ELF file '%s': %s", - elf_file, strerror(errno)); + if (!PyErr_Occurred()) { + int err = errno; + _set_debug_oserror_from_errno_with_filename(err, elf_file, + "Failed to close ELF file '%s': %s", + elf_file, strerror(err)); + } result = 0; } return result; @@ -720,9 +790,10 @@ search_linux_map_for_section(proc_handle_t *handle, const char* secname, const c FILE* maps_file = fopen(maps_file_path, "r"); if (maps_file == NULL) { - PyErr_Format(PyExc_OSError, + int err = errno; + _set_debug_oserror_from_errno_with_filename(err, maps_file_path, "Cannot open process memory map file '%s' for PID %d section search: %s", - maps_file_path, handle->pid, strerror(errno)); + maps_file_path, handle->pid, strerror(err)); return 0; } @@ -787,26 +858,39 @@ search_linux_map_for_section(proc_handle_t *handle, const char* secname, const c } if (strstr(filename, substr)) { - if (PyErr_ExceptionMatches(PyExc_PermissionError)) { - retval = 0; - break; - } PyErr_Clear(); retval = search_elf_file_for_section(handle, secname, start, path); - if (retval - && (validator == NULL || validator(handle, retval))) - { + if (retval) { + if (validator == NULL || validator(handle, retval)) { + break; + } + if (_Py_RemoteDebug_HasPermissionError()) { + retval = 0; + break; + } + } + else if (_Py_RemoteDebug_HasPermissionError()) { break; } retval = 0; } } + if (retval == 0 && !PyErr_Occurred() && ferror(maps_file)) { + int err = errno; + _set_debug_oserror_from_errno_with_filename(err, maps_file_path, + "Failed to read process map file '%s' for PID %d section search: %s", + maps_file_path, handle->pid, strerror(err)); + } + PyMem_Free(line); if (fclose(maps_file) != 0) { - PyErr_Format(PyExc_OSError, - "Failed to close process map file '%s': %s", - maps_file_path, strerror(errno)); + if (!PyErr_Occurred()) { + int err = errno; + _set_debug_oserror_from_errno_with_filename(err, maps_file_path, + "Failed to close process map file '%s': %s", + maps_file_path, strerror(err)); + } retval = 0; } @@ -829,9 +913,9 @@ static int is_process_alive(HANDLE hProcess) { static void* analyze_pe(const wchar_t* mod_path, BYTE* remote_base, const char* secname) { HANDLE hFile = CreateFileW(mod_path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) { - PyErr_SetFromWindowsErr(0); DWORD error = GetLastError(); - PyErr_Format(PyExc_OSError, + PyErr_SetFromWindowsErr(error); + _set_debug_exception_cause(PyExc_OSError, "Cannot open PE file for section '%s' analysis (error %lu)", secname, error); return NULL; @@ -839,9 +923,9 @@ static void* analyze_pe(const wchar_t* mod_path, BYTE* remote_base, const char* HANDLE hMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, 0); if (!hMap) { - PyErr_SetFromWindowsErr(0); DWORD error = GetLastError(); - PyErr_Format(PyExc_OSError, + PyErr_SetFromWindowsErr(error); + _set_debug_exception_cause(PyExc_OSError, "Cannot create file mapping for PE file section '%s' analysis (error %lu)", secname, error); CloseHandle(hFile); @@ -850,9 +934,9 @@ static void* analyze_pe(const wchar_t* mod_path, BYTE* remote_base, const char* BYTE* mapView = (BYTE*)MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0); if (!mapView) { - PyErr_SetFromWindowsErr(0); DWORD error = GetLastError(); - PyErr_Format(PyExc_OSError, + PyErr_SetFromWindowsErr(error); + _set_debug_exception_cause(PyExc_OSError, "Cannot map view of PE file for section '%s' analysis (error %lu)", secname, error); CloseHandle(hMap); @@ -910,9 +994,9 @@ search_windows_map_for_section(proc_handle_t* handle, const char* secname, const } while (hProcSnap == INVALID_HANDLE_VALUE && GetLastError() == ERROR_BAD_LENGTH); if (hProcSnap == INVALID_HANDLE_VALUE) { - PyErr_SetFromWindowsErr(0); DWORD error = GetLastError(); - PyErr_Format(PyExc_PermissionError, + PyErr_SetFromWindowsErr(error); + _set_debug_exception_cause(PyExc_OSError, "Unable to create module snapshot for PID %d section '%s' " "search (error %lu). Check permissions or PID validity", handle->pid, secname, error); @@ -923,17 +1007,46 @@ search_windows_map_for_section(proc_handle_t* handle, const char* secname, const moduleEntry.dwSize = sizeof(moduleEntry); void* runtime_addr = NULL; - for (BOOL hasModule = Module32FirstW(hProcSnap, &moduleEntry); hasModule; hasModule = Module32NextW(hProcSnap, &moduleEntry)) { + if (!Module32FirstW(hProcSnap, &moduleEntry)) { + DWORD error = GetLastError(); + PyErr_SetFromWindowsErr(error); + _set_debug_exception_cause(PyExc_OSError, + "Unable to enumerate modules for PID %d section '%s' " + "search (error %lu)", + handle->pid, secname, error); + CloseHandle(hProcSnap); + return 0; + } + + do { // Look for either python executable or DLL if (wcsstr(moduleEntry.szModule, substr)) { + PyErr_Clear(); void *candidate = analyze_pe(moduleEntry.szExePath, moduleEntry.modBaseAddr, secname); - if (candidate != NULL - && (validator == NULL || validator(handle, (uintptr_t)candidate))) - { - runtime_addr = candidate; + if (candidate != NULL) { + if (validator == NULL || validator(handle, (uintptr_t)candidate)) { + runtime_addr = candidate; + break; + } + if (_Py_RemoteDebug_HasPermissionError()) { + break; + } + } + else if (_Py_RemoteDebug_HasPermissionError()) { break; } } + } while (Module32NextW(hProcSnap, &moduleEntry)); + + if (runtime_addr == NULL && !PyErr_Occurred()) { + DWORD error = GetLastError(); + if (error != ERROR_NO_MORE_FILES) { + PyErr_SetFromWindowsErr(error); + _set_debug_exception_cause(PyExc_OSError, + "Module enumeration failed for PID %d section '%s' " + "search (error %lu)", + handle->pid, secname, error); + } } CloseHandle(hProcSnap); @@ -954,19 +1067,21 @@ _Py_RemoteDebug_GetPyRuntimeAddress(proc_handle_t* handle) address = search_windows_map_for_section(handle, "PyRuntime", L"python", _Py_RemoteDebug_ValidatePyRuntimeCookie); if (address == 0) { - // Error out: 'python' substring covers both executable and DLL - PyObject *exc = PyErr_GetRaisedException(); - PyErr_Format(PyExc_RuntimeError, - "Failed to find the PyRuntime section in process %d on Windows platform", - handle->pid); - _PyErr_ChainExceptions1(exc); + if (!_Py_RemoteDebug_HasPermissionError()) { + // Error out: 'python' substring covers both executable and DLL + PyObject *exc = PyErr_GetRaisedException(); + PyErr_Format(PyExc_RuntimeError, + "Failed to find the PyRuntime section in process %d on Windows platform", + handle->pid); + _PyErr_ChainExceptions1(exc); + } } #elif defined(__linux__) && HAVE_PROCESS_VM_READV // On Linux, search for 'python' in executable or DLL address = search_linux_map_for_section(handle, "PyRuntime", "python", _Py_RemoteDebug_ValidatePyRuntimeCookie); if (address == 0) { - if (!PyErr_ExceptionMatches(PyExc_PermissionError)) { + if (!_Py_RemoteDebug_HasPermissionError()) { // Error out: 'python' substring covers both executable and DLL PyObject *exc = PyErr_GetRaisedException(); PyErr_Format(PyExc_RuntimeError, @@ -982,17 +1097,19 @@ _Py_RemoteDebug_GetPyRuntimeAddress(proc_handle_t* handle) PyErr_Clear(); address = search_map_for_section(handle, "PyRuntime", *candidate, _Py_RemoteDebug_ValidatePyRuntimeCookie); - if (address != 0) { + if (address != 0 || _Py_RemoteDebug_HasPermissionError()) { break; } } if (address == 0) { - PyObject *exc = PyErr_GetRaisedException(); - PyErr_Format(PyExc_RuntimeError, - "Failed to find the PyRuntime section in process %d " - "on macOS platform (tried both libpython and python)", - handle->pid); - _PyErr_ChainExceptions1(exc); + if (!_Py_RemoteDebug_HasPermissionError()) { + PyObject *exc = PyErr_GetRaisedException(); + PyErr_Format(PyExc_RuntimeError, + "Failed to find the PyRuntime section in process %d " + "on macOS platform (tried both libpython and python)", + handle->pid); + _PyErr_ChainExceptions1(exc); + } } #else _set_debug_exception_cause(PyExc_RuntimeError, @@ -1013,9 +1130,9 @@ open_proc_mem_fd(proc_handle_t *handle) handle->memfd = open(mem_file_path, O_RDWR); if (handle->memfd == -1) { - PyErr_SetFromErrno(PyExc_OSError); - _set_debug_exception_cause(PyExc_OSError, - "failed to open file %s: %s", mem_file_path, strerror(errno)); + int err = errno; + _set_debug_oserror_from_errno_with_filename(err, mem_file_path, + "failed to open file %s: %s", mem_file_path, strerror(err)); return -1; } return 0; @@ -1026,6 +1143,9 @@ open_proc_mem_fd(proc_handle_t *handle) static int read_remote_memory_fallback(proc_handle_t *handle, uintptr_t remote_address, size_t len, void* dst) { + if (len == 0) { + return 0; + } if (handle->memfd == -1) { if (open_proc_mem_fd(handle) < 0) { return -1; @@ -1043,14 +1163,23 @@ read_remote_memory_fallback(proc_handle_t *handle, uintptr_t remote_address, siz read_bytes = preadv(handle->memfd, local, 1, offset); if (read_bytes < 0) { + int err = errno; + errno = err; PyErr_SetFromErrno(PyExc_OSError); _set_debug_exception_cause(PyExc_OSError, "preadv failed for PID %d at address 0x%lx " "(size %zu, partial read %zd bytes): %s", - handle->pid, remote_address + result, len - result, result, strerror(errno)); + handle->pid, remote_address + result, len - result, result, strerror(err)); return -1; } + if (read_bytes == 0) { + PyErr_Format(PyExc_OSError, + "preadv returned 0 bytes for PID %d at address 0x%lx " + "(size %zu, partial read %zd bytes)", + handle->pid, remote_address + result, len - result, result); + return -1; + } result += read_bytes; } while ((size_t)read_bytes != local[0].iov_len); return 0; @@ -1062,11 +1191,15 @@ read_remote_memory_fallback(proc_handle_t *handle, uintptr_t remote_address, siz static int _Py_RemoteDebug_ReadRemoteMemory(proc_handle_t *handle, uintptr_t remote_address, size_t len, void* dst) { + if (len == 0) { + return 0; + } #ifdef MS_WINDOWS SIZE_T read_bytes = 0; SIZE_T result = 0; do { if (!ReadProcessMemory(handle->hProcess, (LPCVOID)(remote_address + result), (char*)dst + result, len - result, &read_bytes)) { + DWORD error = GetLastError(); // Check if the process is still alive: we need to be able to tell our caller // that the process is dead and not just that the read failed. if (!is_process_alive(handle->hProcess)) { @@ -1074,14 +1207,20 @@ _Py_RemoteDebug_ReadRemoteMemory(proc_handle_t *handle, uintptr_t remote_address PyErr_SetFromErrno(PyExc_OSError); return -1; } - PyErr_SetFromWindowsErr(0); - DWORD error = GetLastError(); + PyErr_SetFromWindowsErr(error); _set_debug_exception_cause(PyExc_OSError, "ReadProcessMemory failed for PID %d at address 0x%lx " "(size %zu, partial read %zu bytes): Windows error %lu", handle->pid, remote_address + result, len - result, result, error); return -1; } + if (read_bytes == 0) { + PyErr_Format(PyExc_OSError, + "ReadProcessMemory returned 0 bytes for PID %d at address 0x%lx " + "(size %zu, partial read %zu bytes)", + handle->pid, remote_address + result, len - result, result); + return -1; + } result += read_bytes; } while (result < len); return 0; @@ -1102,31 +1241,40 @@ _Py_RemoteDebug_ReadRemoteMemory(proc_handle_t *handle, uintptr_t remote_address read_bytes = process_vm_readv(handle->pid, local, 1, remote, 1, 0); if (read_bytes < 0) { - if (errno == ENOSYS) { + int err = errno; + if (err == ENOSYS) { return read_remote_memory_fallback(handle, remote_address, len, dst); } + errno = err; PyErr_SetFromErrno(PyExc_OSError); - if (errno == ESRCH) { + if (err == ESRCH) { return -1; } _set_debug_exception_cause(PyExc_OSError, "process_vm_readv failed for PID %d at address 0x%lx " "(size %zu, partial read %zd bytes): %s", - handle->pid, remote_address + result, len - result, result, strerror(errno)); + handle->pid, remote_address + result, len - result, result, strerror(err)); return -1; } + if (read_bytes == 0) { + PyErr_Format(PyExc_OSError, + "process_vm_readv returned 0 bytes for PID %d at address 0x%lx " + "(size %zu, partial read %zd bytes)", + handle->pid, remote_address + result, len - result, result); + return -1; + } result += read_bytes; } while ((size_t)read_bytes != local[0].iov_len); return 0; #elif defined(__APPLE__) && defined(TARGET_OS_OSX) && TARGET_OS_OSX - Py_ssize_t result = -1; + mach_vm_size_t bytes_read = 0; kern_return_t kr = mach_vm_read_overwrite( handle->task, (mach_vm_address_t)remote_address, len, (mach_vm_address_t)dst, - (mach_vm_size_t*)&result); + &bytes_read); if (kr != KERN_SUCCESS) { switch (err_get_code(kr)) { @@ -1170,6 +1318,13 @@ _Py_RemoteDebug_ReadRemoteMemory(proc_handle_t *handle, uintptr_t remote_address } return -1; } + if (bytes_read != (mach_vm_size_t)len) { + PyErr_Format(PyExc_OSError, + "mach_vm_read_overwrite read %llu of %zu bytes for PID %d at " + "address 0x%lx", + (unsigned long long)bytes_read, len, handle->pid, remote_address); + return -1; + } return 0; #else Py_UNREACHABLE(); @@ -1181,6 +1336,9 @@ _Py_RemoteDebug_ReadRemoteMemory(proc_handle_t *handle, uintptr_t remote_address static int _Py_RemoteDebug_WriteRemoteMemoryFallback(proc_handle_t *handle, uintptr_t remote_address, size_t len, const void* src) { + if (len == 0) { + return 0; + } if (handle->memfd == -1) { if (open_proc_mem_fd(handle) < 0) { return -1; @@ -1198,10 +1356,19 @@ _Py_RemoteDebug_WriteRemoteMemoryFallback(proc_handle_t *handle, uintptr_t remot written = pwritev(handle->memfd, local, 1, offset); if (written < 0) { + int err = errno; + errno = err; PyErr_SetFromErrno(PyExc_OSError); return -1; } + if (written == 0) { + PyErr_Format(PyExc_OSError, + "pwritev wrote 0 bytes for PID %d at address 0x%lx " + "(size %zu, partial write %zd bytes)", + handle->pid, remote_address + result, len - result, result); + return -1; + } result += written; } while ((size_t)written != local[0].iov_len); return 0; @@ -1212,19 +1379,29 @@ _Py_RemoteDebug_WriteRemoteMemoryFallback(proc_handle_t *handle, uintptr_t remot UNUSED static int _Py_RemoteDebug_WriteRemoteMemory(proc_handle_t *handle, uintptr_t remote_address, size_t len, const void* src) { + if (len == 0) { + return 0; + } #ifdef MS_WINDOWS SIZE_T written = 0; SIZE_T result = 0; do { if (!WriteProcessMemory(handle->hProcess, (LPVOID)(remote_address + result), (const char*)src + result, len - result, &written)) { - PyErr_SetFromWindowsErr(0); DWORD error = GetLastError(); + PyErr_SetFromWindowsErr(error); _set_debug_exception_cause(PyExc_OSError, "WriteProcessMemory failed for PID %d at address 0x%lx " "(size %zu, partial write %zu bytes): Windows error %lu", handle->pid, remote_address + result, len - result, result, error); return -1; } + if (written == 0) { + PyErr_Format(PyExc_OSError, + "WriteProcessMemory wrote 0 bytes for PID %d at address 0x%lx " + "(size %zu, partial write %zu bytes)", + handle->pid, remote_address + result, len - result, result); + return -1; + } result += written; } while (result < len); return 0; @@ -1245,17 +1422,26 @@ _Py_RemoteDebug_WriteRemoteMemory(proc_handle_t *handle, uintptr_t remote_addres written = process_vm_writev(handle->pid, local, 1, remote, 1, 0); if (written < 0) { - if (errno == ENOSYS) { + int err = errno; + if (err == ENOSYS) { return _Py_RemoteDebug_WriteRemoteMemoryFallback(handle, remote_address, len, src); } + errno = err; PyErr_SetFromErrno(PyExc_OSError); _set_debug_exception_cause(PyExc_OSError, "process_vm_writev failed for PID %d at address 0x%lx " "(size %zu, partial write %zd bytes): %s", - handle->pid, remote_address + result, len - result, result, strerror(errno)); + handle->pid, remote_address + result, len - result, result, strerror(err)); return -1; } + if (written == 0) { + PyErr_Format(PyExc_OSError, + "process_vm_writev wrote 0 bytes for PID %d at address 0x%lx " + "(size %zu, partial write %zd bytes)", + handle->pid, remote_address + result, len - result, result); + return -1; + } result += written; } while ((size_t)written != local[0].iov_len); return 0; From 340b4dd6ffaeec92498a21d36949703e986dc2f6 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 26 May 2026 01:15:56 +0200 Subject: [PATCH 147/818] [3.15] gh-149619: Harden _remote_debugging error paths (GH-150349) (#150434) gh-149619: Harden _remote_debugging error paths (GH-150349) (cherry picked from commit a5be25d3bdc1b3cbc9638a3249c0e3db5a97ebc6) Co-authored-by: Pablo Galindo Salgado From d73e43317e08e6d2ce693c61ca6e751996da2d43 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 26 May 2026 03:04:49 +0200 Subject: [PATCH 148/818] [3.15] gh-149931: Fix memory leaks on failed realloc (GH-149932) (#150439) --- Modules/_remote_debugging/frames.c | 6 ++++-- Modules/timemodule.c | 9 ++++++--- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/Modules/_remote_debugging/frames.c b/Modules/_remote_debugging/frames.c index 8d8019396b3e31..d73cd080dc477f 100644 --- a/Modules/_remote_debugging/frames.c +++ b/Modules/_remote_debugging/frames.c @@ -56,12 +56,14 @@ process_single_stack_chunk( return -1; } - this_chunk = PyMem_RawRealloc(this_chunk, actual_size); - if (!this_chunk) { + char *tmp = PyMem_RawRealloc(this_chunk, actual_size); + if (!tmp) { + PyMem_RawFree(this_chunk); PyErr_NoMemory(); set_exception_cause(unwinder, PyExc_MemoryError, "Failed to reallocate stack chunk buffer"); return -1; } + this_chunk = tmp; if (_Py_RemoteDebug_PagedReadRemoteMemory(&unwinder->handle, chunk_addr, actual_size, this_chunk) < 0) { PyMem_RawFree(this_chunk); diff --git a/Modules/timemodule.c b/Modules/timemodule.c index 25e744d7da25c7..d90bf1f2ef90ed 100644 --- a/Modules/timemodule.c +++ b/Modules/timemodule.c @@ -820,12 +820,15 @@ time_strftime1(time_char **outbuf, size_t *bufsize, PyErr_NoMemory(); return NULL; } - *outbuf = (time_char *)PyMem_Realloc(*outbuf, - *bufsize*sizeof(time_char)); - if (*outbuf == NULL) { + time_char *tmp = (time_char *)PyMem_Realloc(*outbuf, + *bufsize*sizeof(time_char)); + if (tmp == NULL) { + PyMem_Free(*outbuf); + *outbuf = NULL; PyErr_NoMemory(); return NULL; } + *outbuf = tmp; #if defined _MSC_VER && _MSC_VER >= 1400 && defined(__STDC_SECURE_LIB__) errno = 0; #endif From 413663b26a48ff0218987b216043d677d7a01397 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 26 May 2026 06:03:35 +0200 Subject: [PATCH 149/818] [3.15] gh-150443: Exclude explicit dup3 and pipe2 checks on iOS builds. (GH-150444) (#150446) Exclude explicit dup3 and pipe2 checks on iOS builds. (cherry picked from commit 629da5c914b4407e01c1dc06cbcbd8dce825fef3) Co-authored-by: Russell Keith-Magee --- configure | 26 +++++++++++++------------- configure.ac | 6 +++--- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/configure b/configure index 9ad2171460f7ac..7abc41648b3c45 100755 --- a/configure +++ b/configure @@ -20020,12 +20020,6 @@ if test "x$ac_cv_func_dup" = xyes then : printf "%s\n" "#define HAVE_DUP 1" >>confdefs.h -fi -ac_fn_c_check_func "$LINENO" "dup3" "ac_cv_func_dup3" -if test "x$ac_cv_func_dup3" = xyes -then : - printf "%s\n" "#define HAVE_DUP3 1" >>confdefs.h - fi ac_fn_c_check_func "$LINENO" "execv" "ac_cv_func_execv" if test "x$ac_cv_func_execv" = xyes @@ -20500,12 +20494,6 @@ if test "x$ac_cv_func_pipe" = xyes then : printf "%s\n" "#define HAVE_PIPE 1" >>confdefs.h -fi -ac_fn_c_check_func "$LINENO" "pipe2" "ac_cv_func_pipe2" -if test "x$ac_cv_func_pipe2" = xyes -then : - printf "%s\n" "#define HAVE_PIPE2 1" >>confdefs.h - fi ac_fn_c_check_func "$LINENO" "plock" "ac_cv_func_plock" if test "x$ac_cv_func_plock" = xyes @@ -21173,7 +21161,13 @@ fi # header definition prevents usage - autoconf doesn't use the headers), or # raise an error if used at runtime. Force these symbols off. if test "$ac_sys_system" != "iOS" ; then - ac_fn_c_check_func "$LINENO" "getentropy" "ac_cv_func_getentropy" + ac_fn_c_check_func "$LINENO" "dup3" "ac_cv_func_dup3" +if test "x$ac_cv_func_dup3" = xyes +then : + printf "%s\n" "#define HAVE_DUP3 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "getentropy" "ac_cv_func_getentropy" if test "x$ac_cv_func_getentropy" = xyes then : printf "%s\n" "#define HAVE_GETENTROPY 1" >>confdefs.h @@ -21184,6 +21178,12 @@ if test "x$ac_cv_func_getgroups" = xyes then : printf "%s\n" "#define HAVE_GETGROUPS 1" >>confdefs.h +fi +ac_fn_c_check_func "$LINENO" "pipe2" "ac_cv_func_pipe2" +if test "x$ac_cv_func_pipe2" = xyes +then : + printf "%s\n" "#define HAVE_PIPE2 1" >>confdefs.h + fi ac_fn_c_check_func "$LINENO" "system" "ac_cv_func_system" if test "x$ac_cv_func_system" = xyes diff --git a/configure.ac b/configure.ac index a51e173e5293f2..47a6e59623b830 100644 --- a/configure.ac +++ b/configure.ac @@ -5469,7 +5469,7 @@ fi AC_CHECK_FUNCS([ \ accept4 alarm bind_textdomain_codeset chmod chown clearenv \ clock closefrom close_range confstr \ - copy_file_range ctermid dladdr dup dup3 execv explicit_bzero explicit_memset \ + copy_file_range ctermid dladdr dup execv explicit_bzero explicit_memset \ faccessat fchmod fchmodat fchown fchownat fdopendir fdwalk fexecve \ fork fork1 fpathconf fstatat ftime ftruncate futimens futimes futimesat \ gai_strerror getegid geteuid getgid getgrent getgrgid getgrgid_r \ @@ -5479,7 +5479,7 @@ AC_CHECK_FUNCS([ \ getspnam getuid getwd grantpt if_nameindex initgroups kill killpg lchown linkat \ lockf lstat lutimes madvise mbrtowc memrchr mkdirat mkfifo mkfifoat \ mknod mknodat mktime mmap mremap nice openat opendir pathconf pause pipe \ - pipe2 plock poll ppoll posix_fadvise posix_fallocate posix_openpt posix_spawn posix_spawnp \ + plock poll ppoll posix_fadvise posix_fallocate posix_openpt posix_spawn posix_spawnp \ posix_spawn_file_actions_addclosefrom_np \ pread preadv preadv2 process_vm_readv \ pthread_cond_timedwait_relative_np pthread_condattr_setclock pthread_init \ @@ -5516,7 +5516,7 @@ fi # header definition prevents usage - autoconf doesn't use the headers), or # raise an error if used at runtime. Force these symbols off. if test "$ac_sys_system" != "iOS" ; then - AC_CHECK_FUNCS([getentropy getgroups system]) + AC_CHECK_FUNCS([dup3 getentropy getgroups pipe2 system]) fi AC_CHECK_DECL([dirfd], From 16a31fac483b5ad035908855c1ed4544eadab542 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 26 May 2026 19:05:11 +0200 Subject: [PATCH 150/818] [3.15] gh-148557: Use em-config to locate trampoline clang (GH-148556) (#150481) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When CC is wrapped by ccache, the Emscripten trampoline rule cannot derive the matching clang path by treating CC as a single executable path. Query the active LLVM toolchain path with em-config instead. (cherry picked from commit 1310d2c25242041f0a218012426fba14e756eef8) Co-authored-by: Clément Péron --- Makefile.pre.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.pre.in b/Makefile.pre.in index 669a2c9527075c..9c358bc6fbc681 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -3211,7 +3211,7 @@ Python/asm_trampoline.o: $(srcdir)/Python/asm_trampoline.S Python/emscripten_trampoline_inner.wasm: $(srcdir)/Python/emscripten_trampoline_inner.c # emcc has a path that ends with emsdk/upstream/emscripten/emcc, we're looking for emsdk/upstream/bin/clang. - $$(dirname $$(dirname $(CC)))/bin/clang -o $@ $< -mgc -O2 -Wl,--no-entry -Wl,--import-table -Wl,--import-memory -target wasm32-unknown-unknown -nostdlib + $$(em-config LLVM_ROOT)/clang -o $@ $< -mgc -O2 -Wl,--no-entry -Wl,--import-table -Wl,--import-memory -target wasm32-unknown-unknown -nostdlib Python/emscripten_trampoline_wasm.c: Python/emscripten_trampoline_inner.wasm $(PYTHON_FOR_REGEN) $(srcdir)/Platforms/emscripten/prepare_external_wasm.py $< $@ getWasmTrampolineModule From 79e17d7fa5bbd0e83e6d32ba3076633a2f8df3ea Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 26 May 2026 21:21:36 +0200 Subject: [PATCH 151/818] [3.15] gh-88726: Stop using non-standard charset names eucgb2312_cn and big5_tw in email (GH-149959) (GH-150491) (cherry picked from commit 5e467f4331d4cb7a8e2986c27af7eb68ccaccb37) Co-authored-by: Serhiy Storchaka --- Lib/email/charset.py | 2 - Lib/test/test_email/test_asian_codecs.py | 56 +++++++++++++++++++ ...6-05-17-22-37-02.gh-issue-88726.BAoL6j.rst | 2 + 3 files changed, 58 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-05-17-22-37-02.gh-issue-88726.BAoL6j.rst diff --git a/Lib/email/charset.py b/Lib/email/charset.py index 5036c3f58a5633..c4b246455f86c6 100644 --- a/Lib/email/charset.py +++ b/Lib/email/charset.py @@ -93,8 +93,6 @@ # Map charsets to their Unicode codec strings. CODEC_MAP = { - 'gb2312': 'eucgb2312_cn', - 'big5': 'big5_tw', # Hack: We don't want *any* conversion for stuff marked us-ascii, as all # sorts of garbage might be sent to us in the guise of 7-bit us-ascii. # Let that stuff pass through without conversion to/from Unicode. diff --git a/Lib/test/test_email/test_asian_codecs.py b/Lib/test/test_email/test_asian_codecs.py index ca44f54c69b39b..85979ffd8169a7 100644 --- a/Lib/test/test_email/test_asian_codecs.py +++ b/Lib/test/test_email/test_asian_codecs.py @@ -58,6 +58,62 @@ def test_japanese_codecs(self): # TK: full decode comparison eq(str(h).encode(jcode), subject_bytes) + h = Header("Japanese") + s = '\u65e5\u672c\u8a9e' # 日本語 + h.append(s, Charset('euc-jp')) + h.append(s, Charset('iso-2022-jp')) + h.append(s, Charset('shift_jis')) + eq(h.encode(), """\ +Japanese =?iso-2022-jp?b?GyRCRnxLXDhsGyhC?= =?iso-2022-jp?b?GyRCRnxLXDhsGyhC?= + =?iso-2022-jp?b?GyRCRnxLXDhsGyhC?=""") + eq(decode_header(h.encode()), + [(b'Japanese ', None), + (b'\x1b$BF|K\\8l\x1b(B\x1b$BF|K\\8l\x1b(B\x1b$BF|K\\8l\x1b(B', 'iso-2022-jp'), + ]) + + def test_chinese_codecs(self): + eq = self.ndiffAssertEqual + h = Header("Chinese") + s = '\u4e2d\u6587' # 中文 + h.append(s, Charset('gb2312')) + h.append(s, Charset('gbk')) + h.append(s, Charset('gb18030')) + h.append(s, Charset('hz')) + h.append(s, Charset('big5')) + h.append(s, Charset('big5hkscs')) + eq(h.encode(), """\ +Chinese =?gb2312?b?1tDOxA==?= =?gbk?b?1tDOxA==?= =?gb18030?b?1tDOxA==?= + =?hz?b?fntWUE5Efn0=?= =?big5?b?pKSk5Q==?= =?big5hkscs?b?pKSk5Q==?=""") + eq(decode_header(h.encode()), + [(b'Chinese ', None), + (b'\xd6\xd0\xce\xc4', 'gb2312'), + (b'\xd6\xd0\xce\xc4', 'gbk'), + (b'\xd6\xd0\xce\xc4', 'gb18030'), + (b'~{VPND~}', 'hz'), + (b'\xa4\xa4\xa4\xe5', 'big5'), + (b'\xa4\xa4\xa4\xe5', 'big5hkscs'), + ]) + + def test_korean_codecs(self): + eq = self.ndiffAssertEqual + h = Header("Korean") + s = '\ud55c\uad6d\uc5b4' # 한국어 + h.append(s, Charset('euc-kr')) + h.append(s, Charset('ks_c_5601-1987')) + h.append(s, Charset('cp949')) + h.append(s, Charset('iso-2022-kr')) + h.append(s, Charset('johab')) + eq(h.encode(), """\ +Korean =?euc-kr?b?x9Gxub7u?= =?ks_c_5601-1987?b?x9Gxub7uIMfRsbm+7g==?= + =?iso-2022-kr?b?GyQpQw5HUTE5Pm4P?= =?johab?b?0GWKgrTh?=""") + eq(decode_header(h.encode()), + [(b'Korean ', None), + (b'\xc7\xd1\xb1\xb9\xbe\xee', 'euc-kr'), + (b'\xc7\xd1\xb1\xb9\xbe\xee \xc7\xd1\xb1\xb9\xbe\xee', 'ks_c_5601-1987'), + (b'\x1b$)C\x0eGQ19>n\x0f', 'iso-2022-kr'), + (b'\xd0e\x8a\x82\xb4\xe1', 'johab'), + ]) + def test_payload_encoding_utf8(self): jhello = str(b'\xa5\xcf\xa5\xed\xa1\xbc\xa5\xef\xa1\xbc' b'\xa5\xeb\xa5\xc9\xa1\xaa', 'euc-jp') diff --git a/Misc/NEWS.d/next/Library/2026-05-17-22-37-02.gh-issue-88726.BAoL6j.rst b/Misc/NEWS.d/next/Library/2026-05-17-22-37-02.gh-issue-88726.BAoL6j.rst new file mode 100644 index 00000000000000..ba9058d79c9873 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-05-17-22-37-02.gh-issue-88726.BAoL6j.rst @@ -0,0 +1,2 @@ +The :mod:`email` package now uses standard MIME charset names "gb2312" and +"big5" instead of non-standard names "eucgb2312_cn" and "big5_tw". From 528356eac0adf70fed0cf37dbb04c8fd529672d8 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 26 May 2026 21:46:16 +0200 Subject: [PATCH 152/818] [3.15] gh-150175: Fix ThreadingMock call_count race condition (GH-150176) (#150182) gh-150175: Fix ThreadingMock call_count race condition (GH-150176) ThreadingMock._increment_mock_call() was not thread-safe. Multiple threads calling the mock simultaneously could lose increments due to race conditions on call_count and other attributes. Fix by overriding _increment_mock_call in ThreadingMixin and wrapping it with the existing _mock_calls_events_lock. (cherry picked from commit 388e023fe1197c1ffed374520ed45df4ac72b8f5) Co-authored-by: saisneha196 <156835592+saisneha196@users.noreply.github.com> --- Lib/unittest/mock.py | 4 ++++ .../Library/2026-05-21-11-25-58.gh-issue-150175.8H4Caz.rst | 3 +++ 2 files changed, 7 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2026-05-21-11-25-58.gh-issue-150175.8H4Caz.rst diff --git a/Lib/unittest/mock.py b/Lib/unittest/mock.py index 1cee67fa5d7094..2f6f03c7a11ae6 100644 --- a/Lib/unittest/mock.py +++ b/Lib/unittest/mock.py @@ -3121,6 +3121,10 @@ def _mock_call(self, *args, **kwargs): return ret_value + def _increment_mock_call(self, /, *args, **kwargs): + with self._mock_calls_events_lock: + super()._increment_mock_call(*args, **kwargs) + def wait_until_called(self, *, timeout=_timeout_unset): """Wait until the mock object is called. diff --git a/Misc/NEWS.d/next/Library/2026-05-21-11-25-58.gh-issue-150175.8H4Caz.rst b/Misc/NEWS.d/next/Library/2026-05-21-11-25-58.gh-issue-150175.8H4Caz.rst new file mode 100644 index 00000000000000..80fc80d4d50a63 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-05-21-11-25-58.gh-issue-150175.8H4Caz.rst @@ -0,0 +1,3 @@ +Fix race condition in :class:`unittest.mock.ThreadingMock` where +concurrent calls could lose increments to ``call_count`` and other +attributes due to a missing lock in ``_increment_mock_call``. From d2b10e75c7093fd9637dc8428d94cb8c723f808d Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 27 May 2026 12:52:02 +0200 Subject: [PATCH 153/818] [3.15] gh-149571: Fix the C implementation of Element.itertext() (GH-149929) (GH-150509) It no longer emits text for comments and processing instructions. (cherry picked from commit 7de4fcd44585f572acbcee23f5c7018b2b3f0983) Co-authored-by: Serhiy Storchaka --- Lib/test/test_xml_etree.py | 26 +++++++++++++++++++ ...-05-17-02-25-56.gh-issue-149571.LNyuWJ.rst | 2 ++ Modules/_elementtree.c | 4 +++ 3 files changed, 32 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2026-05-17-02-25-56.gh-issue-149571.LNyuWJ.rst diff --git a/Lib/test/test_xml_etree.py b/Lib/test/test_xml_etree.py index 3a41ea97a2e0a2..f43f1708a0fabd 100644 --- a/Lib/test/test_xml_etree.py +++ b/Lib/test/test_xml_etree.py @@ -3657,6 +3657,32 @@ def test_basic(self): doc = ET.XML("a&b&c&") self.assertEqual(''.join(doc.itertext()), 'a&b&c&') + def test_comment(self): + e = ET.Element('root') + e.text = 'before' + comment = ET.Comment('comment') + self.assertEqual(comment.text, 'comment') + comment.tail = 'after' + e.append(comment) + self.assertEqual(''.join(e.itertext()), 'beforeafter') + self.assertEqual(list(e.iter()), [e, comment]) + self.assertEqual(list(e.iter('root')), [e]) + self.assertEqual(''.join(comment.itertext()), '') + self.assertEqual(list(comment.iter()), [comment]) + + def test_processinginstruction(self): + e = ET.Element('root') + e.text = 'before' + pi = ET.PI('test', 'instruction') + self.assertEqual(pi.text, 'test instruction') + pi.tail = 'after' + e.append(pi) + self.assertEqual(''.join(e.itertext()), 'beforeafter') + self.assertEqual(list(e.iter()), [e, pi]) + self.assertEqual(list(e.iter('root')), [e]) + self.assertEqual(''.join(pi.itertext()), '') + self.assertEqual(list(pi.iter()), [pi]) + def test_corners(self): # single root, no subelements a = ET.Element('a') diff --git a/Misc/NEWS.d/next/Library/2026-05-17-02-25-56.gh-issue-149571.LNyuWJ.rst b/Misc/NEWS.d/next/Library/2026-05-17-02-25-56.gh-issue-149571.LNyuWJ.rst new file mode 100644 index 00000000000000..2b71d9cf2200be --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-05-17-02-25-56.gh-issue-149571.LNyuWJ.rst @@ -0,0 +1,2 @@ +Fix the C implementation of :meth:`xml.etree.ElementTree.Element.itertext`: +it no longer emits text for comments and processing instructions. diff --git a/Modules/_elementtree.c b/Modules/_elementtree.c index eb69df22c6ef0a..f827274eeffba8 100644 --- a/Modules/_elementtree.c +++ b/Modules/_elementtree.c @@ -2297,6 +2297,10 @@ elementiter_next(PyObject *op) return NULL; } if (it->gettext) { + if (elem->tag != Py_None && !PyUnicode_Check(elem->tag)) { + Py_DECREF(elem); + continue; + } text = element_get_text(elem); goto gettext; } From cc6fea844f614fb0ac779f84f5e83a260359b2de Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 27 May 2026 14:52:48 +0200 Subject: [PATCH 154/818] [3.15] gh-150389: Make perf profiler tests resilient (GH-150437) (#150515) --- Lib/test/test_perf_profiler.py | 166 +++++++++++++++++++++------------ 1 file changed, 104 insertions(+), 62 deletions(-) diff --git a/Lib/test/test_perf_profiler.py b/Lib/test/test_perf_profiler.py index 597e6599352049..425c76dd01ed7c 100644 --- a/Lib/test/test_perf_profiler.py +++ b/Lib/test/test_perf_profiler.py @@ -34,6 +34,21 @@ def supports_trampoline_profiling(): raise unittest.SkipTest("perf trampoline profiling not supported") +def _perf_env(**env_vars): + env = os.environ.copy() + # Keep perf's output stable regardless of the builder's perf config. + env.update( + { + "DEBUGINFOD_URLS": "", + "PERF_CONFIG": os.devnull, + } + ) + if env_vars: + env.update(env_vars) + env["PYTHON_JIT"] = "0" + return env + + class TestPerfTrampoline(unittest.TestCase): def setUp(self): super().setUp() @@ -63,13 +78,12 @@ def baz(): """ with temp_dir() as script_dir: script = make_script(script_dir, "perftest", code) - env = {**os.environ, "PYTHON_JIT": "0"} with subprocess.Popen( [sys.executable, "-Xperf", script], text=True, stderr=subprocess.PIPE, stdout=subprocess.PIPE, - env=env, + env=_perf_env(), ) as process: stdout, stderr = process.communicate() @@ -132,13 +146,12 @@ def baz(): """ with temp_dir() as script_dir: script = make_script(script_dir, "perftest", code) - env = {**os.environ, "PYTHON_JIT": "0"} with subprocess.Popen( [sys.executable, "-Xperf", script], text=True, stderr=subprocess.PIPE, stdout=subprocess.PIPE, - env=env, + env=_perf_env(), ) as process: stdout, stderr = process.communicate() @@ -198,13 +211,12 @@ def test_trampoline_works_after_fork_with_many_code_objects(self): """ with temp_dir() as script_dir: script = make_script(script_dir, "perftest", code) - env = {**os.environ, "PYTHON_JIT": "0"} with subprocess.Popen( [sys.executable, "-Xperf", script], text=True, stderr=subprocess.PIPE, stdout=subprocess.PIPE, - env=env, + env=_perf_env(), ) as process: stdout, stderr = process.communicate() @@ -242,13 +254,12 @@ def baz(): code = set_eval_hook + code with temp_dir() as script_dir: script = make_script(script_dir, "perftest", code) - env = {**os.environ, "PYTHON_JIT": "0"} with subprocess.Popen( [sys.executable, script], text=True, stderr=subprocess.PIPE, stdout=subprocess.PIPE, - env=env, + env=_perf_env(), ) as process: stdout, stderr = process.communicate() @@ -345,9 +356,12 @@ def perf_command_works(): "-c", 'print("hello")', ) - env = {**os.environ, "PYTHON_JIT": "0"} stdout = subprocess.check_output( - cmd, cwd=script_dir, text=True, stderr=subprocess.STDOUT, env=env + cmd, + cwd=script_dir, + text=True, + stderr=subprocess.STDOUT, + env=_perf_env(), ) except (subprocess.SubprocessError, OSError): return False @@ -359,43 +373,49 @@ def perf_command_works(): def run_perf(cwd, *args, use_jit=False, **env_vars): - env = os.environ.copy() - if env_vars: - env.update(env_vars) - env["PYTHON_JIT"] = "0" + env = _perf_env(**env_vars) output_file = cwd + "/perf_output.perf" - if not use_jit: - base_cmd = ( - "perf", - "record", - "--no-buildid", - "--no-buildid-cache", - "-g", - "--call-graph=fp", - "-o", output_file, - "--" - ) + base_cmd = [ + "perf", + "record", + "--no-buildid", + "--no-buildid-cache", + "-g", + "--call-graph=dwarf,65528" if use_jit else "--call-graph=fp", + ] + if use_jit: + perf_commands = [] + # Some builders have low perf_event_mlock_kb limits. + mmap_sizes = ("4M", "2M", "1M", "512K", "256K", "128K", None) + for mmap_size in mmap_sizes: + command = base_cmd.copy() + if mmap_size is not None: + command += ["-F99", "-k1", "-m", mmap_size] + else: + command += ["-F99", "-k1"] + command += ["-o", output_file, "--"] + perf_commands.append(command) else: - base_cmd = ( - "perf", - "record", - "--no-buildid", - "--no-buildid-cache", - "-g", - "--call-graph=dwarf,65528", - "-F99", - "-k1", - "-o", - output_file, - "--", + perf_commands = [base_cmd + ["-o", output_file, "--"]] + + mmap_pages_error = "try again with a smaller value of -m/--mmap_pages" + for index, base_cmd in enumerate(perf_commands): + proc = subprocess.run( + base_cmd + list(args), + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + env=env, + text=True, ) - proc = subprocess.run( - base_cmd + args, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - env=env, - text=True, - ) + if ( + proc.returncode + and use_jit + and index != len(perf_commands) - 1 + and mmap_pages_error in proc.stderr + ): + continue + break + if proc.returncode: print(proc.stderr, file=sys.stderr) raise ValueError(f"Perf failed with return code {proc.returncode}") @@ -425,16 +445,34 @@ def run_perf(cwd, *args, use_jit=False, **env_vars): class TestPerfProfilerMixin: - def run_perf(self, script_dir, perf_mode, script): + PERF_CAPTURE_ATTEMPTS = 3 + + def run_perf(self, script_dir, script, activate_trampoline=True): raise NotImplementedError() + def run_perf_with_retries( + self, script_dir, script, expected_symbols=(), activate_trampoline=True + ): + stdout = stderr = "" + for _ in range(self.PERF_CAPTURE_ATTEMPTS): + stdout, stderr = self.run_perf( + script_dir, script, activate_trampoline=activate_trampoline + ) + if activate_trampoline and any( + symbol not in stdout for symbol in expected_symbols + ): + continue + break + return stdout, stderr + def test_python_calls_appear_in_the_stack_if_perf_activated(self): with temp_dir() as script_dir: code = """if 1: + from itertools import repeat + def foo(n): - x = 0 - for i in range(n): - x += i + for _ in repeat(None, n): + pass def bar(n): foo(n) @@ -442,23 +480,29 @@ def bar(n): def baz(n): bar(n) - baz(10000000) + baz(40000000) """ script = make_script(script_dir, "perftest", code) - stdout, stderr = self.run_perf(script_dir, script) - self.assertEqual(stderr, "") + expected_symbols = [ + f"py::foo:{script}", + f"py::bar:{script}", + f"py::baz:{script}", + ] + stdout, _ = self.run_perf_with_retries( + script_dir, script, expected_symbols + ) - self.assertIn(f"py::foo:{script}", stdout) - self.assertIn(f"py::bar:{script}", stdout) - self.assertIn(f"py::baz:{script}", stdout) + for expected_symbol in expected_symbols: + self.assertIn(expected_symbol, stdout) def test_python_calls_do_not_appear_in_the_stack_if_perf_deactivated(self): with temp_dir() as script_dir: code = """if 1: + from itertools import repeat + def foo(n): - x = 0 - for i in range(n): - x += i + for _ in repeat(None, n): + pass def bar(n): foo(n) @@ -466,13 +510,12 @@ def bar(n): def baz(n): bar(n) - baz(10000000) + baz(40000000) """ script = make_script(script_dir, "perftest", code) - stdout, stderr = self.run_perf( + stdout, _ = self.run_perf_with_retries( script_dir, script, activate_trampoline=False ) - self.assertEqual(stderr, "") self.assertNotIn(f"py::foo:{script}", stdout) self.assertNotIn(f"py::bar:{script}", stdout) @@ -542,13 +585,12 @@ def compile_trampolines_for_all_functions(): with temp_dir() as script_dir: script = make_script(script_dir, "perftest", code) - env = {**os.environ, "PYTHON_JIT": "0"} with subprocess.Popen( [sys.executable, "-Xperf", script], universal_newlines=True, stderr=subprocess.PIPE, stdout=subprocess.PIPE, - env=env, + env=_perf_env(), ) as process: stdout, stderr = process.communicate() From e565d12acb8fd14ad4432c25daf79882794cca60 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 27 May 2026 17:24:47 +0200 Subject: [PATCH 155/818] [3.15] gh-149861: Fix rule in match statement `case_block` PEG grammar (GH-149908) (cherry picked from commit 99c254e2f79a4197524bef61bf0d12251ee273e6) Co-authored-by: Ivy Xu --- Doc/reference/compound_stmts.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/reference/compound_stmts.rst b/Doc/reference/compound_stmts.rst index a819c41d834aa7..63baefd33e88c5 100644 --- a/Doc/reference/compound_stmts.rst +++ b/Doc/reference/compound_stmts.rst @@ -620,7 +620,7 @@ The match statement is used for pattern matching. Syntax: match_stmt: 'match' `subject_expr` ":" NEWLINE INDENT `case_block`+ DEDENT subject_expr: `flexible_expression` "," [`flexible_expression_list` [',']] : | `assignment_expression` - case_block: 'case' `patterns` [`guard`] ":" `!block` + case_block: 'case' `patterns` [`guard`] ":" `suite` .. note:: This section uses single quotes to denote From f216c8963139bf858415e2d09cf938d3e29558df Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 27 May 2026 23:47:03 +0200 Subject: [PATCH 156/818] [3.15] gh-84353: Preserve non-UTF-8 filenames when appending to ZipFile (GH-150091) (GH-150527) Preserve non-UTF-8 filenames when appending to a ZipFile. --------- (cherry picked from commit 24c6bbc92b6dd0ce9b7ff799049498299f70f97d) Co-authored-by: Serhiy Storchaka Co-authored-by: Gregory P. Smith --- Lib/test/test_zipfile/test_core.py | 40 +++++++++++-------- Lib/zipfile/__init__.py | 8 +++- ...6-05-19-19-00-49.gh-issue-84353.ZU5zaQ.rst | 5 +++ 3 files changed, 35 insertions(+), 18 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-05-19-19-00-49.gh-issue-84353.ZU5zaQ.rst diff --git a/Lib/test/test_zipfile/test_core.py b/Lib/test/test_zipfile/test_core.py index 30550263ad50aa..ffed328b171fda 100644 --- a/Lib/test/test_zipfile/test_core.py +++ b/Lib/test/test_zipfile/test_core.py @@ -3640,29 +3640,23 @@ def test_read_with_unsuitable_metadata_encoding(self): def test_read_after_append(self): newname = '\u56db' # Han 'four' - expected_names = [name.encode('shift_jis').decode('cp437') - for name in self.file_names[:2]] + self.file_names[2:] - expected_names.append(newname) - expected_content = (*self.file_content, b"newcontent") + newname2 = 'fünf' # representable in cp437, but still stored as UTF-8 + expected_names = [*self.file_names, newname, newname2] + mojibake_expected_names = [name.encode('shift_jis').decode('cp437') + if i < 2 else name + for i, name in enumerate(expected_names)] + expected_content = (*self.file_content, b"newcontent", b"newcontent2") with zipfile.ZipFile(TESTFN, "a") as zipfp: zipfp.writestr(newname, "newcontent") - self.assertEqual(sorted(zipfp.namelist()), sorted(expected_names)) + zipfp.writestr(newname2, "newcontent2") + self.assertEqual(sorted(zipfp.namelist()), sorted(mojibake_expected_names)) with zipfile.ZipFile(TESTFN, "r") as zipfp: - self._test_read(zipfp, expected_names, expected_content) + self._test_read(zipfp, mojibake_expected_names, expected_content) with zipfile.ZipFile(TESTFN, "r", metadata_encoding='shift_jis') as zipfp: - self.assertEqual(sorted(zipfp.namelist()), sorted(expected_names)) - for i, (name, content) in enumerate(zip(expected_names, expected_content)): - info = zipfp.getinfo(name) - self.assertEqual(info.filename, name) - self.assertEqual(info.file_size, len(content)) - if i < 2: - with self.assertRaises(zipfile.BadZipFile): - zipfp.read(name) - else: - self.assertEqual(zipfp.read(name), content) + self._test_read(zipfp, expected_names, expected_content) def test_write_with_metadata_encoding(self): ZF = zipfile.ZipFile @@ -3671,6 +3665,20 @@ def test_write_with_metadata_encoding(self): "^metadata_encoding is only"): ZF("nonesuch.zip", mode, metadata_encoding="shift_jis") + def test_add_comment(self): + with zipfile.ZipFile(TESTFN, "r") as zipfp: + mojibake_expected_names = zipfp.namelist() + + with zipfile.ZipFile(TESTFN, "a") as zipfp: + zipfp.comment = b'comment' + self.assertEqual(zipfp.namelist(), mojibake_expected_names) + + with zipfile.ZipFile(TESTFN, "r") as zipfp: + self._test_read(zipfp, mojibake_expected_names, self.file_content) + + with zipfile.ZipFile(TESTFN, "r", metadata_encoding='shift_jis') as zipfp: + self._test_read(zipfp, self.file_names, self.file_content) + def test_cli_with_metadata_encoding(self): errmsg = "Non-conforming encodings not supported with -c." args = ["--metadata-encoding=shift_jis", "-c", "nonesuch", "nonesuch"] diff --git a/Lib/zipfile/__init__.py b/Lib/zipfile/__init__.py index d91cb509a6ff4f..71e4dd4f6f625c 100644 --- a/Lib/zipfile/__init__.py +++ b/Lib/zipfile/__init__.py @@ -566,8 +566,12 @@ def FileHeader(self, zip64=None): return header + filename + extra def _encodeFilenameFlags(self): + if self.flag_bits & _MASK_UTF_FILENAME: + encoding = 'ascii' + else: + encoding = 'cp437' try: - return self.filename.encode('ascii'), self.flag_bits + return self.filename.encode(encoding), self.flag_bits & ~_MASK_UTF_FILENAME except UnicodeEncodeError: return self.filename.encode('utf-8'), self.flag_bits | _MASK_UTF_FILENAME @@ -1812,7 +1816,7 @@ def _open_to_write(self, zinfo, force_zip64=False): zinfo.compress_size = 0 zinfo.CRC = 0 - zinfo.flag_bits = 0x00 + zinfo.flag_bits = _MASK_UTF_FILENAME if zinfo.compress_type == ZIP_LZMA: # Compressed data includes an end-of-stream (EOS) marker zinfo.flag_bits |= _MASK_COMPRESS_OPTION_1 diff --git a/Misc/NEWS.d/next/Library/2026-05-19-19-00-49.gh-issue-84353.ZU5zaQ.rst b/Misc/NEWS.d/next/Library/2026-05-19-19-00-49.gh-issue-84353.ZU5zaQ.rst new file mode 100644 index 00000000000000..84fb12e2abd81a --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-05-19-19-00-49.gh-issue-84353.ZU5zaQ.rst @@ -0,0 +1,5 @@ +Preserve non-UTF-8 encoded filenames when appending to a +:class:`zipfile.ZipFile`. Previously, non-ASCII names stored in a legacy +encoding (without the UTF-8 flag bit set) could be corrupted when the +central directory was rewritten: they were decoded as cp437 and then +re-stored as UTF-8. From 0e08bba32eb78b46493bd200879655d2d02e6b9d Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 28 May 2026 12:23:56 +0200 Subject: [PATCH 157/818] [3.15] Add prominent crash warning to `ctypes` docs (GH-150410) (GH-150547) (cherry picked from commit b53f6ca850b500621474e82931c3e7216d9a1cb1) Co-authored-by: Stan Ulbrych Co-authored-by: Petr Viktorin --- Doc/library/ctypes.rst | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/Doc/library/ctypes.rst b/Doc/library/ctypes.rst index 438afa04c6630d..618ae89921c348 100644 --- a/Doc/library/ctypes.rst +++ b/Doc/library/ctypes.rst @@ -14,6 +14,14 @@ used to wrap these libraries in pure Python. .. include:: ../includes/optional-module.rst +.. warning:: + + :mod:`!ctypes` provides low-level access to native libraries and the + process's memory, bypassing Python's safety mechanisms and allowing + execution of arbitrary native code. + Incorrect use can corrupt data and objects, reveal sensitive information, + cause crashes, or otherwise compromise the running process. + .. _ctypes-ctypes-tutorial: @@ -198,10 +206,8 @@ argument values:: OSError: exception: access violation reading 0x00000020 >>> -There are, however, enough ways to crash Python with :mod:`!ctypes`, so you -should be careful anyway. The :mod:`faulthandler` module can be helpful in -debugging crashes (e.g. from segmentation faults produced by erroneous C library -calls). +The :mod:`faulthandler` module can help debug crashes, +such as segmentation faults produced by erroneous C library calls. ``None``, integers, bytes objects and (unicode) strings are the only native Python objects that can directly be used as parameters in these function calls. From 77666483b71561116f922b3847c044c631d8e647 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 28 May 2026 19:15:27 +0200 Subject: [PATCH 158/818] [3.15] gh-150046: Fix `test_add_python_opts` to ignore `PYTHON*` env vars (GH-150089) (#150561) gh-150046: Fix `test_add_python_opts` to ignore `PYTHON*` env vars (GH-150089) Avoid the runtime environment from affecting the tests' behaviours, which notably checks the warning filters which can be controlled by various PYTHON environment variables. (cherry picked from commit ef2246f788832a64ba7c5215c8e72f8e539e59b4) Co-authored-by: Pradyun Gedam --- Lib/test/test_regrtest.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_regrtest.py b/Lib/test/test_regrtest.py index 02f6e0c74b5ce8..874c6bb76b1afe 100644 --- a/Lib/test/test_regrtest.py +++ b/Lib/test/test_regrtest.py @@ -2283,7 +2283,8 @@ def test_python_opts(self): proc = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, - text=True) + text=True, + env=support.make_clean_env()) self.assertEqual(proc.returncode, 0, proc) def test_add_python_opts(self): From 21fa311c044704a1638b2ae0dc480fd9f7f68159 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 29 May 2026 00:57:04 +0200 Subject: [PATCH 159/818] [3.15] gh-149029: Update SQLite to 3.53.1 for binary releases (GH-149767) (#150559) (cherry picked from commit 9242700c149c490c56d2a415b395b5f51d94a49a) Co-authored-by: Adam Johnson Co-authored-by: Ned Deily --- Mac/BuildScript/build-installer.py | 6 +++--- .../2026-04-26-23-14-45.gh-issue-149029.oPTXP4.rst | 1 + .../macOS/2026-04-26-23-15-09.gh-issue-149029.Lsx--T.rst | 1 + Misc/externals.spdx.json | 8 ++++---- PCbuild/get_externals.bat | 2 +- PCbuild/python.props | 2 +- PCbuild/readme.txt | 2 +- Platforms/Android/__main__.py | 2 +- 8 files changed, 13 insertions(+), 11 deletions(-) create mode 100644 Misc/NEWS.d/next/Windows/2026-04-26-23-14-45.gh-issue-149029.oPTXP4.rst create mode 100644 Misc/NEWS.d/next/macOS/2026-04-26-23-15-09.gh-issue-149029.Lsx--T.rst diff --git a/Mac/BuildScript/build-installer.py b/Mac/BuildScript/build-installer.py index c5f92a99a1e076..e0e7076d681887 100755 --- a/Mac/BuildScript/build-installer.py +++ b/Mac/BuildScript/build-installer.py @@ -359,9 +359,9 @@ def library_recipes(): ), ), dict( - name="SQLite 3.50.4", - url="https://www.sqlite.org/2025/sqlite-autoconf-3500400.tar.gz", - checksum="a3db587a1b92ee5ddac2f66b3edb41b26f9c867275782d46c3a088977d6a5b18", + name="SQLite 3.53.1", + url="https://www.sqlite.org/2026/sqlite-autoconf-3530100.tar.gz", + checksum="83e6b2020a034e9a7ad4a72feea59e1ad52f162e09cbd26735a3ffb98359fc4f", extra_cflags=('-Os ' '-DSQLITE_ENABLE_FTS5 ' '-DSQLITE_ENABLE_FTS4 ' diff --git a/Misc/NEWS.d/next/Windows/2026-04-26-23-14-45.gh-issue-149029.oPTXP4.rst b/Misc/NEWS.d/next/Windows/2026-04-26-23-14-45.gh-issue-149029.oPTXP4.rst new file mode 100644 index 00000000000000..6c4c6403b98984 --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2026-04-26-23-14-45.gh-issue-149029.oPTXP4.rst @@ -0,0 +1 @@ +Update Windows installer to ship with SQLite 3.53.1. diff --git a/Misc/NEWS.d/next/macOS/2026-04-26-23-15-09.gh-issue-149029.Lsx--T.rst b/Misc/NEWS.d/next/macOS/2026-04-26-23-15-09.gh-issue-149029.Lsx--T.rst new file mode 100644 index 00000000000000..157a70f5e3cefc --- /dev/null +++ b/Misc/NEWS.d/next/macOS/2026-04-26-23-15-09.gh-issue-149029.Lsx--T.rst @@ -0,0 +1 @@ +Update macOS installer to ship with SQLite version 3.53.1. diff --git a/Misc/externals.spdx.json b/Misc/externals.spdx.json index 9a571fba732ab4..080330c1cb75a5 100644 --- a/Misc/externals.spdx.json +++ b/Misc/externals.spdx.json @@ -91,21 +91,21 @@ "checksums": [ { "algorithm": "SHA256", - "checksumValue": "fb5ab81f27612b0a7b4861ba655906c76dc85ee969e7a4905d2075aff931e8d0" + "checksumValue": "15e8fc7dc059f7b156e53629540951c2691acd71e027f6f8f66dacab5c66c884" } ], - "downloadLocation": "https://github.com/python/cpython-source-deps/archive/refs/tags/sqlite-3.50.4.0.tar.gz", + "downloadLocation": "https://github.com/python/cpython-source-deps/archive/refs/tags/sqlite-3.53.1.0.tar.gz", "externalRefs": [ { "referenceCategory": "SECURITY", - "referenceLocator": "cpe:2.3:a:sqlite:sqlite:3.50.4.0:*:*:*:*:*:*:*", + "referenceLocator": "cpe:2.3:a:sqlite:sqlite:3.53.1.0:*:*:*:*:*:*:*", "referenceType": "cpe23Type" } ], "licenseConcluded": "NOASSERTION", "name": "sqlite", "primaryPackagePurpose": "SOURCE", - "versionInfo": "3.50.4.0" + "versionInfo": "3.53.1.0" }, { "SPDXID": "SPDXRef-PACKAGE-tcl", diff --git a/PCbuild/get_externals.bat b/PCbuild/get_externals.bat index 368bc489bfa968..f6ba3d0fef3a60 100644 --- a/PCbuild/get_externals.bat +++ b/PCbuild/get_externals.bat @@ -56,7 +56,7 @@ set libraries=%libraries% bzip2-1.0.8 if NOT "%IncludeLibffiSrc%"=="false" set libraries=%libraries% libffi-3.4.4 if NOT "%IncludeSSLSrc%"=="false" set libraries=%libraries% openssl-3.5.6 set libraries=%libraries% mpdecimal-4.0.0 -set libraries=%libraries% sqlite-3.50.4.0 +set libraries=%libraries% sqlite-3.53.1.0 if NOT "%IncludeTkinterSrc%"=="false" set libraries=%libraries% tcl-9.0.3.0 if NOT "%IncludeTkinterSrc%"=="false" set libraries=%libraries% tk-9.0.3.1 set libraries=%libraries% xz-5.8.1.1 diff --git a/PCbuild/python.props b/PCbuild/python.props index f70321f887ef8c..edcda8fd8fc55d 100644 --- a/PCbuild/python.props +++ b/PCbuild/python.props @@ -98,7 +98,7 @@ - $(ExternalsDir)sqlite-3.50.4.0\ + $(ExternalsDir)sqlite-3.53.1.0\ $(ExternalsDir)bzip2-1.0.8\ $(ExternalsDir)xz-5.8.1.1\ $(ExternalsDir)libffi-3.4.4\ diff --git a/PCbuild/readme.txt b/PCbuild/readme.txt index 6aecbfff182dcb..ea8adf21c279a6 100644 --- a/PCbuild/readme.txt +++ b/PCbuild/readme.txt @@ -242,7 +242,7 @@ _ssl again when building. _sqlite3 - Wraps SQLite 3.50.4, which is itself built by sqlite3.vcxproj + Wraps SQLite 3.53.1, which is itself built by sqlite3.vcxproj Homepage: https://www.sqlite.org/ diff --git a/Platforms/Android/__main__.py b/Platforms/Android/__main__.py index d2546cf76c206b..5c41aaca6ebf0b 100755 --- a/Platforms/Android/__main__.py +++ b/Platforms/Android/__main__.py @@ -220,7 +220,7 @@ def unpack_deps(host, prefix_dir, cache_dir): "bzip2-1.0.8-3", "libffi-3.4.4-3", "openssl-3.5.6-0", - "sqlite-3.50.4-0", + "sqlite-3.53.1-0", "xz-5.4.6-1", "zstd-1.5.7-2" ]: From d842895a9d01dc34c448ca3e65d28aae469c8c23 Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Fri, 29 May 2026 10:09:38 +0200 Subject: [PATCH 160/818] [3.15] gh-141984: Reword docs on "enclosed" atom grammar (GH-148622) (GH-150552) Reorganize and reword the docs on atoms in parentheses, brackets and braces: parenthesized groups, list/set/dict/tuple displays, and comprehensions. (Generator expressions and yield atoms are left for later.) In the spirit of better matching the underlying grammar, *comprehensions* are covered separately from non-comprehension displays. Also, parenthesized forms (with a single expression) and tuple displays are separated. All sections are rewritten to start with simple cases and build up to the full formal grammar. (cherry picked from commit 55f25183263b9a52fa246817344cdb32d6c3d722) Co-authored-by: Blaise Pabon Co-authored-by: Stan Ulbrych <89152624+StanFromIreland@users.noreply.github.com> --- Doc/reference/expressions.rst | 754 ++++++++++++++++++++++++++-------- Doc/tools/removed-ids.txt | 13 + 2 files changed, 592 insertions(+), 175 deletions(-) diff --git a/Doc/reference/expressions.rst b/Doc/reference/expressions.rst index 68dcfc00bbd99c..12c1446e071240 100644 --- a/Doc/reference/expressions.rst +++ b/Doc/reference/expressions.rst @@ -48,9 +48,16 @@ Atoms .. index:: atom Atoms are the most basic elements of expressions. -The simplest atoms are :ref:`names ` or literals. -Forms enclosed in parentheses, brackets or braces are also categorized -syntactically as atoms. +The simplest atoms are :ref:`builtin constants `, +:ref:`names ` and :ref:`literals `. +More complex atoms are enclosed in paired delimiters: + +- ``()`` (parentheses): :ref:`groups `, + :ref:`tuple displays `, + :ref:`yield atoms `, and + :ref:`generator expressions `; +- ``[]`` (square brackets): :ref:`list displays `; +- ``{}`` (curly braces): :ref:`dictionary ` and :ref:`set ` displays. Formally, the syntax for atoms is: @@ -58,21 +65,25 @@ Formally, the syntax for atoms is: :group: python-grammar atom: - | 'True' - | 'False' - | 'None' - | '...' + | `builtin_constant` | `identifier` | `literal` - | `enclosure` - enclosure: - | `parenth_form` - | `list_display` - | `dict_display` - | `set_display` - | `generator_expression` + | `parenthesized_enclosure` + | `bracketed_enclosure` + | `braced_enclosure` + parenthesized_enclosure: + | `group` + | `tuple` | `yield_atom` - + | `generator_expression` + bracketed_enclosure: + | `listcomp` + | `list` + braced_enclosure: + | `dictcomp` + | `dict` + | `setcomp` + | `set` .. _atom-singletons: @@ -99,6 +110,13 @@ Evaluation of these atoms yields the corresponding value. ^^^^^ SyntaxError: cannot assign to False +Formally, the syntax for built-in constants is: + +.. grammar-snippet:: + :group: python-grammar + + builtin_constant: 'True' | 'False' | 'None' | '...' + .. _atom-identifiers: Identifiers (Names) @@ -201,6 +219,7 @@ The formal grammar for literals is: literal: `strings` | `NUMBER` +.. _literals-identity: .. index:: triple: immutable; data; type @@ -309,128 +328,134 @@ Formally: strings: (`STRING` | `fstring`)+ | `tstring`+ -.. _parenthesized: - -Parenthesized forms -------------------- - .. index:: single: parenthesized form - single: () (parentheses); tuple display + single: () (parentheses) -A parenthesized form is an optional expression list enclosed in parentheses: +.. _parenthesized-forms: +.. _parenthesized: -.. productionlist:: python-grammar - parenth_form: "(" [`starred_expression`] ")" +Parenthesized groups +-------------------- -A parenthesized expression list yields whatever that expression list yields: if -the list contains at least one comma, it yields a tuple; otherwise, it yields -the single expression that makes up the expression list. +A :dfn:`parenthesized group` is an expression enclosed in parentheses. +The group evaluates to the same value as the expression inside. -.. index:: pair: empty; tuple +Groups are used to override or clarify +:ref:`operator precedence `, +in the same way as in math notation. +For example:: -An empty pair of parentheses yields an empty tuple object. Since tuples are -immutable, the same rules as for literals apply (i.e., two occurrences of the empty -tuple may or may not yield the same object). + >>> 3 << 2 | 4 + 12 + >>> 3 << (2 | 4) # Override precedence of the | (bitwise OR) + 192 + >>> (3 << 2) | 4 # Same as without parentheses (but more clear) + 12 -.. index:: - single: comma - single: , (comma) +Note that not everything in parentheses is a *group*. +Specifically, a parenthesized group must include exactly one expression, +and cannot end with a comma. +See :ref:`tuple displays ` and +:ref:`generator expressions ` for other parenthesized forms. -Note that tuples are not formed by the parentheses, but rather by use of the -comma. The exception is the empty tuple, for which parentheses *are* -required --- allowing unparenthesized "nothing" in expressions would cause -ambiguities and allow common typos to pass uncaught. +Formally, the syntax for groups is: +.. grammar-snippet:: + :group: python-grammar -.. _comprehensions: + group: '(' `assignment_expression` ')' -Displays for lists, sets and dictionaries ------------------------------------------ +.. _displays-for-lists-sets-and-dictionaries: +.. _displays: + +Container displays +------------------ .. index:: single: comprehensions -For constructing a list, a set or a dictionary Python provides special syntax -called "displays", each of them in two flavors: +For constructing builtin containers (lists, sets, tuples or dictionaries), +Python provides special syntax called :dfn:`displays`. +There are subtle differences between the four kinds of displays, +detailed in the following sections. +All displays, however, consist of comma-separated items enclosed in paired +delimiters. -* either the container contents are listed explicitly, or +For example, a *list display* is a series of expressions enclosed in +square brackets:: -* they are computed via a set of looping and filtering instructions, called a - :dfn:`comprehension`. + >>> ["one", "two", "three"] + ['one', 'two', 'three'] + >>> [1 + 2, 2 + 3] + [3, 5] -.. index:: - single: for; in comprehensions - single: if; in comprehensions - single: async for; in comprehensions +In list, tuple and dictionary (but not set) displays, the series may be empty:: -Common syntax elements for comprehensions are: + >>> [] # empty list + [] + >>> () # empty tuple + () + >>> {} # empty dictionary + {} -.. productionlist:: python-grammar - comprehension: `flexible_expression` `comp_for` - comp_for: ["async"] "for" `target_list` "in" `or_test` [`comp_iter`] - comp_iter: `comp_for` | `comp_if` - comp_if: "if" `or_test` [`comp_iter`] - -The comprehension consists of a single expression followed by at least one -:keyword:`!for` clause and zero or more :keyword:`!for` or :keyword:`!if` -clauses. In this case, the elements of the new container are those that would -be produced by considering each of the :keyword:`!for` or :keyword:`!if` -clauses a block, nesting from left to right, and evaluating the expression to -produce an element each time the innermost block is reached. If the expression -is starred, the result will instead be unpacked to produce zero or more -elements. - -However, aside from the iterable expression in the leftmost :keyword:`!for` clause, -the comprehension is executed in a separate implicitly nested scope. This ensures -that names assigned to in the target list don't "leak" into the enclosing scope. +.. index:: pair: trailing; comma -The iterable expression in the leftmost :keyword:`!for` clause is evaluated -directly in the enclosing scope and then passed as an argument to the implicitly -nested scope. Subsequent :keyword:`!for` clauses and any filter condition in the -leftmost :keyword:`!for` clause cannot be evaluated in the enclosing scope as -they may depend on the values obtained from the leftmost iterable. For example: -``[x*y for x in range(10) for y in range(x, x+10)]``. +If the series is not empty, the items may be followed by an additional comma, +which has no effect:: -To ensure the comprehension always results in a container of the appropriate -type, ``yield`` and ``yield from`` expressions are prohibited in the implicitly -nested scope. + >>> ["one", "two", "three",] # note comma after "three" + ['one', 'two', 'three'] -.. index:: - single: await; in comprehensions +.. note:: -Since Python 3.6, in an :keyword:`async def` function, an :keyword:`!async for` -clause may be used to iterate over a :term:`asynchronous iterator`. -A comprehension in an :keyword:`!async def` function may consist of either a -:keyword:`!for` or :keyword:`!async for` clause following the leading -expression, may contain additional :keyword:`!for` or :keyword:`!async for` -clauses, and may also use :keyword:`await` expressions. + The trailing comma is often used for displays that span multiple lines + (using :ref:`implicit line joining `), + so when a future programmer adds a new entry at the end, they do not + need to modify an existing line:: -If a comprehension contains :keyword:`!async for` clauses, or if it contains -:keyword:`!await` expressions or other asynchronous comprehensions anywhere except -the iterable expression in the leftmost :keyword:`!for` clause, it is called an -:dfn:`asynchronous comprehension`. An asynchronous comprehension may suspend the -execution of the coroutine function in which it appears. -See also :pep:`530`. + >>> [ + ... 'one', + ... 'two', + ... 'three', + ... ] + ['one', 'two', 'three'] -.. versionadded:: 3.6 - Asynchronous comprehensions were introduced. +At runtime, when a display is evaluated, the listed items are evaluated from +left to right and placed into a new container of the appropriate type. -.. versionchanged:: 3.8 - ``yield`` and ``yield from`` prohibited in the implicitly nested scope. +.. index:: + pair: iterable; unpacking + single: * (asterisk); in expression lists -.. versionchanged:: 3.11 - Asynchronous comprehensions are now allowed inside comprehensions in - asynchronous functions. Outer comprehensions implicitly become - asynchronous. +For tuple, list and set (but not dict) displays, any item in the display may +be prefixed with an asterisk (``*``). +This denotes :ref:`iterable unpacking `. +At runtime, the asterisk-prefixed expression must evaluate to an iterable, +whose contents are inserted into the container at the location of +the unpacking. For example:: + + >>> numbers = (1, 2) + >>> [*numbers, 'word', *numbers] + [1, 2, 'word', 1, 2] + +Dictionary displays use a similar mechanism called +*dictionary unpacking*, denoted with a double +asterisk (``**``). +See :ref:`dict` for details. + +A more advanced form of displays are :dfn:`comprehensions`, where items are +computed via a set of looping and filtering instructions. +See the :ref:`comprehensions` section for details. -.. versionchanged:: 3.15 - Unpacking with the ``*`` operator is now allowed in the expression. +.. versionadded:: 3.5 + Iterable and dictionary unpacking in displays, originally proposed + by :pep:`448`. .. _lists: List displays -------------- +^^^^^^^^^^^^^ .. index:: pair: list; display @@ -440,23 +465,30 @@ List displays single: [] (square brackets); list expression single: , (comma); expression list -A list display is a possibly empty series of expressions enclosed in square -brackets: +A :dfn:`list display` is a possibly empty series of expressions enclosed in +square brackets. For example:: -.. productionlist:: python-grammar - list_display: "[" [`flexible_expression_list` | `comprehension`] "]" + >>> ["one", "two", "three"] + ['one', 'two', 'three'] + >>> ["one"] # One-element list + ['one'] + >>> [] # empty list + [] + +See :ref:`displays` for general information on displays. + +The formal grammar for list displays is: -A list display yields a new list object, the contents being specified by either -a list of expressions or a comprehension. When a comma-separated list of -expressions is supplied, its elements are evaluated from left to right and -placed into the list object in that order. When a comprehension is supplied, -the list is constructed from the elements resulting from the comprehension. +.. grammar-snippet:: + :group: python-grammar + + list: '[' [`flexible_expression_list`] ']' .. _set: Set displays ------------- +^^^^^^^^^^^^ .. index:: pair: set; display @@ -465,26 +497,94 @@ Set displays single: {} (curly brackets); set expression single: , (comma); expression list -A set display is denoted by curly braces and distinguishable from dictionary -displays by the lack of colons separating keys and values: +A :dfn:`set display` is a *non-empty* series of expressions enclosed in +curly braces. For example:: + + >>> {"one", "two", "three"} + {'one', 'three', 'two'} + >>> {"one"} # One-element set + {'one'} + +See :ref:`displays` for general information on displays. + +There is no special syntax for the empty set. +The ``{}`` literal is a :ref:`dictionary display ` that constructs an +empty dictionary. +Call :class:`set() ` with no arguments to get an empty set. + +The formal grammar for set displays is: + +.. grammar-snippet:: + :group: python-grammar + + set: '{' `flexible_expression_list` '}' -.. productionlist:: python-grammar - set_display: "{" (`flexible_expression_list` | `comprehension`) "}" -A set display yields a new mutable set object, the contents being specified by -either a sequence of expressions or a comprehension. When a comma-separated -list of expressions is supplied, its elements are evaluated from left to right -and added to the set object. When a comprehension is supplied, the set is -constructed from the elements resulting from the comprehension. +.. index:: + single: tuple display + single: comma + single: , (comma) + +.. _tuple-display: + +.. index:: pair: empty; tuple + +Tuple displays +^^^^^^^^^^^^^^ + +A :dfn:`tuple display` is a series of expressions enclosed in +parentheses. For example:: -An empty set cannot be constructed with ``{}``; this literal constructs an empty -dictionary. + >>> (1, 2) + (1, 2) + >>> () # an empty tuple + () + +See :ref:`displays` for general information on displays. + +To avoid ambiguity, if a tuple display has exactly one element, +it requires a trailing comma. +Without it, you get a :ref:`parenthesized group `:: + + >>> ('single',) # single-element tuple + ('single',) + >>> ('single') # no comma: single string + 'single' + +To put it in other words, a tuple display is a parenthesized list of either: + +- two or more comma-separated expressions, or +- zero or more expressions, each followed by a comma. + +Since tuples are immutable, :ref:`object identity rules for literals ` +also apply to tuples: at runtime, two occurrences of tuples with the same +values may or may not yield the same object. + +.. note:: + Python's syntax also includes :ref:`expression lists `, + where a comma-separated list of expressions is *not* enclosed in parentheses + but evaluates to tuple. + + In other words, when it comes to tuple syntax, the comma is more important + that the use of parentheses. + Only the empty tuple is spelled without a comma. + + +The formal grammar for tuple displays is: + +.. grammar-snippet:: + :group: python-grammar + + tuple: + | '(' `flexible_expression` (',' `flexible_expression`)+ [','] ')' + | '(' `flexible_expression` ',' ')' + | '(' ')' .. _dict: Dictionary displays -------------------- +^^^^^^^^^^^^^^^^^^^ .. index:: pair: dictionary; display @@ -495,59 +595,149 @@ Dictionary displays single: : (colon); in dictionary expressions single: , (comma); in dictionary displays -A dictionary display is a possibly empty series of dict items (key/value pairs) -enclosed in curly braces: +A :dfn:`dictionary display` is a possibly empty series of :dfn:`dict items` +enclosed in curly braces. +Each dict item is a colon-separated pair of expressions: the :dfn:`key` +and its associated :dfn:`value`. +For example:: -.. productionlist:: python-grammar - dict_display: "{" [`dict_item_list` | `dict_comprehension`] "}" - dict_item_list: `dict_item` ("," `dict_item`)* [","] - dict_comprehension: `dict_item` `comp_for` - dict_item: `expression` ":" `expression` | "**" `or_expr` + >>> {1: 'one', 2: 'two'} + {1: 'one', 2: 'two'} -A dictionary display yields a new dictionary object. +At runtime, when a dictionary comprehension is evaluated, the expressions +are evaluated from left to right. +Each key object is used as a key into the dictionary to store the +corresponding value. +This means that you can specify the same key multiple times in the +comprehension, and the final dictionary's value for a given key will be the +last one given. +For example:: -If a comma-separated sequence of dict items is given, they are evaluated -from left to right to define the entries of the dictionary: each key object is -used as a key into the dictionary to store the corresponding value. This means -that you can specify the same key multiple times in the dict item list, and the -final dictionary's value for that key will be the last one given. + >>> { + ... 1: 'this will be overridden', + ... 2: 'two', + ... 1: 'also overridden', + ... 1: 'one', + ... } + {1: 'one', 2: 'two'} .. index:: unpacking; dictionary single: **; in dictionary displays -A double asterisk ``**`` denotes :dfn:`dictionary unpacking`. -Its operand must be a :term:`mapping`. Each mapping item is added -to the new dictionary. Later values replace values already set by -earlier dict items and earlier dictionary unpackings. +.. _dict-unpacking: + +Instead of a key-value pair, a dict item may be an expression prefixed by +a double asterisk ``**``. This denotes :dfn:`dictionary unpacking`. +At runtime, the expression must evaluate to a :term:`mapping`; +each item of the mapping is added to the new dictionary. +As with key-value pairs, later values replace values already set by +earlier items and unpackings. +This may be used to override a set of defaults:: + + >>> defaults = {'color': 'blue', 'count': 8} + >>> overrides = {'color': 'yellow'} + >>> {**defaults, **overrides} + {'color': 'yellow', 'count': 8} .. versionadded:: 3.5 Unpacking into dictionary displays, originally proposed by :pep:`448`. -A dict comprehension may take one of two forms: +The formal grammar for dict displays is: -- The first form uses two expressions separated with a colon followed by the - usual "for" and "if" clauses. When the comprehension is run, the resulting - key and value elements are inserted in the new dictionary in the order they - are produced. +.. grammar-snippet:: + :group: python-grammar -- The second form uses a single expression prefixed by the ``**`` dictionary - unpacking operator followed by the usual "for" and "if" clauses. When the - comprehension is evaluated, the expression is evaluated and then unpacked, - inserting zero or more key/value pairs into the new dictionary. + dict: '{' [`double_starred_kvpairs`] '}' + double_starred_kvpairs: ','.`double_starred_kvpair`+ [','] + double_starred_kvpair: '**' `or_expr` | `kvpair` + kvpair: `expression` ':' `expression` -Both forms of dictionary comprehension retain the property that if the same key -is specified multiple times, the associated value in the resulting dictionary -will be the last one specified. -.. index:: pair: immutable; object - hashable +.. index:: + single: comprehensions + single: for; in comprehensions + +.. _comprehensions: + +Comprehensions +-------------- + +List, set and dictionary :dfn:`comprehensions` are a form of +:ref:`container displays ` where items are computed via a set of +looping and filtering instructions rather than listed explicitly. + +In its simplest form, a comprehension consists of a single expression +followed by a :keyword:`!for` clause. +The :keyword:`!for` clause has the same syntax as the header of a +:ref:`for statement `, without a trailing colon. + +For example, a list of the first ten squares is:: + + >>> [x**2 for x in range(10)] + [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] + +At run time, a list comprehension creates a new list. +The expression after :keyword:`!in` must evaluate to an :term:`iterable`. +For each element of this iterable, the element is bound to the :keyword:`!for` +clause's target as in a :keyword:`!for` statement, then the expression +before :keyword:`!for` is evaluated with the target in scope and the result +is added to the new list. +Thus, the example above is roughly equivalent to defining and calling +the following function:: + + def make_list_of_squares(iterable): + result = [] + for x in iterable: + result.append(x**2) + return result + + make_list_of_squares(range(10)) + +Set comprehensions work similarly. +For example, here is a set of lowercase letters:: + + >>> {x.lower() for x in ['a', 'A', 'b', 'C']} + {'c', 'a', 'b'} + +At run time, this corresponds roughly to calling this function:: -Restrictions on the types of the key values are listed earlier in section -:ref:`types`. (To summarize, the key type should be :term:`hashable`, which excludes -all mutable objects.) Clashes between duplicate keys are not detected; the last -value (textually rightmost in the display) stored for a given key value -prevails. + def make_lowercase_set(iterable): + result = set(iterable) + for x in iterable: + result.append(x.lower()) + return result + + make_lowercase_set(['a', 'A', 'b', 'C']) + +Dictionary comprehensions start with a colon-separated key-value pair instead +of an expression. For example:: + + >>> {func.__name__: func for func in [print, hex, any]} + {'print': , + 'hex': , + 'any': } + +At run time, this corresponds roughly to:: + + def make_dict_mapping_names_to_functions(iterable): + result = {} + for func in iterable: + result[func.__name__] = func + return result + + iterable([print, hex, any]) + +As in other kinds of dictionary displays, the same key may be specified +multiple times. +Earlier values are overwritten by ones that are evaluated later. + +There are no *tuple comprehensions*. +A similar syntax is instead used for :ref:`generator expressions `, +from which you can construct a tuple like this:: + + >>> tuple(x**2 for x in range(10)) + (0, 1, 4, 9, 16, 25, 36, 49, 64, 81) .. versionchanged:: 3.8 Prior to Python 3.8, in dict comprehensions, the evaluation order of key @@ -555,8 +745,206 @@ prevails. the key. Starting with 3.8, the key is evaluated before the value, as proposed by :pep:`572`. -.. versionchanged:: 3.15 - Unpacking with the ``**`` operator is now allowed in dictionary comprehensions. + +.. index:: single: if; in comprehensions + +Filtering in comprehensions +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The :keyword:`!for` clause may be followed by an :keyword:`!if` clause +with an expression. + +For example, a list of names from the :mod:`math` module +that start with ``f`` is:: + + >>> [name for name in vars(math) if name.startswith('f')] + ['fabs', 'factorial', 'floor', 'fma', 'fmod', 'frexp', 'fsum'] + +At run time, the expression after :keyword:`!if` is evaluated before +each element is added to the resulting container, and if it is false, +the element is skipped. +Thus, the above example roughly corresponds to defining and calling the +following function:: + + def get_math_f_names(iterable): + result = [] + for name in iterable: + if name.startswith('f'): + result.append(name) + return result + + get_math_f_names(vars(math)) + +Filtering is a special case of more complex comprehensions. +See the next section for a more formal description. + + +.. _complex-comprehensions: + +Complex comprehensions +^^^^^^^^^^^^^^^^^^^^^^ + +Generally, a comprehension's initial :keyword:`!for` clause may be followed by +zero or more additional :keyword:`!for` or :keyword:`!if` clauses. +For example, here is a list of names exposed by two Python modules, +filtered to only include names that start with ``a``:: + + >>> import array + >>> import math + >>> [ + ... name + ... for module in [array, math] + ... for name in vars(module) + ... if name.startswith('a') + ... ] + ['array', 'acos', 'acosh', 'asin', 'asinh', 'atan', 'atan2', 'atanh'] + +At run time, this roughly corresponds to defining and calling:: + + def get_a_names(iterable): + result = [] + for module in iterable: + for name in vars(module): + if name.startswith('a'): + result.append(name) + return result + + get_a_names([array, math]) + +The elements of the new container are those that would be produced by +considering each of the :keyword:`!for` or :keyword:`!if` clauses a block, +nesting from left to right, and evaluating the expression to produce an +element (or dictionary entry) each time the innermost block is reached. + +Aside from the iterable expression in the leftmost :keyword:`!for` clause, +the comprehension is executed in a separate implicitly nested scope. +This ensures that names assigned to in the target list don't "leak" into +the enclosing scope. +For example:: + + >>> x = 'old value' + >>> [x**2 for x in range(10)] # this `x` is local to the comprehension + >>> x + 'old value' + +The iterable expression in the leftmost :keyword:`!for` clause is evaluated +directly in the enclosing scope and then passed as an argument to the implicitly +nested scope. + +Subsequent :keyword:`!for` clauses and any filter condition in the +leftmost :keyword:`!for` clause cannot be evaluated in the enclosing scope as +they may depend on the values obtained from the leftmost iterable. + +To ensure the comprehension always results in a container of the appropriate +type, ``yield`` and ``yield from`` expressions are prohibited in the implicitly +nested scope. + +:ref:`Assignment expressions ` are not allowed +inside comprehension iterable expressions (that is, the expressions after +the :keyword:`!in` keyword), nor anywhere within comprehensions that +appear directly in a class definition. + +.. versionchanged:: 3.8 + ``yield`` and ``yield from`` prohibited in the implicitly nested scope. + + +Unpacking in comprehensions +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +If the expression of a list or set comprehension is starred, the result will +be :ref:`unpacked ` to produce +zero or more elements. + +This is often used for "flattening" lists, for example:: + + >>> students = ['Petr', 'Blaise', 'Jarka'] + >>> teachers = ['Salim', 'Bartosz'] + >>> lists_of_people = [students, teachers] + >>> [*people for people in lists_of_people] + ['Petr', 'Blaise', 'Jarka', 'Salim', 'Bartosz'] + +At run time, this comprehension roughly corresponds to:: + + def flatten_names(lists_of_people): + result = [] + for people in lists_of_people: + result.extend(people) + return result + +In dict comprehensions, a double-starred expression will be evaluated and +then unpacked using :ref:`dictionary unpacking `, +inserting zero or more key/value pairs into the new dictionary. +As in other kinds of dictionary displays, if the same key is specified +multiple times, the associated value in the resulting dictionary +will be the last one specified. + +For example:: + + >>> system_defaults = {'color': 'blue', 'count': 8} + >>> user_defaults = {'color': 'yellow'} + >>> overrides = {'count': 5} + + >>> configuration_sets = [system_defaults, user_defaults, overrides] + + >>> {**d for d in configuration_sets} + {'color': 'yellow', 'count': 5} + +.. versionadded:: 3.15 + + Unpacking in comprehensions using the ``*`` and ``**`` operators + was introduced in :pep:`798`. + + +.. index:: + single: async for; in comprehensions + single: await; in comprehensions + +Asynchronous comprehensions +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +In an :keyword:`async def` function, an :keyword:`!async for` +clause may be used to iterate over a :term:`asynchronous iterator`. +A comprehension in an :keyword:`!async def` function may consist of either a +:keyword:`!for` or :keyword:`!async for` clause following the leading +expression, may contain additional :keyword:`!for` or :keyword:`!async for` +clauses, and may also use :keyword:`await` expressions. + +If a comprehension contains :keyword:`!async for` clauses, or if it contains +:keyword:`!await` expressions or other asynchronous comprehensions anywhere except +the iterable expression in the leftmost :keyword:`!for` clause, it is called an +:dfn:`asynchronous comprehension`. An asynchronous comprehension may suspend the +execution of the coroutine function in which it appears. + +.. versionadded:: 3.6 + + Asynchronous comprehensions were introduced in :pep:`530`. + +.. versionchanged:: 3.11 + Asynchronous comprehensions are now allowed inside comprehensions in + asynchronous functions. Outer comprehensions implicitly become + asynchronous. + +.. _comprehension-grammar: + +Formal grammar for comprehensions +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The formal grammar for comprehensions is: + +.. grammar-snippet:: + :group: python-grammar + + listcomp: '[' `comprehension` ']' + setcomp: '{' `comprehension` '}' + comprehension: `flexible_expression` `for_if_clause`+ + + dictcomp: + | '{' `kvpair` `for_if_clause`+ '}' + | '{' '**' `expression` `for_if_clause`+ '}' + + for_if_clause: + | ['async'] 'for' `target_list` 'in' `or_test` ('if' `or_test`)* + .. _genexpr: @@ -571,7 +959,7 @@ Generator expressions A generator expression is a compact generator notation in parentheses: .. productionlist:: python-grammar - generator_expression: "(" `flexible_expression` `comp_for` ")" + generator_expression: "(" `comprehension` ")" A generator expression yields a new generator object. Its syntax is the same as for comprehensions, except that it is enclosed in parentheses instead of @@ -2178,6 +2566,10 @@ functions created with lambda expressions cannot contain statements or annotations. +.. index:: + single: comma + single: , (comma) + .. _exprlists: Expression lists @@ -2202,12 +2594,32 @@ containing at least one comma yields a tuple. The length of the tuple is the number of expressions in the list. The expressions are evaluated from left to right. +.. index:: pair: trailing; comma + +A trailing comma is required only to create a one-item tuple, +such as ``1,``; it is optional in all other cases. +A single expression without a +trailing comma doesn't create a tuple, but rather yields the value of that +expression. (To create an empty tuple, use an empty pair of parentheses: +``()``.) + + +.. _iterable-unpacking: + .. index:: pair: iterable; unpacking single: * (asterisk); in expression lists -An asterisk ``*`` denotes :dfn:`iterable unpacking`. Its operand must be -an :term:`iterable`. The iterable is expanded into a sequence of items, +Iterable unpacking +------------------ + +In an expression list or tuple, list or set display, any expression +may be prefixed with an asterisk (``*``). +This denotes :dfn:`iterable unpacking`. + +At runtime, the asterisk-prefixed expression must evaluate +to an :term:`iterable`. +The iterable is expanded into a sequence of items, which are included in the new tuple, list, or set, at the site of the unpacking. @@ -2217,15 +2629,6 @@ the unpacking. .. versionadded:: 3.11 Any item in an expression list may be starred. See :pep:`646`. -.. index:: pair: trailing; comma - -A trailing comma is required only to create a one-item tuple, -such as ``1,``; it is optional in all other cases. -A single expression without a -trailing comma doesn't create a tuple, but rather yields the value of that -expression. (To create an empty tuple, use an empty pair of parentheses: -``()``.) - .. _evalorder: @@ -2249,6 +2652,7 @@ their suffixes:: .. _operator-summary: +.. _operator-precedence: Operator precedence =================== diff --git a/Doc/tools/removed-ids.txt b/Doc/tools/removed-ids.txt index 5e3ef2efe271fd..2d5917f4d240f5 100644 --- a/Doc/tools/removed-ids.txt +++ b/Doc/tools/removed-ids.txt @@ -5,3 +5,16 @@ c-api/allocation.html: deprecated-aliases c-api/file.html: deprecated-api library/asyncio-task.html: terminating-a-task-group + +## Old names for grammar tokens +reference/expressions.html: grammar-token-python-grammar-comp_for +reference/expressions.html: grammar-token-python-grammar-comp_if +reference/expressions.html: grammar-token-python-grammar-comp_iter +reference/expressions.html: grammar-token-python-grammar-dict_comprehension +reference/expressions.html: grammar-token-python-grammar-dict_display +reference/expressions.html: grammar-token-python-grammar-dict_item +reference/expressions.html: grammar-token-python-grammar-dict_item_list +reference/expressions.html: grammar-token-python-grammar-enclosure +reference/expressions.html: grammar-token-python-grammar-list_display +reference/expressions.html: grammar-token-python-grammar-parenth_form +reference/expressions.html: grammar-token-python-grammar-set_display From b980552f348aa4a9648280e10cd82362f0434204 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 29 May 2026 15:10:56 +0200 Subject: [PATCH 161/818] [3.15] gh-150107: Fix asyncio sendfile fallback ignoring non-zero offset (GH-150270) (#150570) gh-150107: Fix asyncio sendfile fallback ignoring non-zero offset (GH-150270) (cherry picked from commit c72d5ea638731ec29723ded2d26ec7f997f06f17) Co-authored-by: Grant Herman Co-authored-by: Victor Stinner --- Lib/asyncio/base_events.py | 5 +- Lib/asyncio/proactor_events.py | 3 +- Lib/asyncio/unix_events.py | 18 +++--- Lib/asyncio/windows_events.py | 3 + Lib/test/test_asyncio/test_sendfile.py | 55 +++++++++++++++++++ ...-05-22-17-09-28.gh-issue-150107.GD72-D.rst | 3 + 6 files changed, 73 insertions(+), 14 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-05-22-17-09-28.gh-issue-150107.GD72-D.rst diff --git a/Lib/asyncio/base_events.py b/Lib/asyncio/base_events.py index 7a6837546d930f..b651f40dc4a1ec 100644 --- a/Lib/asyncio/base_events.py +++ b/Lib/asyncio/base_events.py @@ -968,7 +968,7 @@ async def _sock_sendfile_native(self, sock, file, offset, count): f"and file {file!r} combination") async def _sock_sendfile_fallback(self, sock, file, offset, count): - if offset: + if hasattr(file, 'seek'): file.seek(offset) blocksize = ( min(count, constants.SENDFILE_FALLBACK_READBUFFER_SIZE) @@ -1285,7 +1285,6 @@ async def sendfile(self, transport, file, offset=0, count=None, raise RuntimeError( f"fallback is disabled and native sendfile is not " f"supported for transport {transport!r}") - return await self._sendfile_fallback(transport, file, offset, count) @@ -1294,7 +1293,7 @@ async def _sendfile_native(self, transp, file, offset, count): "sendfile syscall is not supported") async def _sendfile_fallback(self, transp, file, offset, count): - if offset: + if hasattr(file, 'seek'): file.seek(offset) blocksize = min(count, 16384) if count else 16384 buf = bytearray(blocksize) diff --git a/Lib/asyncio/proactor_events.py b/Lib/asyncio/proactor_events.py index 2dc1569d780791..cf2902b4c76559 100644 --- a/Lib/asyncio/proactor_events.py +++ b/Lib/asyncio/proactor_events.py @@ -756,8 +756,7 @@ async def _sock_sendfile_native(self, sock, file, offset, count): offset += blocksize total_sent += blocksize finally: - if total_sent > 0: - file.seek(offset) + file.seek(offset) async def _sendfile_native(self, transp, file, offset, count): resume_reading = transp.is_reading() diff --git a/Lib/asyncio/unix_events.py b/Lib/asyncio/unix_events.py index 49e8067ee7b4e5..ab57efd48fce65 100644 --- a/Lib/asyncio/unix_events.py +++ b/Lib/asyncio/unix_events.py @@ -384,12 +384,12 @@ def _sock_sendfile_native_impl(self, fut, registered_fd, sock, fileno, # order to simplify the common case. self.remove_writer(registered_fd) if fut.cancelled(): - self._sock_sendfile_update_filepos(fileno, offset, total_sent) + self._sock_sendfile_update_filepos(fileno, offset) return if count: blocksize = count - total_sent if blocksize <= 0: - self._sock_sendfile_update_filepos(fileno, offset, total_sent) + self._sock_sendfile_update_filepos(fileno, offset) fut.set_result(total_sent) return @@ -423,20 +423,20 @@ def _sock_sendfile_native_impl(self, fut, registered_fd, sock, fileno, # plain send(). err = exceptions.SendfileNotAvailableError( "os.sendfile call failed") - self._sock_sendfile_update_filepos(fileno, offset, total_sent) + self._sock_sendfile_update_filepos(fileno, offset) fut.set_exception(err) else: - self._sock_sendfile_update_filepos(fileno, offset, total_sent) + self._sock_sendfile_update_filepos(fileno, offset) fut.set_exception(exc) except (SystemExit, KeyboardInterrupt): raise except BaseException as exc: - self._sock_sendfile_update_filepos(fileno, offset, total_sent) + self._sock_sendfile_update_filepos(fileno, offset) fut.set_exception(exc) else: if sent == 0: # EOF - self._sock_sendfile_update_filepos(fileno, offset, total_sent) + self._sock_sendfile_update_filepos(fileno, offset) fut.set_result(total_sent) else: offset += sent @@ -447,9 +447,9 @@ def _sock_sendfile_native_impl(self, fut, registered_fd, sock, fileno, fd, sock, fileno, offset, count, blocksize, total_sent) - def _sock_sendfile_update_filepos(self, fileno, offset, total_sent): - if total_sent > 0: - os.lseek(fileno, offset, os.SEEK_SET) + def _sock_sendfile_update_filepos(self, fileno, offset): + # After this helper runs, the source fd's lseek pointer is at offset." + os.lseek(fileno, offset, os.SEEK_SET) def _sock_add_cancellation_callback(self, fut, sock): def cb(fut): diff --git a/Lib/asyncio/windows_events.py b/Lib/asyncio/windows_events.py index 5f75b17d8ca649..0bf7732136f1f8 100644 --- a/Lib/asyncio/windows_events.py +++ b/Lib/asyncio/windows_events.py @@ -610,6 +610,9 @@ def sendfile(self, sock, file, offset, count): ov = _overlapped.Overlapped(NULL) offset_low = offset & 0xffff_ffff offset_high = (offset >> 32) & 0xffff_ffff + # TransmitFile ignores OVERLAPPED.Offset for handles not opened with + # FILE_FLAG_OVERLAPPED, so seek the CRT file pointer to match. + file.seek(offset) ov.TransmitFile(sock.fileno(), msvcrt.get_osfhandle(file.fileno()), offset_low, offset_high, diff --git a/Lib/test/test_asyncio/test_sendfile.py b/Lib/test/test_asyncio/test_sendfile.py index dcd963b3355ef8..7afd7de3bb936e 100644 --- a/Lib/test/test_asyncio/test_sendfile.py +++ b/Lib/test/test_asyncio/test_sendfile.py @@ -228,6 +228,61 @@ def test_sock_sendfile_zero_size(self): self.assertEqual(ret, 0) self.assertEqual(self.file.tell(), 0) + def check_sock_sendfile_offset(self, data, offset, force_fallback=False): + sock, proto = self.prepare_socksendfile() + with tempfile.TemporaryFile() as f: + f.write(data) + f.flush() + self.assertEqual(f.tell(), len(data)) + + if force_fallback: + async def _sock_sendfile_fail(sock, file, offset, count): + raise asyncio.exceptions.SendfileNotAvailableError() + with support.swap_attr(self.loop, '_sock_sendfile_native', _sock_sendfile_fail): + ret = self.run_loop(self.loop.sock_sendfile(sock, f, offset, None)) + else: + ret = self.run_loop(self.loop.sock_sendfile(sock, f, offset, None)) + + self.assertEqual(f.tell(), len(data)) + + sock.close() + self.run_loop(proto.wait_closed()) + + self.assertEqual(ret, len(data) - offset) + + + def test_sock_sendfile_offset(self): + data = b'abcdef' + for offset in (0, len(data) // 2, len(data)): + for force_fallback in (False, True): + with self.subTest(offset=offset, force_fallback=force_fallback): + self.check_sock_sendfile_offset(data, offset, force_fallback) + + def check_sendfile_offset(self, offset, fallback): + srv_proto, cli_proto = self.prepare_sendfile() + self.file.seek(123) + coro = self.loop.sendfile(cli_proto.transport, self.file, offset, fallback=fallback) + try: + ret = self.run_loop(coro) + except asyncio.SendfileNotAvailableError: + if fallback: + raise + cli_proto.transport.close() + self.run_loop(srv_proto.done) + return + cli_proto.transport.close() + self.run_loop(srv_proto.done) + self.assertEqual(ret, len(self.DATA) - offset) + self.assertEqual(srv_proto.nbytes, len(self.DATA) - offset) + self.assertEqual(srv_proto.data, self.DATA[offset:]) + self.assertEqual(self.file.tell(), len(self.DATA)) + + def test_sendfile_offset(self): + for offset in (0, len(self.DATA) // 2, len(self.DATA)): + for fallback in (False, True): + with self.subTest(offset=offset, fallback=fallback): + self.check_sendfile_offset(offset, fallback) + def test_sock_sendfile_mix_with_regular_send(self): buf = b"mix_regular_send" * (4 * 1024) # 64 KiB sock, proto = self.prepare_socksendfile() diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-22-17-09-28.gh-issue-150107.GD72-D.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-22-17-09-28.gh-issue-150107.GD72-D.rst new file mode 100644 index 00000000000000..a13f249e48cc02 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-22-17-09-28.gh-issue-150107.GD72-D.rst @@ -0,0 +1,3 @@ +:mod:`asyncio`: ``sendfile()`` and ``sock_sendfile()`` event loop methods +now call ``file.seek(offset)`` if *file* has a ``seek()`` method, +even if *offset* is ``0`` (default value). From 59e709b17ee84aa407ca9e0a3994916cb48ff909 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 29 May 2026 21:07:29 +0200 Subject: [PATCH 162/818] [3.15] Add a security warning about `pydoc`'s HTTP server (#150573) (cherry picked from commit 5535c1f9c08e929f96fa5d798277e3a2c91ed12a) Co-authored-by: Stan Ulbrych --- Doc/library/pydoc.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Doc/library/pydoc.rst b/Doc/library/pydoc.rst index f236eba8457657..a0cfb440a36ffa 100644 --- a/Doc/library/pydoc.rst +++ b/Doc/library/pydoc.rst @@ -68,6 +68,11 @@ will start a HTTP server on port 1234, allowing you to browse the documentation at ``http://localhost:1234/`` in your preferred web browser. Specifying ``0`` as the port number will select an arbitrary unused port. +.. warning:: + + The :mod:`!pydoc` HTTP server is intended for local use during + development and is not suitable for production use. + :program:`python -m pydoc -n ` will start the server listening at the given hostname. By default the hostname is 'localhost' but if you want the server to be reached from other machines, you may want to change the host name that the From a2ba8b192ed6c02e3a3943ad1551c1b38d1cc599 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 29 May 2026 21:48:48 +0200 Subject: [PATCH 163/818] [3.15] gh-150403: Document frozendict in language reference Mappings section (GH-150404) (GH-150590) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (cherry picked from commit 779694faba3e80b944f528a56e9b756b55637541) Co-authored-by: Oral Ersoy Dokumacı --- Doc/reference/datamodel.rst | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst index aef5bbe151cfeb..e13b2c9db490a1 100644 --- a/Doc/reference/datamodel.rst +++ b/Doc/reference/datamodel.rst @@ -496,7 +496,7 @@ subscript notation ``a[k]`` selects the item indexed by ``k`` from the mapping :keyword:`del` statements. The built-in function :func:`len` returns the number of items in a mapping. -There is currently a single intrinsic mapping type: +There are two intrinsic mapping types: Dictionaries @@ -535,6 +535,20 @@ module. an implementation detail at that time rather than a language guarantee. +Frozen dictionaries +^^^^^^^^^^^^^^^^^^^ + +.. index:: pair: object; frozendict + +These represent an immutable dictionary. They are created by the built-in +:func:`frozendict` constructor. A frozendict is :term:`hashable` if all of +its keys and values are hashable, in which case it can be used as an element +of a set, or as a key in another mapping. :class:`!frozendict` is not a +subclass of :class:`dict`; it inherits directly from :class:`object`. + +.. versionadded:: 3.15 + + Callable types -------------- From 863c7e0f9f9d72b8a2b87759b1ab51a0c4293de9 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 29 May 2026 23:30:50 +0200 Subject: [PATCH 164/818] [3.15] gh-149056: Properly pass array_hook in json.load() to json.loads() (GH-149057) (GH-150591) (cherry picked from commit f87d9605d3f9489d33aaf97a97fa9cb81cd7cc40) Co-authored-by: Thomas Kowalski --- Lib/json/__init__.py | 2 +- Lib/test/test_json/test_decode.py | 7 +++++++ .../Library/2026-04-29-08-10-17.gh-issue-149056.jnaD4W.rst | 2 ++ 3 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2026-04-29-08-10-17.gh-issue-149056.jnaD4W.rst diff --git a/Lib/json/__init__.py b/Lib/json/__init__.py index 9681a8fe53ec48..37a86831ff9483 100644 --- a/Lib/json/__init__.py +++ b/Lib/json/__init__.py @@ -307,7 +307,7 @@ def load(fp, *, cls=None, object_hook=None, parse_float=None, cls=cls, object_hook=object_hook, parse_float=parse_float, parse_int=parse_int, parse_constant=parse_constant, object_pairs_hook=object_pairs_hook, - array_hook=None, **kw) + array_hook=array_hook, **kw) def loads(s, *, cls=None, object_hook=None, parse_float=None, diff --git a/Lib/test/test_json/test_decode.py b/Lib/test/test_json/test_decode.py index d846c8af7ec434..1d51fb2de0e69e 100644 --- a/Lib/test/test_json/test_decode.py +++ b/Lib/test/test_json/test_decode.py @@ -87,6 +87,13 @@ def test_array_hook(self): self.assertEqual(self.loads('[]', array_hook=tuple), ()) + def test_load_array_hook(self): + # json.load must forward array_hook to loads + fp = StringIO('[10, 20, 30]') + result = self.json.load(fp, array_hook=tuple) + self.assertEqual(result, (10, 20, 30)) + self.assertEqual(type(result), tuple) + def test_decoder_optimizations(self): # Several optimizations were made that skip over calls to # the whitespace regex, so this test is designed to try and diff --git a/Misc/NEWS.d/next/Library/2026-04-29-08-10-17.gh-issue-149056.jnaD4W.rst b/Misc/NEWS.d/next/Library/2026-04-29-08-10-17.gh-issue-149056.jnaD4W.rst new file mode 100644 index 00000000000000..0026d02c876257 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-04-29-08-10-17.gh-issue-149056.jnaD4W.rst @@ -0,0 +1,2 @@ +Fix :func:`json.load` not forwarding the *array_hook* argument to +:func:`json.loads`. Patch by Thomas Kowalski. From 2f9131575b611dfc749242e8bbc6805bbc14683b Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sat, 30 May 2026 00:48:10 +0300 Subject: [PATCH 165/818] [3.15] gh-149489: Fix ElementTree serialization to HTML (GH-149490) (GH-150595) * The content of comments, processing instructions and elements "xmp", "iframe", "noembed", "noframes", and "plaintext" is no longer escaped. * The "plaintext" element no longer have the closing tag. * Add support of empty attributes (with value None). (cherry picked from commit bcd29e466f55d8b4e3849ed6ada8ce86a46f5072) --- Lib/test/test_xml_etree.py | 40 ++++++++++++++++++- Lib/xml/etree/ElementTree.py | 24 ++++++----- ...-05-07-14-18-47.gh-issue-149489.bX9iHe.rst | 5 +++ 3 files changed, 58 insertions(+), 11 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-05-07-14-18-47.gh-issue-149489.bX9iHe.rst diff --git a/Lib/test/test_xml_etree.py b/Lib/test/test_xml_etree.py index f43f1708a0fabd..27ea3c8c32fd8a 100644 --- a/Lib/test/test_xml_etree.py +++ b/Lib/test/test_xml_etree.py @@ -1281,7 +1281,15 @@ def check(p, expected, namespaces=None): {'': 'http://www.w3.org/2001/XMLSchema', 'ns': 'http://www.w3.org/2001/XMLSchema'}) - def test_processinginstruction(self): + def test_comment_serialization(self): + comm = ET.Comment(' & ham') + # comments are not escaped + self.assertEqual(ET.tostring(comm), b'') + self.assertEqual(ET.tostring(comm, method='html'), b'') + # no comments in text serialization + self.assertEqual(ET.tostring(comm, method='text'), b'') + + def test_processinginstruction_serialization(self): # Test ProcessingInstruction directly self.assertEqual(ET.tostring(ET.ProcessingInstruction('test', 'instruction')), @@ -1290,12 +1298,32 @@ def test_processinginstruction(self): b'') # Issue #2746 - + # processing instructions are not escaped self.assertEqual(ET.tostring(ET.PI('test', '')), b'?>') self.assertEqual(ET.tostring(ET.PI('test', '\xe3'), 'latin-1'), b"\n" b"\xe3?>") + pi = ET.PI('test', 'ham & eggs < spam') + self.assertEqual(ET.tostring(pi), b'') + self.assertEqual(ET.tostring(pi, method='html'), b'') + # no processing instructions in text serialization + self.assertEqual(ET.tostring(pi, method='text'), b'') + + def test_empty_attribute_serialization(self): + # empty attrs only work in html + elem = ET.Element('tag', attrib={'attr': None}) + self.assertRaises(TypeError, ET.tostring, elem) + self.assertEqual(ET.tostring(elem, method='html'), b'') + + @support.subTests('tag', ("script", "style", "xmp", "iframe", "noembed", "noframes")) + def test_html_cdata_elems_serialization(self, tag): + # content of raw text elements is not escaped in html + tag = tag.title() + elem = ET.Element(tag) + elem.text = '&ham' + self.assertEqual(ET.tostring(elem, method='html'), + ('<%s>&ham' % (tag, tag)).encode()) def test_html_empty_elems_serialization(self): # issue 15970 @@ -1311,6 +1339,14 @@ def test_html_empty_elems_serialization(self): method='html') self.assertEqual(serialized, expected) + def test_html_plaintext_serialization(self): + # content of plaintext is not escaped in html + # no end tag for plaintext + elem = ET.Element('PlainText') + elem.text = '&ham' + self.assertEqual(ET.tostring(elem, method='html'), + b'<spam>&ham') + def test_dump_attribute_order(self): # See BPO 34160 e = ET.Element('cirriculum', status='public', company='example') diff --git a/Lib/xml/etree/ElementTree.py b/Lib/xml/etree/ElementTree.py index 75bebc0b1668ab..53727d7940b3f2 100644 --- a/Lib/xml/etree/ElementTree.py +++ b/Lib/xml/etree/ElementTree.py @@ -917,17 +917,20 @@ def _serialize_xml(write, elem, qnames, namespaces, if elem.tail: write(_escape_cdata(elem.tail)) +_CDATA_CONTENT_ELEMENTS = {"script", "style", "xmp", "iframe", "noembed", + "noframes", "plaintext"} + HTML_EMPTY = {"area", "base", "basefont", "br", "col", "embed", "frame", "hr", "img", "input", "isindex", "link", "meta", "param", "source", - "track", "wbr"} + "track", "wbr", "plaintext"} def _serialize_html(write, elem, qnames, namespaces, **kwargs): tag = elem.tag text = elem.text if tag is Comment: - write("<!--%s-->" % _escape_cdata(text)) + write("<!--%s-->" % text) elif tag is ProcessingInstruction: - write("<?%s?>" % _escape_cdata(text)) + write("<?%s?>" % text) else: tag = qnames[tag] if tag is None: @@ -951,16 +954,19 @@ def _serialize_html(write, elem, qnames, namespaces, **kwargs): for k, v in items: if isinstance(k, QName): k = k.text - if isinstance(v, QName): - v = qnames[v.text] + k = qnames[k] + if v is None: + write(" %s" % k) # empty attr else: - v = _escape_attrib_html(v) - # FIXME: handle boolean attributes - write(" %s=\"%s\"" % (qnames[k], v)) + if isinstance(v, QName): + v = qnames[v.text] + else: + v = _escape_attrib_html(v) + write(" %s=\"%s\"" % (k, v)) write(">") ltag = tag.lower() if text: - if ltag == "script" or ltag == "style": + if ltag in _CDATA_CONTENT_ELEMENTS: write(text) else: write(_escape_cdata(text)) diff --git a/Misc/NEWS.d/next/Library/2026-05-07-14-18-47.gh-issue-149489.bX9iHe.rst b/Misc/NEWS.d/next/Library/2026-05-07-14-18-47.gh-issue-149489.bX9iHe.rst new file mode 100644 index 00000000000000..1550c893fd7c45 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-05-07-14-18-47.gh-issue-149489.bX9iHe.rst @@ -0,0 +1,5 @@ +Fix :mod:`~xml.etree.ElementTree` serialization to HTML. The content of +comments, processing instructions and elements "xmp", "iframe", "noembed", +"noframes", and "plaintext" is no longer escaped. The "plaintext" element no +longer have the closing tag. Add support of empty attributes (with value +``None``). From 187982aa7d61ec00378498a483c0f92b3992f4be Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 30 May 2026 11:25:38 +0200 Subject: [PATCH 166/818] [3.15] gh-150501: Correct `inspect.getattr_static` docs signature (GH-150504) (#150601) gh-150501: Correct `inspect.getattr_static` docs signature (GH-150504) (cherry picked from commit 678fd8452cc2d7f9a50cb5d4e5ae44a60b724248) Co-authored-by: Jonathan Dung <jonathandung@yahoo.com> --- Doc/library/inspect.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Doc/library/inspect.rst b/Doc/library/inspect.rst index 92840e702fbbfe..a0f7379b12a8a6 100644 --- a/Doc/library/inspect.rst +++ b/Doc/library/inspect.rst @@ -1614,10 +1614,11 @@ properties, will be invoked and :meth:`~object.__getattr__` and may be called. For cases where you want passive introspection, like documentation tools, this -can be inconvenient. :func:`getattr_static` has the same signature as :func:`getattr` +can be inconvenient. :func:`getattr_static` has a similar signature as :func:`getattr` but avoids executing code when it fetches attributes. -.. function:: getattr_static(obj, attr, default=None) +.. function:: getattr_static(obj, attr) + getattr_static(obj, attr, default) Retrieve attributes without triggering dynamic lookup via the descriptor protocol, :meth:`~object.__getattr__` From b952986ced6dbf48e77c951a1245343a32c08006 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 30 May 2026 12:49:26 +0200 Subject: [PATCH 167/818] [3.15] gh-135898: Add section to free-threading howto about memory usage (GH-143279) (#150607) gh-135898: Add section to free-threading howto about memory usage (GH-143279) (cherry picked from commit 62a45fa91c64bd1e1ad46ed66c07b65a7971042e) Co-authored-by: Neil Schemenauer <nas-github@arctrix.com> Co-authored-by: Kumar Aditya <kumaraditya@python.org> --- Doc/howto/free-threading-python.rst | 129 ++++++++++++++++++++++++++++ 1 file changed, 129 insertions(+) diff --git a/Doc/howto/free-threading-python.rst b/Doc/howto/free-threading-python.rst index 380c2be04957d5..53bea1db191d76 100644 --- a/Doc/howto/free-threading-python.rst +++ b/Doc/howto/free-threading-python.rst @@ -165,3 +165,132 @@ 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. + + +Increased memory usage +---------------------- + +The free-threaded build will typically use more memory compared to the default +build. There are multiple reasons for this, mostly due to design decisions. + + +All interned strings are immortal +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +For modern Python versions (since version 2.3), interning a string (e.g. with +:func:`sys.intern`) does not cause it to become immortal. Instead, if the last +reference to that string disappears, it will be removed from the interned +string table. This is not the case for the free-threaded build and any interned +string will become immortal, surviving until interpreter shutdown. + + +Non-GC objects have a larger object header +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The free-threaded build uses a different :c:type:`PyObject` structure. Instead +of having the GC related information allocated before the :c:type:`PyObject` +structure, like in the default build, the GC related info is part of the normal +object header. For example, on the AMD64 platform, ``None`` uses 32 bytes on +the free-threaded build vs 16 bytes for the default build. GC objects (such as +dicts and lists) are the same size for both builds since the free-threaded +build does not use additional space for the GC info. + + +QSBR can delay freeing of memory +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +In order to safely implement lock-free data structures, a safe memory +reclamation (SMR) scheme is used, known as quiescent state-based reclamation +(QSBR). This means that the memory backing data structures allowing lock-free +access will use QSBR, which defers the free operation, rather than immediately +freeing the memory. Two examples of these data structures are the list object +and the dictionary keys object. See ``InternalDocs/qsbr.md`` in the CPython +source tree for more details on how QSBR is implemented. Running +:func:`gc.collect` should cause all memory being held by QSBR to be actually +freed. Note that even when QSBR frees the memory, the underlying memory +allocator may not immediately return that memory to the OS and so the resident +set size (RSS) of the process might not decrease. + + +mimalloc allocator vs pymalloc +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The default build will normally use the "pymalloc" memory allocator for small +allocations (512 bytes or smaller). The free-threaded build does not use +pymalloc and allocates all Python objects using the "mimalloc" allocator. The +pymalloc allocator has the following properties that help keep memory usage +low: small per-allocated-block overhead, effective memory fragmentation +prevention, and quick return of free memory to the operating system. The +mimalloc allocator does quite well in these respects as well but can have some +more overhead. + +In the free-threaded build, mimalloc manages memory in a number of separate +heaps (currently four). For example, all GC supporting objects are allocated +from their own heap. Using separate heaps means that free memory in one heap +cannot be used for an allocation that uses another heap. Also, some heaps are +configured to use QSBR (quiescent-state based reclamation) when freeing the +memory that backs up the heap (known as "pages" in mimalloc terminology). The +use of QSBR creates a delay between all memory blocks for a page being freed +and the memory page being released, either for new allocations or back to the +OS. + +The mimalloc allocator also defers returning freed memory back to the OS. You +can reduce that delay by setting the environment variable +:envvar:`!MIMALLOC_PURGE_DELAY` to ``0``. Note that this will likely reduce +the performance of the allocator. + + +Free-threaded reference counting can cause objects to live longer +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +In the default build, when an object's reference count reaches zero, it is +normally deallocated. The free-threaded build uses "biased reference +counting", with a fast-path for objects "owned" by the current thread and a +slow path for other objects. See :pep:`703` for additional details. Any time +an object's reference count ends up in a "queued" state, deallocation can be +deferred. The queued state is cleared from the "eval breaker" section of the +bytecode evaluator. + +The free-threaded build also allows a different mode of reference counting, +known as "deferred reference counting". This mode is enabled by setting a flag +on a per-object basis. Deferred reference counting is enabled for the +following types: + +* module objects +* module top-level functions +* class methods defined in the class scope +* descriptor objects +* thread-local objects, created by :class:`threading.local` + +When deferred reference counting is enabled, references from Python function +stacks are not added to the reference count. This scheme reduces the overhead +of reference counting, especially for objects used from multiple threads. +Because the stack references are not counted, objects with deferred reference +counting are not immediately freed when their internal reference count goes to +zero. Instead, they are examined by the next GC run and, if no stack +references to them are found, they are freed. This means these objects are +freed by the GC and not when their reference count goes to zero, as is typical. + + +Per-thread reference counting can delay freeing objects +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +To avoid contention on the reference count fields of frequently shared +objects, the free-threaded build also uses "per-thread reference counting" +for a few selected object types. Rather than updating a single shared +reference count, each thread maintains its own local reference count array, +indexed by a unique id assigned to the object. The true reference count is +only computed by summing the per-thread counts when the object's local +count drops to zero. Per-thread reference counting is currently used for: + +* heap type objects (classes created in Python) +* code objects +* the ``__dict__`` of module objects + +Because the per-thread counts must be merged back to the object before it +can be deallocated, objects using per-thread reference counting are +typically freed later than they would be in the default build. In +particular, such an object is usually not freed until the thread that +referenced it reaches a safe point (for example, in the "eval breaker" +section of the bytecode evaluator) or exits. Running :func:`gc.collect` +will merge the per-thread counts and allow these objects to be freed. From e4cdee6c19aba3cb086b255858f6d7b953dddba4 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 30 May 2026 19:03:58 +0200 Subject: [PATCH 168/818] [3.15] gh-129851: Fix the documentation for -m command (GH-129862) (GH-150614) (cherry picked from commit 9baa7c63bee1ad2b243f16109a3fd206a1f13a6a) Co-authored-by: Dhruv Singla <68206552+d-s-dc@users.noreply.github.com> --- Doc/using/cmdline.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Doc/using/cmdline.rst b/Doc/using/cmdline.rst index 59e8f4f9f5a3e4..d84cd42062a678 100644 --- a/Doc/using/cmdline.rst +++ b/Doc/using/cmdline.rst @@ -50,8 +50,8 @@ additional methods of invocation: * When called with ``-c command``, it executes the Python statement(s) given as *command*. Here *command* may contain multiple statements separated by newlines. -* When called with ``-m module-name``, the given module is located on the - Python module path and executed as a script. +* When called with ``-m module-name``, the given module is located using the standard + import mechanism and executed as a script. In non-interactive mode, the entire input is parsed before it is executed. @@ -78,8 +78,8 @@ source. .. option:: -m <module-name> - Search :data:`sys.path` for the named module and execute its contents as - the :mod:`__main__` module. + Locate the module using the standard import mechanism and execute its contents + as the :mod:`__main__` module. Since the argument is a *module* name, you must not give a file extension (``.py``). The module name should be a valid absolute Python module name, but From 7cf2b37b66f681e1a61916b8b83b67771582fa93 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 30 May 2026 19:15:02 +0200 Subject: [PATCH 169/818] [3.15] gh-150406: Check result of PyThread_allocate_lock() for netdb_lock (GH-150407) (GH-150616) (cherry picked from commit 1e18c45495185cb547d43c3dd4c1cbdd8482867b) Co-authored-by: Thomas Kowalski <thom.kowa@gmail.com> --- .../Library/2026-05-25-17-00-00.gh-issue-150406.jF3g63.rst | 3 +++ Modules/socketmodule.c | 3 +++ 2 files changed, 6 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2026-05-25-17-00-00.gh-issue-150406.jF3g63.rst diff --git a/Misc/NEWS.d/next/Library/2026-05-25-17-00-00.gh-issue-150406.jF3g63.rst b/Misc/NEWS.d/next/Library/2026-05-25-17-00-00.gh-issue-150406.jF3g63.rst new file mode 100644 index 00000000000000..230e961abd3f58 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-05-25-17-00-00.gh-issue-150406.jF3g63.rst @@ -0,0 +1,3 @@ +Fix a possible crash occurring during :mod:`socket` module initialization +when the system is out of memory on platforms without a reentrant +``gethostbyname``. diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c index 722287fbb134c3..cf7aadfe95a721 100644 --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -9285,6 +9285,9 @@ socket_exec(PyObject *m) /* Initialize gethostbyname lock */ #if defined(USE_GETHOSTBYNAME_LOCK) netdb_lock = PyThread_allocate_lock(); + if (netdb_lock == NULL) { + goto error; + } #endif #ifdef MS_WINDOWS From ccfa50a0782a1d1ea504e8d5bc78ace57d99d968 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 31 May 2026 06:08:20 +0200 Subject: [PATCH 170/818] [3.15] gh-141444:fix broken URLs and examples in urllib.request.rst (GH-144863) (#150642) gh-141444:fix broken URLs and examples in urllib.request.rst (GH-144863) * Doc: fix broken URLs and examples in urllib.request.rst (gh-141444) * Doc: update urllib.request examples to handle gzip compression --------- (cherry picked from commit 0f1f7c7889873deb7c2e2c3f18695bf636e7752c) Co-authored-by: Paper Moon <tangyuan0821@email.cn> Co-authored-by: Senthil Kumaran <senthil@python.org> --- Doc/library/urllib.request.rst | 54 +++++++++++++++++++--------------- 1 file changed, 31 insertions(+), 23 deletions(-) diff --git a/Doc/library/urllib.request.rst b/Doc/library/urllib.request.rst index 64e915d042d4a0..03518d49d437ce 100644 --- a/Doc/library/urllib.request.rst +++ b/Doc/library/urllib.request.rst @@ -1051,7 +1051,7 @@ AbstractBasicAuthHandler Objects *headers* should be the error headers. *host* is either an authority (e.g. ``"python.org"``) or a URL containing an - authority component (e.g. ``"http://python.org/"``). In either case, the + authority component (e.g. ``"https://python.org/"``). In either case, the authority must not contain a userinfo component (so, ``"python.org"`` and ``"python.org:80"`` are fine, ``"joe:password@python.org"`` is not). @@ -1247,10 +1247,14 @@ This example gets the python.org main page and displays the first 300 bytes of it:: >>> import urllib.request - >>> with urllib.request.urlopen('http://www.python.org/') as f: - ... print(f.read(300)) - ... - b'<!doctype html>\n<!--[if lt IE 7]> <html class="no-js ie6 lt-ie7 lt-ie8 lt-ie9"> <![endif]-->\n<!--[if IE 7]> <html class="no-js ie7 lt-ie8 lt-ie9"> <![endif]-->\n<!--[if IE 8]> <html class="no-js ie8 lt-ie9"> + >>> with urllib.request.urlopen('https://www.python.org/') as f: + ... # The response may be compressed (for example, 'gzip'). + ... print(f.headers.get('Content-Encoding')) + ... data = f.read() + ... if f.headers.get('Content-Encoding') == 'gzip': + ... import gzip + ... data = gzip.decompress(data) + ... print(data[:300].decode('utf-8', errors='replace')) Note that urlopen returns a bytes object. This is because there is no way for urlopen to automatically determine the encoding of the byte stream @@ -1267,26 +1271,30 @@ For additional information, see the W3C document: https://www.w3.org/Internation As the python.org website uses *utf-8* encoding as specified in its meta tag, we will use the same for decoding the bytes object:: - >>> with urllib.request.urlopen('http://www.python.org/') as f: - ... print(f.read(100).decode('utf-8')) + >>> with urllib.request.urlopen('https://www.python.org/') as f: + ... # Check for compression and decode appropriately. + ... enc = f.headers.get('Content-Encoding') + ... data = f.read() + ... if enc == 'gzip': + ... import gzip + ... data = gzip.decompress(data) + ... print(data[:100].decode('utf-8', errors='replace')) ... - <!doctype html> - <!--[if lt IE 7]> <html class="no-js ie6 lt-ie7 lt-ie8 lt-ie9"> <![endif]--> - <!- It is also possible to achieve the same result without using the :term:`context manager` approach:: >>> import urllib.request - >>> f = urllib.request.urlopen('http://www.python.org/') + >>> f = urllib.request.urlopen('https://www.python.org/') >>> try: - ... print(f.read(100).decode('utf-8')) + ... enc = f.headers.get('Content-Encoding') + ... data = f.read() + ... if enc == 'gzip': + ... import gzip + ... data = gzip.decompress(data) + ... print(data[:100].decode('utf-8', errors='replace')) ... finally: ... f.close() - ... - <!doctype html> - <!--[if lt IE 7]> <html class="no-js ie6 lt-ie7 lt-ie8 lt-ie9"> <![endif]--> - <!-- In the following example, we are sending a data-stream to the stdin of a CGI and reading the data it returns to us. Note that this example will only work @@ -1357,7 +1365,7 @@ Use the *headers* argument to the :class:`Request` constructor, or:: import urllib.request req = urllib.request.Request('http://www.example.com/') - req.add_header('Referer', 'http://www.python.org/') + req.add_header('Referer', 'https://www.python.org/') # Customize the default User-Agent header value: req.add_header('User-Agent', 'urllib-example/0.1 (Contact: . . .)') with urllib.request.urlopen(req) as f: @@ -1386,7 +1394,7 @@ containing parameters:: >>> import urllib.request >>> import urllib.parse >>> params = urllib.parse.urlencode({'spam': 1, 'eggs': 2, 'bacon': 0}) - >>> url = "http://www.musi-cal.com/cgi-bin/query?%s" % params + >>> url = "https://www.python.org/?%s" % params >>> with urllib.request.urlopen(url) as f: ... print(f.read().decode('utf-8')) ... @@ -1398,7 +1406,7 @@ from urlencode is encoded to bytes before it is sent to urlopen as data:: >>> import urllib.parse >>> data = urllib.parse.urlencode({'spam': 1, 'eggs': 2, 'bacon': 0}) >>> data = data.encode('ascii') - >>> with urllib.request.urlopen("http://requestb.in/xrbl82xr", data) as f: + >>> with urllib.request.urlopen("https://httpbin.org/post", data) as f: ... print(f.read().decode('utf-8')) ... @@ -1408,15 +1416,15 @@ environment settings:: >>> import urllib.request >>> proxies = {'http': 'http://proxy.example.com:8080/'} >>> opener = urllib.request.build_opener(urllib.request.ProxyHandler(proxies)) - >>> with opener.open("http://www.python.org") as f: + >>> with opener.open("https://www.python.org") as f: ... f.read().decode('utf-8') ... The following example uses no proxies at all, overriding environment settings:: >>> import urllib.request - >>> opener = urllib.request.build_opener(urllib.request.ProxyHandler({}})) - >>> with opener.open("http://www.python.org/") as f: + >>> opener = urllib.request.build_opener(urllib.request.ProxyHandler({})) + >>> with opener.open("https://www.python.org/") as f: ... f.read().decode('utf-8') ... @@ -1449,7 +1457,7 @@ some point in the future. The following example illustrates the most common usage scenario:: >>> import urllib.request - >>> local_filename, headers = urllib.request.urlretrieve('http://python.org/') + >>> local_filename, headers = urllib.request.urlretrieve('https://python.org/') >>> html = open(local_filename) >>> html.close() From 9a393438a7e30f4909c288a90f7637f4ce68e21a Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 31 May 2026 06:22:11 +0200 Subject: [PATCH 171/818] [3.15] gh-149857: Clarify multiprocessing Process argument wording (GH-149919) (#149933) gh-149857: Clarify multiprocessing Process argument wording (GH-149919) Use consistent 'picklable' wording (cherry picked from commit 1bab6c919212cbac9be9e37bbd4d85865051f17f) Co-authored-by: Mani Salahmand <78011313+ManiSalahmand@users.noreply.github.com> --- Doc/library/multiprocessing.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Doc/library/multiprocessing.rst b/Doc/library/multiprocessing.rst index 187143d02cd7bf..7b17df08f7dc71 100644 --- a/Doc/library/multiprocessing.rst +++ b/Doc/library/multiprocessing.rst @@ -100,10 +100,10 @@ To show the individual process IDs involved, here is an expanded example:: For an explanation of why the ``if __name__ == '__main__'`` part is necessary, see :ref:`multiprocessing-programming`. -The arguments to :class:`Process` usually need to be unpickleable from within -the child process. If you tried typing the above example directly into a REPL it -could lead to an :exc:`AttributeError` in the child process trying to locate the -*f* function in the ``__main__`` module. +The arguments to :class:`Process` usually need to be picklable so they can be +passed to the child process. If you tried typing the above example directly +into a REPL it could lead to an :exc:`AttributeError` in the child process +trying to locate the *f* function in the ``__main__`` module. .. _multiprocessing-start-methods: From d03250657a5badf5a09760ecaa51db1dcd751cdd Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 31 May 2026 09:28:45 +0200 Subject: [PATCH 172/818] [3.15] gh-117291: Explain usage of null bytes in Array(c_char).value (GH-117292) (GH-150649) (cherry picked from commit 73d8e9a47cc13ce1b9b1bdfdeaa958639b144f55) Co-authored-by: Patrick Rauscher <prauscher@prauscher.de> --- Doc/library/multiprocessing.rst | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Doc/library/multiprocessing.rst b/Doc/library/multiprocessing.rst index 7b17df08f7dc71..2d13053915830b 100644 --- a/Doc/library/multiprocessing.rst +++ b/Doc/library/multiprocessing.rst @@ -1723,7 +1723,10 @@ inherited by child processes. Note that *lock* is a keyword only argument. Note that an array of :data:`ctypes.c_char` has *value* and *raw* - attributes which allow one to use it to store and retrieve strings. + attributes which can both be used to store and retrieve byte strings. + While *raw* allows interaction with a :class:`bytes` object the full size of + the array, reading *value* will terminate after a null byte, like most + programming languages handle strings. The :mod:`!multiprocessing.sharedctypes` module From 3084bdc54b8b1cb8ff0eb30dddf61239af2260ca Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 31 May 2026 09:52:55 +0200 Subject: [PATCH 173/818] [3.15] gh-150524: Remove outdated note in binascii.a2b_hex() documentation (GH-150525) (GH-150627) bytes.fromhex() accepts ASCII bytes and bytes-like objects as input since 3.14 (cherry picked from commit af10734907d2d7df4c4d754174804aec7c5d6a72) Co-authored-by: Joshix-1 <57299889+Joshix-1@users.noreply.github.com> --- Doc/library/binascii.rst | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Doc/library/binascii.rst b/Doc/library/binascii.rst index 60afe9261d51fa..ceb80a35a1a76b 100644 --- a/Doc/library/binascii.rst +++ b/Doc/library/binascii.rst @@ -367,9 +367,8 @@ The :mod:`!binascii` module defines the following functions: *ignorechars* should be a :term:`bytes-like object` containing characters to ignore from the input. - Similar functionality (accepting only text string arguments, but more - liberal towards whitespace) is also accessible using the - :meth:`bytes.fromhex` class method. + Similar functionality (but more liberal towards whitespace) is also accessible + using the :meth:`bytes.fromhex` class method. .. versionchanged:: 3.15 Added the *ignorechars* parameter. From 2ff80c7533fca37d9a2044b3c01ad276d4f5e0cd Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 31 May 2026 10:14:15 +0200 Subject: [PATCH 174/818] [3.15] gh-131178: Fix mimetypes CLI docs, mention that errors go to stdout (GH-149683) (#150655) gh-131178: Fix mimetypes CLI docs, mention that errors go to stdout (GH-149683) (cherry picked from commit 2b94b923943a1f75cdbd5a5e4e2eb5f93eb43e23) Co-authored-by: htjworld <116538001+htjworld@users.noreply.github.com> Co-authored-by: sobolevn <mail@sobolevn.me> --- Doc/library/mimetypes.rst | 7 +++-- Lib/test/test_mimetypes.py | 57 +++++++++++++++++++++++++++++++++++++- 2 files changed, 60 insertions(+), 4 deletions(-) diff --git a/Doc/library/mimetypes.rst b/Doc/library/mimetypes.rst index 0facacd50fd389..c2ccabe3cc5389 100644 --- a/Doc/library/mimetypes.rst +++ b/Doc/library/mimetypes.rst @@ -348,7 +348,7 @@ it converts file extensions to MIME types. For each ``type`` entry, the script writes a line into the standard output stream. If an unknown type occurs, it writes an error message into the -standard error stream and exits with the return code ``1``. +standard output stream and exits with the return code ``1``. .. mimetypes-cli-example: @@ -375,7 +375,7 @@ interface: $ # get a MIME type for a rare file extension $ python -m mimetypes filename.pict - error: unknown extension of filename.pict + error: media type unknown for filename.pict $ # now look in the extended database built into Python $ python -m mimetypes --lenient filename.pict @@ -397,7 +397,8 @@ interface: $ python -m mimetypes filename.sh filename.nc filename.xxx filename.txt type: application/x-sh encoding: None type: application/x-netcdf encoding: None - error: unknown extension of filename.xxx + error: media type unknown for filename.xxx + type: text/plain encoding: None $ # try to feed an unknown MIME type $ python -m mimetypes --extension audio/aac audio/opus audio/future audio/x-wav diff --git a/Lib/test/test_mimetypes.py b/Lib/test/test_mimetypes.py index 2d618081521e10..b49f05c66fcfbe 100644 --- a/Lib/test/test_mimetypes.py +++ b/Lib/test/test_mimetypes.py @@ -6,8 +6,9 @@ import unittest.mock from platform import win32_edition from test import support -from test.support import cpython_only, force_not_colorized, os_helper +from test.support import cpython_only, force_not_colorized, os_helper, requires_subprocess from test.support.import_helper import ensure_lazy_imports +from test.support.script_helper import assert_python_ok, assert_python_failure try: import _winapi @@ -508,5 +509,59 @@ def test_invocation_error(self): self.assertEqual(result, expected) +@requires_subprocess() +class CommandLineSubprocessTest(unittest.TestCase): + def test_help(self): + rc, stdout, stderr = assert_python_ok('-m', 'mimetypes', '--help') + self.assertIn(b'mimetypes', stdout) + self.assertIn(b'--extension', stdout) + self.assertIn(b'--lenient', stdout) + + def test_type_lookup(self): + rc, stdout, stderr = assert_python_ok('-m', 'mimetypes', 'foo.pdf') + self.assertEqual(stdout.strip(), b'type: application/pdf encoding: None') + self.assertEqual(stderr, b'') + + def test_type_lookup_unknown(self): + rc, stdout, stderr = assert_python_failure('-m', 'mimetypes', 'foo.unknownext12345') + self.assertEqual(stdout.strip(), b'error: media type unknown for foo.unknownext12345') + self.assertEqual(stderr, b'') + + def test_extension_flag(self): + rc, stdout, stderr = assert_python_ok('-m', 'mimetypes', '-e', 'image/jpeg') + self.assertEqual(stdout.strip(), b'.jpg') + self.assertEqual(stderr, b'') + + def test_extension_flag_unknown(self): + rc, stdout, stderr = assert_python_failure('-m', 'mimetypes', '-e', 'image/unknowntype12345') + self.assertEqual(stdout.strip(), b'error: unknown type image/unknowntype12345') + self.assertEqual(stderr, b'') + + def test_lenient_flag(self): + rc, stdout, stderr = assert_python_ok('-m', 'mimetypes', '-e', '--lenient', 'text/xul') + self.assertIn(b'.xul', stdout) + self.assertEqual(stderr, b'') + + def test_multiple_inputs(self): + rc, stdout, stderr = assert_python_ok('-m', 'mimetypes', 'foo.pdf', 'foo.png') + self.assertIn(b'type: application/pdf encoding: None', stdout) + self.assertIn(b'type: image/png encoding: None', stdout) + self.assertEqual(stderr, b'') + + def test_multiple_inputs_with_error(self): + rc, stdout, stderr = assert_python_failure( + '-m', 'mimetypes', 'foo.pdf', 'foo.unknownext12345' + ) + self.assertIn(b'type: application/pdf encoding: None', stdout) + self.assertIn(b'error: media type unknown for foo.unknownext12345', stdout) + self.assertEqual(stderr, b'') + + @force_not_colorized + def test_unknown_flag(self): + rc, stdout, stderr = assert_python_failure('-m', 'mimetypes', '--unknown-flag', 'foo.pdf') + self.assertEqual(stdout, b'') + self.assertIn(b'error: unrecognized arguments: --unknown-flag', stderr) + + if __name__ == "__main__": unittest.main() From c5655dfe51764e7e4dc2ba515acd03b8c96823a9 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 31 May 2026 12:04:18 +0200 Subject: [PATCH 175/818] [3.15] Correct frexp() docs for zero and non-finite numbers (GH-149753) (GH-150652) 0.5 <= abs(m) < 1 is only true for finite nonzero numbers (cherry picked from commit 5b5ffce05c211a5b0b74cd95eeb4c463614ee136) Co-authored-by: Sergey B Kirpichev <skirpichev@gmail.com> --- Doc/library/math.rst | 10 ++++++---- Modules/clinic/mathmodule.c.h | 7 ++++--- Modules/mathmodule.c | 7 ++++--- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/Doc/library/math.rst b/Doc/library/math.rst index 9cc8c5d6886324..41a9a0ab55d8fa 100644 --- a/Doc/library/math.rst +++ b/Doc/library/math.rst @@ -255,10 +255,12 @@ Floating point manipulation functions .. function:: frexp(x) - Return the mantissa and exponent of *x* as the pair ``(m, e)``. *m* is a float - and *e* is an integer such that ``x == m * 2**e`` exactly. If *x* is zero, - returns ``(0.0, 0)``, otherwise ``0.5 <= abs(m) < 1``. This is used to "pick - apart" the internal representation of a float in a portable way. + Return the mantissa and exponent of *x* as the pair ``(m, e)``. + If *x* is a finite nonzero number, then *m* is a float with + ``0.5 <= abs(m) < 1.0`` and an integer *e* is such that + ``x == m * 2**e`` exactly. Else, return ``(x, 0)``. + This is used to "pick apart" the internal representation of + a float in a portable way. Note that :func:`frexp` has a different call/return pattern than its C equivalents: it takes a single argument and return a pair of diff --git a/Modules/clinic/mathmodule.c.h b/Modules/clinic/mathmodule.c.h index 6a1b1a45d1d93a..a5e583c180defe 100644 --- a/Modules/clinic/mathmodule.c.h +++ b/Modules/clinic/mathmodule.c.h @@ -198,8 +198,9 @@ PyDoc_STRVAR(math_frexp__doc__, "\n" "Return the mantissa and exponent of x, as pair (m, e).\n" "\n" -"m is a float and e is an int, such that x = m * 2.**e.\n" -"If x is 0, m and e are both 0. Else 0.5 <= abs(m) < 1.0."); +"If x is a finite nonzero number, then m is a float with\n" +"0.5 <= abs(m) < 1.0 and an integer e is such that\n" +"x == m * 2**e exactly. Else, return (x, 0)."); #define MATH_FREXP_METHODDEF \ {"frexp", (PyCFunction)math_frexp, METH_O, math_frexp__doc__}, @@ -1163,4 +1164,4 @@ math_ulp(PyObject *module, PyObject *arg) exit: return return_value; } -/*[clinic end generated code: output=80c666aef8d2df36 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=3452ce8caa2d1bd7 input=a9049054013a1b77]*/ diff --git a/Modules/mathmodule.c b/Modules/mathmodule.c index a7616ad70e4afe..5636a00afe10c4 100644 --- a/Modules/mathmodule.c +++ b/Modules/mathmodule.c @@ -1438,13 +1438,14 @@ math.frexp Return the mantissa and exponent of x, as pair (m, e). -m is a float and e is an int, such that x = m * 2.**e. -If x is 0, m and e are both 0. Else 0.5 <= abs(m) < 1.0. +If x is a finite nonzero number, then m is a float with +0.5 <= abs(m) < 1.0 and an integer e is such that +x == m * 2**e exactly. Else, return (x, 0). [clinic start generated code]*/ static PyObject * math_frexp_impl(PyObject *module, double x) -/*[clinic end generated code: output=03e30d252a15ad4a input=96251c9e208bc6e9]*/ +/*[clinic end generated code: output=03e30d252a15ad4a input=215cf8ea28a0959b]*/ { int i; /* deal with special cases directly, to sidestep platform From 2fb2a23cbd41b640afda105ed767778ab191cbee Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 31 May 2026 14:16:58 +0200 Subject: [PATCH 176/818] [3.15] gh-150636: Clarify difference between copy.copy() and the copy() methods (GH-150637) (GH-150665) (cherry picked from commit 1de909b32411fc1c4d4c42b4f8221b86096c6353) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Pieter Eendebak <pieter.eendebak@gmail.com> Co-authored-by: Stan Ulbrych <stan@python.org> --- Doc/library/copy.rst | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Doc/library/copy.rst b/Doc/library/copy.rst index 121c44a16ad43b..39fc7800d03a91 100644 --- a/Doc/library/copy.rst +++ b/Doc/library/copy.rst @@ -72,9 +72,13 @@ file, socket, window, or any similar types. It does "copy" functions and classes (shallow and deeply), by returning the original object unchanged; this is compatible with the way these are treated by the :mod:`pickle` module. -Shallow copies of dictionaries can be made using :meth:`dict.copy`, and -of lists by assigning a slice of the entire list, for example, -``copied_list = original_list[:]``. +Shallow copies of many collections can be made using the corresponding +:meth:`!copy` method (such as :meth:`list.copy`, :meth:`dict.copy` or +:meth:`set.copy`), and of sequences (such as lists or bytearrays) by making +a slice of the entire sequence (``sequence[:]``). +However, these methods and slicing can create an instance of the base type +when copying an instance of a subclass, whereas :func:`copy.copy` normally +returns an instance of the same type. .. index:: pair: module; pickle From ea58c352b717c8ea06a43c76bf99985bd42c288b Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 31 May 2026 14:19:43 +0200 Subject: [PATCH 177/818] [3.15] Clarify docs for scheduler.run(blocking=False) (GH-129575) (GH-150668) (cherry picked from commit 2f8f569ba911ab3cff1356a15a3e688adc4ae917) Co-authored-by: M. Greyson Christoforo <grey@christoforo.net> --- Doc/library/sched.rst | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Doc/library/sched.rst b/Doc/library/sched.rst index 70541c5f3cb367..037e27f031d0c8 100644 --- a/Doc/library/sched.rst +++ b/Doc/library/sched.rst @@ -117,9 +117,11 @@ Scheduler Objects function passed to the constructor) for the next event, then execute it and so on until there are no more scheduled events. - If *blocking* is false executes the scheduled events due to expire soonest - (if any) and then return the deadline of the next scheduled call in the - scheduler (if any). + If *blocking* is false, immediately executes all events in the queue which have + a time value less than or equal to the current *timefunc* value (if any) and + returns the difference between the current *timefunc* value and the time value + of the next scheduled event in the scheduler's event queue. If the queue is + empty, returns ``None``. Either *action* or *delayfunc* can raise an exception. In either case, the scheduler will maintain a consistent state and propagate the exception. If an From fed5c744dfff9a4cae04becf6cc33228f31793c6 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 31 May 2026 21:21:08 +0200 Subject: [PATCH 178/818] [3.15] gh-140553: Mark `*gettext` parameters as positionaly only in documentation (GH-140598) (cherry picked from commit 1837c17bc78b8169cd6c1c5799dcf6a71c3eac83) Co-authored-by: Stan Ulbrych <stan@python.org> --- Doc/library/gettext.rst | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/Doc/library/gettext.rst b/Doc/library/gettext.rst index 2de16fe40362b3..2ab7ba7df19cf1 100644 --- a/Doc/library/gettext.rst +++ b/Doc/library/gettext.rst @@ -51,19 +51,19 @@ class-based API instead. .. index:: single: _ (underscore); gettext -.. function:: gettext(message) +.. function:: gettext(message, /) Return the localized translation of *message*, based on the current global domain, language, and locale directory. This function is usually aliased as :func:`!_` in the local namespace (see examples below). -.. function:: dgettext(domain, message) +.. function:: dgettext(domain, message, /) Like :func:`.gettext`, but look the message up in the specified *domain*. -.. function:: ngettext(singular, plural, n) +.. function:: ngettext(singular, plural, n, /) Like :func:`.gettext`, but consider plural forms. If a translation is found, apply the plural formula to *n*, and return the resulting message (some @@ -78,15 +78,15 @@ class-based API instead. formulas for a variety of languages. -.. function:: dngettext(domain, singular, plural, n) +.. function:: dngettext(domain, singular, plural, n, /) Like :func:`ngettext`, but look the message up in the specified *domain*. -.. function:: pgettext(context, message) -.. function:: dpgettext(domain, context, message) -.. function:: npgettext(context, singular, plural, n) -.. function:: dnpgettext(domain, context, singular, plural, n) +.. function:: pgettext(context, message, /) +.. function:: dpgettext(domain, context, message, /) +.. function:: npgettext(context, singular, plural, n, /) +.. function:: dnpgettext(domain, context, singular, plural, n, /) Similar to the corresponding functions without the ``p`` in the prefix (that is, :func:`gettext`, :func:`dgettext`, :func:`ngettext`, :func:`dngettext`), @@ -223,20 +223,20 @@ are the methods of :class:`!NullTranslations`: translation for a given message. - .. method:: gettext(message) + .. method:: gettext(message, /) If a fallback has been set, forward :meth:`!gettext` to the fallback. Otherwise, return *message*. Overridden in derived classes. - .. method:: ngettext(singular, plural, n) + .. method:: ngettext(singular, plural, n, /) If a fallback has been set, forward :meth:`!ngettext` to the fallback. Otherwise, return *singular* if *n* is 1; return *plural* otherwise. Overridden in derived classes. - .. method:: pgettext(context, message) + .. method:: pgettext(context, message, /) If a fallback has been set, forward :meth:`pgettext` to the fallback. Otherwise, return the translated message. Overridden in derived classes. @@ -244,7 +244,7 @@ are the methods of :class:`!NullTranslations`: .. versionadded:: 3.8 - .. method:: npgettext(context, singular, plural, n) + .. method:: npgettext(context, singular, plural, n, /) If a fallback has been set, forward :meth:`npgettext` to the fallback. Otherwise, return the translated message. Overridden in derived classes. @@ -322,7 +322,7 @@ unexpected, or if other problems occur while reading the file, instantiating a The following methods are overridden from the base class implementation: - .. method:: gettext(message) + .. method:: gettext(message, /) Look up the *message* id in the catalog and return the corresponding message string, as a Unicode string. If there is no entry in the catalog for the @@ -331,7 +331,7 @@ unexpected, or if other problems occur while reading the file, instantiating a *message* id is returned. - .. method:: ngettext(singular, plural, n) + .. method:: ngettext(singular, plural, n, /) Do a plural-forms lookup of a message id. *singular* is used as the message id for purposes of lookup in the catalog, while *n* is used to determine which @@ -352,7 +352,7 @@ unexpected, or if other problems occur while reading the file, instantiating a n) % {'num': n} - .. method:: pgettext(context, message) + .. method:: pgettext(context, message, /) Look up the *context* and *message* id in the catalog and return the corresponding message string, as a Unicode string. If there is no @@ -363,7 +363,7 @@ unexpected, or if other problems occur while reading the file, instantiating a .. versionadded:: 3.8 - .. method:: npgettext(context, singular, plural, n) + .. method:: npgettext(context, singular, plural, n, /) Do a plural-forms lookup of a message id. *singular* is used as the message id for purposes of lookup in the catalog, while *n* is used to From 487b23d546d265cab7809bc166097f7ed0843968 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 31 May 2026 22:12:22 +0200 Subject: [PATCH 179/818] [3.15] gh-150685: update bundled pip to 26.1.2 (gh-150686) (gh-150687) --- Lib/ensurepip/__init__.py | 2 +- ...ne-any.whl => pip-26.1.2-py3-none-any.whl} | Bin 1812777 -> 1813144 bytes ...-05-31-17-47-30.gh-issue-150685.EBB2mU.rst | 1 + 3 files changed, 2 insertions(+), 1 deletion(-) rename Lib/ensurepip/_bundled/{pip-26.1.1-py3-none-any.whl => pip-26.1.2-py3-none-any.whl} (93%) create mode 100644 Misc/NEWS.d/next/Library/2026-05-31-17-47-30.gh-issue-150685.EBB2mU.rst diff --git a/Lib/ensurepip/__init__.py b/Lib/ensurepip/__init__.py index ab6b95e0ba60c0..e14d23b35cf7a9 100644 --- a/Lib/ensurepip/__init__.py +++ b/Lib/ensurepip/__init__.py @@ -10,7 +10,7 @@ __all__ = ["version", "bootstrap"] -_PIP_VERSION = "26.1.1" +_PIP_VERSION = "26.1.2" # Directory of system wheel packages. Some Linux distribution packaging # policies recommend against bundling dependencies. For example, Fedora diff --git a/Lib/ensurepip/_bundled/pip-26.1.1-py3-none-any.whl b/Lib/ensurepip/_bundled/pip-26.1.2-py3-none-any.whl similarity index 93% rename from Lib/ensurepip/_bundled/pip-26.1.1-py3-none-any.whl rename to Lib/ensurepip/_bundled/pip-26.1.2-py3-none-any.whl index ab0307c7716212a514231bfc5149437cfb9df70a..24b5cc90ace64391f8ff6ac218837e03f980d485 100644 GIT binary patch delta 73433 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 Rkl`T%<p71UTO6N;{|~mcdO-jH delta 73016 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 diff --git a/Misc/NEWS.d/next/Library/2026-05-31-17-47-30.gh-issue-150685.EBB2mU.rst b/Misc/NEWS.d/next/Library/2026-05-31-17-47-30.gh-issue-150685.EBB2mU.rst new file mode 100644 index 00000000000000..eb7f31112d004c --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-05-31-17-47-30.gh-issue-150685.EBB2mU.rst @@ -0,0 +1 @@ +Update bundled pip to 26.1.2 From 2c1e4bb6e295f72b38e0f92b0ccbcc80a64e61a8 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 1 Jun 2026 11:31:52 +0200 Subject: [PATCH 180/818] [3.15] gh-148605: Remove irepeat() thread test from test_bytes (GH-150576) (#150660) gh-148605: Remove irepeat() thread test from test_bytes (GH-150576) (cherry picked from commit 350e9de7650e224fd3abe8f389976071e8fae6d2) Co-authored-by: Victor Stinner <vstinner@python.org> --- Lib/test/test_bytes.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/Lib/test/test_bytes.py b/Lib/test/test_bytes.py index b1cdbe04765ed0..e0e8dd4eccfb1b 100644 --- a/Lib/test/test_bytes.py +++ b/Lib/test/test_bytes.py @@ -2700,10 +2700,6 @@ def iconcat(b, a): # MODIFIES! b.wait() a += c - def irepeat(b, a): # MODIFIES! - b.wait() - a *= 2 - def subscript(b, a): b.wait() try: assert a[0] != 0xdd @@ -2837,9 +2833,10 @@ def check(funcs, a=None, *args): check([clear] + [repeat] * 10) check([clear] + [iconcat] * 10) - check([clear] + [irepeat] * 10) check([clear] + [ass_subscript] * 10) check([clear] + [repr_] * 10) + # gh-148605: Do not test "a *= 2" since it allocates up to 4 GiB using + # 10 threads # value errors From 4ce8de3550f6f4860a0087bfd67a95fe8342a9eb Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 1 Jun 2026 12:00:55 +0200 Subject: [PATCH 181/818] [3.15] gh-150372: Add missing null check on completer_word_break_characters in readline.c (GH-150251) (GH-150628) (cherry picked from commit 56bd9ea676d5ab4d5f6c68aefc3125ef5a216157) Co-authored-by: Thomas Kowalski <thom.kowa@gmail.com> --- .../2026-05-25-07-22-05.gh-issue-150372.9hLqhe.rst | 2 ++ Modules/readline.c | 8 ++++++++ 2 files changed, 10 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2026-05-25-07-22-05.gh-issue-150372.9hLqhe.rst diff --git a/Misc/NEWS.d/next/Library/2026-05-25-07-22-05.gh-issue-150372.9hLqhe.rst b/Misc/NEWS.d/next/Library/2026-05-25-07-22-05.gh-issue-150372.9hLqhe.rst new file mode 100644 index 00000000000000..7b83bd8fe73f11 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-05-25-07-22-05.gh-issue-150372.9hLqhe.rst @@ -0,0 +1,2 @@ +:mod:`readline`: Fix a potential crash during tab completion caused by an +out-of-memory error during module initialization. diff --git a/Modules/readline.c b/Modules/readline.c index 2cc3d40baa3aba..c580d2022fccf3 100644 --- a/Modules/readline.c +++ b/Modules/readline.c @@ -1406,6 +1406,10 @@ setup_readline(readlinestate *mod_state) completer_word_break_characters = strdup(" \t\n`~!@#$%^&*()-=+[{]}\\|;:'\",<>/?"); /* All nonalphanums except '.' */ + + if (!completer_word_break_characters) { + goto error; + } #ifdef WITH_EDITLINE // libedit uses rl_basic_word_break_characters instead of // rl_completer_word_break_characters as complete delimiter @@ -1449,6 +1453,10 @@ setup_readline(readlinestate *mod_state) RESTORE_LOCALE(saved_locale) return 0; + +error: + RESTORE_LOCALE(saved_locale) + return -1; } /* Wrapper around GNU readline that handles signals differently. */ From 58335eebef7d15e21866e7e618136d2ce752d404 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 1 Jun 2026 14:05:52 +0200 Subject: [PATCH 182/818] [3.15] gh-150368: Change Windows user group to secure identifier in test_tempfile (GH-150369) (#150701) gh-150368: Change Windows user group to secure identifier in test_tempfile (GH-150369) (cherry picked from commit 9d64c355b5471e2d27e036d3662e97567d259c61) Co-authored-by: Dawid Konrad Kohnke <51542233+anytokin@users.noreply.github.com> --- Lib/test/test_tempfile.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_tempfile.py b/Lib/test/test_tempfile.py index b2b5390af33b00..638140b96d4517 100644 --- a/Lib/test/test_tempfile.py +++ b/Lib/test/test_tempfile.py @@ -332,7 +332,9 @@ def test_read_only_directory(self): with _inside_empty_temp_dir(): probe = os.path.join(tempfile.tempdir, 'probe') if os.name == 'nt': - cmd = ['icacls', tempfile.tempdir, '/deny', 'Everyone:(W)'] + # Use security identifier *S-1-1-0 instead + # of localized "Everyone" to not depend on the locale. + cmd = ['icacls', tempfile.tempdir, '/deny', '*S-1-1-0:(W)'] stdout = None if support.verbose > 1 else subprocess.DEVNULL subprocess.run(cmd, check=True, stdout=stdout) else: @@ -355,7 +357,9 @@ def test_read_only_directory(self): self.make_temp() finally: if os.name == 'nt': - cmd = ['icacls', tempfile.tempdir, '/grant:r', 'Everyone:(M)'] + # Use security identifier *S-1-1-0 instead + # of localized "Everyone" to not depend on the locale. + cmd = ['icacls', tempfile.tempdir, '/grant:r', '*S-1-1-0:(M)'] subprocess.run(cmd, check=True, stdout=stdout) else: os.chmod(tempfile.tempdir, oldmode) From e60e8cfe8bda635923507bb36949d42ae780564e Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 1 Jun 2026 15:33:02 +0200 Subject: [PATCH 183/818] [3.15] gh-149046: fix: correctly handle `str` subclasses in `io.StringIO` (GH-149047) (#150706) gh-149046: fix: correctly handle `str` subclasses in `io.StringIO` (GH-149047) (cherry picked from commit c98773633c97463e35eb51fac81d1095e8061fe0) Co-authored-by: Thomas Kowalski <thom.kowa@gmail.com> --- Lib/test/test_io/test_memoryio.py | 19 +++++++++++++++++++ ...-04-27-11-12-00.gh-issue-149046.74shDd.rst | 2 ++ Modules/_io/stringio.c | 4 +++- 3 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2026-04-27-11-12-00.gh-issue-149046.74shDd.rst diff --git a/Lib/test/test_io/test_memoryio.py b/Lib/test/test_io/test_memoryio.py index 482b183da23ffa..3669ac0b038b71 100644 --- a/Lib/test/test_io/test_memoryio.py +++ b/Lib/test/test_io/test_memoryio.py @@ -967,6 +967,25 @@ def test_setstate(self): memio.close() self.assertRaises(ValueError, memio.__setstate__, ("closed", "", 0, None)) + def test_write_str_subclass(self): + # Writing a str subclass should use the subclass's unicode data + # directly, not call __str__ on it (which may return a different + # value). gh-149047 + class MyStr(str): + def __str__(self): + return "WRONG" + + s = MyStr("correct") + memio = self.ioclass() + memio.write(s) + self.assertEqual(memio.getvalue(), "correct") + + # Also test the fast path where pos == string_size (STATE_ACCUMULATING) + memio2 = self.ioclass() + memio2.write(MyStr("hello ")) + memio2.write(MyStr("world")) + self.assertEqual(memio2.getvalue(), "hello world") + class CStringIOPickleTest(PyStringIOPickleTest): UnsupportedOperation = io.UnsupportedOperation diff --git a/Misc/NEWS.d/next/Library/2026-04-27-11-12-00.gh-issue-149046.74shDd.rst b/Misc/NEWS.d/next/Library/2026-04-27-11-12-00.gh-issue-149046.74shDd.rst new file mode 100644 index 00000000000000..b05c4222e30fcd --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-04-27-11-12-00.gh-issue-149046.74shDd.rst @@ -0,0 +1,2 @@ +:mod:`io`: Fix :class:`io.StringIO` serialization: no longer call ``str(obj)`` on :class:`str` +subclasses. Patch by Thomas Kowalski. diff --git a/Modules/_io/stringio.c b/Modules/_io/stringio.c index 0d9196f3647dde..b8601383ad0a26 100644 --- a/Modules/_io/stringio.c +++ b/Modules/_io/stringio.c @@ -225,7 +225,9 @@ write_str(stringio *self, PyObject *obj) if (self->state == STATE_ACCUMULATING) { if (self->string_size == self->pos) { - if (PyUnicodeWriter_WriteStr(self->writer, decoded)) + // gh-149046: Avoid PyUnicodeWriter_WriteStr() which calls str(obj) + // on str subclasses + if (_PyUnicodeWriter_WriteStr((_PyUnicodeWriter*)self->writer, decoded)) goto fail; goto success; } From b65c28206fe3e8cc3fbf33b99b563e967986da3d Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 1 Jun 2026 16:59:09 +0200 Subject: [PATCH 184/818] [3.15] gh-150157: Fix critical section for PyDict_Next() in _pickle.c (GH-150158) (#150711) (cherry picked from commit c5516e7e371f7b273eb37c7b65f14ef14ee81f11) Co-authored-by: Thomas Kowalski <thom.kowa@gmail.com> --- ...5-21-20-47-45.gh-issue-150157.ZvmO-bQZ.rst | 3 +++ Modules/_pickle.c | 20 +++++++++++++++---- 2 files changed, 19 insertions(+), 4 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-05-21-20-47-45.gh-issue-150157.ZvmO-bQZ.rst diff --git a/Misc/NEWS.d/next/Library/2026-05-21-20-47-45.gh-issue-150157.ZvmO-bQZ.rst b/Misc/NEWS.d/next/Library/2026-05-21-20-47-45.gh-issue-150157.ZvmO-bQZ.rst new file mode 100644 index 00000000000000..3a12e26cf736f7 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-05-21-20-47-45.gh-issue-150157.ZvmO-bQZ.rst @@ -0,0 +1,3 @@ +Fix a crash in free-threaded builds that occurs when pickling by name +objects without a ``__module__`` attribute while :data:`sys.modules` +is concurrently being modified. diff --git a/Modules/_pickle.c b/Modules/_pickle.c index 7b87be23269d40..6219706f903159 100644 --- a/Modules/_pickle.c +++ b/Modules/_pickle.c @@ -2055,22 +2055,34 @@ whichmodule(PickleState *st, PyObject *global, PyObject *global_name, PyObject * return NULL; } if (PyDict_CheckExact(modules)) { + PyObject *found_name = NULL; + int error = 0; i = 0; + Py_BEGIN_CRITICAL_SECTION(modules); while (PyDict_Next(modules, &i, &module_name, &module)) { Py_INCREF(module_name); Py_INCREF(module); if (_checkmodule(module_name, module, global, dotted_path) == 0) { Py_DECREF(module); - Py_DECREF(modules); - return module_name; + found_name = module_name; + break; } Py_DECREF(module); Py_DECREF(module_name); if (PyErr_Occurred()) { - Py_DECREF(modules); - return NULL; + error = 1; + break; } } + Py_END_CRITICAL_SECTION(); + if (error) { + Py_DECREF(modules); + return NULL; + } + if (found_name != NULL) { + Py_DECREF(modules); + return found_name; + } } else { PyObject *iterator = PyObject_GetIter(modules); From 3a12e9f5242c1a2d9ce34ed04159f501b3795bba Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 1 Jun 2026 18:07:33 +0200 Subject: [PATCH 185/818] [3.15] gh-149534: Fix unification of `defaultdict` and `frozendict` with `|` (GH-149539) (#150709) gh-149534: Fix unification of `defaultdict` and `frozendict` with `|` (GH-149539) (cherry picked from commit cc0269334fdf7be12de79316882befd5cdb4cf7e) Co-authored-by: sobolevn <mail@sobolevn.me> --- Lib/test/test_defaultdict.py | 12 ++++++++++++ .../2026-05-08-09-11-48.gh-issue-149534.Tw7eeY.rst | 1 + Modules/_collectionsmodule.c | 2 +- 3 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2026-05-08-09-11-48.gh-issue-149534.Tw7eeY.rst diff --git a/Lib/test/test_defaultdict.py b/Lib/test/test_defaultdict.py index a193eb10f16d17..cc78f01e3e2ebd 100644 --- a/Lib/test/test_defaultdict.py +++ b/Lib/test/test_defaultdict.py @@ -186,6 +186,18 @@ def test_union(self): with self.assertRaises(TypeError): i |= None + # frozendict + i_fd = i | frozendict(s) + self.assertIs(type(i_fd), defaultdict) + self.assertIs(i_fd.default_factory, int) + self.assertDictEqual(i_fd, {1: "one", 2: 2, 0: "zero"}) + self.assertEqual(list(i_fd), [1, 2, 0]) + + fd_i = frozendict(s) | i + self.assertIs(type(fd_i), frozendict) + self.assertEqual(fd_i, {1: "one", 2: 2, 0: "zero"}) + self.assertEqual(list(fd_i), [0, 1, 2]) + def test_factory_conflict_with_set_value(self): key = "conflict_test" count = 0 diff --git a/Misc/NEWS.d/next/Library/2026-05-08-09-11-48.gh-issue-149534.Tw7eeY.rst b/Misc/NEWS.d/next/Library/2026-05-08-09-11-48.gh-issue-149534.Tw7eeY.rst new file mode 100644 index 00000000000000..0938935a75d8c1 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-05-08-09-11-48.gh-issue-149534.Tw7eeY.rst @@ -0,0 +1 @@ +Fix merging of :class:`collections.defaultdict` and :class:`frozendict`. diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c index d702d655a406b6..541ca48633bb56 100644 --- a/Modules/_collectionsmodule.c +++ b/Modules/_collectionsmodule.c @@ -2421,7 +2421,7 @@ defdict_or(PyObject* left, PyObject* right) self = right; other = left; } - if (!PyDict_Check(other)) { + if (!PyAnyDict_Check(other)) { Py_RETURN_NOTIMPLEMENTED; } // Like copy(), this calls the object's class. From 9c1e3af17a9645ca7318b2d48481c832aebf8eae Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 1 Jun 2026 19:39:51 +0200 Subject: [PATCH 186/818] [3.15] gh-121109: Fix performance of tarfile reading with "r|*" (GH-121296) (GH-150604) (cherry picked from commit 6d7a19e5334636f77cac135120fe81f343a73876) Co-authored-by: Tomi Belan <tomi.belan@gmail.com> --- Lib/tarfile.py | 58 ++++++++++++------- Misc/ACKS | 1 + ...-07-02-20-57-43.gh-issue-121109.Tp6R2s.rst | 2 + 3 files changed, 39 insertions(+), 22 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2024-07-02-20-57-43.gh-issue-121109.Tp6R2s.rst diff --git a/Lib/tarfile.py b/Lib/tarfile.py index 5bf2ede090100a..55e4a4e0c9a29c 100644 --- a/Lib/tarfile.py +++ b/Lib/tarfile.py @@ -380,7 +380,6 @@ def __init__(self, name, mode, comptype, fileobj, bufsize, except ImportError: raise CompressionError("bz2 module is not available") from None if mode == "r": - self.dbuf = b"" self.cmp = bz2.BZ2Decompressor() self.exception = OSError else: @@ -392,7 +391,6 @@ def __init__(self, name, mode, comptype, fileobj, bufsize, except ImportError: raise CompressionError("lzma module is not available") from None if mode == "r": - self.dbuf = b"" self.cmp = lzma.LZMADecompressor() self.exception = lzma.LZMAError else: @@ -403,7 +401,6 @@ def __init__(self, name, mode, comptype, fileobj, bufsize, except ImportError: raise CompressionError("compression.zstd module is not available") from None if mode == "r": - self.dbuf = b"" self.cmp = zstd.ZstdDecompressor() self.exception = zstd.ZstdError else: @@ -485,7 +482,6 @@ def _init_read_gz(self): """Initialize for reading a gzip compressed fileobj. """ self.cmp = self.zlib.decompressobj(-self.zlib.MAX_WBITS) - self.dbuf = b"" # taken from gzip.GzipFile with some alterations if self.__read(2) != b"\037\213": @@ -543,26 +539,44 @@ def _read(self, size): if self.comptype == "tar": return self.__read(size) - c = len(self.dbuf) - t = [self.dbuf] + c = 0 + t = [] while c < size: - # Skip underlying buffer to avoid unaligned double buffering. - if self.buf: - buf = self.buf - self.buf = b"" + if self.comptype == "gz": + # zlib interface is different than others. + # It returns data in unconsumed_tail. + if self.buf: + cbuf = self.buf + self.buf = b"" + else: + cbuf = self.fileobj.read(self.bufsize) + if not cbuf: + break + + try: + dbuf = self.cmp.decompress(cbuf, size - c) + self.buf = self.cmp.unconsumed_tail + except self.exception as e: + raise ReadError("invalid compressed data") from e else: - buf = self.fileobj.read(self.bufsize) - if not buf: - break - try: - buf = self.cmp.decompress(buf) - except self.exception as e: - raise ReadError("invalid compressed data") from e - t.append(buf) - c += len(buf) - t = b"".join(t) - self.dbuf = t[size:] - return t[:size] + # Other decompressors have needs_input. + # decompress() can buffer data internally. + if self.cmp.needs_input: + cbuf = self.fileobj.read(self.bufsize) + if not cbuf: + break + else: + cbuf = b"" + + try: + dbuf = self.cmp.decompress(cbuf, size - c) + except self.exception as e: + raise ReadError("invalid compressed data") from e + + t.append(dbuf) + c += len(dbuf) + + return b"".join(t) def __read(self, size): """Return size bytes from stream. If internal buffer is empty, diff --git a/Misc/ACKS b/Misc/ACKS index 234d0d2d0a2a16..14f0db7549534b 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -144,6 +144,7 @@ Bas van Beek Ian Beer Stefan Behnel Reimer Behrends +Tomi Belan Maxime Bélanger Ben Bell Thomas Bellman diff --git a/Misc/NEWS.d/next/Library/2024-07-02-20-57-43.gh-issue-121109.Tp6R2s.rst b/Misc/NEWS.d/next/Library/2024-07-02-20-57-43.gh-issue-121109.Tp6R2s.rst new file mode 100644 index 00000000000000..eca6014e4a0aed --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-07-02-20-57-43.gh-issue-121109.Tp6R2s.rst @@ -0,0 +1,2 @@ +Fix :mod:`tarfile` performance issue when reading archives in streaming mode +(e.g. ``r|*``). From 7e9057d89239c7e1f5615075ec539743861be684 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 1 Jun 2026 21:31:36 +0200 Subject: [PATCH 187/818] [3.15] gh-148672: Document namespace subpackages inside regular packages (GH-150056) (#150729) gh-148672: Document namespace subpackages inside regular packages (GH-150056) (cherry picked from commit 9ba2a891798a06508f63e216d3a1b6907b39eec4) Co-authored-by: Taeknology <20297177+Taeknology@users.noreply.github.com> --- Doc/reference/import.rst | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Doc/reference/import.rst b/Doc/reference/import.rst index 83f0ee75e7aebd..4c8811560de2e3 100644 --- a/Doc/reference/import.rst +++ b/Doc/reference/import.rst @@ -122,6 +122,12 @@ Importing ``parent.one`` will implicitly execute ``parent/__init__.py`` and ``parent.three`` will execute ``parent/two/__init__.py`` and ``parent/three/__init__.py`` respectively. +A subdirectory inside a regular package that does not contain an +``__init__.py`` file is treated as an implicit +:ref:`namespace package <reference-namespace-package>` (a "namespace +subpackage") rooted in that parent. See :pep:`420` for the underlying +specification. + .. _reference-namespace-package: @@ -153,6 +159,12 @@ physically located next to ``parent/two``. In this case, Python will create a namespace package for the top-level ``parent`` package whenever it or one of its subpackages is imported. +Namespace packages may also be nested inside a regular package. When the +import system searches a regular package's ``__path__`` and encounters a +subdirectory that does not contain an ``__init__.py`` file, that +subdirectory becomes a :term:`portion` contributing to a namespace +subpackage of the enclosing regular package. + See also :pep:`420` for the namespace package specification. From a4781e601454eac60b55962d5d386cdf20138e26 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 1 Jun 2026 22:58:05 +0200 Subject: [PATCH 188/818] [3.15] gh-150429: Fix sampling profiler generator stack test (GH-150433) (#150734) --- .../test_sampling_profiler/test_blocking.py | 71 ++++++++++++------- 1 file changed, 45 insertions(+), 26 deletions(-) diff --git a/Lib/test/test_profiling/test_sampling_profiler/test_blocking.py b/Lib/test/test_profiling/test_sampling_profiler/test_blocking.py index 102eb51b556cc7..1f4b6da3281056 100644 --- a/Lib/test/test_profiling/test_sampling_profiler/test_blocking.py +++ b/Lib/test/test_profiling/test_sampling_profiler/test_blocking.py @@ -39,8 +39,9 @@ class TestBlockingModeStackAccuracy(unittest.TestCase): @classmethod def setUpClass(cls): # Test script that uses a generator consumed in a loop. - # When consume_generator is on the arithmetic lines (temp1, temp2, etc.), - # fibonacci_generator should NOT be in the stack at all. + # When consume_generator is the executing leaf frame on the arithmetic + # lines (temp1, temp2, etc.), fibonacci_generator should NOT be in the + # stack at all. # Line numbers are important here - see ARITHMETIC_LINES below. cls.generator_script = textwrap.dedent(''' def fibonacci_generator(n): @@ -65,29 +66,32 @@ def main(): main() ''') # Line numbers of the arithmetic operations in consume_generator. - # These are the lines where fibonacci_generator should NOT be in the stack. - # The socket injection code adds 7 lines before our script. - # temp1 = value + 1 -> line 17 - # temp2 = value * 2 -> line 18 - # temp3 = value - 1 -> line 19 - # result = ... -> line 20 - cls.ARITHMETIC_LINES = {17, 18, 19, 20} + # These are the lines where fibonacci_generator should NOT be in the + # stack when consume_generator is the executing leaf frame. They account + # for the socket prelude added by test_subprocess(). + # temp1 = value + 1 -> line 16 + # temp2 = value * 2 -> line 17 + # temp3 = value - 1 -> line 18 + # result = ... -> line 19 + cls.ARITHMETIC_LINES = {16, 17, 18, 19} def test_generator_not_under_consumer_arithmetic(self): """Test that fibonacci_generator doesn't appear when consume_generator does arithmetic. - When consume_generator is executing arithmetic lines (temp1, temp2, etc.), - fibonacci_generator should NOT be anywhere in the stack - it's not being - called at that point. + When consume_generator is the leaf frame on arithmetic lines (temp1, + temp2, etc.), fibonacci_generator should NOT be anywhere in the stack - + it's not being called at that point. Non-leaf frame line numbers are + caller/resume metadata, not proof that the frame is executing. Valid stacks: - - consume_generator at 'for value in gen:' line WITH fibonacci_generator - at the top (generator is yielding) + - fibonacci_generator at the top (generator is executing), with + consume_generator below it - consume_generator at arithmetic lines WITHOUT fibonacci_generator (we're just doing math, not calling the generator) Invalid stacks (indicate torn/inconsistent reads): - - consume_generator at arithmetic lines WITH fibonacci_generator + - consume_generator leaf frame at arithmetic lines WITH + fibonacci_generator anywhere in the stack Note: call_tree is ordered from bottom (index 0) to top (index -1). @@ -110,6 +114,8 @@ def test_generator_not_under_consumer_arithmetic(self): total_samples = 0 invalid_stacks = 0 arithmetic_samples = 0 + generator_samples = 0 + generator_not_leaf_samples = 0 for (call_tree, _thread_id), count in collector.stack_counter.items(): total_samples += count @@ -117,15 +123,21 @@ def test_generator_not_under_consumer_arithmetic(self): if not call_tree: continue - # Find consume_generator in the stack and check its line number - for i, (filename, lineno, funcname) in enumerate(call_tree): - if funcname == "consume_generator" and lineno in self.ARITHMETIC_LINES: - arithmetic_samples += count - # Check if fibonacci_generator appears anywhere in this stack - func_names = [frame[2] for frame in call_tree] - if "fibonacci_generator" in func_names: - invalid_stacks += count - break + # Non-leaf frame line numbers can point at resume locations while + # a callee is the executing leaf frame. + _, lineno, funcname = call_tree[-1] + func_names = [frame[2] for frame in call_tree] + + if "fibonacci_generator" in func_names: + generator_samples += count + if funcname != "fibonacci_generator": + generator_not_leaf_samples += count + + if funcname == "consume_generator" and lineno in self.ARITHMETIC_LINES: + arithmetic_samples += count + # Check if fibonacci_generator appears anywhere in this stack. + if "fibonacci_generator" in func_names: + invalid_stacks += count self.assertGreater(total_samples, 10, f"Expected at least 10 samples, got {total_samples}") @@ -134,8 +146,15 @@ def test_generator_not_under_consumer_arithmetic(self): self.assertGreater(arithmetic_samples, 0, f"Expected some samples on arithmetic lines, got {arithmetic_samples}") + self.assertGreater(generator_samples, 0, + f"Expected some samples in fibonacci_generator, got {generator_samples}") + + self.assertEqual(generator_not_leaf_samples, 0, + f"Found {generator_not_leaf_samples}/{generator_samples} stacks where " + f"fibonacci_generator appears but is not the leaf frame.") + self.assertEqual(invalid_stacks, 0, f"Found {invalid_stacks}/{arithmetic_samples} invalid stacks where " f"fibonacci_generator appears in the stack when consume_generator " - f"is on an arithmetic line. This indicates torn/inconsistent stack " - f"traces are being captured.") + f"is the leaf frame on an arithmetic line. This indicates " + f"torn/inconsistent stack traces are being captured.") From a4f33368700c8a873d363e1b171b66331c69a8a0 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 2 Jun 2026 00:24:31 +0200 Subject: [PATCH 189/818] [3.15] gh-148508: Add another common pattern for iOS SSL failures to test_ssl (GH-150442) (#150697) gh-148508: Add another common pattern for iOS SSL failures to test_ssl (GH-150442) Match also '[SSL: HTTP_REQUEST] http request (_ssl.c:1143)'. (cherry picked from commit 540b3d0a7fa7cd842f064f79b1410cbd6868bffa) Co-authored-by: Russell Keith-Magee <russell@keith-magee.com> --- Lib/test/test_ssl.py | 15 +++++++++++---- Platforms/Apple/testbed/__main__.py | 2 +- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py index f1f7a07701de16..b51fc3cf09ff8a 100644 --- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py @@ -5642,17 +5642,24 @@ def non_linux_skip_if_other_okay_error(self, err): return # Expect the full test setup to always work on Linux. if (isinstance(err, ConnectionResetError) or (isinstance(err, OSError) and err.errno == errno.EINVAL) or - re.search('wrong.version.number', str(getattr(err, "reason", "")), re.I) or - re.search('record.layer.failure', str(getattr(err, "reason", "")), re.I) + re.search( + # Matches the following error messages: + # '[SSL: WRONG_VERSION_NUMBER] wrong version number (_ssl.c:1123)' + # '[SSL: RECORD_LAYER_FAILURE] record layer failure (_ssl.c:1109)' + # '[SSL: HTTP_REQUEST] http request (_ssl.c:1143)' + r'wrong.version.number|record.layer.failure|http.request', + str(getattr(err, "reason", "")), + re.IGNORECASE, + ) ): # On Windows the TCP RST leads to a ConnectionResetError # (ECONNRESET) which Linux doesn't appear to surface to userspace. # If wrap_socket() winds up on the "if connected:" path and doing # the actual wrapping... we get an SSLError from OpenSSL. This is # typically WRONG_VERSION_NUMBER. The same happens on iOS, but - # RECORD_LAYER_FAILURE is the error. + # RECORD_LAYER_FAILURE or HTTP_REQUEST is the error. # - # While appropriate, neither is the scenario we're specifically + # While appropriate, these scenarios aren't what we're specifically # trying to test. The way this test is written is known to work on # Linux. We'll skip it anywhere else that it does not present as # doing so. diff --git a/Platforms/Apple/testbed/__main__.py b/Platforms/Apple/testbed/__main__.py index 0dd77ab8b82797..b3eed38571d970 100644 --- a/Platforms/Apple/testbed/__main__.py +++ b/Platforms/Apple/testbed/__main__.py @@ -21,7 +21,7 @@ LOG_PREFIX_REGEX = re.compile( r"^\d{4}-\d{2}-\d{2}" # YYYY-MM-DD r"\s+\d+:\d{2}:\d{2}\.\d+\+\d{4}" # HH:MM:SS.ssssss+ZZZZ - r"\s+iOSTestbed\[\d+:\w+\]" # Process/thread ID + r"\s+iOSTestbed\[\d+:\w+\] " # Process/thread ID ) From 042428f443483ae49948346601c187f23060810a Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 2 Jun 2026 00:53:51 +0200 Subject: [PATCH 190/818] [3.15] gh-150644: Tag Apple system log messages as public. (GH-150645) (#150738) macOS 26 changed the default visibility of "dynamic" system messages. This changes the logging strategy to tag all messages as "public" so they are visible in the system log without special configuration. (cherry picked from commit 71fc4c66d3e675a5481b6b76e6c707c9b6f1e0e0) Co-authored-by: Russell Keith-Magee <russell@keith-magee.com> --- .../next/macOS/2026-05-31-10-40-00.gh-issue-150644.zLWyjj.rst | 3 +++ Python/pylifecycle.c | 4 +++- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/macOS/2026-05-31-10-40-00.gh-issue-150644.zLWyjj.rst diff --git a/Misc/NEWS.d/next/macOS/2026-05-31-10-40-00.gh-issue-150644.zLWyjj.rst b/Misc/NEWS.d/next/macOS/2026-05-31-10-40-00.gh-issue-150644.zLWyjj.rst new file mode 100644 index 00000000000000..7452a7c765c0a8 --- /dev/null +++ b/Misc/NEWS.d/next/macOS/2026-05-31-10-40-00.gh-issue-150644.zLWyjj.rst @@ -0,0 +1,3 @@ +When system logging is enabled (with ``config.use_system_logger``, messages +are now tagged as public. This allows the macOS 26 system logger to view +messages without special configuration. diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 46579a45f4cc39..f8d9836d90ba78 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -3324,7 +3324,9 @@ apple_log_write_impl(PyObject *self, PyObject *args) // Pass the user-provided text through explicit %s formatting // to avoid % literals being interpreted as a formatting directive. - os_log_with_type(OS_LOG_DEFAULT, logtype, "%s", text); + // Using {public} ensures "dynamic" string messages are visible + // in the log without special configuration. + os_log_with_type(OS_LOG_DEFAULT, logtype, "%{public}s", text); Py_RETURN_NONE; } From 848ba18bcd31335051e0d085b5ef8eee49e35511 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 2 Jun 2026 04:11:51 +0200 Subject: [PATCH 191/818] [3.15] gh-150228: Improve the PEP 829 batch processing APIs (GH-150542) (#150748) gh-150228: Improve the PEP 829 batch processing APIs (GH-150542) * gh-150228: Improve the PEP 829 batch processing APIs As previously discussed with @ncoghlan and approved for 3.15b2 by @hugovk, this implements the batch processing APIs for addsitedir() and friends. We remove the `defer_processing_start_files` flag which required some implicit module global state, and promote StartupState to the public documented API. This also moves the bulk of the module global functions into methods of the `StartupState` class, so it removes the awkward APIs in 3.15b1. Now, instances of this class are an accumulator for startup state, using `StartupState.process()` to process them. Callers can now batch up startup state themselves by using the methods on this class. The module global functions are shims for this which preserve the legacy APIs and semantics using the new state class. This PR also fixes the interleaving regression identified by @ncoghlan in the same issue. Now, .pth file sys.path extensions are added to sys.path after the sitedir that the .pth file is found in, restoring the legacy behavior. Along the way, I've made a lot of improvements to function docstrings, site.rst documentation, and comments in the code explaining what's going on. * Add a note that if known_paths is provided to StartupState.__init__(), it will get mutated in place. * Improve some conditional flows. * Improve some comments. * Improve the what's new entry. * Make test_impl_exec_imports_suppressed_by_matching_start() more robust Based on PR comment, we need to read both the .pth and .start files, and prove that the .pth file's import line (which passes a bigger increment) is not called, but the .start file's entry point (which uses the default increment) is called. * As per review, move some methods to the private API _read_pth_file() and _read_start_file() are not intended to be part of the public API surface outside of the site module, so even though they are used by methods outside of the StartupState class, make them privately named. * Resolve several review feedbacks * Move a `versionadded` * Better list comprehension formatting (use the output from `ruff format --line-length 78`) * Add docs for site.makepath() and point the case-normalization requirement to this utility function. * Note that StartupState.process() is not idempotent. * Address another feedback comment This time, we get rid of the legacy implementation `reset` local, which was always difficult to understand, and just implement a return value based on the processing mode selected. * Changes based on gh-150228 review The comment by @encukou that started this change: ``` I still see two red flags here though: an argument that doesn't combine with other arguments, and (another instance of) changing the return type based on an argument. Did you consider adding a StartupState.addsitedir(sitedir) method, instead of the startup_state argument? ``` As it turns out, this is an even cleaner design. By moving the bulk of the previous module global functions into `StartupState` methods, we can get rid of all the awkward `startup_state` keyword-only arguments which conflict with `known_path` (Petr's first point). We can also get rid of the return value dichotomy (Petr's second point) because now we can preserve exactly the Python 3.14 API in the module global functions, and implement the better APIs in the class methods. We also generally don't have to pass around `process_known_sitedirs`. Now the following module global functions are essentially shims around class methods: * site.addsitedir() -> StartupState.addsitedir() * site.addusersitepackages() -> StartupState.addusersitepackages() * site.addsitepackages() -> StartupState.addsitepackages() * Additional minor changes * Remove a now unused parameter (cherry picked from commit 27ebd9abce76543e95748a7534e5218acd514db2) Co-authored-by: Barry Warsaw <barry@python.org> Co-authored-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> --- Doc/library/site.rst | 87 +++- Doc/whatsnew/3.15.rst | 13 +- Lib/site.py | 463 ++++++++++-------- Lib/test/test_site.py | 321 ++++++------ ...-05-27-11-18-36.gh-issue-150228.pNPiO-.rst | 11 + 5 files changed, 527 insertions(+), 368 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-05-27-11-18-36.gh-issue-150228.pNPiO-.rst diff --git a/Doc/library/site.rst b/Doc/library/site.rst index 656fbd142dfb0f..11a5484c2b1336 100644 --- a/Doc/library/site.rst +++ b/Doc/library/site.rst @@ -356,7 +356,79 @@ Module contents This function used to be called unconditionally. -.. function:: addsitedir(sitedir, known_paths=None, *, defer_processing_start_files=False) +.. function:: makepath(*paths) + + Join *paths* with :func:`os.path.join`, attempt to make the result + absolute with :func:`os.path.abspath`, and return a 2-tuple containing + the absolute path and its case-normalized form as produced by + :func:`os.path.normcase`. If :func:`os.path.abspath` raises + :exc:`OSError`, the joined path is used unchanged for the + case-normalization step. + + The second element of the returned tuple is the form used throughout the + :mod:`!site` module to compare paths on case-insensitive file systems, and + is what populates the ``known_paths`` sets that prevent duplicate + :data:`sys.path` entries in various APIs within this module. + + +.. class:: StartupState(known_paths=None) + + Instances of this class accumulate interpreter startup configuration data + from one or more site directories. They are the preferred interface for + batching the processing of :file:`.pth` and :file:`.start` files across + multiple site directories, so that every :data:`sys.path` extension is + visible before any startup code runs. + + The optional *known_paths* argument is a set of case-normalized paths + (which can be produced by :func:`makepath`) used to prevent duplicate + :data:`sys.path` entries. When ``None`` (the default), the set is built + from the current :data:`sys.path`. :func:`main` implicitly uses an + instance of this class. + + Typical use: + + .. code-block:: python + + state = site.StartupState() + for sitedir in site_dirs: + state.addsitedir(sitedir) + state.process() + + .. versionadded:: 3.15 + + .. method:: addsitedir(sitedir) + + Read the :file:`.pth` and :file:`.start` files in *sitedir* and + record their :data:`sys.path` extensions, deprecated :file:`.pth` + ``import`` lines, and :file:`.start` entry points on this state. + The recorded data is not applied until :meth:`process` is called. + + .. method:: addusersitepackages() + + Add the per-user site-packages directory, if enabled and if it exists. + The directory's startup data is accumulated for later processing by + :meth:`process`. + + .. method:: addsitepackages(prefixes=None) + + Add global site-packages directories, computed from *prefixes* or from + the global :data:`PREFIXES` when *prefixes* is ``None``. Each + directory's startup data is accumulated for later processing by + :meth:`process`. + + .. method:: process() + + Apply the accumulated state by first adding the path extensions to + :data:`sys.path`, then executing the :file:`.start` file entry points + and :file:`.pth` file ``import`` lines (:ref:`deprecated + <site-pth-files>`). + + This method is not idempotent and must not be called more than once + on the same instance. Doing so will apply the accumulated state + more than once, re-running entry points and ``import`` lines. + + +.. function:: addsitedir(sitedir, known_paths=None) Add a directory to sys.path and parse the :file:`.pth` and :file:`.start` files found in that directory. Typically used in :mod:`sitecustomize` or @@ -366,17 +438,15 @@ Module contents used to prevent duplicate :data:`sys.path` entries. When ``None`` (the default), the set is built from the current :data:`sys.path`. - While :file:`.pth` and :file:`.start` files are always parsed, set - *defer_processing_start_files* to ``True`` to prevent processing the - startup data found in those files, so that you can process them explicitly - (this is typically used by the :func:`main` function). + For batched processing across multiple site directories, build a + :class:`StartupState` explicitly and call :meth:`StartupState.addsitedir` + on it; that defers :file:`.pth` and :file:`.start` processing until a + single :meth:`StartupState.process` call, ensuring every :data:`sys.path` + extension is visible before any startup code runs. .. versionchanged:: 3.15 Also processes :file:`.start` files. See :ref:`site-start-files`. - All :file:`.pth` and :file:`.start` files are now read and - accumulated before any path extensions, ``import`` line execution, - or entry point invocations take place. .. function:: getsitepackages() @@ -447,4 +517,3 @@ value greater than 2 if there is an error. * :pep:`370` -- Per user site-packages directory * :pep:`829` -- Startup entry points and the deprecation of import lines in ``.pth`` files * :ref:`sys-path-init` -- The initialization of :data:`sys.path`. - diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst index 5ef4e36241af2c..371a9feb861393 100644 --- a/Doc/whatsnew/3.15.rst +++ b/Doc/whatsnew/3.15.rst @@ -479,7 +479,18 @@ matching :file:`.start` file is found, ``import`` lines in :file:`.pth` files are ignored. There is no change to :data:`sys.path` extension lines in :file:`.pth` files. -(Contributed by Barry Warsaw in :gh:`148641`.) +The :mod:`site` module also provides :class:`site.StartupState` to batch +startup processing for multiple site directories, ensuring all static path +extensions are applied before any startup code is executed. :func:`site.main` +uses an instance of this class implicitly to batch process all startup +configuration files during normal interpreter startup. Callers needing the +same batching behavior can build a :class:`~site.StartupState` directly and +drive it with :meth:`~site.StartupState.addsitedir`, +:meth:`~site.StartupState.addusersitepackages`, and +:meth:`~site.StartupState.addsitepackages`, then call +:meth:`~site.StartupState.process` once at the end of the batch. + +(Contributed by Barry Warsaw in :gh:`148641` and :gh:`150228`.) .. _whatsnew315-abi3t: diff --git a/Lib/site.py b/Lib/site.py index 239ee0d6f57bce..b7f5c7f0246bc1 100644 --- a/Lib/site.py +++ b/Lib/site.py @@ -157,34 +157,24 @@ def _init_pathinfo(): # PEP 829 implementation notes. # # Startup information (.pth and .start file information) can be processed in -# implicit or explicit batches. Implicit batches are handled by the site.py -# machinery automatically, while explicit batches are driven by user code and -# processed on boundaries defined by that code. -# -# addsitedir() calls which use the default defer_processing_start_files=False -# are self-contained: they create a per-call _StartupState, populate it from -# the site directory's .pth/.start files, run process() on it, and then throw -# the state away. This is implicit batching and in that case the -# _startup_state global variable stays None. +# implicit or explicit batches. Implicit batches are self-contained +# site.addsitedir() calls: they create a per-call StartupState, populate it +# from the site directory's .pth and .start files, run process() on it, and +# then throw the state away. # # main() needs different semantics: it accumulates state across multiple -# addsitedir() calls (user-site plus all global site-packages) so that -# every sys.path extension is visible *before* any startup code (.pth -# import lines and .start entry points) runs. Callers opt into this by -# passing defer_processing_start_files=True, which preserves the _StartupState -# into the global _startup_state. Subsequent addsitedir() calls (with -# or without defer_processing_start_files=True) then write into that -# same shared state, and a later process_startup_files() call flushes -# all the state and resets the global to None. +# StartupState.addsitedir() calls (user-site plus all global site-packages) so +# that every sys.path extension is visible *before* any startup code (.start +# entry points and .pth import lines) runs. Callers can opt into the same +# behavior by creating a StartupState directly and calling its addsitedir(), +# addusersitepackages(), and addsitepackages() methods, then invoking +# process() once at the end of the batch. # -# Here's the CRITICAL reentrancy invariant: process_startup_files() must clear -# the global _startup_state *before* calling state.process(), so that any -# reentrant site.addsitedir() calls reached from an exec'd .pth import line or -# a .start entry point falls into the per-call branch and gets its own fresh -# state. Otherwise the recursive addsitedir() would mutate the very dicts -# that the outer state.process() is iterating. This is the bug reported in -# gh-149504. -_startup_state = None +# Here's the CRITICAL reentrancy invariant: recursive site.addsitedir() calls +# reached from a .start entry point or an exec'd .pth import line must not +# mutate the StartupState currently being processed. Reentrant calls reach +# the module-level site.addsitedir() shim, which always builds a fresh +# per-call state. def _read_pthstart_file(sitedir, name, suffix): @@ -238,45 +228,174 @@ def _read_pthstart_file(sitedir, name, suffix): return content.splitlines(), filename -class _StartupState: +class StartupState: """Per-batch accumulator for .pth and .start file processing. - A _StartupState collects sys.path extensions, deprecated .pth import - lines, and .start entry points read from one or more site-packages - directories. Calling process() applies them in PEP 829 order: paths - are added to sys.path first, then import lines from .pth files (skipping - any with a matching .start), then entry points from .start files. + A StartupState collects sys.path extensions, deprecated .pth import lines, + and .start entry points read from one or more site-packages directories. + Calling process() applies them in PEP 829 order: paths are added to + sys.path first, then import lines from .pth files (skipping any with a + matching .start), then entry points from .start files. State lives entirely on the instance; there is no module-level pending state. This is what makes the module reentrancy-safe: a site.addsitedir() call reached recursively from an exec'd import line or a .start entry - point operates on a different _StartupState than the one being processed - by the outer call. + point operates on a different StartupState than the one being processed by + the outer call. - The internal data is intentionally private; the public methods - (read_pth_file, read_start_file, process) are the only supported write - APIs. + The internal data is intentionally private. The lower-level write + methods (_record_sitedir(), _read_pth_file(), _read_start_file()) are + private to the site module; the public surface is addsitedir(), + addusersitepackages(), addsitepackages(), and process(). """ - __slots__ = ('_syspaths', '_importexecs', '_entrypoints') + __slots__ = ( + '_known_paths', + '_processed_sitedirs', + '_path_entries', + '_importexecs', + '_entrypoints', + ) + + def __init__(self, known_paths=None): + """Create an independent startup state. + + *known_paths* is a set of case-normalized paths already present + on sys.path, used to avoid duplicate path entries. When None + (the default), it is initialized from the current sys.path. - def __init__(self): - # All three dicts map "<full path to .pth or .start file>" -> list + A caller-supplied set is stored by reference and mutated in place + as new paths are recorded; pass a fresh set per StartupState if + isolation across instances is required. + """ + self._known_paths = ( + _init_pathinfo() + if known_paths is None + else known_paths) + self._processed_sitedirs = set() + # The sys.path append ledger. This is a list of 2-tuples of the form + # (pthfile, path) where `pthfile` is the .pth file which is extending + # the path, and `path` is the directory to add to sys.path. Note that + # to preserve the interleaving semantics (i.e. .pth file paths are + # added after the sitedir in which the .pth file is found), `path` + # could be a sitedir, in which case `pthfile` will always be None. + self._path_entries = [] + # Both dicts map "<full path to .pth or .start file>" -> list # of items collected from that file. Mapping by filename lets us # cross-reference a .pth and its matching .start (PEP 829 import # suppression rule) and lets _print_error report the source file # when an entry fails. - self._syspaths = {} self._importexecs = {} self._entrypoints = {} - def read_pth_file(self, sitedir, name, known_paths): + def addsitedir(self, sitedir): + """Add a site directory and accumulate its .pth and .start startup data. + + Read the .pth and .start files in *sitedir* and record their + sys.path extensions, deprecated .pth import lines, and .start entry + points on this state. The recorded data is not applied until + process() is called. + + Typically used to batch multiple site directories before a single + process() call, so that every sys.path extension is visible before + any startup code runs. Reentrant calls reached from a .start entry + point or an exec'd .pth import line must not mutate the state + currently being processed; for those cases, use site.addsitedir() + instead, which always creates a fresh per-call state. + """ + self._addsitedir(sitedir, process_known_sitedirs=True) + + def addusersitepackages(self): + """Add the per-user site-packages directory, if enabled. + + The user site directory is added only when user site-packages are + enabled and the directory exists. Its startup data is accumulated + for later processing by process(). + """ + _trace("Processing user site-packages") + user_site = getusersitepackages() + if ENABLE_USER_SITE and os.path.isdir(user_site): + self.addsitedir(user_site) + + def addsitepackages(self, prefixes=None): + """Add global site-packages directories, if they exist. + + Site-packages directories are computed from *prefixes*, or from the + global PREFIXES when *prefixes* is None. Each directory's startup + data is accumulated for later processing by process(). + """ + _trace("Processing global site-packages") + for sitedir in getsitepackages(prefixes): + if os.path.isdir(sitedir): + self.addsitedir(sitedir) + + def _addsitedir(self, sitedir, *, process_known_sitedirs): + """Internal addsitedir() implementation with full dedup control. + + The public addsitedir() always uses process_known_sitedirs=True + (gh-149819 semantics). The module-level legacy known_paths shim + uses process_known_sitedirs=False to preserve 3.14 idempotency + (gh-75723). + """ + sitedir = self._record_sitedir( + sitedir, process_known_sitedirs=process_known_sitedirs) + if sitedir is None: + return + try: + names = os.listdir(sitedir) + except OSError: + return + + # The following phases are defined by PEP 829. + # Phases 1-3: Read .pth files, accumulating paths and import lines. + pth_names = sorted( + name for name in names + if name.endswith(".pth") and not name.startswith(".") + ) + for name in pth_names: + self._read_pth_file(sitedir, name) + + # Phases 6-7: Discover .start files and accumulate their entry points. + # Import lines from .pth files with a matching .start file are + # discarded at flush time by _exec_imports(). + start_names = sorted( + name for name in names + if name.endswith(".start") and not name.startswith(".") + ) + for name in start_names: + self._read_start_file(sitedir, name) + + def _record_sitedir(self, sitedir, *, process_known_sitedirs=True): + sitedir, sitedircase = makepath(sitedir) + # Have we already processed this sitedir? + if sitedircase in self._processed_sitedirs: + return None + # In legacy known_paths mode, a known sitedir means its startup files + # were already processed by an earlier addsitedir() call, so skip it + # to preserve idempotency (gh-75723). In explicit StartupState mode, + # known_paths only tracks sys.path entries; a sitedir may already be + # on sys.path (for example from $PYTHONPATH, gh-149819) but still need + # its .pth and .start files processed once. The separate + # _processed_sitedirs set is what lets explicit batches distinguish + # "already on sys.path" from "startup files already read". + if not process_known_sitedirs and sitedircase in self._known_paths: + return None + # Record that we've processed this sitedir. + self._processed_sitedirs.add(sitedircase) + if sitedircase not in self._known_paths: + self._known_paths.add(sitedircase) + # Add the sitedir to the sys.path extension ledger. There is no + # .pth file to record. + self._path_entries.append((None, sitedir)) + return sitedir + + def _read_pth_file(self, sitedir, name): """Parse a .pth file, accumulating sys.path extensions and import lines. Errors on individual lines do not abort processing of the rest of - the file (PEP 829). ``known_paths`` is the per-batch dedup - ledger: any path already in it is skipped, and newly accepted - paths are added to it so that subsequent .pth files in the same - batch don't add them more than once. + the file (PEP 829). Per-batch deduplication is done against + self._known_paths: any path already in it is skipped, and newly + accepted paths are added to it so that subsequent .pth files in + the same batch don't add them more than once. """ lines, filename = _read_pthstart_file(sitedir, name, ".pth") if lines is None: @@ -308,18 +427,19 @@ def read_pth_file(self, sitedir, name, known_paths): _trace(f"Error in {filename!r}, line {n:d}: {line!r}", exc) continue - # PEP 829 dedup: skip paths already seen in this batch. See - # _startup_state docstring above for batch lifetimes. - if dircase in known_paths: + # PEP 829 dedup: skip paths already seen in this batch. + if dircase in self._known_paths: _trace( f"In {filename!r}, line {n:d}: " f"skipping duplicate sys.path entry: {dir_}" ) else: - self._syspaths.setdefault(filename, []).append(dir_) - known_paths.add(dircase) + # Add this directory to the sys.path extension ledger, while + # also recording the .pth file it was found in. + self._path_entries.append((filename, dir_)) + self._known_paths.add(dircase) - def read_start_file(self, sitedir, name): + def _read_start_file(self, sitedir, name): """Parse a .start file for a list of entry point strings.""" lines, filename = _read_pthstart_file(sitedir, name, ".start") if lines is None: @@ -353,20 +473,31 @@ def process(self): self._execute_start_entrypoints() def _extend_syspath(self): - # Duplicates have already been filtered (in existing sys.path or - # across .pth files via known_paths), and entries are already - # abspath/normpath'd, so all that remains is to confirm the path - # exists. - for filename, dirs in self._syspaths.items(): - for dir_ in dirs: - if os.path.exists(dir_): + # Duplicate path-extension specifications have already been filtered + # out upstream across .pth files within this batch (via known_paths), + # and ledger entries are already abspath/normpath'd. .pth-derived + # entries (filename is not None) are existence-checked and skipped + # with an error if missing. Sitedir entries (filename is None) are + # appended unconditionally: legacy addsitedir() added the sitedir to + # sys.path before attempting to list it, so an unreadable or + # non-existent sitedir still landed on sys.path. Deferring the + # append to here preserves that contract. + for filename, dir_ in self._path_entries: + # As a backstop, known_paths may not have been seeded from sys.path + # (callers can pass an empty set), and multiple StartupState + # instances against the same sys.path don't share state, so always + # do a final anti-duplication check. + if dir_ in sys.path: + continue + if filename is None or os.path.exists(dir_): + if filename is not None: _trace(f"Extending sys.path with {dir_} from {filename}") - sys.path.append(dir_) - else: - _print_error( - f"In {filename}: {dir_} does not exist; " - f"skipping sys.path append" - ) + sys.path.append(dir_) + else: + _print_error( + f"In {filename}: {dir_} does not exist; " + f"skipping sys.path append" + ) def _exec_imports(self): # For each `import` line we've seen in a .pth file, exec() it in @@ -435,26 +566,6 @@ def _execute_start_entrypoints(self): ) -def process_startup_files(): - """Flush any pending startup-file state accumulated during a batch. - - Used by main() (and any external caller that drove addsitedir() with - defer_processing_start_files=True) to apply the accumulated paths - and run the deferred import lines / entry points. - - Reentrancy: the active batch state is detached from _startup_state - *before* state.process() runs. This way, if an exec'd import line - or .start entry point itself calls site.addsitedir(), that call - creates its own per-call _StartupState rather than mutating the dicts - being iterated here. See gh-149504. - """ - global _startup_state - if _startup_state is None: - return - state, _startup_state = _startup_state, None - state.process() - - def addpackage(sitedir, name, known_paths): """Process a .pth file within the site-packages directory.""" if known_paths is None: @@ -463,103 +574,31 @@ def addpackage(sitedir, name, known_paths): else: reset = False - # If a batch is already in progress (for example, main() is still - # accumulating sitedirs), participate in the batch by writing into the - # shared _startup_state and letting the eventual process_startup_files() - # flush it. Otherwise this is a standalone call, so create a unique - # per-call state, populate it, and process it before returning. - if _startup_state is None: - state = _StartupState() - state.read_pth_file(sitedir, name, known_paths) - state.process() - else: - _startup_state.read_pth_file(sitedir, name, known_paths) + state = StartupState(known_paths) + state._read_pth_file(sitedir, name) + state.process() return None if reset else known_paths -def addsitedir(sitedir, known_paths=None, *, defer_processing_start_files=False): - """Add 'sitedir' argument to sys.path if missing and handle startup - files.""" - global _startup_state +def addsitedir(sitedir, known_paths=None): + """Add a site directory and process its startup files. + + For batched processing across multiple site directories, build a + StartupState explicitly and call StartupState.addsitedir() on it; that + defers .pth/.start processing until a single StartupState.process() call. + """ _trace(f"Adding directory: {sitedir!r}") if known_paths is None: - known_paths = _init_pathinfo() - reset = True + state = StartupState(_init_pathinfo()) + state.addsitedir(sitedir) else: - reset = False - sitedir, sitedircase = makepath(sitedir) - - # If the normcase'd new sitedir isn't already known, record it to - # prevent re-processing, append it to sys.path (only if not already - # present), and process all .pth and .start files found in that - # directory. Use a direct sys.path membership check for the append - # guard so that callers (like main()) can pass a fresh known_paths - # set while avoiding duplicate sys.path entries (gh-149819). - if sitedircase not in known_paths: - known_paths.add(sitedircase) - if sitedir not in sys.path: - sys.path.append(sitedir) - - try: - names = os.listdir(sitedir) - except OSError: - return None if reset else known_paths - - # Pick the _StartupState we'll write into. There are three cases: - # - # 1. A batch is already active (_startup_state is set, e.g. because - # main() previously called us with - # defer_processing_start_files=True). Participate in this batch by - # sharing the same state. Don't flush the state since the batch's - # eventual process_startup_files() will do that. - # - # 2. There is no active batch but the caller passed - # defer_processing_start_files=True. Preserve a fresh - # _StartupState into the global _startup_state so that subsequent - # addsitedir() calls participate in this batch, and so that the - # caller's later process_startup_files() finds it. - # - # 3. This is a standalone call (there is no active batch and - # defer_processing_start_files=False). Create a unique per-call - # state, populate it, process it, and then clear it. Per-call - # state is what makes reentrant addsitedir() safe; a recursive call - # from inside process() lands here too and gets its own independent - # state. - - if _startup_state is not None: - state = _startup_state - flush_now = False - elif defer_processing_start_files: - state = _startup_state = _StartupState() - flush_now = False - else: - state = _StartupState() - flush_now = True - - # The following phases are defined by PEP 829. - # Phases 1-3: Read .pth files, accumulating paths and import lines. - pth_names = sorted( - name for name in names - if name.endswith(".pth") and not name.startswith(".") - ) - for name in pth_names: - state.read_pth_file(sitedir, name, known_paths) - - # Phases 6-7: Discover .start files and accumulate their entry points. - # Import lines from .pth files with a matching .start file are - # discarded at flush time by _StartupState._exec_imports(). - start_names = sorted( - name for name in names - if name.endswith(".start") and not name.startswith(".") - ) - for name in start_names: - state.read_start_file(sitedir, name) - - if flush_now: - state.process() - - return None if reset else known_paths + # Preserve gh-75723 idempotency for legacy known_paths mode: a + # sitedir already present in known_paths is skipped, not reprocessed. + state = StartupState(known_paths) + state._addsitedir(sitedir, process_known_sitedirs=False) + state.process() + return known_paths def check_enableusersite(): @@ -671,21 +710,20 @@ def getusersitepackages(): return USER_SITE -def addusersitepackages(known_paths, *, defer_processing_start_files=False): - """Add a per user site-package to sys.path - Each user has its own python directory with site-packages in the - home directory. - """ - # get the per user site-package path - # this call will also make sure USER_BASE and USER_SITE are set - _trace("Processing user site-packages") - user_site = getusersitepackages() +def addusersitepackages(known_paths): + """Add the per-user site-packages directory, if enabled. - if ENABLE_USER_SITE and os.path.isdir(user_site): - addsitedir(user_site, known_paths, defer_processing_start_files=defer_processing_start_files) + The user site directory is added only when user site-packages are enabled + and the directory exists. Return *known_paths*, updated with any paths + added by addsitedir(). + """ + state = StartupState(known_paths) + state.addusersitepackages() + state.process() return known_paths + def getsitepackages(prefixes=None): """Returns a list containing all global site-packages directories. @@ -725,15 +763,20 @@ def getsitepackages(prefixes=None): sitepackages.append(os.path.join(prefix, "Lib", "site-packages")) return sitepackages -def addsitepackages(known_paths, prefixes=None, *, defer_processing_start_files=False): - """Add site-packages to sys.path""" - _trace("Processing global site-packages") - for sitedir in getsitepackages(prefixes): - if os.path.isdir(sitedir): - addsitedir(sitedir, known_paths, defer_processing_start_files=defer_processing_start_files) +def addsitepackages(known_paths, prefixes=None): + """Add global site-packages directories, if they exist. + + Site-packages directories are computed from *prefixes*, or from the global + prefixes when *prefixes* is None. Return *known_paths*, updated with any + paths added by addsitedir(). + """ + state = StartupState(known_paths) + state.addsitepackages(prefixes) + state.process() return known_paths + def setquit(): """Define new builtins 'quit' and 'exit'. @@ -900,6 +943,15 @@ def write_history(): def venv(known_paths): + """Process pyvenv.cfg and add the venv site-packages, if applicable.""" + state = StartupState(known_paths) + _venv(state) + state.process() + return known_paths + + +def _venv(state): + """State-driven implementation of venv(); used by main() for batching.""" global PREFIXES, ENABLE_USER_SITE env = os.environ @@ -939,20 +991,22 @@ def venv(known_paths): sys._home = value if sys.prefix != site_prefix: - _warn(f'Unexpected value in sys.prefix, expected {site_prefix}, got {sys.prefix}', RuntimeWarning) + _warn( + f'Unexpected value in sys.prefix, expected {site_prefix}, got {sys.prefix}', + RuntimeWarning) if sys.exec_prefix != site_prefix: - _warn(f'Unexpected value in sys.exec_prefix, expected {site_prefix}, got {sys.exec_prefix}', RuntimeWarning) + _warn( + f'Unexpected value in sys.exec_prefix, expected {site_prefix}, got {sys.exec_prefix}', + RuntimeWarning) - # Doing this here ensures venv takes precedence over user-site - addsitepackages(known_paths, [sys.prefix]) + # Doing this here ensures venv takes precedence over user-site. + state.addsitepackages([sys.prefix]) if system_site == "true": PREFIXES += [sys.base_prefix, sys.base_exec_prefix] else: ENABLE_USER_SITE = False - return known_paths - def execsitecustomize(): """Run custom site specific code, if available.""" @@ -1009,18 +1063,19 @@ def main(): # Fix __file__ of already imported modules too. abs_paths() - known_paths = venv(known_paths=set()) + state = StartupState(set()) + _venv(state) + if ENABLE_USER_SITE is None: ENABLE_USER_SITE = check_enableusersite() - known_paths = addusersitepackages(known_paths, defer_processing_start_files=True) - known_paths = addsitepackages(known_paths, defer_processing_start_files=True) + + state.addusersitepackages() + state.addsitepackages() # PEP 829: flush accumulated data from all .pth and .start files. # Paths are extended first, then deprecated import lines are exec'd, # and finally .start entry points are executed — ensuring sys.path is - # fully populated before any startup code runs. process_startup_files() - # also clears the pending state so a later addsitedir() call does - # not re-apply already-processed data. - process_startup_files() + # fully populated before any startup code runs. + state.process() setquit() setcopyright() sethelper() diff --git a/Lib/test/test_site.py b/Lib/test/test_site.py index e2a81b82321ede..5fd65ad999210e 100644 --- a/Lib/test/test_site.py +++ b/Lib/test/test_site.py @@ -187,20 +187,17 @@ def test_addsitedir(self): self.pth_file_tests(pth_file) def test_addsitedir_explicit_flush(self): - # addsitedir() reads .pth files and, with - # defer_processing_start_files=True, accumulates pending state - # without flushing. A subsequent process_startup_files() call - # then applies the paths and runs the import lines. + # StartupState.addsitedir() reads .pth files and accumulates pending + # state without flushing. A subsequent state.process() call then + # applies the paths and runs the import lines. pth_file = PthFile() # Ensure we have a clean slate. pth_file.cleanup(prep=True) with pth_file.create(): - # Pass defer_processing_start_files=True to prevent flushing. - site.addsitedir( - pth_file.base_dir, set(), - defer_processing_start_files=True) + state = site.StartupState(known_paths=set()) + state.addsitedir(pth_file.base_dir) self.assertNotIn(pth_file.imported, sys.modules) - site.process_startup_files() + state.process() self.pth_file_tests(pth_file) def test_addsitedir_dotfile(self): @@ -915,16 +912,10 @@ class StartFileTests(unittest.TestCase): def setUp(self): self.enterContext(import_helper.DirsOnSysPath()) self.tmpdir = self.sitedir = self.enterContext(os_helper.temp_dir()) - # Each test gets its own _StartupState to drive the parser and - # processor methods directly. Defensively clear any _startup_state - # that a prior test may have left set via defer_processing_start_files - # without a corresponding process_startup_files() flush. - self.state = site._StartupState() - site._startup_state = None - self.addCleanup(self._reset_startup_state) - - def _reset_startup_state(self): - site._startup_state = None + # Each test gets its own StartupState to batch the parsing and + # explicitly invoke the processing. Seed with an empty known_paths + # so dedup is not influenced by the current sys.path. + self.state = site.StartupState(known_paths=set()) def _make_start(self, content, name='testpkg', basedir=None): """Write a <name>.start file and return its basename. @@ -974,16 +965,17 @@ def _make_mod(self, contents, name='mod', *, package=False, on_path=False): sys.path.insert(0, extdir) return extdir - def _all_entrypoints(self): + def _all_entrypoints(self, state=None): """Flatten state._entrypoints into a list of (filename, entry) tuples.""" result = [] - for filename, entries in self.state._entrypoints.items(): + state = self.state if state is None else state + for filename, entries in state._entrypoints.items(): for entry in entries: result.append((filename, entry)) return result - def _just_entrypoints(self): - return [entry for filename, entry in self._all_entrypoints()] + def _just_entrypoints(self, state=None): + return [entry for filename, entry in self._all_entrypoints(state)] # There are two classes of tests here. Tests that start with `test_impl_` # know details about the implementation and they access non-public methods @@ -993,11 +985,25 @@ def _just_entrypoints(self): # integration semantics and functionality as a caller of the public # surfaces would see. - # --- _StartupState.read_start_file tests --- + # --- Basic StartupState implementation tests --- + + def test_impl_startupstate_defaults_to_sys_path(self): + sys.path.insert(0, self.sitedir) + state = site.StartupState() + self.assertIn(site.makepath(self.sitedir)[1], state._known_paths) + + def test_impl_startupstate_uses_supplied_known_paths(self): + known_paths = set() + state = site.StartupState(known_paths) + state.addsitedir(self.sitedir) + self.assertIs(state._known_paths, known_paths) + self.assertIn(site.makepath(self.sitedir)[1], known_paths) + + # --- StartupState._read_start_file tests --- def test_impl_read_start_file_basic(self): self._make_start("os.path:join\n", name='foo') - self.state.read_start_file(self.sitedir, 'foo.start') + self.state._read_start_file(self.sitedir, 'foo.start') fullname = os.path.join(self.sitedir, 'foo.start') self.assertEqual( self.state._entrypoints[fullname], ['os.path:join'] @@ -1005,7 +1011,7 @@ def test_impl_read_start_file_basic(self): def test_impl_read_start_file_multiple_entries(self): self._make_start("os.path:join\nos.path:exists\n", name='foo') - self.state.read_start_file(self.sitedir, 'foo.start') + self.state._read_start_file(self.sitedir, 'foo.start') fullname = os.path.join(self.sitedir, 'foo.start') self.assertEqual( self.state._entrypoints[fullname], @@ -1014,7 +1020,7 @@ def test_impl_read_start_file_multiple_entries(self): def test_impl_read_start_file_comments_and_blanks(self): self._make_start("# a comment\n\nos.path:join\n \n", name='foo') - self.state.read_start_file(self.sitedir, 'foo.start') + self.state._read_start_file(self.sitedir, 'foo.start') fullname = os.path.join(self.sitedir, 'foo.start') self.assertEqual( self.state._entrypoints[fullname], ['os.path:join'] @@ -1033,7 +1039,7 @@ def test_impl_read_start_file_accepts_all_non_blank_lines(self): "os.path:join\n" # valid ) self._make_start(content, name='foo') - self.state.read_start_file(self.sitedir, 'foo.start') + self.state._read_start_file(self.sitedir, 'foo.start') fullname = os.path.join(self.sitedir, 'foo.start') self.assertEqual(self.state._entrypoints[fullname], [ 'os.path', @@ -1048,7 +1054,7 @@ def test_impl_read_start_file_empty(self): # (with an empty entry point list) so that it suppresses `import` # lines in any matching .pth file. self._make_start("", name='foo') - self.state.read_start_file(self.sitedir, 'foo.start') + self.state._read_start_file(self.sitedir, 'foo.start') fullname = os.path.join(self.sitedir, 'foo.start') self.assertEqual(self.state._entrypoints, {fullname: []}) @@ -1056,13 +1062,13 @@ def test_impl_read_start_file_comments_only(self): # As with an empty file, a comments-only .start file is registered # as present so it can suppress matching .pth `import` lines. self._make_start("# just a comment\n# another\n", name='foo') - self.state.read_start_file(self.sitedir, 'foo.start') + self.state._read_start_file(self.sitedir, 'foo.start') fullname = os.path.join(self.sitedir, 'foo.start') self.assertEqual(self.state._entrypoints, {fullname: []}) def test_impl_read_start_file_nonexistent(self): with captured_stderr(): - self.state.read_start_file(self.tmpdir, 'nonexistent.start') + self.state._read_start_file(self.tmpdir, 'nonexistent.start') self.assertEqual(self.state._entrypoints, {}) @unittest.skipUnless(hasattr(os, 'chflags'), 'test needs os.chflags()') @@ -1071,13 +1077,13 @@ def test_impl_read_start_file_hidden_flags(self): filepath = os.path.join(self.tmpdir, 'foo.start') st = os.stat(filepath) os.chflags(filepath, st.st_flags | stat.UF_HIDDEN) - self.state.read_start_file(self.sitedir, 'foo.start') + self.state._read_start_file(self.sitedir, 'foo.start') self.assertEqual(self.state._entrypoints, {}) def test_impl_one_start_file_with_duplicates_not_deduplicated(self): # PEP 829: duplicate entry points are NOT deduplicated. self._make_start("os.path:join\nos.path:join\n", name='foo') - self.state.read_start_file(self.sitedir, 'foo.start') + self.state._read_start_file(self.sitedir, 'foo.start') fullname = os.path.join(self.sitedir, 'foo.start') self.assertEqual( self.state._entrypoints[fullname], @@ -1087,8 +1093,8 @@ def test_impl_one_start_file_with_duplicates_not_deduplicated(self): def test_impl_two_start_files_with_duplicates_not_deduplicated(self): self._make_start("os.path:join", name="foo") self._make_start("os.path:join", name="bar") - self.state.read_start_file(self.sitedir, 'foo.start') - self.state.read_start_file(self.sitedir, 'bar.start') + self.state._read_start_file(self.sitedir, 'foo.start') + self.state._read_start_file(self.sitedir, 'bar.start') self.assertEqual( self._just_entrypoints(), ['os.path:join', 'os.path:join'], @@ -1099,7 +1105,7 @@ def test_impl_read_start_file_accepts_utf8_bom(self): filepath = os.path.join(self.tmpdir, 'foo.start') with open(filepath, 'wb') as f: f.write(b'\xef\xbb\xbf' + b'os.path:join\n') - self.state.read_start_file(self.sitedir, 'foo.start') + self.state._read_start_file(self.sitedir, 'foo.start') fullname = os.path.join(self.sitedir, 'foo.start') self.assertEqual( self.state._entrypoints[fullname], ['os.path:join'] @@ -1116,23 +1122,23 @@ def test_impl_read_start_file_invalid_utf8_silently_skipped(self): # Bare continuation byte -- invalid as a UTF-8 start byte. f.write(b'\x80\x80\x80\n') with captured_stderr() as err: - self.state.read_start_file(self.sitedir, 'foo.start') + self.state._read_start_file(self.sitedir, 'foo.start') self.assertEqual(self.state._entrypoints, {}) self.assertEqual(err.getvalue(), "") - # --- _StartupState.read_pth_file tests --- + # --- StartupState._read_pth_file tests --- def test_impl_read_pth_file_paths(self): subdir = os.path.join(self.sitedir, 'mylib') os.mkdir(subdir) self._make_pth("mylib\n", name='foo') - self.state.read_pth_file(self.sitedir, 'foo.pth', set()) + self.state._read_pth_file(self.sitedir, 'foo.pth') fullname = os.path.join(self.sitedir, 'foo.pth') - self.assertIn(subdir, self.state._syspaths[fullname]) + self.assertIn((fullname, subdir), self.state._path_entries) def test_impl_read_pth_file_imports_collected(self): self._make_pth("import sys\n", name='foo') - self.state.read_pth_file(self.sitedir, 'foo.pth', set()) + self.state._read_pth_file(self.sitedir, 'foo.pth') fullname = os.path.join(self.sitedir, 'foo.pth') self.assertEqual( self.state._importexecs[fullname], ['import sys'] @@ -1140,23 +1146,21 @@ def test_impl_read_pth_file_imports_collected(self): def test_impl_read_pth_file_comments_and_blanks(self): self._make_pth("# comment\n\n \n", name='foo') - self.state.read_pth_file(self.sitedir, 'foo.pth', set()) - self.assertEqual(self.state._syspaths, {}) + self.state._read_pth_file(self.sitedir, 'foo.pth') + self.assertEqual(self.state._path_entries, []) self.assertEqual(self.state._importexecs, {}) def test_impl_read_pth_file_deduplication(self): subdir = os.path.join(self.sitedir, 'mylib') os.mkdir(subdir) - # An accumulator acts as a deduplication ledger. - known_paths = set() + # self.state._known_paths acts as the deduplication ledger across + # both reads. self._make_pth("mylib\n", name='a') self._make_pth("mylib\n", name='b') - self.state.read_pth_file(self.sitedir, 'a.pth', known_paths) - self.state.read_pth_file(self.sitedir, 'b.pth', known_paths) + self.state._read_pth_file(self.sitedir, 'a.pth') + self.state._read_pth_file(self.sitedir, 'b.pth') # There is only one entry across both files. - all_dirs = [] - for dirs in self.state._syspaths.values(): - all_dirs.extend(dirs) + all_dirs = [dir_ for filename, dir_ in self.state._path_entries] self.assertEqual(all_dirs, [subdir]) def test_impl_read_pth_file_bad_line_continues(self): @@ -1165,9 +1169,9 @@ def test_impl_read_pth_file_bad_line_continues(self): os.mkdir(subdir) self._make_pth("abc\x00def\ngoodpath\n", name='foo') with captured_stderr(): - self.state.read_pth_file(self.sitedir, 'foo.pth', set()) + self.state._read_pth_file(self.sitedir, 'foo.pth') fullname = os.path.join(self.sitedir, 'foo.pth') - self.assertIn(subdir, self.state._syspaths.get(fullname, [])) + self.assertIn((fullname, subdir), self.state._path_entries) def _flags_with_verbose(self, verbose): # Build a sys.flags clone with verbose overridden but every @@ -1189,7 +1193,7 @@ def test_impl_read_pth_file_parse_error_silent_by_default(self): mock.patch('sys.flags', self._flags_with_verbose(False)), captured_stderr() as err, ): - self.state.read_pth_file(self.sitedir, 'foo.pth', set()) + self.state._read_pth_file(self.sitedir, 'foo.pth') self.assertEqual(err.getvalue(), "") def test_impl_read_pth_file_parse_error_reported_under_verbose(self): @@ -1200,7 +1204,7 @@ def test_impl_read_pth_file_parse_error_reported_under_verbose(self): mock.patch('sys.flags', self._flags_with_verbose(True)), captured_stderr() as err, ): - self.state.read_pth_file(self.sitedir, 'foo.pth', set()) + self.state._read_pth_file(self.sitedir, 'foo.pth') out = err.getvalue() self.assertIn('Error in', out) self.assertIn('foo.pth', out) @@ -1220,11 +1224,11 @@ def test_impl_read_pth_file_locale_fallback(self): mock.patch('locale.getencoding', return_value='latin-1'), captured_stderr(), ): - self.state.read_pth_file(self.sitedir, 'foo.pth', set()) + self.state._read_pth_file(self.sitedir, 'foo.pth') fullname = os.path.join(self.sitedir, 'foo.pth') - self.assertIn(subdir, self.state._syspaths.get(fullname, [])) + self.assertIn((fullname, subdir), self.state._path_entries) - # --- _StartupState._execute_start_entrypoints tests --- + # --- StartupState._execute_start_entrypoints tests --- def test_impl_execute_entrypoints_with_callable(self): # An entry point with a callable. @@ -1304,23 +1308,26 @@ def bump(): import countmod self.assertEqual(countmod.call_count, 2) - # --- _StartupState._exec_imports tests --- + # --- StartupState._exec_imports tests --- def test_impl_exec_imports_suppressed_by_matching_start(self): # Import lines from foo.pth are suppressed when foo.start exists. self._make_mod("""\ call_count = 0 -def bump(): +def bump(incr=2): global call_count - call_count += 1 + call_count += incr """, name='countmod', package=False, on_path=True) - pth_fullname = os.path.join(self.sitedir, 'foo.pth') - start_fullname = os.path.join(self.sitedir, 'foo.start') - self.state._importexecs[pth_fullname] = ['import countmod; countmod.bump()'] - self.state._entrypoints[start_fullname] = ['os.path:join'] + self._make_start("countmod:bump\n", name='foo') + self._make_pth("import countmod; countmod.bump(1)\n", name='foo') + self.state._read_pth_file(self.sitedir, 'foo.pth') + self.state._read_start_file(self.sitedir, 'foo.start') self.state._exec_imports() + self.state._execute_start_entrypoints() import countmod - self.assertEqual(countmod.call_count, 0) + # This will be 2 because the entry point is called with no + # arguments, and the .pth import line is never exec'd. + self.assertEqual(countmod.call_count, 2) def test_impl_exec_imports_not_suppressed_by_different_start(self): # Import lines from foo.pth are NOT suppressed by bar.start. @@ -1347,24 +1354,24 @@ def startup(): global called called = True """, name='epmod', package=True, on_path=True) - self.state.read_pth_file(self.sitedir, 'foo.pth', set()) - self.state.read_start_file(self.sitedir, 'foo.start') + self.state._read_pth_file(self.sitedir, 'foo.pth') + self.state._read_start_file(self.sitedir, 'foo.start') self.state._exec_imports() import epmod self.assertFalse(epmod.called) - # --- _StartupState._extend_syspath tests --- + # --- StartupState._extend_syspath tests --- def test_impl_extend_syspath_existing_dir(self): subdir = os.path.join(self.sitedir, 'extlib') os.mkdir(subdir) - self.state._syspaths['test.pth'] = [subdir] + self.state._path_entries.append(('test.pth', subdir)) self.state._extend_syspath() self.assertIn(subdir, sys.path) def test_impl_extend_syspath_nonexistent_dir(self): nonesuch = os.path.join(self.sitedir, 'nosuchdir') - self.state._syspaths['test.pth'] = [nonesuch] + self.state._path_entries.append(('test.pth', nonesuch)) with captured_stderr() as err: self.state._extend_syspath() self.assertNotIn(nonesuch, sys.path) @@ -1415,37 +1422,13 @@ def test_addsitedir_dedups_paths_across_pth_files(self): def test_addsitedir_discovers_start_files(self): # addsitedir() should discover .start files and accumulate entries. - # With defer_processing_start_files=True the preserved state lives on - # site._startup_state and isn't flushed until the caller invokes - # process_startup_files(). self._make_start("os.path:join\n", name='foo') - site.addsitedir( - self.sitedir, set(), - defer_processing_start_files=True, - ) + state = site.StartupState(known_paths=set()) + state.addsitedir(self.sitedir) fullname = os.path.join(self.sitedir, 'foo.start') self.assertIn( - 'os.path:join', site._startup_state._entrypoints[fullname] - ) - - def test_impl_exec_imports_skips_when_matching_start(self): - # When foo.start exists, import lines in foo.pth are skipped - # at flush time by _StartupState._exec_imports(). - self._make_start("os.path:join\n", name='foo') - self._make_pth("import sys\n", name='foo') - site.addsitedir( - self.sitedir, set(), - defer_processing_start_files=True, - ) - pth_fullname = os.path.join(self.sitedir, 'foo.pth') - start_fullname = os.path.join(self.sitedir, 'foo.start') - # Import line was collected... - self.assertIn( - 'import sys', - site._startup_state._importexecs.get(pth_fullname, []), + 'os.path:join', state._entrypoints[fullname] ) - # ...but _exec_imports() will skip it because foo.start exists. - site._startup_state._exec_imports() def test_addsitedir_pth_paths_still_work_with_start(self): # Path lines in .pth files still work even when a .start file exists. @@ -1453,99 +1436,129 @@ def test_addsitedir_pth_paths_still_work_with_start(self): os.mkdir(subdir) self._make_start("os.path:join\n", name='foo') self._make_pth("mylib\n", name='foo') - site.addsitedir( - self.sitedir, set(), - defer_processing_start_files=True, - ) + state = site.StartupState(known_paths=set()) + state.addsitedir(self.sitedir) fullname = os.path.join(self.sitedir, 'foo.pth') - self.assertIn( - subdir, site._startup_state._syspaths.get(fullname, []) - ) + self.assertIn((fullname, subdir), state._path_entries) def test_addsitedir_start_alphabetical_order(self): # Multiple .start files are discovered alphabetically. - # _all_entrypoints() reads from self.state, so swap in the - # preserved batch state for the duration of the assertion. self._make_start("os.path:join\n", name='zzz') self._make_start("os.path:exists\n", name='aaa') - site.addsitedir( - self.sitedir, set(), - defer_processing_start_files=True, - ) - self.state = site._startup_state - all_entries = self._all_entrypoints() - entries = [entry for _, entry in all_entries] + state = site.StartupState(known_paths=set()) + state.addsitedir(self.sitedir) + entries = self._just_entrypoints(state) idx_a = entries.index('os.path:exists') idx_z = entries.index('os.path:join') self.assertLess(idx_a, idx_z) - def test_addsitedir_pth_before_start(self): - # PEP 829: .pth files are scanned before .start files. - # Create a .pth and .start with the same basename; verify - # the .pth data is collected before .start data. + def test_addsitedir_pth_and_start(self): + # Create a .pth and .start with the same basename; verify both the + # .pth data and .start data is collected. subdir = os.path.join(self.sitedir, 'mylib') os.mkdir(subdir) self._make_pth("mylib\n", name='foo') self._make_start("os.path:join\n", name='foo') - site.addsitedir( - self.sitedir, set(), - defer_processing_start_files=True, - ) + state = site.StartupState(known_paths=set()) + state.addsitedir(self.sitedir) # Both should be collected. pth_fullname = os.path.join(self.sitedir, 'foo.pth') start_fullname = os.path.join(self.sitedir, 'foo.start') - self.assertIn( - subdir, site._startup_state._syspaths.get(pth_fullname, []) - ) + self.assertIn((pth_fullname, subdir), state._path_entries) self.assertIn( 'os.path:join', - site._startup_state._entrypoints.get(start_fullname, []), + state._entrypoints.get(start_fullname, []), ) def test_impl_addsitedir_skips_dotfile_start(self): - # .start files starting with '.' are skipped. Defer flushing so - # the preserved batch state stays inspectable on - # site._startup_state; otherwise process_startup_files() would - # detach and consume it regardless of whether the dotfile was - # picked up. + # .start files starting with '.' are skipped. + # This will create `.hidden.start`. self._make_start("os.path:join\n", name='.hidden') - site.addsitedir( - self.sitedir, set(), - defer_processing_start_files=True, - ) - self.assertEqual(site._startup_state._entrypoints, {}) + state = site.StartupState(known_paths=set()) + state.addsitedir(self.sitedir) + self.assertEqual(state._entrypoints, {}) def test_addsitedir_standalone_flushes(self): - # When called with defer_processing_start_files=False (the - # default), addsitedir creates a per-call _StartupState and - # processes it before returning, so the caller sees the effect - # immediately. No batch state is left behind on - # site._startup_state. + # Standalone addsitedir creates a per-call StartupState and processes + # it before returning, so the caller sees the effect immediately. subdir = os.path.join(self.sitedir, 'flushlib') os.mkdir(subdir) self._make_pth("flushlib\n", name='foo') - site.addsitedir(self.sitedir) # known_paths=None + # No arguments means state is implied and processing is eager. + site.addsitedir(self.sitedir) self.assertIn(subdir, sys.path) - self.assertIsNone(site._startup_state) - def test_addsitedir_defer_does_not_flush(self): - # With defer_processing_start_files=True, addsitedir accumulates - # pending state but does not flush; sys.path is updated only when - # process_startup_files() is called explicitly. The accumulated - # state lives on the lazily-promoted site._startup_state. + def test_addsitedir_explicit_startup_state_does_not_flush(self): + # With an explicit StartupState, addsitedir accumulates pending state + # but does not flush it; sys.path is updated only when process() is + # called explicitly. subdir = os.path.join(self.sitedir, 'acclib') os.mkdir(subdir) self._make_pth("acclib\n", name='foo') - site.addsitedir( - self.sitedir, set(), - defer_processing_start_files=True, - ) + state = site.StartupState(known_paths=set()) + state.addsitedir(self.sitedir) # Path is pending, not yet on sys.path. self.assertNotIn(subdir, sys.path) fullname = os.path.join(self.sitedir, 'foo.pth') - self.assertIn( - subdir, site._startup_state._syspaths.get(fullname, []) - ) + self.assertIn((fullname, subdir), state._path_entries) + + def test_addsitedir_startup_state_preserves_site_relative_order(self): + # As pointed out by @ncoghlan in + # https://github.com/python/cpython/issues/150228#issuecomment-4528614952 + # a subtle ordering change was inadvertently introduced where the + # interspersing of the sitedirs with the sys.path extensions they defined + # was lost during batch mode. You'd see all the sitedirs, then all path + # extensions. This test ensures that the old interspersing behavior + # has been restored. + # + # Let's start by creating two sitedirs, each with an extension directory + # which will be added to sys.path by .pth files in the respective sitedirs. + sitedir2 = self.enterContext(os_helper.temp_dir()) + extdir1 = os.path.join(self.sitedir, 'ext1') + extdir2 = os.path.join(sitedir2, 'ext2') + os.mkdir(extdir1) + os.mkdir(extdir2) + self._make_pth(extdir1 + "\n", name='one') + self._make_pth(extdir2 + "\n", name='two', basedir=sitedir2) + # Now create an explicit batch, add each sitedir, then process the + # entire batch. + state = site.StartupState(known_paths=set()) + state.addsitedir(self.sitedir) + state.addsitedir(sitedir2) + state.process() + # Ensure that on sys.path we see this interspersed order: + # [sitedir1, extdir1, sitedir2, extdir2] + indexes = [ + sys.path.index(path) + for path in (self.sitedir, extdir1, sitedir2, extdir2) + ] + # If the index ordering is the same, we preserved the intersperse. + self.assertEqual(indexes, sorted(indexes)) + + def test_addsitedir_startup_state_paths_before_entrypoints(self): + # Ensure that sys.path extensions are available by the time + # .start file entry points are called. + extdir = self._make_mod("""\ +called = False +def hook(): + global called + called = True +""") + self.assertNotIn(extdir, sys.path) + self._make_pth("extdir\n", name='extlib') + self._make_start("mod:hook\n", name='extlib') + # Before the startup state is explicitly processed, neither + # the path extension is added, nor the entry point called. + state = site.StartupState(known_paths=set()) + state.addsitedir(self.sitedir) + self.assertNotIn(extdir, sys.path) + self.assertNotIn('mod', sys.modules) + # After processing the batch, sys.path is extended and + # the entry point was called. + state.process() + self.assertIn(extdir, sys.path) + import mod + self.assertTrue(mod.called) def test_pth_path_is_available_to_start_entrypoint(self): # Core PEP 829 invariant: all .pth path extensions are applied to diff --git a/Misc/NEWS.d/next/Library/2026-05-27-11-18-36.gh-issue-150228.pNPiO-.rst b/Misc/NEWS.d/next/Library/2026-05-27-11-18-36.gh-issue-150228.pNPiO-.rst new file mode 100644 index 00000000000000..8c03989e90b240 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-05-27-11-18-36.gh-issue-150228.pNPiO-.rst @@ -0,0 +1,11 @@ +The new :class:`site.StartupState` class lets callers batch-process +:pep:`829` startup configuration files across multiple site directories +before any startup code runs, with public +:meth:`~site.StartupState.addsitedir`, +:meth:`~site.StartupState.addusersitepackages`, +:meth:`~site.StartupState.addsitepackages`, and +:meth:`~site.StartupState.process` methods. The signature of +:func:`site.addsitedir` is unchanged from Python 3.14. The +:data:`!defer_processing_start_files` argument and the +``process_startup_files()`` function added earlier in the 3.15 cycle have +been removed; use :class:`!site.StartupState` instead. From ef4508966038b6e63847b85715acf639690093f0 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 2 Jun 2026 10:03:51 +0200 Subject: [PATCH 192/818] [3.15] gh-89554: Document NoneType, NotImplementedType and EllipsisType as classes (GH-150682) (GH-150755) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Always use the directive and the role "class" instead of "data" for NoneType, NotImplementedType and EllipsisType. (cherry picked from commit e40190e104c81b61cdc6f71a391e28de53bbc1d8) Co-authored-by: Bernát Gábor <gaborjbernat@gmail.com> --- Doc/library/constants.rst | 6 +++--- Doc/library/types.rst | 6 +++--- Doc/whatsnew/3.10.rst | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Doc/library/constants.rst b/Doc/library/constants.rst index d058ba206c6cd6..6f005f98bd3ede 100644 --- a/Doc/library/constants.rst +++ b/Doc/library/constants.rst @@ -22,7 +22,7 @@ A small number of constants live in the built-in namespace. They are: An object frequently used to represent the absence of a value, as when default arguments are not passed to a function. Assignments to ``None`` are illegal and raise a :exc:`SyntaxError`. - ``None`` is the sole instance of the :data:`~types.NoneType` type. + ``None`` is the sole instance of the :class:`~types.NoneType` type. .. data:: NotImplemented @@ -33,7 +33,7 @@ A small number of constants live in the built-in namespace. They are: the other type; may be returned by the in-place binary special methods (e.g. :meth:`~object.__imul__`, :meth:`~object.__iand__`, etc.) for the same purpose. It should not be evaluated in a boolean context. - :data:`!NotImplemented` is the sole instance of the :data:`types.NotImplementedType` type. + :data:`!NotImplemented` is the sole instance of the :class:`types.NotImplementedType` type. .. note:: @@ -68,7 +68,7 @@ A small number of constants live in the built-in namespace. They are: The same as the ellipsis literal "``...``", an object frequently used to indicate that something is omitted. Assignment to ``Ellipsis`` is possible, but assignment to ``...`` raises a :exc:`SyntaxError`. - ``Ellipsis`` is the sole instance of the :data:`types.EllipsisType` type. + ``Ellipsis`` is the sole instance of the :class:`types.EllipsisType` type. .. data:: __debug__ diff --git a/Doc/library/types.rst b/Doc/library/types.rst index 74898baa521bd6..b4793be9bdfd70 100644 --- a/Doc/library/types.rst +++ b/Doc/library/types.rst @@ -143,7 +143,7 @@ If you instantiate any of these types, note that signatures may vary between Pyt Standard names are defined for the following types: -.. data:: NoneType +.. class:: NoneType The type of :data:`None`. @@ -233,7 +233,7 @@ Standard names are defined for the following types: .. versionadded:: 3.7 -.. data:: NotImplementedType +.. class:: NotImplementedType The type of :data:`NotImplemented`. @@ -273,7 +273,7 @@ Standard names are defined for the following types: creating :class:`!ModuleType` instances which ensures the various attributes are set appropriately. -.. data:: EllipsisType +.. class:: EllipsisType The type of :data:`Ellipsis`. diff --git a/Doc/whatsnew/3.10.rst b/Doc/whatsnew/3.10.rst index 8a78dbd90382ed..0a01462aa430e7 100644 --- a/Doc/whatsnew/3.10.rst +++ b/Doc/whatsnew/3.10.rst @@ -1446,8 +1446,8 @@ as a positional-only argument. types ----- -Reintroduce the :data:`types.EllipsisType`, :data:`types.NoneType` -and :data:`types.NotImplementedType` classes, providing a new set +Reintroduce the :class:`types.EllipsisType`, :class:`types.NoneType` +and :class:`types.NotImplementedType` classes, providing a new set of types readily interpretable by type checkers. (Contributed by Bas van Beek in :issue:`41810`.) From 506b41d458e7fc08d4adc1a8eca5743377f7562b Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 2 Jun 2026 10:08:01 +0200 Subject: [PATCH 193/818] [3.15] gh-89554: Document weakref type objects as classes (GH-150678) (GH-150760) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the "class" directive instead of "data" for ReferenceType, ProxyType and CallableProxyType. (cherry picked from commit 10c421970beca89df92a918f2247fb8850d3b6cc) Co-authored-by: Bernát Gábor <gaborjbernat@gmail.com> --- Doc/library/weakref.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/library/weakref.rst b/Doc/library/weakref.rst index 87dd860da4dcc4..318da931fc314c 100644 --- a/Doc/library/weakref.rst +++ b/Doc/library/weakref.rst @@ -324,17 +324,17 @@ same issues as the :meth:`WeakKeyDictionary.keyrefs` method. .. versionadded:: 3.4 -.. data:: ReferenceType +.. class:: ReferenceType The type object for weak references objects. -.. data:: ProxyType +.. class:: ProxyType The type object for proxies of objects which are not callable. -.. data:: CallableProxyType +.. class:: CallableProxyType The type object for proxies of callable objects. From b48cf0ec0c226186f1ee311eb880e20a6a3e7029 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 2 Jun 2026 10:11:19 +0200 Subject: [PATCH 194/818] [3.15] gh-89554: Document standard type objects in types as classes (GH-150676) (GH-150761) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the directive and the role "class" instead of "data" for classes exposed in the types module. (cherry picked from commit bc055444e4ade9e210139d07200f602a4a9feb67) Co-authored-by: Bernát Gábor <gaborjbernat@gmail.com> --- .../a-conceptual-overview-of-asyncio.rst | 2 +- Doc/library/types.rst | 36 +++++++++---------- Doc/whatsnew/3.10.rst | 2 +- Doc/whatsnew/3.15.rst | 4 +-- 4 files changed, 22 insertions(+), 22 deletions(-) diff --git a/Doc/howto/a-conceptual-overview-of-asyncio.rst b/Doc/howto/a-conceptual-overview-of-asyncio.rst index 3adfedbf410ecc..7a7a87cb958400 100644 --- a/Doc/howto/a-conceptual-overview-of-asyncio.rst +++ b/Doc/howto/a-conceptual-overview-of-asyncio.rst @@ -115,7 +115,7 @@ The terms "coroutine function" and "coroutine object" are often conflated as coroutine. That can be confusing! In this article, coroutine specifically refers to a coroutine object, or more -precisely, an instance of :data:`types.CoroutineType` (native coroutine). +precisely, an instance of :class:`types.CoroutineType` (native coroutine). Note that coroutines can also exist as instances of :class:`collections.abc.Coroutine` -- a distinction that matters for type checking. diff --git a/Doc/library/types.rst b/Doc/library/types.rst index b4793be9bdfd70..9f7b7579519052 100644 --- a/Doc/library/types.rst +++ b/Doc/library/types.rst @@ -150,8 +150,8 @@ Standard names are defined for the following types: .. versionadded:: 3.10 -.. data:: FunctionType - LambdaType +.. class:: FunctionType + LambdaType The type of user-defined functions and functions created by :keyword:`lambda` expressions. @@ -162,13 +162,13 @@ Standard names are defined for the following types: and is not raised for normal compilation. -.. data:: GeneratorType +.. class:: GeneratorType The type of :term:`generator`-iterator objects, created by generator functions. -.. data:: CoroutineType +.. class:: CoroutineType The type of :term:`coroutine` objects, created by :keyword:`async def` functions. @@ -176,7 +176,7 @@ Standard names are defined for the following types: .. versionadded:: 3.5 -.. data:: AsyncGeneratorType +.. class:: AsyncGeneratorType The type of :term:`asynchronous generator`-iterator objects, created by asynchronous generator functions. @@ -196,7 +196,7 @@ Standard names are defined for the following types: required by the initializer. The audit event only occurs for direct instantiation of code objects, and is not raised for normal compilation. -.. data:: CellType +.. class:: CellType The type for cell objects: such objects are used as containers for a function's :term:`closure variables <closure variable>`. @@ -204,20 +204,20 @@ Standard names are defined for the following types: .. versionadded:: 3.8 -.. data:: MethodType +.. class:: MethodType The type of methods of user-defined class instances. -.. data:: BuiltinFunctionType - BuiltinMethodType +.. class:: BuiltinFunctionType + BuiltinMethodType The type of built-in functions like :func:`len` or :func:`sys.exit`, and methods of built-in classes. (Here, the term "built-in" means "written in C".) -.. data:: WrapperDescriptorType +.. class:: WrapperDescriptorType The type of methods of some built-in data types and base classes such as :meth:`object.__init__` or :meth:`object.__lt__`. @@ -225,7 +225,7 @@ Standard names are defined for the following types: .. versionadded:: 3.7 -.. data:: MethodWrapperType +.. class:: MethodWrapperType The type of *bound* methods of some built-in data types and base classes. For example it is the type of :code:`object().__str__`. @@ -240,14 +240,14 @@ Standard names are defined for the following types: .. versionadded:: 3.10 -.. data:: MethodDescriptorType +.. class:: MethodDescriptorType The type of methods of some built-in data types such as :meth:`str.join`. .. versionadded:: 3.7 -.. data:: ClassMethodDescriptorType +.. class:: ClassMethodDescriptorType The type of *unbound* class methods of some built-in data types such as ``dict.__dict__['fromkeys']``. @@ -327,13 +327,13 @@ Standard names are defined for the following types: dynamically. -.. data:: FrameType +.. class:: FrameType The type of :ref:`frame objects <frame-objects>` such as found in :attr:`tb.tb_frame <traceback.tb_frame>` if ``tb`` is a traceback object. -.. data:: FrameLocalsProxyType +.. class:: FrameLocalsProxyType The type of frame locals proxy objects, as found on the :attr:`frame.f_locals` attribute. @@ -343,7 +343,7 @@ Standard names are defined for the following types: .. seealso:: :pep:`667` -.. data:: LazyImportType +.. class:: LazyImportType The type of lazy import proxy objects. These objects are created when a module is lazily imported and serve as placeholders until the module is @@ -355,7 +355,7 @@ Standard names are defined for the following types: .. seealso:: :pep:`810` -.. data:: GetSetDescriptorType +.. class:: GetSetDescriptorType The type of objects defined in extension modules with ``PyGetSetDef``, such as :attr:`FrameType.f_locals <frame.f_locals>` or ``array.array.typecode``. @@ -364,7 +364,7 @@ Standard names are defined for the following types: :class:`property` type, but for classes defined in extension modules. -.. data:: MemberDescriptorType +.. class:: MemberDescriptorType The type of objects defined in extension modules with ``PyMemberDef``, such as ``datetime.timedelta.days``. This type is used as descriptor for simple C diff --git a/Doc/whatsnew/3.10.rst b/Doc/whatsnew/3.10.rst index 0a01462aa430e7..f687b6c85591fc 100644 --- a/Doc/whatsnew/3.10.rst +++ b/Doc/whatsnew/3.10.rst @@ -1928,7 +1928,7 @@ Changes in the Python API (Contributed by Yurii Karabas, Andrew Svetlov, Yury Selivanov and Kyle Stanley in :issue:`42392`.) -* The :data:`types.FunctionType` constructor now inherits the current builtins +* The :class:`types.FunctionType` constructor now inherits the current builtins if the *globals* dictionary has no ``"__builtins__"`` key, rather than using ``{"None": None}`` as builtins: same behavior as :func:`eval` and :func:`exec` functions. Defining a function with ``def function(...): ...`` diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst index 371a9feb861393..99c5a9478e2460 100644 --- a/Doc/whatsnew/3.15.rst +++ b/Doc/whatsnew/3.15.rst @@ -184,7 +184,7 @@ eager: import myapp.slow_module # lazy (matches filter) import json # eager (does not match filter) -The proxy type itself is available as :data:`types.LazyImportType` for code +The proxy type itself is available as :class:`types.LazyImportType` for code that needs to detect lazy imports programmatically. There are some restrictions on where the ``lazy`` keyword can be used. Lazy @@ -1662,7 +1662,7 @@ types ----- * Expose the write-through :func:`locals` proxy type - as :data:`types.FrameLocalsProxyType`. + as :class:`types.FrameLocalsProxyType`. This represents the type of the :attr:`frame.f_locals` attribute, as described in :pep:`667`. From 35dc2483721ccd98a821ca444875c505a45f312d Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 2 Jun 2026 10:16:05 +0200 Subject: [PATCH 195/818] [3.15] gh-89554: Document typing.ParamSpecArgs and ParamSpecKwargs as classes (GH-150677) (GH-150763) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the directive "class" instead of "data" for ParamSpecArgs and ParamSpecKwargs. (cherry picked from commit 35c314d2b7282e729c2d86716fc94e1fe38f25da) Co-authored-by: Bernát Gábor <gaborjbernat@gmail.com> --- Doc/library/typing.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index b2167cbc63a1ff..ef6016d45c1f8b 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -2292,8 +2292,8 @@ without the dedicated syntax, as documented below. * :data:`Concatenate` * :ref:`annotating-callables` -.. data:: ParamSpecArgs - ParamSpecKwargs +.. class:: ParamSpecArgs + ParamSpecKwargs Arguments and keyword arguments attributes of a :class:`ParamSpec`. The ``P.args`` attribute of a ``ParamSpec`` is an instance of ``ParamSpecArgs``, From 0472179937c8cd843b384a8ce73958c20d0a6877 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 2 Jun 2026 11:22:17 +0200 Subject: [PATCH 196/818] [3.15] Fix two typos in 'Exception Handling' C-API documentation (GH-150674) (#150772) (cherry picked from commit cee3327b9264a653cdbd2f9bb1ffa74a95be66e9) Co-authored-by: Manoj K M <manojkm24dev@gmail.com> --- Doc/c-api/exceptions.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/c-api/exceptions.rst b/Doc/c-api/exceptions.rst index fd9ea6272df7d8..f3f408c400bed0 100644 --- a/Doc/c-api/exceptions.rst +++ b/Doc/c-api/exceptions.rst @@ -412,7 +412,7 @@ an error value). .. c:function:: int PyErr_WarnFormat(PyObject *category, Py_ssize_t stack_level, const char *format, ...) - Function similar to :c:func:`PyErr_WarnEx`, but use + Function similar to :c:func:`PyErr_WarnEx`, but uses :c:func:`PyUnicode_FromFormat` to format the warning message. *format* is an ASCII-encoded string. @@ -1392,7 +1392,7 @@ Tracebacks This function will return ``NULL`` on success, or an error message on error. - This function is meant to debug debug situations such as segfaults, fatal + This function is meant to debug situations such as segfaults, fatal errors, and similar. It calls :c:func:`PyUnstable_DumpTraceback` for each thread. It only writes the tracebacks of the first *max_threads* threads, further output is truncated with the line ``...``. If *max_threads* is 0, the From 94c58db97797be3c1fd4dee67e8469353a89c50b Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 2 Jun 2026 11:26:05 +0200 Subject: [PATCH 197/818] [3.15] gh-123138: Updated email.headerregistry docs to include required keyword parse_tree (GH-134450) (GH-150623) (cherry picked from commit 2c20f9ce17abcbc36a105fd9de0b15797b6401ae) Co-authored-by: Gustaf <79180496+gostak-dd@users.noreply.github.com> --- Doc/library/email.headerregistry.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Doc/library/email.headerregistry.rst b/Doc/library/email.headerregistry.rst index c6924a0ac29c97..619c17c98e8d89 100644 --- a/Doc/library/email.headerregistry.rst +++ b/Doc/library/email.headerregistry.rst @@ -93,9 +93,10 @@ headers. ``kwds`` is a dictionary containing one pre-initialized key, ``defects``. ``defects`` is an empty list. The parse method should append any detected defects to this list. On return, the ``kwds`` dictionary *must* contain - values for at least the keys ``decoded`` and ``defects``. ``decoded`` - should be the string value for the header (that is, the header value fully - decoded to unicode). The parse method should assume that *string* may + values for at least the keys ``decoded``, ``defects`` and ``parse_tree``. + ``decoded`` should be the string value for the header (that is, the header + value fully decoded to unicode). ``parse_tree`` is set to the parse tree obtained + from parsing the header. The parse method should assume that *string* may contain content-transfer-encoded parts, but should correctly handle all valid unicode characters as well so that it can parse un-encoded header values. From 1835400ff5c36e01851c740e3fa82b1309a07b97 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 2 Jun 2026 11:36:03 +0200 Subject: [PATCH 198/818] [3.15] gh-149738: Fix segmentation fault bug in sqllite3 (GH-149754) (#150768) gh-149738: Fix segmentation fault bug in sqllite3 (GH-149754) Deleting the `row_factory` or `text_factory` attribute is no longer allowed. (cherry picked from commit 60fdb3192b897168ec0418fb0ea6c8d2d49ea513) Co-authored-by: Sepehr Rasouli <sepehrrasouli06@gmail.com> --- Doc/library/sqlite3.rst | 9 ++++ Lib/test/test_sqlite3/test_factory.py | 10 ++++ ...-05-13-06-54-41.gh-issue-149738.4BLFoH.rst | 2 + Modules/_sqlite/connection.c | 47 ++++++++++++++++++- 4 files changed, 66 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-05-13-06-54-41.gh-issue-149738.4BLFoH.rst diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst index 484260e63dd5f2..3a75d44f3f7d21 100644 --- a/Doc/library/sqlite3.rst +++ b/Doc/library/sqlite3.rst @@ -1417,6 +1417,9 @@ Connection objects See :ref:`sqlite3-howto-row-factory` for more details. + .. versionchanged:: next + Deleting the ``row_factory`` attribute is no longer allowed. + .. attribute:: text_factory A :term:`callable` that accepts a :class:`bytes` parameter @@ -1426,6 +1429,9 @@ Connection objects See :ref:`sqlite3-howto-encoding` for more details. + .. versionchanged:: next + Deleting the ``text_factory`` attribute is no longer allowed. + .. attribute:: total_changes Return the total number of database rows that have been modified, inserted, or @@ -1709,6 +1715,9 @@ Cursor objects See :ref:`sqlite3-howto-row-factory` for more details. + .. versionchanged:: next + Deleting the ``row_factory`` attribute is no longer allowed. + .. The sqlite3.Row example used to be a how-to. It has now been incorporated into the Row reference. We keep the anchor here in order not to break diff --git a/Lib/test/test_sqlite3/test_factory.py b/Lib/test/test_sqlite3/test_factory.py index 776659e3b16108..a9abeab3193688 100644 --- a/Lib/test/test_sqlite3/test_factory.py +++ b/Lib/test/test_sqlite3/test_factory.py @@ -146,6 +146,16 @@ def test_sqlite_row_index(self): with self.assertRaises(IndexError): row[complex()] # index must be int or string + def test_delete_connection_row_factory(self): + # gh-149738: deleting row_factory should raise an exception + with self.assertRaises(AttributeError): + del self.con.row_factory + + def test_delete_connection_text_factory(self): + # gh-149738: deleting text_factory should raise an exception + with self.assertRaises(AttributeError): + del self.con.text_factory + def test_sqlite_row_index_unicode(self): row = self.con.execute("select 1 as \xff").fetchone() self.assertEqual(row["\xff"], 1) diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-13-06-54-41.gh-issue-149738.4BLFoH.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-13-06-54-41.gh-issue-149738.4BLFoH.rst new file mode 100644 index 00000000000000..e62b681d716650 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-13-06-54-41.gh-issue-149738.4BLFoH.rst @@ -0,0 +1,2 @@ +:mod:`sqlite3`: Disallow removing ``row_factory`` and ``text_factory`` attributes +of a connection to prevent a crash on a query. diff --git a/Modules/_sqlite/connection.c b/Modules/_sqlite/connection.c index f596cc1ab36a19..892740b05e55c9 100644 --- a/Modules/_sqlite/connection.c +++ b/Modules/_sqlite/connection.c @@ -557,6 +557,47 @@ pysqlite_connection_cursor_impl(pysqlite_Connection *self, PyObject *factory) return cursor; } +static PyObject * +connection_get_row_factory(PyObject *op, void *closure) +{ + pysqlite_Connection *self = (pysqlite_Connection *)op; + return Py_NewRef(self->row_factory); +} + +static int +connection_set_row_factory(PyObject *op, PyObject *value, void *closure) +{ + pysqlite_Connection *self = (pysqlite_Connection *)op; + if (value == NULL) { + PyErr_SetString(PyExc_AttributeError, + "cannot delete row_factory attribute"); + return -1; + } + Py_XSETREF(self->row_factory, Py_NewRef(value)); + return 0; +} + +static PyObject * +connection_get_text_factory(PyObject *op, void *closure) +{ + pysqlite_Connection *self = (pysqlite_Connection *)op; + return Py_NewRef(self->text_factory); +} + +static int +connection_set_text_factory(PyObject *op, PyObject *value, void *closure) +{ + pysqlite_Connection *self = (pysqlite_Connection *)op; + if (value == NULL) { + PyErr_SetString(PyExc_AttributeError, + "cannot delete text_factory attribute"); + return -1; + } + Py_XSETREF(self->text_factory, Py_NewRef(value)); + return 0; +} + + /*[clinic input] _sqlite3.Connection.blobopen as blobopen @@ -2620,6 +2661,10 @@ static PyGetSetDef connection_getset[] = { {"in_transaction", pysqlite_connection_get_in_transaction, NULL}, {"autocommit", get_autocommit, set_autocommit}, {"__text_signature__", get_sig, NULL}, + {"row_factory", connection_get_row_factory, + connection_set_row_factory}, + {"text_factory", connection_get_text_factory, + connection_set_text_factory}, {NULL} }; @@ -2667,8 +2712,6 @@ static struct PyMemberDef connection_members[] = {"InternalError", _Py_T_OBJECT, offsetof(pysqlite_Connection, InternalError), Py_READONLY}, {"ProgrammingError", _Py_T_OBJECT, offsetof(pysqlite_Connection, ProgrammingError), Py_READONLY}, {"NotSupportedError", _Py_T_OBJECT, offsetof(pysqlite_Connection, NotSupportedError), Py_READONLY}, - {"row_factory", _Py_T_OBJECT, offsetof(pysqlite_Connection, row_factory)}, - {"text_factory", _Py_T_OBJECT, offsetof(pysqlite_Connection, text_factory)}, {NULL} }; From c5512bd7c1dc28055660565275012766941d3066 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 2 Jun 2026 12:10:04 +0200 Subject: [PATCH 199/818] [3.15] gh-149079: Fix O(n^2) canonical ordering in unicodedata.normalize() (GH-149080) (#150776) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the insertion sort used for canonical ordering of combining characters with a hybrid approach: insertion sort for short runs (< 20) and counting sort for longer runs, reducing worst-case complexity from O(n^2) to O(n). This prevents denial of service via crafted Unicode strings with many combining characters in alternating CCC order. (cherry picked from commit 991224b1e8311c85f198f6dd8208bf8cff7fc26f) Co-authored-by: Seth Larson <seth@python.org> Co-authored-by: ch4n3-yoon <ch4n3.yoon@gmail.com> Co-authored-by: Seokchan Yoon <13852925+ch4n3-yoon@users.noreply.github.com> Co-authored-by: Stan Ulbrych <stan@python.org> Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com> Co-authored-by: Petr Viktorin <encukou@gmail.com> Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Maurycy Pawłowski-Wieroński <maurycy@maurycy.com> --- Lib/test/test_unicodedata.py | 28 ++++ ...-04-27-16-36-11.gh-issue-149079.vKl-LM.rst | 5 + Modules/unicodedata.c | 143 ++++++++++++++---- 3 files changed, 150 insertions(+), 26 deletions(-) create mode 100644 Misc/NEWS.d/next/Security/2026-04-27-16-36-11.gh-issue-149079.vKl-LM.rst diff --git a/Lib/test/test_unicodedata.py b/Lib/test/test_unicodedata.py index 060d81415aa1f1..ad25be3da8cb34 100644 --- a/Lib/test/test_unicodedata.py +++ b/Lib/test/test_unicodedata.py @@ -616,6 +616,34 @@ def test_issue10254(self): b = 'C\u0338' * 20 + '\xC7' self.assertEqual(self.db.normalize('NFC', a), b) + def test_long_combining_mark_run(self): + # gh-149079: avoid quadratic canonical ordering. + payload = "a" + ("\u0300\u0327" * 32) + nfd = "a" + ("\u0327" * 32) + ("\u0300" * 32) + nfc = "\u00e0" + ("\u0327" * 32) + ("\u0300" * 31) + + self.assertEqual(self.db.normalize("NFD", payload), nfd) + self.assertEqual(self.db.normalize("NFKD", payload), nfd) + self.assertEqual(self.db.normalize("NFC", payload), nfc) + self.assertEqual(self.db.normalize("NFKC", payload), nfc) + + def test_combining_mark_run_fast_paths(self): + # gh-149079: cover short runs and already-sorted long runs. + short_payload = "a" + ("\u0300\u0327" * 9) + "\u0300" + short_nfd = "a" + ("\u0327" * 9) + ("\u0300" * 10) + short_nfc = "\u00e0" + ("\u0327" * 9) + ("\u0300" * 9) + long_sorted = "a" + ("\u0327" * 30) + ("\u0300" * 30) + long_sorted_nfc = "\u00e0" + ("\u0327" * 30) + ("\u0300" * 29) + + self.assertEqual(self.db.normalize("NFD", short_payload), short_nfd) + self.assertEqual(self.db.normalize("NFKD", short_payload), short_nfd) + self.assertEqual(self.db.normalize("NFC", short_payload), short_nfc) + self.assertEqual(self.db.normalize("NFKC", short_payload), short_nfc) + self.assertEqual(self.db.normalize("NFD", long_sorted), long_sorted) + self.assertEqual(self.db.normalize("NFKD", long_sorted), long_sorted) + self.assertEqual(self.db.normalize("NFC", long_sorted), long_sorted_nfc) + self.assertEqual(self.db.normalize("NFKC", long_sorted), long_sorted_nfc) + def test_issue29456(self): # Fix #29456 u1176_str_a = '\u1100\u1176\u11a8' diff --git a/Misc/NEWS.d/next/Security/2026-04-27-16-36-11.gh-issue-149079.vKl-LM.rst b/Misc/NEWS.d/next/Security/2026-04-27-16-36-11.gh-issue-149079.vKl-LM.rst new file mode 100644 index 00000000000000..4ed22b58f7405f --- /dev/null +++ b/Misc/NEWS.d/next/Security/2026-04-27-16-36-11.gh-issue-149079.vKl-LM.rst @@ -0,0 +1,5 @@ +Fix a potential denial of service in :func:`unicodedata.normalize`. The +canonical ordering step of Unicode normalization used a quadratic-time insertion +sort for reordering combining characters, which could be exploited with +crafted input containing many combining characters in non-canonical order. +Replaced with a linear-time counting sort for long runs. diff --git a/Modules/unicodedata.c b/Modules/unicodedata.c index 6bb25fc0b63781..60df6821693813 100644 --- a/Modules/unicodedata.c +++ b/Modules/unicodedata.c @@ -556,19 +556,80 @@ get_decomp_record(PyObject *self, Py_UCS4 code, (*index)++; } +/* Small combining runs are usually cheaper with insertion sort. */ +#define CANONICAL_ORDERING_COUNTING_SORT_THRESHOLD 20 + +static void +canonical_ordering_sort_insertion(int kind, void *data, + Py_ssize_t start, Py_ssize_t end) +{ + for (Py_ssize_t i = start + 1; i < end; i++) { + Py_UCS4 code = PyUnicode_READ(kind, data, i); + unsigned char combining = _getrecord_ex(code)->combining; + Py_ssize_t j = i; + + while (j > start) { + Py_UCS4 previous = PyUnicode_READ(kind, data, j - 1); + if (_getrecord_ex(previous)->combining <= combining) { + break; + } + PyUnicode_WRITE(kind, data, j, previous); + j--; + } + if (j != i) { + PyUnicode_WRITE(kind, data, j, code); + } + } +} + +static void +canonical_ordering_sort_counting(int kind, void *data, + Py_ssize_t start, Py_ssize_t end, + Py_UCS4 *sortbuf) +{ + Py_ssize_t counts[256] = {0}; + Py_ssize_t run_length = end - start; + Py_ssize_t total = 0; + + for (Py_ssize_t i = start; i < end; i++) { + Py_UCS4 code = PyUnicode_READ(kind, data, i); + unsigned char combining = _getrecord_ex(code)->combining; + counts[combining]++; + } + + for (size_t i = 0; i < Py_ARRAY_LENGTH(counts); i++) { + Py_ssize_t count = counts[i]; + counts[i] = total; + total += count; + } + + /* Reuse counts[] as the next output slot for each CCC. */ + for (Py_ssize_t i = start; i < end; i++) { + Py_UCS4 code = PyUnicode_READ(kind, data, i); + unsigned char combining = _getrecord_ex(code)->combining; + sortbuf[counts[combining]++] = code; + } + for (Py_ssize_t i = 0; i < run_length; i++) { + PyUnicode_WRITE(kind, data, start + i, sortbuf[i]); + } +} + static PyObject* nfd_nfkd(PyObject *self, PyObject *input, int k) { PyObject *result; Py_UCS4 *output; Py_ssize_t i, o, osize; - int kind; - const void *data; + int input_kind, result_kind; + const void *input_data; + void *result_data; /* Longest decomposition in Unicode 3.2: U+FDFA */ Py_UCS4 stack[20]; Py_ssize_t space, isize; int index, prefix, count, stackptr; unsigned char prev, cur; + Py_UCS4 *sortbuf = NULL; + Py_ssize_t sortbuflen = 0; stackptr = 0; isize = PyUnicode_GET_LENGTH(input); @@ -588,11 +649,11 @@ nfd_nfkd(PyObject *self, PyObject *input, int k) return NULL; } i = o = 0; - kind = PyUnicode_KIND(input); - data = PyUnicode_DATA(input); + input_kind = PyUnicode_KIND(input); + input_data = PyUnicode_DATA(input); while (i < isize) { - stack[stackptr++] = PyUnicode_READ(kind, data, i++); + stack[stackptr++] = PyUnicode_READ(input_kind, input_data, i++); while(stackptr) { Py_UCS4 code = stack[--stackptr]; /* Hangul Decomposition adds three characters in @@ -660,34 +721,64 @@ nfd_nfkd(PyObject *self, PyObject *input, int k) if (!result) return NULL; - kind = PyUnicode_KIND(result); - data = PyUnicode_DATA(result); + result_kind = PyUnicode_KIND(result); + result_data = PyUnicode_DATA(result); - /* Sort canonically. */ + /* Sort each consecutive combining-character run canonically. */ i = 0; - prev = _getrecord_ex(PyUnicode_READ(kind, data, i))->combining; - for (i++; i < PyUnicode_GET_LENGTH(result); i++) { - cur = _getrecord_ex(PyUnicode_READ(kind, data, i))->combining; - if (prev == 0 || cur == 0 || prev <= cur) { - prev = cur; + while (i < o) { + Py_ssize_t run_length, run_start; + int needs_sort = 0; + + Py_UCS4 ch = PyUnicode_READ(result_kind, result_data, i); + prev = _getrecord_ex(ch)->combining; + if (prev == 0) { + i++; continue; } - /* Non-canonical order. Need to switch *i with previous. */ - o = i - 1; - while (1) { - Py_UCS4 tmp = PyUnicode_READ(kind, data, o+1); - PyUnicode_WRITE(kind, data, o+1, - PyUnicode_READ(kind, data, o)); - PyUnicode_WRITE(kind, data, o, tmp); - o--; - if (o < 0) - break; - prev = _getrecord_ex(PyUnicode_READ(kind, data, o))->combining; - if (prev == 0 || prev <= cur) + + run_start = i++; + while (i < o) { + Py_UCS4 ch = PyUnicode_READ(result_kind, result_data, i); + cur = _getrecord_ex(ch)->combining; + if (cur == 0) { break; + } + if (prev > cur) { + needs_sort = 1; + } + prev = cur; + i++; + } + if (!needs_sort) { + continue; + } + + run_length = i - run_start; + if (run_length < CANONICAL_ORDERING_COUNTING_SORT_THRESHOLD) { + canonical_ordering_sort_insertion(result_kind, result_data, + run_start, i); + continue; } - prev = _getrecord_ex(PyUnicode_READ(kind, data, i))->combining; + + if (run_length > sortbuflen) { + Py_UCS4 *new_sortbuf = PyMem_Resize(sortbuf, + Py_UCS4, + run_length); + if (new_sortbuf == NULL) { + PyErr_NoMemory(); + PyMem_Free(sortbuf); + Py_DECREF(result); + return NULL; + } + sortbuf = new_sortbuf; + sortbuflen = run_length; + } + + canonical_ordering_sort_counting(result_kind, result_data, + run_start, i, sortbuf); } + PyMem_Free(sortbuf); return result; } From 8fcec28e666679a9226c568b29458b5057789b96 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 2 Jun 2026 13:31:13 +0200 Subject: [PATCH 200/818] [3.15] Fix typos in C API documentation (GH-149588) (#149662) Co-authored-by: pengyu lee <lipengyu@kylinos.cn> --- Doc/c-api/slots.rst | 4 ++-- Doc/c-api/synchronization.rst | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/c-api/slots.rst b/Doc/c-api/slots.rst index b61c2f2e17bbc3..84a125cb60bae7 100644 --- a/Doc/c-api/slots.rst +++ b/Doc/c-api/slots.rst @@ -7,10 +7,10 @@ Definition slots To define :ref:`module objects <moduleobjects>` and :ref:`classes <creating-heap-types>` using the C API, you may use -an array of *slots* -- essentally, key-value pairs that describe features +an array of *slots* -- essentially, key-value pairs that describe features of the object to create. This decouples the data from the structures used at runtime, allowing CPython --- and other Python C API implementations -- to update the stuctures without +-- and other Python C API implementations -- to update the structures without breaking backwards compatibility. This section documents slots in general. diff --git a/Doc/c-api/synchronization.rst b/Doc/c-api/synchronization.rst index 7e9894f4d692d6..6f18c047a24a92 100644 --- a/Doc/c-api/synchronization.rst +++ b/Doc/c-api/synchronization.rst @@ -238,7 +238,7 @@ are not available. .. c:function:: void PyCriticalSection_BeginMutex(PyCriticalSection *c, PyMutex *m); void PyCriticalSection2_BeginMutex(PyCriticalSection2 *c, PyMutex *m1, PyMutex *m2); - .. (These need to be in a separate section without a Stable ABI anotation.) + .. (These need to be in a separate section without a Stable ABI annotation.) To be used only as in the macro expansions listed :ref:`earlier in this section <critical-section-macros>`. From 80f3d798a71f43514384243f47e8fac2181d2b35 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 2 Jun 2026 13:32:04 +0200 Subject: [PATCH 201/818] [3.15] gh-150720: Remove '-d 1' in test_script_error_treatment (GH-150736) (#150746) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: László Kiss Kollár <kiss.kollar.laszlo@gmail.com> --- .../test_profiling/test_sampling_profiler/test_integration.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/Lib/test/test_profiling/test_sampling_profiler/test_integration.py b/Lib/test/test_profiling/test_sampling_profiler/test_integration.py index c6731e956391a9..3487647b76683e 100644 --- a/Lib/test/test_profiling/test_sampling_profiler/test_integration.py +++ b/Lib/test/test_profiling/test_sampling_profiler/test_integration.py @@ -686,8 +686,6 @@ def test_script_error_treatment(self): "-m", "profiling.sampling.cli", "run", - "-d", - "1", script_file.name, ], capture_output=True, From de7576edfa6e6fd46e433b668ae0610e89640230 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> Date: Tue, 2 Jun 2026 15:05:14 +0300 Subject: [PATCH 202/818] [3.15] Update `SOURCE_URI` for `3.15` branch (#150783) --- Doc/tools/extensions/pyspecific.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/tools/extensions/pyspecific.py b/Doc/tools/extensions/pyspecific.py index f9bf273e7624a0..85e7f5454252d2 100644 --- a/Doc/tools/extensions/pyspecific.py +++ b/Doc/tools/extensions/pyspecific.py @@ -22,7 +22,7 @@ from sphinx.util.docutils import SphinxDirective # Used in conf.py and updated here by python/release-tools/run_release.py -SOURCE_URI = 'https://github.com/python/cpython/tree/main/%s' +SOURCE_URI = 'https://github.com/python/cpython/tree/3.15/%s' class PyAwaitableMixin(object): def handle_signature(self, sig, signode): From c5248b7acf85bf900a01145842800c765c4690a6 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 2 Jun 2026 15:07:05 +0200 Subject: [PATCH 203/818] [3.15] gh-89554: Document _thread.LockType as a class (GH-150684) (#150785) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gh-89554: Document _thread.LockType as a class (GH-150684) _thread.LockType is a class (the type of lock objects), but was documented with the ".. data::" directive, so ":class:" cross-references to it cannot resolve against a py:class target. Switch the entry to ".. class::", move it next to the lock methods, and document acquire(), release() and locked() as methods of the class. Keep the old _thread.lock.* URL fragments working with raw HTML anchors. (cherry picked from commit e37ce569773b5e4e5c0e6042d4adfde2e9608f13) Co-authored-by: Bernát Gábor <gaborjbernat@gmail.com> --- Doc/library/_thread.rst | 79 +++++++++++++++++++++-------------------- 1 file changed, 41 insertions(+), 38 deletions(-) diff --git a/Doc/library/_thread.rst b/Doc/library/_thread.rst index 47f5eabb6f2180..13f463a1e95340 100644 --- a/Doc/library/_thread.rst +++ b/Doc/library/_thread.rst @@ -36,11 +36,6 @@ This module defines the following constants and functions: This is now a synonym of the built-in :exc:`RuntimeError`. -.. data:: LockType - - This is the type of lock objects. - - .. function:: start_new_thread(function, args[, kwargs]) Start a new thread and return its identifier. The thread executes the @@ -162,58 +157,66 @@ This module defines the following constants and functions: .. versionadded:: 3.2 -Lock objects have the following methods: +.. raw:: html + + <!-- Keep the old URL fragments working (see gh-89554) --> + <span id='thread.lock.acquire'></span> + <span id='thread.lock.release'></span> + <span id='thread.lock.locked'></span> +.. class:: LockType -.. method:: lock.acquire(blocking=True, timeout=-1) + This is the type of lock objects. - Without any optional argument, this method acquires the lock unconditionally, if - necessary waiting until it is released by another thread (only one thread at a - time can acquire a lock --- that's their reason for existence). + Lock objects have the following methods: - If the *blocking* argument is present, the action depends on its - value: if it is false, the lock is only acquired if it can be acquired - immediately without waiting, while if it is true, the lock is acquired - unconditionally as above. + .. method:: acquire(blocking=True, timeout=-1) - If the floating-point *timeout* argument is present and positive, it - specifies the maximum wait time in seconds before returning. A negative - *timeout* argument specifies an unbounded wait. You cannot specify - a *timeout* if *blocking* is false. + Without any optional argument, this method acquires the lock unconditionally, if + necessary waiting until it is released by another thread (only one thread at a + time can acquire a lock --- that's their reason for existence). - The return value is ``True`` if the lock is acquired successfully, - ``False`` if not. + If the *blocking* argument is present, the action depends on its + value: if it is false, the lock is only acquired if it can be acquired + immediately without waiting, while if it is true, the lock is acquired + unconditionally as above. - .. versionchanged:: 3.2 - The *timeout* parameter is new. + If the floating-point *timeout* argument is present and positive, it + specifies the maximum wait time in seconds before returning. A negative + *timeout* argument specifies an unbounded wait. You cannot specify + a *timeout* if *blocking* is false. - .. versionchanged:: 3.2 - Lock acquires can now be interrupted by signals on POSIX. + The return value is ``True`` if the lock is acquired successfully, + ``False`` if not. - .. versionchanged:: 3.14 - Lock acquires can now be interrupted by signals on Windows. + .. versionchanged:: 3.2 + The *timeout* parameter is new. + .. versionchanged:: 3.2 + Lock acquires can now be interrupted by signals on POSIX. -.. method:: lock.release() + .. versionchanged:: 3.14 + Lock acquires can now be interrupted by signals on Windows. - Releases the lock. The lock must have been acquired earlier, but not - necessarily by the same thread. + .. method:: release() + Releases the lock. The lock must have been acquired earlier, but not + necessarily by the same thread. -.. method:: lock.locked() + .. method:: locked() - Return the status of the lock: ``True`` if it has been acquired by some thread, - ``False`` if not. + Return the status of the lock: ``True`` if it has been acquired by some thread, + ``False`` if not. -In addition to these methods, lock objects can also be used via the -:keyword:`with` statement, e.g.:: + In addition to these methods, lock objects can also be used via the + :keyword:`with` statement, e.g.:: - import _thread + import _thread - a_lock = _thread.allocate_lock() + a_lock = _thread.allocate_lock() - with a_lock: - print("a_lock is locked while this executes") + with a_lock: + print("a_lock is locked while this executes") **Caveats:** From b17bcfdf7e716809254ba4e9168164bc81e8a2ca Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 2 Jun 2026 15:36:52 +0200 Subject: [PATCH 204/818] [3.15] gh-150766: export `_PyGC_VisitFrameStack` and `_PyGC_VisitStackRef` functions (GH-150767) (#150787) gh-150766: export `_PyGC_VisitFrameStack` and `_PyGC_VisitStackRef` functions (GH-150767) (cherry picked from commit df34a2f7122dcc6d230493b138e301675a290c49) Co-authored-by: Kumar Aditya <kumaraditya@python.org> --- Include/internal/pycore_gc.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Include/internal/pycore_gc.h b/Include/internal/pycore_gc.h index bfe52f42f1141c..84cbb56a919215 100644 --- a/Include/internal/pycore_gc.h +++ b/Include/internal/pycore_gc.h @@ -335,8 +335,9 @@ extern void _Py_RunGC(PyThreadState *tstate); union _PyStackRef; // GC visit callback for tracked interpreter frames -extern int _PyGC_VisitFrameStack(_PyInterpreterFrame *frame, visitproc visit, void *arg); -extern int _PyGC_VisitStackRef(union _PyStackRef *ref, visitproc visit, void *arg); +// GH-150766: exported for greenlet +PyAPI_FUNC(int) _PyGC_VisitFrameStack(_PyInterpreterFrame *frame, visitproc visit, void *arg); +PyAPI_FUNC(int) _PyGC_VisitStackRef(union _PyStackRef *ref, visitproc visit, void *arg); #ifdef Py_GIL_DISABLED extern void _PyGC_VisitObjectsWorldStopped(PyInterpreterState *interp, From 33b2879c3aeb6d4c6995bf6cda848f5731091a8d Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 2 Jun 2026 16:18:03 +0200 Subject: [PATCH 205/818] [3.15] gh-149187: Document `frozendict()` under 'Built-in Functions' (GH-149185) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (cherry picked from commit 86867edb84a53d60e3ec9d3d2e83f4ed09692b95) Co-authored-by: Øyvind Rønningstad <oyvind.ronningstad@nordicsemi.no> --- Doc/library/functions.rst | 57 +++++++++++++++++++++++++-------------- 1 file changed, 37 insertions(+), 20 deletions(-) diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst index 0393e2dc776db4..def2a211d1b3b4 100644 --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -19,24 +19,25 @@ are always available. They are listed here in alphabetical order. | | :func:`ascii` | | :func:`filter` | | :func:`map` | | **S** | | | | | :func:`float` | | :func:`max` | | |func-set|_ | | | **B** | | :func:`format` | | |func-memoryview|_ | | :func:`setattr` | -| | :func:`bin` | | |func-frozenset|_ | | :func:`min` | | :func:`sentinel` | -| | :func:`bool` | | | | | | :func:`slice` | -| | :func:`breakpoint` | | **G** | | **N** | | :func:`sorted` | -| | |func-bytearray|_ | | :func:`getattr` | | :func:`next` | | :func:`staticmethod` | -| | |func-bytes|_ | | :func:`globals` | | | | |func-str|_ | -| | | | | | **O** | | :func:`sum` | -| | **C** | | **H** | | :func:`object` | | :func:`super` | -| | :func:`callable` | | :func:`hasattr` | | :func:`oct` | | **T** | -| | :func:`chr` | | :func:`hash` | | :func:`open` | | |func-tuple|_ | -| | :func:`classmethod` | | :func:`help` | | :func:`ord` | | :func:`type` | -| | :func:`compile` | | :func:`hex` | | | | | -| | :func:`complex` | | | | **P** | | **V** | -| | | | **I** | | :func:`pow` | | :func:`vars` | -| | **D** | | :func:`id` | | :func:`print` | | | -| | :func:`delattr` | | :func:`input` | | :func:`property` | | **Z** | -| | |func-dict|_ | | :func:`int` | | | | :func:`zip` | -| | :func:`dir` | | :func:`isinstance` | | | | | -| | :func:`divmod` | | :func:`issubclass` | | | | **_** | +| | :func:`bin` | | |func-frozendict|_ | | :func:`min` | | :func:`sentinel` | +| | :func:`bool` | | |func-frozenset|_ | | | | :func:`slice` | +| | :func:`breakpoint` | | | | **N** | | :func:`sorted` | +| | |func-bytearray|_ | | **G** | | :func:`next` | | :func:`staticmethod` | +| | |func-bytes|_ | | :func:`getattr` | | | | |func-str|_ | +| | | | :func:`globals` | | **O** | | :func:`sum` | +| | **C** | | | | :func:`object` | | :func:`super` | +| | :func:`callable` | | **H** | | :func:`oct` | | | +| | :func:`chr` | | :func:`hasattr` | | :func:`open` | | **T** | +| | :func:`classmethod` | | :func:`hash` | | :func:`ord` | | |func-tuple|_ | +| | :func:`compile` | | :func:`help` | | | | :func:`type` | +| | :func:`complex` | | :func:`hex` | | **P** | | | +| | | | | | :func:`pow` | | **V** | +| | **D** | | **I** | | :func:`print` | | :func:`vars` | +| | :func:`delattr` | | :func:`id` | | :func:`property` | | | +| | |func-dict|_ | | :func:`input` | | | | **Z** | +| | :func:`dir` | | :func:`int` | | | | :func:`zip` | +| | :func:`divmod` | | :func:`isinstance` | | | | | +| | | | :func:`issubclass` | | | | **_** | | | | | :func:`iter` | | | | :func:`__import__` | +-------------------------+-----------------------+-----------------------+-------------------------+ @@ -44,6 +45,7 @@ are always available. They are listed here in alphabetical order. used, with replacement texts to make the output in the table consistent .. |func-dict| replace:: ``dict()`` +.. |func-frozendict| replace:: ``frozendict()`` .. |func-frozenset| replace:: ``frozenset()`` .. |func-memoryview| replace:: ``memoryview()`` .. |func-set| replace:: ``set()`` @@ -485,8 +487,8 @@ are always available. They are listed here in alphabetical order. Create a new dictionary. The :class:`dict` object is the dictionary class. See :class:`dict` and :ref:`typesmapping` for documentation about this class. - For other containers see the built-in :class:`list`, :class:`set`, and - :class:`tuple` classes, as well as the :mod:`collections` module. + For other containers see the built-in :class:`frozendict`, :class:`list`, + :class:`set`, and :class:`tuple` classes, as well as the :mod:`collections` module. .. function:: dir() @@ -864,6 +866,21 @@ are always available. They are listed here in alphabetical order. if *format_spec* is not an empty string. +.. _func-frozendict: +.. class:: frozendict(**kwargs) + frozendict(mapping, /, **kwargs) + frozendict(iterable, /, **kwargs) + :noindex: + + Create a new frozen dictionary. The :class:`frozendict` object is a built-in class. + See :class:`frozendict` and :ref:`typesmapping` for documentation about this class. + + For other containers see the built-in :class:`dict`, :class:`list`, :class:`set`, + and :class:`tuple` classes, as well as the :mod:`collections` module. + + .. versionadded:: 3.15 + + .. _func-frozenset: .. class:: frozenset(iterable=(), /) :noindex: From 13a7cce3638a11f59872925f37e398876a3c003e Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 2 Jun 2026 17:20:39 +0200 Subject: [PATCH 206/818] [3.15] Silence experimental coroutine deprecation warnings (GH-150788) (#150794) Co-authored-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> Co-authored-by: Zachary Ware <zach@python.org> --- PC/python_uwp.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/PC/python_uwp.cpp b/PC/python_uwp.cpp index 8cdb8d722cdb9a..1b44216dc20d1e 100644 --- a/PC/python_uwp.cpp +++ b/PC/python_uwp.cpp @@ -13,6 +13,7 @@ #if defined(__clang__) #define _SILENCE_CLANG_COROUTINE_MESSAGE #endif +#define _SILENCE_EXPERIMENTAL_COROUTINE_DEPRECATION_WARNINGS #include <appmodel.h> #include <winrt\Windows.ApplicationModel.h> From 94a64bbc6ce89644cf02b82c723d9cc37f6a1870 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> Date: Tue, 2 Jun 2026 18:28:30 +0300 Subject: [PATCH 207/818] Python 3.15.0b2 --- Doc/library/sqlite3.rst | 6 +- Include/patchlevel.h | 4 +- Lib/pydoc_data/module_docs.py | 2 +- Lib/pydoc_data/topics.py | 261 ++++-- Misc/NEWS.d/3.15.0b2.rst | 795 ++++++++++++++++++ ...-05-18-16-00-41.gh-issue-148260.UwFiIX.rst | 3 - ...-05-21-15-14-59.gh-issue-148294.VtFaW4.rst | 2 - ...-02-25-13-37-10.gh-issue-145235.-1ySNR.rst | 3 - ...-05-12-16-47-21.gh-issue-149725.HZLBTZ.rst | 2 - ...-04-15-15-48-04.gh-issue-148450.2MEVqH.rst | 1 - ...-05-07-03-18-59.gh-issue-149459.5fhAqP.rst | 1 - ...-05-09-15-22-32.gh-issue-144957.u1F2aQ.rst | 2 - ...-05-10-07-42-36.gh-issue-149642.6ZksML.rst | 2 - ...-05-10-16-43-50.gh-issue-148829.gscS14.rst | 2 - ...-05-11-14-48-56.gh-issue-149676.6aTrw1.rst | 1 - ...-05-12-16-47-23.gh-issue-139808.iIs7_E.rst | 2 - ...-05-13-06-54-41.gh-issue-149738.4BLFoH.rst | 2 - ...-05-14-19-41-03.gh-issue-149807.IwGaCo.rst | 2 - ...-05-15-11-31-57.gh-issue-149816.ugN2rx.rst | 1 - ...-05-16-11-03-54.gh-issue-149816.X_gqMT.rst | 1 - ...-05-18-13-47-17.gh-issue-149590.IPBeQx.rst | 1 - ...-05-18-16-54-54.gh-issue-150042.LSr5W8.rst | 1 - ...-05-18-18-36-28.gh-issue-148587.-RD3z5.rst | 1 - ...-05-20-13-06-17.gh-issue-150146.i5m_SL.rst | 5 - ...-05-22-17-09-28.gh-issue-150107.GD72-D.rst | 3 - ...-05-23-22-08-01.gh-issue-149449.2lhQFF.rst | 3 - ...-05-24-14-45-00.gh-issue-149156.NP73rB.rst | 3 - ...-05-25-16-00-22.gh-issue-150374.Emu6d8.rst | 1 - .../2021-10-18-13-46-55.bpo-45509.Upwb60.rst | 1 - ...-07-02-20-57-43.gh-issue-121109.Tp6R2s.rst | 2 - ...-11-02-02-02-31.gh-issue-107398.uUtA6Q.rst | 1 - ...-03-01-13-36-02.gh-issue-128110.9wx_G0.rst | 5 - ...-05-19-20-29-35.gh-issue-133998.KmElUw.rst | 5 - ...-05-19-21-08-25.gh-issue-134261.ravGYm.rst | 1 - ...-08-30-07-44-30.gh-issue-86533.pathlib.rst | 4 - ...3-26-09-30-00.gh-issue-146452.Y2N6qZ8J.rst | 2 - ...-04-23-12-50-15.gh-issue-148441.zvpCkR.rst | 4 - ...-04-27-11-12-00.gh-issue-149046.74shDd.rst | 2 - ...-04-29-08-10-17.gh-issue-149056.jnaD4W.rst | 2 - ...-05-07-14-18-47.gh-issue-149489.bX9iHe.rst | 5 - ...-05-07-21-58-17.gh-issue-149388.DDBPeA.rst | 1 - ...-05-08-09-11-48.gh-issue-149534.Tw7eeY.rst | 1 - ...-05-08-15-08-35.gh-issue-112821.t9T1YD.rst | 4 - ...-05-09-21-02-08.gh-issue-149614.U4snj3.rst | 1 - ...-05-10-07-21-51.gh-issue-139489.rS7LTA.rst | 1 - ...-05-10-19-26-50.gh-issue-149584.x7Qm9A.rst | 4 - ...-05-10-23-51-23.gh-issue-149504.pDSCbn.rst | 5 - ...-05-12-06-24-54.gh-issue-149701.8v9RTm.rst | 1 - ...-05-12-13-03-45.gh-issue-149718.SaM1NJ.rst | 4 - ...-05-13-23-18-39.gh-issue-149801.S_FfGr.rst | 2 - ...-05-14-15-55-28.gh-issue-149816.ZaXQ0q.rst | 2 - ...-05-15-16-28-00.gh-issue-149819.fixpth.rst | 4 - ...-05-15-18-44-20.gh-issue-142349.fHK3v1.rst | 1 - ...-05-16-21-08-33.gh-issue-149921.I1yNML.rst | 2 - ...-05-17-02-25-56.gh-issue-149571.LNyuWJ.rst | 2 - ...6-05-17-22-37-02.gh-issue-88726.BAoL6j.rst | 2 - ...-05-18-07-44-46.gh-issue-149995.vvtFHn.rst | 1 - ...-05-18-17-17-20.gh-issue-149189.a8IooK.rst | 1 - ...6-05-19-19-00-49.gh-issue-84353.ZU5zaQ.rst | 5 - ...-05-21-11-25-58.gh-issue-150175.8H4Caz.rst | 3 - ...5-21-20-47-45.gh-issue-150157.ZvmO-bQZ.rst | 3 - ...-05-25-07-22-05.gh-issue-150372.9hLqhe.rst | 2 - ...-05-25-17-00-00.gh-issue-150406.jF3g63.rst | 3 - ...-05-27-11-18-36.gh-issue-150228.pNPiO-.rst | 11 - ...-05-31-17-47-30.gh-issue-150685.EBB2mU.rst | 1 - ...-04-26-19-30-45.gh-issue-149018.a9SqWb.rst | 3 - ...-04-27-16-36-11.gh-issue-149079.vKl-LM.rst | 5 - ...-05-03-21-00-00.gh-issue-149486.tarflt.rst | 5 - ...-05-08-02-18-54.gh-issue-149474.ujQ-mu.rst | 3 - ...6-05-10-18-05-32.gh-issue-87451.XkKB6M.rst | 6 - ...-05-11-21-15-07.gh-issue-149698.OudOcW.rst | 2 - ...-05-13-14-53-23.gh-issue-149776.orqgsn.rst | 2 - ...-05-25-15-39-53.gh-issue-150387.yzZ7jq.rst | 5 - ...-05-22-18-51-09.gh-issue-150258.dh8GVK.rst | 1 - ...-04-26-23-14-45.gh-issue-149029.oPTXP4.rst | 1 - ...-04-29-14-44-51.gh-issue-138489.234aj6.rst | 4 - ...-05-06-21-36-53.gh-issue-124111.m4OBX8.rst | 1 - ...-05-14-22-09-46.gh-issue-149786.UI-HZM.rst | 1 - ...-04-26-23-15-09.gh-issue-149029.Lsx--T.rst | 1 - ...-05-31-10-40-00.gh-issue-150644.zLWyjj.rst | 3 - README.rst | 2 +- 81 files changed, 987 insertions(+), 272 deletions(-) create mode 100644 Misc/NEWS.d/3.15.0b2.rst delete mode 100644 Misc/NEWS.d/next/Build/2026-05-18-16-00-41.gh-issue-148260.UwFiIX.rst delete mode 100644 Misc/NEWS.d/next/Build/2026-05-21-15-14-59.gh-issue-148294.VtFaW4.rst delete mode 100644 Misc/NEWS.d/next/C_API/2026-02-25-13-37-10.gh-issue-145235.-1ySNR.rst delete mode 100644 Misc/NEWS.d/next/C_API/2026-05-12-16-47-21.gh-issue-149725.HZLBTZ.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-04-15-15-48-04.gh-issue-148450.2MEVqH.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-05-07-03-18-59.gh-issue-149459.5fhAqP.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-05-09-15-22-32.gh-issue-144957.u1F2aQ.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-05-10-07-42-36.gh-issue-149642.6ZksML.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-05-10-16-43-50.gh-issue-148829.gscS14.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-05-11-14-48-56.gh-issue-149676.6aTrw1.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-05-12-16-47-23.gh-issue-139808.iIs7_E.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-05-13-06-54-41.gh-issue-149738.4BLFoH.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-05-14-19-41-03.gh-issue-149807.IwGaCo.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-05-15-11-31-57.gh-issue-149816.ugN2rx.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-05-16-11-03-54.gh-issue-149816.X_gqMT.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-05-18-13-47-17.gh-issue-149590.IPBeQx.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-05-18-16-54-54.gh-issue-150042.LSr5W8.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-05-18-18-36-28.gh-issue-148587.-RD3z5.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-05-20-13-06-17.gh-issue-150146.i5m_SL.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-05-22-17-09-28.gh-issue-150107.GD72-D.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-05-23-22-08-01.gh-issue-149449.2lhQFF.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-05-24-14-45-00.gh-issue-149156.NP73rB.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-05-25-16-00-22.gh-issue-150374.Emu6d8.rst delete mode 100644 Misc/NEWS.d/next/Library/2021-10-18-13-46-55.bpo-45509.Upwb60.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-07-02-20-57-43.gh-issue-121109.Tp6R2s.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-11-02-02-02-31.gh-issue-107398.uUtA6Q.rst delete mode 100644 Misc/NEWS.d/next/Library/2025-03-01-13-36-02.gh-issue-128110.9wx_G0.rst delete mode 100644 Misc/NEWS.d/next/Library/2025-05-19-20-29-35.gh-issue-133998.KmElUw.rst delete mode 100644 Misc/NEWS.d/next/Library/2025-05-19-21-08-25.gh-issue-134261.ravGYm.rst delete mode 100644 Misc/NEWS.d/next/Library/2025-08-30-07-44-30.gh-issue-86533.pathlib.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-03-26-09-30-00.gh-issue-146452.Y2N6qZ8J.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-04-23-12-50-15.gh-issue-148441.zvpCkR.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-04-27-11-12-00.gh-issue-149046.74shDd.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-04-29-08-10-17.gh-issue-149056.jnaD4W.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-05-07-14-18-47.gh-issue-149489.bX9iHe.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-05-07-21-58-17.gh-issue-149388.DDBPeA.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-05-08-09-11-48.gh-issue-149534.Tw7eeY.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-05-08-15-08-35.gh-issue-112821.t9T1YD.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-05-09-21-02-08.gh-issue-149614.U4snj3.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-05-10-07-21-51.gh-issue-139489.rS7LTA.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-05-10-19-26-50.gh-issue-149584.x7Qm9A.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-05-10-23-51-23.gh-issue-149504.pDSCbn.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-05-12-06-24-54.gh-issue-149701.8v9RTm.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-05-12-13-03-45.gh-issue-149718.SaM1NJ.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-05-13-23-18-39.gh-issue-149801.S_FfGr.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-05-14-15-55-28.gh-issue-149816.ZaXQ0q.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-05-15-16-28-00.gh-issue-149819.fixpth.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-05-15-18-44-20.gh-issue-142349.fHK3v1.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-05-16-21-08-33.gh-issue-149921.I1yNML.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-05-17-02-25-56.gh-issue-149571.LNyuWJ.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-05-17-22-37-02.gh-issue-88726.BAoL6j.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-05-18-07-44-46.gh-issue-149995.vvtFHn.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-05-18-17-17-20.gh-issue-149189.a8IooK.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-05-19-19-00-49.gh-issue-84353.ZU5zaQ.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-05-21-11-25-58.gh-issue-150175.8H4Caz.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-05-21-20-47-45.gh-issue-150157.ZvmO-bQZ.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-05-25-07-22-05.gh-issue-150372.9hLqhe.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-05-25-17-00-00.gh-issue-150406.jF3g63.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-05-27-11-18-36.gh-issue-150228.pNPiO-.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-05-31-17-47-30.gh-issue-150685.EBB2mU.rst delete mode 100644 Misc/NEWS.d/next/Security/2026-04-26-19-30-45.gh-issue-149018.a9SqWb.rst delete mode 100644 Misc/NEWS.d/next/Security/2026-04-27-16-36-11.gh-issue-149079.vKl-LM.rst delete mode 100644 Misc/NEWS.d/next/Security/2026-05-03-21-00-00.gh-issue-149486.tarflt.rst delete mode 100644 Misc/NEWS.d/next/Security/2026-05-08-02-18-54.gh-issue-149474.ujQ-mu.rst delete mode 100644 Misc/NEWS.d/next/Security/2026-05-10-18-05-32.gh-issue-87451.XkKB6M.rst delete mode 100644 Misc/NEWS.d/next/Security/2026-05-11-21-15-07.gh-issue-149698.OudOcW.rst delete mode 100644 Misc/NEWS.d/next/Tests/2026-05-13-14-53-23.gh-issue-149776.orqgsn.rst delete mode 100644 Misc/NEWS.d/next/Tests/2026-05-25-15-39-53.gh-issue-150387.yzZ7jq.rst delete mode 100644 Misc/NEWS.d/next/Tools-Demos/2026-05-22-18-51-09.gh-issue-150258.dh8GVK.rst delete mode 100644 Misc/NEWS.d/next/Windows/2026-04-26-23-14-45.gh-issue-149029.oPTXP4.rst delete mode 100644 Misc/NEWS.d/next/Windows/2026-04-29-14-44-51.gh-issue-138489.234aj6.rst delete mode 100644 Misc/NEWS.d/next/Windows/2026-05-06-21-36-53.gh-issue-124111.m4OBX8.rst delete mode 100644 Misc/NEWS.d/next/Windows/2026-05-14-22-09-46.gh-issue-149786.UI-HZM.rst delete mode 100644 Misc/NEWS.d/next/macOS/2026-04-26-23-15-09.gh-issue-149029.Lsx--T.rst delete mode 100644 Misc/NEWS.d/next/macOS/2026-05-31-10-40-00.gh-issue-150644.zLWyjj.rst diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst index 3a75d44f3f7d21..36f080b56ffea7 100644 --- a/Doc/library/sqlite3.rst +++ b/Doc/library/sqlite3.rst @@ -1417,7 +1417,7 @@ Connection objects See :ref:`sqlite3-howto-row-factory` for more details. - .. versionchanged:: next + .. versionchanged:: 3.15 Deleting the ``row_factory`` attribute is no longer allowed. .. attribute:: text_factory @@ -1429,7 +1429,7 @@ Connection objects See :ref:`sqlite3-howto-encoding` for more details. - .. versionchanged:: next + .. versionchanged:: 3.15 Deleting the ``text_factory`` attribute is no longer allowed. .. attribute:: total_changes @@ -1715,7 +1715,7 @@ Cursor objects See :ref:`sqlite3-howto-row-factory` for more details. - .. versionchanged:: next + .. versionchanged:: 3.15 Deleting the ``row_factory`` attribute is no longer allowed. diff --git a/Include/patchlevel.h b/Include/patchlevel.h index cdca931566577f..649609136fec80 100644 --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -24,10 +24,10 @@ #define PY_MINOR_VERSION 15 #define PY_MICRO_VERSION 0 #define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_BETA -#define PY_RELEASE_SERIAL 1 +#define PY_RELEASE_SERIAL 2 /* Version as a string */ -#define PY_VERSION "3.15.0b1+" +#define PY_VERSION "3.15.0b2" /*--end constants--*/ diff --git a/Lib/pydoc_data/module_docs.py b/Lib/pydoc_data/module_docs.py index 1a3126d3db9590..0505210b0bfe0d 100644 --- a/Lib/pydoc_data/module_docs.py +++ b/Lib/pydoc_data/module_docs.py @@ -1,4 +1,4 @@ -# Autogenerated by Sphinx on Thu May 7 16:26:23 2026 +# Autogenerated by Sphinx on Tue Jun 2 18:28:34 2026 # as part of the release process. module_docs = { diff --git a/Lib/pydoc_data/topics.py b/Lib/pydoc_data/topics.py index 5f61001c46b79c..3ab289ebed6a6f 100644 --- a/Lib/pydoc_data/topics.py +++ b/Lib/pydoc_data/topics.py @@ -1,4 +1,4 @@ -# Autogenerated by Sphinx on Thu May 7 16:26:23 2026 +# Autogenerated by Sphinx on Tue Jun 2 18:28:34 2026 # as part of the release process. topics = { @@ -2344,9 +2344,9 @@ def foo(): The match statement is used for pattern matching. Syntax: match_stmt: 'match' subject_expr ":" NEWLINE INDENT case_block+ DEDENT - subject_expr: `!star_named_expression` "," `!star_named_expressions`? - | `!named_expression` - case_block: 'case' patterns [guard] ":" `!block` + subject_expr: flexible_expression "," [flexible_expression_list [',']] + | assignment_expression + case_block: 'case' patterns [guard] ":" suite Note: @@ -2437,7 +2437,7 @@ def foo(): Guards ------ - guard: "if" `!named_expression` + guard: "if" assignment_expression A "guard" (which is part of the "case") must succeed for code inside the "case" block to execute. It takes the form: "if" followed by an @@ -4971,61 +4971,49 @@ def inner(x): 'dict': r'''Dictionary displays ******************* -A dictionary display is a possibly empty series of dict items -(key/value pairs) enclosed in curly braces: - - dict_display: "{" [dict_item_list | dict_comprehension] "}" - dict_item_list: dict_item ("," dict_item)* [","] - dict_comprehension: dict_item comp_for - dict_item: expression ":" expression | "**" or_expr - -A dictionary display yields a new dictionary object. - -If a comma-separated sequence of dict items is given, they are -evaluated from left to right to define the entries of the dictionary: -each key object is used as a key into the dictionary to store the -corresponding value. This means that you can specify the same key -multiple times in the dict item list, and the final dictionary’s value -for that key will be the last one given. - -A double asterisk "**" denotes *dictionary unpacking*. Its operand -must be a *mapping*. Each mapping item is added to the new -dictionary. Later values replace values already set by earlier dict -items and earlier dictionary unpackings. +A *dictionary display* is a possibly empty series of *dict items* +enclosed in curly braces. Each dict item is a colon-separated pair of +expressions: the *key* and its associated *value*. For example: + + >>> {1: 'one', 2: 'two'} + {1: 'one', 2: 'two'} + +At runtime, when a dictionary comprehension is evaluated, the +expressions are evaluated from left to right. Each key object is used +as a key into the dictionary to store the corresponding value. This +means that you can specify the same key multiple times in the +comprehension, and the final dictionary’s value for a given key will +be the last one given. For example: + + >>> { + ... 1: 'this will be overridden', + ... 2: 'two', + ... 1: 'also overridden', + ... 1: 'one', + ... } + {1: 'one', 2: 'two'} + +Instead of a key-value pair, a dict item may be an expression prefixed +by a double asterisk "**". This denotes *dictionary unpacking*. At +runtime, the expression must evaluate to a *mapping*; each item of the +mapping is added to the new dictionary. As with key-value pairs, later +values replace values already set by earlier items and unpackings. +This may be used to override a set of defaults: + + >>> defaults = {'color': 'blue', 'count': 8} + >>> overrides = {'color': 'yellow'} + >>> {**defaults, **overrides} + {'color': 'yellow', 'count': 8} Added in version 3.5: Unpacking into dictionary displays, originally proposed by **PEP 448**. -A dict comprehension may take one of two forms: - -* The first form uses two expressions separated with a colon followed - by the usual “for” and “if” clauses. When the comprehension is run, - the resulting key and value elements are inserted in the new - dictionary in the order they are produced. - -* The second form uses a single expression prefixed by the "**" - dictionary unpacking operator followed by the usual “for” and “if” - clauses. When the comprehension is evaluated, the expression is - evaluated and then unpacked, inserting zero or more key/value pairs - into the new dictionary. - -Both forms of dictionary comprehension retain the property that if the -same key is specified multiple times, the associated value in the -resulting dictionary will be the last one specified. - -Restrictions on the types of the key values are listed earlier in -section The standard type hierarchy. (To summarize, the key type -should be *hashable*, which excludes all mutable objects.) Clashes -between duplicate keys are not detected; the last value (textually -rightmost in the display) stored for a given key value prevails. +The formal grammar for dict displays is: -Changed in version 3.8: Prior to Python 3.8, in dict comprehensions, -the evaluation order of key and value was not well-defined. In -CPython, the value was evaluated before the key. Starting with 3.8, -the key is evaluated before the value, as proposed by **PEP 572**. - -Changed in version 3.15: Unpacking with the "**" operator is now -allowed in dictionary comprehensions. + dict: '{' [double_starred_kvpairs] '}' + double_starred_kvpairs: ','.double_starred_kvpair+ [','] + double_starred_kvpair: '**' or_expr | kvpair + kvpair: expression ':' expression ''', 'dynamic-features': r'''Interaction with dynamic features ********************************* @@ -5655,8 +5643,22 @@ class of the instance or a *non-virtual base class* thereof. The is the number of expressions in the list. The expressions are evaluated from left to right. -An asterisk "*" denotes *iterable unpacking*. Its operand must be an -*iterable*. The iterable is expanded into a sequence of items, which +A trailing comma is required only to create a one-item tuple, such as +"1,"; it is optional in all other cases. A single expression without a +trailing comma doesn’t create a tuple, but rather yields the value of +that expression. (To create an empty tuple, use an empty pair of +parentheses: "()".) + + +Iterable unpacking +================== + +In an expression list or tuple, list or set display, any expression +may be prefixed with an asterisk ("*"). This denotes *iterable +unpacking*. + +At runtime, the asterisk-prefixed expression must evaluate to an +*iterable*. The iterable is expanded into a sequence of items, which are included in the new tuple, list, or set, at the site of the unpacking. @@ -5665,12 +5667,6 @@ class of the instance or a *non-virtual base class* thereof. The Added in version 3.11: Any item in an expression list may be starred. See **PEP 646**. - -A trailing comma is required only to create a one-item tuple, such as -"1,"; it is optional in all other cases. A single expression without a -trailing comma doesn’t create a tuple, but rather yields the value of -that expression. (To create an empty tuple, use an empty pair of -parentheses: "()".) ''', 'floating': r'''Floating-point literals *********************** @@ -6015,7 +6011,8 @@ class of the instance or a *non-virtual base class* thereof. The | | is not supported. | +-----------+------------------------------------------------------------+ -For a locale aware separator, use the "'n'" presentation type instead. +For a locale-aware separator, use the "'n'" float presentation type or +integer presentation type instead. Changed in version 3.1: Added the "','" option (see also **PEP 378**). @@ -6061,7 +6058,10 @@ class of the instance or a *non-virtual base class* thereof. The +-----------+------------------------------------------------------------+ | "'n'" | Number. This is the same as "'d'", except that it uses the | | | current locale setting to insert the appropriate digit | - | | group separators. | + | | group separators. Note that the default locale is not the | + | | system locale. Depending on your use case, you may wish to | + | | set "LC_NUMERIC" with "locale.setlocale()" before using | + | | "'n'". | +-----------+------------------------------------------------------------+ | None | The same as "'d'". | +-----------+------------------------------------------------------------+ @@ -6135,7 +6135,10 @@ class of the instance or a *non-virtual base class* thereof. The +-----------+------------------------------------------------------------+ | "'n'" | Number. This is the same as "'g'", except that it uses the | | | current locale setting to insert the appropriate digit | - | | group separators for the integral part of a number. | + | | group separators for the integral part of a number. Note | + | | that the default locale is not the system locale. | + | | Depending on your use case, you may wish to set | + | | "LC_NUMERIC" with "locale.setlocale()" before using "'n'". | +-----------+------------------------------------------------------------+ | "'%'" | Percentage. Multiplies the number by 100 and displays in | | | fixed ("'f'") format, followed by a percent sign. | @@ -7231,21 +7234,113 @@ def <lambda>(parameters): See section Function definitions for the syntax of parameter lists. Note that functions created with lambda expressions cannot contain statements or annotations. +''', + 'lazy': r'''Lazy imports +************ + +The "lazy" keyword is a soft keyword that only has special meaning +when it appears immediately before an "import" or "from" statement. +When an import statement is preceded by the "lazy" keyword, the import +becomes *lazy*: the module is not loaded immediately at the import +statement. Instead, a lazy proxy object is created and bound to the +name. The actual module is loaded on first use of that name. + +Lazy imports are only permitted at module scope. Using "lazy" inside a +function, class body, or "try"/"except"/"finally" block raises a +"SyntaxError". Star imports cannot be lazy ("lazy from module import +*" is a syntax error), and future statements cannot be lazy. + +When using "lazy from ... import", each imported name is bound to a +lazy proxy object. The first access to any of these names triggers +loading of the entire module and resolves only that specific name to +its actual value. Other names remain as lazy proxies until they are +accessed. + +Example: + + lazy import json + import sys + + print('json' in sys.modules) # False - json module not yet loaded + + # First use triggers loading + result = json.dumps({"hello": "world"}) + + print('json' in sys.modules) # True - now loaded + +If an error occurs during module loading (such as "ImportError" or +"SyntaxError"), it is raised at the point where the lazy import is +first used, not at the import statement itself. + +See **PEP 810** for the full specification of lazy imports. + +Added in version 3.15. + + +Compatibility via "__lazy_modules__" +==================================== + +As an alternative to using the "lazy" keyword, a module can opt into +lazy loading for specific imports by defining a module-level +"__lazy_modules__" variable. When present, it must be a container of +fully qualified module name strings. Any regular (non-"lazy") +"import" statement at module scope whose target appears in +"__lazy_modules__" is treated as a lazy import, exactly as if the +"lazy" keyword had been used. + +This provides a way to enable lazy loading for specific dependencies +without changing individual "import" statements. This is useful when +supporting Python versions older than 3.15 while using lazy imports in +3.15+: + + __lazy_modules__ = ["json", "pathlib"] + + import json # loaded lazily (name is in __lazy_modules__) + import os # loaded eagerly (name not in __lazy_modules__) + + import pathlib # loaded lazily + +Relative imports are resolved to their absolute name before the +lookup, so "__lazy_modules__" must always contain fully qualified +module names. + +For "from"-style imports, the relevant name is the module following +"from", not the names of its members: + + # In mypackage/mymodule.py + __lazy_modules__ = ["mypackage", "mypackage.sub.utils"] + + from . import helper # loaded lazily: . resolves to mypackage + from .sub.utils import func # loaded lazily: .sub.utils resolves to mypackage.sub.utils + import json # loaded eagerly (not in __lazy_modules__) + +Imports inside functions, class bodies, or "try"/"except"/"finally" +blocks are always eager, regardless of "__lazy_modules__". + +Setting "-X lazy_imports=none" (or the "PYTHON_LAZY_IMPORTS" +environment variable to "none") overrides "__lazy_modules__" and +forces all imports to be eager. + +Added in version 3.15. ''', 'lists': r'''List displays ************* -A list display is a possibly empty series of expressions enclosed in -square brackets: +A *list display* is a possibly empty series of expressions enclosed in +square brackets. For example: + + >>> ["one", "two", "three"] + ['one', 'two', 'three'] + >>> ["one"] # One-element list + ['one'] + >>> [] # empty list + [] - list_display: "[" [flexible_expression_list | comprehension] "]" +See Container displays for general information on displays. -A list display yields a new list object, the contents being specified -by either a list of expressions or a comprehension. When a comma- -separated list of expressions is supplied, its elements are evaluated -from left to right and placed into the list object in that order. -When a comprehension is supplied, the list is constructed from the -elements resulting from the comprehension. +The formal grammar for list displays is: + + list: '[' [flexible_expression_list] ']' ''', 'naming': r'''Naming and binding ****************** @@ -11059,6 +11154,8 @@ class is used in a class pattern with positional arguments, each not a prefix or suffix; rather, all combinations of its values are stripped. + Whitespace characters are defined by "str.isspace()". + For example: >>> ' spacious '.strip() @@ -12447,7 +12544,7 @@ def foo(): target of assignments or "del" statements. The built-in function "len()" returns the number of items in a mapping. -There is currently a single intrinsic mapping type: +There are two intrinsic mapping types: Dictionaries @@ -12481,6 +12578,18 @@ def foo(): rather than a language guarantee. +Frozen dictionaries +------------------- + +These represent an immutable dictionary. They are created by the +built-in "frozendict()" constructor. A frozendict is *hashable* if +all of its keys and values are hashable, in which case it can be used +as an element of a set, or as a key in another mapping. "frozendict" +is not a subclass of "dict"; it inherits directly from "object". + +Added in version 3.15. + + Callable types ============== diff --git a/Misc/NEWS.d/3.15.0b2.rst b/Misc/NEWS.d/3.15.0b2.rst new file mode 100644 index 00000000000000..24fef1907d5122 --- /dev/null +++ b/Misc/NEWS.d/3.15.0b2.rst @@ -0,0 +1,795 @@ +.. date: 2026-05-11-21-15-07 +.. gh-issue: 149698 +.. nonce: OudOcW +.. release date: 2026-06-02 +.. section: Security + +Update bundled `libexpat <https://libexpat.github.io/>`_ to version 2.8.1 +for the fix for :cve:`2026-45186`. + +.. + +.. date: 2026-05-10-18-05-32 +.. gh-issue: 87451 +.. nonce: XkKB6M +.. section: Security + +The :mod:`ftplib` module's undocumented ``ftpcp`` function no longer trusts +the IPv4 address value returned from the source server in response to the +``PASV`` command by default, completing the fix for CVE-2021-4189. As with +:class:`ftplib.FTP`, the former behavior can be re-enabled by setting the +``trust_server_pasv_ipv4_address`` attribute on the source +:class:`ftplib.FTP` instance to ``True``. Thanks to Qi Deng at Aurascape AI +for the report. + +.. + +.. date: 2026-05-08-02-18-54 +.. gh-issue: 149474 +.. nonce: ujQ-mu +.. section: Security + +Fix the binary writer in :mod:`profiling.sampling` not firing the audit +(:pep:`578`) when creating the output file. The writer and the reader now +accept any path-like object. Patch by Maurycy Pawłowski-Wieroński. + +.. + +.. date: 2026-05-03-21-00-00 +.. gh-issue: 149486 +.. nonce: tarflt +.. section: Security + +:func:`tarfile.data_filter` now validates link targets using the same +normalised value that is written to disk, strips trailing separators from +the member name when resolving a symlink's directory, and rejects link +members that would replace the destination directory itself. This closes +several path-traversal bypasses of the ``data`` extraction filter. + +.. + +.. date: 2026-04-27-16-36-11 +.. gh-issue: 149079 +.. nonce: vKl-LM +.. section: Security + +Fix a potential denial of service in :func:`unicodedata.normalize`. The +canonical ordering step of Unicode normalization used a quadratic-time +insertion sort for reordering combining characters, which could be exploited +with crafted input containing many combining characters in non-canonical +order. Replaced with a linear-time counting sort for long runs. + +.. + +.. date: 2026-04-26-19-30-45 +.. gh-issue: 149018 +.. nonce: a9SqWb +.. section: Security + +Improved protection against XML hash-flooding attacks in +:mod:`xml.parsers.expat` and :mod:`xml.etree.ElementTree` when Python is +compiled with libExpat 2.8.0 or later. + +.. + +.. date: 2026-05-25-16-00-22 +.. gh-issue: 150374 +.. nonce: Emu6d8 +.. section: Core and Builtins + +Fix double release of the import lock on lazy import reification errors. + +.. + +.. date: 2026-05-24-14-45-00 +.. gh-issue: 149156 +.. nonce: NP73rB +.. section: Core and Builtins + +Fix an intermittent crash after :func:`os.fork` when perf trampoline +profiling is enabled and the child returns through trampoline frames +inherited from the parent process. + +.. + +.. date: 2026-05-23-22-08-01 +.. gh-issue: 149449 +.. nonce: 2lhQFF +.. section: Core and Builtins + +Fix a use-after-free crash when the :mod:`unicodedata` module was removed +from :data:`sys.modules` and garbage-collected between calls that decode +``\N{...}`` escapes or use the ``namereplace`` codec error handler. + +.. + +.. date: 2026-05-22-17-09-28 +.. gh-issue: 150107 +.. nonce: GD72-D +.. section: Core and Builtins + +:mod:`asyncio`: ``sendfile()`` and ``sock_sendfile()`` event loop methods +now call ``file.seek(offset)`` if *file* has a ``seek()`` method, even if +*offset* is ``0`` (default value). + +.. + +.. date: 2026-05-20-13-06-17 +.. gh-issue: 150146 +.. nonce: i5m_SL +.. section: Core and Builtins + +Fix a crash on a complex type variable substitution. + +``from typing import TypeVar; memoryview[TypeVar("")][*typing.Mapping[..., +...]]`` used to fail due to missing ``NULL`` check on ``_unpack_args`` C +function call. + +.. + +.. date: 2026-05-18-18-36-28 +.. gh-issue: 148587 +.. nonce: -RD3z5 +.. section: Core and Builtins + +``sys.lazy_modules`` is now a set instead of a dict as initially spelled out +in PEP 810. + +.. + +.. date: 2026-05-18-16-54-54 +.. gh-issue: 150042 +.. nonce: LSr5W8 +.. section: Core and Builtins + +Fix refleak in queue.SimpleQueue.put if memory allocation fails. + +.. + +.. date: 2026-05-18-13-47-17 +.. gh-issue: 149590 +.. nonce: IPBeQx +.. section: Core and Builtins + +Fix crash when faulthandler is imported more than once. + +.. + +.. date: 2026-05-16-11-03-54 +.. gh-issue: 149816 +.. nonce: X_gqMT +.. section: Core and Builtins + +Fix a race condition in ``_PyBytes_FromList`` in free-threading mode. + +.. + +.. date: 2026-05-15-11-31-57 +.. gh-issue: 149816 +.. nonce: ugN2rx +.. section: Core and Builtins + +Fix a race condition in :class:`memoryview` with free-threading. + +.. + +.. date: 2026-05-14-19-41-03 +.. gh-issue: 149807 +.. nonce: IwGaCo +.. section: Core and Builtins + +Fix ``hash(frozendict)``: compute the hash of each ``(key, value)`` pair +correctly. Patch by Victor Stinner. + +.. + +.. date: 2026-05-13-06-54-41 +.. gh-issue: 149738 +.. nonce: 4BLFoH +.. section: Core and Builtins + +:mod:`sqlite3`: Disallow removing ``row_factory`` and ``text_factory`` +attributes of a connection to prevent a crash on a query. + +.. + +.. date: 2026-05-12-16-47-23 +.. gh-issue: 139808 +.. nonce: iIs7_E +.. section: Core and Builtins + +Add branch protections for AArch64 (BTI/PAC) in assembly code used by +:option:`-X perf_jit <-X>` (Linux perf profiler integration). + +.. + +.. date: 2026-05-11-14-48-56 +.. gh-issue: 149676 +.. nonce: 6aTrw1 +.. section: Core and Builtins + +Fix ``frozendict | frozendict`` hash. + +.. + +.. date: 2026-05-10-16-43-50 +.. gh-issue: 148829 +.. nonce: gscS14 +.. section: Core and Builtins + +:class:`sentinel` objects now support a ``repr=`` argument and their +:attr:`~sentinel.__module__` attribute is writable. + +.. + +.. date: 2026-05-10-07-42-36 +.. gh-issue: 149642 +.. nonce: 6ZksML +.. section: Core and Builtins + +Allow imports inside ``exec()`` calls within functions under +``PYTHON_LAZY_IMPORTS=all``. + +.. + +.. date: 2026-05-09-15-22-32 +.. gh-issue: 144957 +.. nonce: u1F2aQ +.. section: Core and Builtins + +Fix lazy ``from`` imports of module attributes provided by module-level +``__getattr__``. + +.. + +.. date: 2026-05-07-03-18-59 +.. gh-issue: 149459 +.. nonce: 5fhAqP +.. section: Core and Builtins + +Fix a crash in the JIT optimizer when a specialized ``LOAD_SPECIAL`` guard +deoptimized after inserting the synthetic ``NULL`` stack entry. + +.. + +.. date: 2026-04-15-15-48-04 +.. gh-issue: 148450 +.. nonce: 2MEVqH +.. section: Core and Builtins + +Fix ``abc.register()`` so it invalidates type version tags for registered +classes. + +.. + +.. date: 2026-05-31-17-47-30 +.. gh-issue: 150685 +.. nonce: EBB2mU +.. section: Library + +Update bundled pip to 26.1.2 + +.. + +.. date: 2026-05-27-11-18-36 +.. gh-issue: 150228 +.. nonce: pNPiO- +.. section: Library + +The new :class:`site.StartupState` class lets callers batch-process +:pep:`829` startup configuration files across multiple site directories +before any startup code runs, with public +:meth:`~site.StartupState.addsitedir`, +:meth:`~site.StartupState.addusersitepackages`, +:meth:`~site.StartupState.addsitepackages`, and +:meth:`~site.StartupState.process` methods. The signature of +:func:`site.addsitedir` is unchanged from Python 3.14. The +:data:`!defer_processing_start_files` argument and the +``process_startup_files()`` function added earlier in the 3.15 cycle have +been removed; use :class:`!site.StartupState` instead. + +.. + +.. date: 2026-05-25-17-00-00 +.. gh-issue: 150406 +.. nonce: jF3g63 +.. section: Library + +Fix a possible crash occurring during :mod:`socket` module initialization +when the system is out of memory on platforms without a reentrant +``gethostbyname``. + +.. + +.. date: 2026-05-25-07-22-05 +.. gh-issue: 150372 +.. nonce: 9hLqhe +.. section: Library + +:mod:`readline`: Fix a potential crash during tab completion caused by an +out-of-memory error during module initialization. + +.. + +.. date: 2026-05-21-20-47-45 +.. gh-issue: 150157 +.. nonce: ZvmO-bQZ +.. section: Library + +Fix a crash in free-threaded builds that occurs when pickling by name +objects without a ``__module__`` attribute while :data:`sys.modules` is +concurrently being modified. + +.. + +.. date: 2026-05-21-11-25-58 +.. gh-issue: 150175 +.. nonce: 8H4Caz +.. section: Library + +Fix race condition in :class:`unittest.mock.ThreadingMock` where concurrent +calls could lose increments to ``call_count`` and other attributes due to a +missing lock in ``_increment_mock_call``. + +.. + +.. date: 2026-05-19-19-00-49 +.. gh-issue: 84353 +.. nonce: ZU5zaQ +.. section: Library + +Preserve non-UTF-8 encoded filenames when appending to a +:class:`zipfile.ZipFile`. Previously, non-ASCII names stored in a legacy +encoding (without the UTF-8 flag bit set) could be corrupted when the +central directory was rewritten: they were decoded as cp437 and then +re-stored as UTF-8. + +.. + +.. date: 2026-05-18-17-17-20 +.. gh-issue: 149189 +.. nonce: a8IooK +.. section: Library + +Revert the changes to :mod:`pprint` defaults. Patch by Hugo van Kemenade. + +.. + +.. date: 2026-05-18-07-44-46 +.. gh-issue: 149995 +.. nonce: vvtFHn +.. section: Library + +Update various docstrings in :mod:`typing`. + +.. + +.. date: 2026-05-17-22-37-02 +.. gh-issue: 88726 +.. nonce: BAoL6j +.. section: Library + +The :mod:`email` package now uses standard MIME charset names "gb2312" and +"big5" instead of non-standard names "eucgb2312_cn" and "big5_tw". + +.. + +.. date: 2026-05-17-02-25-56 +.. gh-issue: 149571 +.. nonce: LNyuWJ +.. section: Library + +Fix the C implementation of :meth:`xml.etree.ElementTree.Element.itertext`: +it no longer emits text for comments and processing instructions. + +.. + +.. date: 2026-05-16-21-08-33 +.. gh-issue: 149921 +.. nonce: I1yNML +.. section: Library + +Fix reference leaks in error paths of the :mod:`!_interpchannels` and +:mod:`!_interpqueues` extension modules. + +.. + +.. date: 2026-05-15-18-44-20 +.. gh-issue: 142349 +.. nonce: fHK3v1 +.. section: Library + +Add :keyword:`lazy` to the list of support topic by :func:`help`. + +.. + +.. date: 2026-05-15-16-28-00 +.. gh-issue: 149819 +.. nonce: fixpth +.. section: Library + +Fix regression in :func:`site.addsitedir` where ``.pth`` files were no +longer processed in Python subprocesses. This happened because +:func:`site.main` seeded ``known_paths`` with entries inherited from the +parent process, causing ``addsitedir`` to skip ``.pth`` processing. + +.. + +.. date: 2026-05-14-15-55-28 +.. gh-issue: 149816 +.. nonce: ZaXQ0q +.. section: Library + +Fix a race condition in ``_random.Random.__init__`` method in free-threading +mode. + +.. + +.. date: 2026-05-13-23-18-39 +.. gh-issue: 149801 +.. nonce: S_FfGr +.. section: Library + +Add IANA registered names and aliases with leading zeros before number (like +IBM00858, CP00858, IBM01140, CP01140) for corresponding codecs. + +.. + +.. date: 2026-05-12-13-03-45 +.. gh-issue: 149718 +.. nonce: SaM1NJ +.. section: Library + +Coalesce consecutive identical stack frames in Tachyon, so aggregating +collectors (pstats, collapsed, flamegraph, gecko) receive one collect. +Improves sample rate 3x, error rate and missed rate drop by 70%. Patch by +Maurycy Pawłowski-Wieroński. + +.. + +.. date: 2026-05-12-06-24-54 +.. gh-issue: 149701 +.. nonce: 8v9RTm +.. section: Library + +Fix bad return code from Lib/venv/bin/activate if hashing is disabled + +.. + +.. date: 2026-05-10-23-51-23 +.. gh-issue: 149504 +.. nonce: pDSCbn +.. section: Library + +Fix :func:`site.addsitedir` to allow re-entrant calls from within startup +files. Previously, a ``.pth`` file containing an ``import`` line that +called :func:`site.addsitedir` (or a ``.start`` entry point doing the same) +could crash with ``RuntimeError: dictionary changed size during iteration`` +during site initialization, breaking tools such as ``uv run --with``. + +.. + +.. date: 2026-05-10-19-26-50 +.. gh-issue: 149584 +.. nonce: x7Qm9A +.. section: Library + +Fix excessive overhead in the Tachyon profiler when inspecting a remote +process by avoiding repeated remote page-cache scans, batching predicted +remote reads, and reusing cached profiler result objects. Patch by Pablo +Galindo and Maurycy Pawłowski-Wieroński. + +.. + +.. date: 2026-05-10-07-21-51 +.. gh-issue: 139489 +.. nonce: rS7LTA +.. section: Library + +Add :func:`xml.is_valid_text` to ``xml.__all__``. + +.. + +.. date: 2026-05-09-21-02-08 +.. gh-issue: 149614 +.. nonce: U4snj3 +.. section: Library + +Fix a regression that broke the ability to deepcopy +:class:`argparse.ArgumentParser` instances. + +.. + +.. date: 2026-05-08-15-08-35 +.. gh-issue: 112821 +.. nonce: t9T1YD +.. section: Library + +In the REPL, autocompletion might run arbitrary code in the getter of a +descriptor. If that getter raised an exception, autocompletion would fail to +present any options for the entire object. Autocompletion now works as +expected for these objects. + +.. + +.. date: 2026-05-08-09-11-48 +.. gh-issue: 149534 +.. nonce: Tw7eeY +.. section: Library + +Fix merging of :class:`collections.defaultdict` and :class:`frozendict`. + +.. + +.. date: 2026-05-07-21-58-17 +.. gh-issue: 149388 +.. nonce: DDBPeA +.. section: Library + +Make :class:`!asyncio.windows_utils.PipeHandle` closing idempotent. + +.. + +.. date: 2026-05-07-14-18-47 +.. gh-issue: 149489 +.. nonce: bX9iHe +.. section: Library + +Fix :mod:`~xml.etree.ElementTree` serialization to HTML. The content of +comments, processing instructions and elements "xmp", "iframe", "noembed", +"noframes", and "plaintext" is no longer escaped. The "plaintext" element no +longer have the closing tag. Add support of empty attributes (with value +``None``). + +.. + +.. date: 2026-04-29-08-10-17 +.. gh-issue: 149056 +.. nonce: jnaD4W +.. section: Library + +Fix :func:`json.load` not forwarding the *array_hook* argument to +:func:`json.loads`. Patch by Thomas Kowalski. + +.. + +.. date: 2026-04-27-11-12-00 +.. gh-issue: 149046 +.. nonce: 74shDd +.. section: Library + +:mod:`io`: Fix :class:`io.StringIO` serialization: no longer call +``str(obj)`` on :class:`str` subclasses. Patch by Thomas Kowalski. + +.. + +.. date: 2026-04-23-12-50-15 +.. gh-issue: 148441 +.. nonce: zvpCkR +.. section: Library + +:mod:`xml.parsers.expat`: prevent a crash in +:meth:`~xml.parsers.expat.xmlparser.CharacterDataHandler` when the character +data size exceeds the parser's :attr:`buffer size +<xml.parsers.expat.xmlparser.buffer_size>`. + +.. + +.. date: 2026-03-26-09-30-00 +.. gh-issue: 146452 +.. nonce: Y2N6qZ8J +.. section: Library + +Fix segfault in :mod:`pickle` when pickling a dictionary concurrently +mutated by another thread in the free-threaded build. + +.. + +.. date: 2025-08-30-07-44-30 +.. gh-issue: 86533 +.. nonce: pathlib +.. section: Library + +The :func:`os.makedirs` function and :meth:`pathlib.Path.mkdir` method now +have a *parent_mode* parameter to specify the mode for intermediate +directories when creating parent directories. This allows one to match the +behavior from Python 3.6 and earlier for :func:`os.makedirs`. + +.. + +.. date: 2025-05-19-21-08-25 +.. gh-issue: 134261 +.. nonce: ravGYm +.. section: Library + +zip: On reproducible builds, ZipFile uses UTC instead of the local time when +writing file datetimes to avoid underflows. + +.. + +.. date: 2025-05-19-20-29-35 +.. gh-issue: 133998 +.. nonce: KmElUw +.. section: Library + +Fix :exc:`struct.error` exception when creating a file with +:class:`gzip.GzipFile` or compressing data with :func:`gzip.compress` if the +system time is outside the range 00:00:00 UTC, January 1, 1970 through +06:28:15 UTC, February 7, 2106, or explicitly passed *mtime* argument is +outside the range ``0`` to ``2**32-1``. + +.. + +.. date: 2025-03-01-13-36-02 +.. gh-issue: 128110 +.. nonce: 9wx_G0 +.. section: Library + +Fix bug in the parsing of :mod:`email` address headers that could result in +extraneous spaces in the decoded text when using a modern email policy. +Space between pairs of adjacent :rfc:`2047` encoded-words is now ignored, +per section 6.2 (and consistent with existing parsing of unstructured +headers like *Subject*). + +.. + +.. date: 2024-11-02-02-02-31 +.. gh-issue: 107398 +.. nonce: uUtA6Q +.. section: Library + +Fix :mod:`tarfile` stream mode exception when process the file with the gzip +extra field. + +.. + +.. date: 2024-07-02-20-57-43 +.. gh-issue: 121109 +.. nonce: Tp6R2s +.. section: Library + +Fix :mod:`tarfile` performance issue when reading archives in streaming mode +(e.g. ``r|*``). + +.. + +.. bpo: 45509 +.. date: 2021-10-18-13-46-55 +.. nonce: Upwb60 +.. section: Library + +Gzip headers are now checked for corrupted NAME, COMMENT and HCRC fields. + +.. + +.. date: 2026-05-25-15-39-53 +.. gh-issue: 150387 +.. nonce: yzZ7jq +.. section: Tests + +Fix hang in +``test.test_profiling.test_sampling_profiler.test_live_collector_ui.TestLiveModeErrors.test_run_failed_script_live`` +on slow buildbots. The test now always queues a final ``q`` keystroke so the +live TUI loop exits even when the profiler collects enough samples to enter +the post-finished input loop. + +.. + +.. date: 2026-05-13-14-53-23 +.. gh-issue: 149776 +.. nonce: orqgsn +.. section: Tests + +Fix test_socket on Linux kernel 7.1 and newer: skip UDP Lite tests if it's +not supported. Patch by Victor Stinner. + +.. + +.. date: 2026-05-21-15-14-59 +.. gh-issue: 148294 +.. nonce: VtFaW4 +.. section: Build + +Corrected the use of ``AC_PATH_TOOL`` in ``configure.ac`` to allow a C++ +compiler to be found on :envvar:`!PATH`. + +.. + +.. date: 2026-05-18-16-00-41 +.. gh-issue: 148260 +.. nonce: UwFiIX +.. section: Build + +On Linux when Python is linked to the musl C library, use a thread stack +size of at least 1 MiB instead of musl default which is 128 kiB. Patch by +Victor Stinner. + +.. + +.. date: 2026-05-14-22-09-46 +.. gh-issue: 149786 +.. nonce: UI-HZM +.. section: Windows + +Fixes virtual environment launchers on Windows free-threaded builds. + +.. + +.. date: 2026-05-06-21-36-53 +.. gh-issue: 124111 +.. nonce: m4OBX8 +.. section: Windows + +Updated Windows builds to use Tcl/Tk 9.0.3. + +.. + +.. date: 2026-04-29-14-44-51 +.. gh-issue: 138489 +.. nonce: 234aj6 +.. section: Windows + +Windows distributions now include a :file:`build-details.json` file (see +:pep:`739`). The legacy installer does not install it, but all other +distributions from python.org and all preset configurations in the +``PC\layout`` script will include one. + +.. + +.. date: 2026-04-26-23-14-45 +.. gh-issue: 149029 +.. nonce: oPTXP4 +.. section: Windows + +Update Windows installer to ship with SQLite 3.53.1. + +.. + +.. date: 2026-05-31-10-40-00 +.. gh-issue: 150644 +.. nonce: zLWyjj +.. section: macOS + +When system logging is enabled (with ``config.use_system_logger``, messages +are now tagged as public. This allows the macOS 26 system logger to view +messages without special configuration. + +.. + +.. date: 2026-04-26-23-15-09 +.. gh-issue: 149029 +.. nonce: Lsx--T +.. section: macOS + +Update macOS installer to ship with SQLite version 3.53.1. + +.. + +.. date: 2026-05-22-18-51-09 +.. gh-issue: 150258 +.. nonce: dh8GVK +.. section: Tools/Demos + +Update the tooltip on the Tachyon flame graph to show both absolute and +relative percentages. + +.. + +.. date: 2026-05-12-16-47-21 +.. gh-issue: 149725 +.. nonce: HZLBTZ +.. section: C API + +Add :c:func:`PySentinel_CheckExact` for exact :class:`sentinel` type tests +to accompany the existing :c:func:`PySentinel_Check`. + +.. + +.. date: 2026-02-25-13-37-10 +.. gh-issue: 145235 +.. nonce: -1ySNR +.. section: C API + +Made :c:func:`PyDict_AddWatcher`, :c:func:`PyDict_ClearWatcher`, +:c:func:`PyDict_Watch`, and :c:func:`PyDict_Unwatch` thread-safe on the +:term:`free threaded <free threading>` build. diff --git a/Misc/NEWS.d/next/Build/2026-05-18-16-00-41.gh-issue-148260.UwFiIX.rst b/Misc/NEWS.d/next/Build/2026-05-18-16-00-41.gh-issue-148260.UwFiIX.rst deleted file mode 100644 index 8248c24cbd511a..00000000000000 --- a/Misc/NEWS.d/next/Build/2026-05-18-16-00-41.gh-issue-148260.UwFiIX.rst +++ /dev/null @@ -1,3 +0,0 @@ -On Linux when Python is linked to the musl C library, use a thread stack -size of at least 1 MiB instead of musl default which is 128 kiB. Patch by -Victor Stinner. diff --git a/Misc/NEWS.d/next/Build/2026-05-21-15-14-59.gh-issue-148294.VtFaW4.rst b/Misc/NEWS.d/next/Build/2026-05-21-15-14-59.gh-issue-148294.VtFaW4.rst deleted file mode 100644 index 861261dd97269f..00000000000000 --- a/Misc/NEWS.d/next/Build/2026-05-21-15-14-59.gh-issue-148294.VtFaW4.rst +++ /dev/null @@ -1,2 +0,0 @@ -Corrected the use of ``AC_PATH_TOOL`` in ``configure.ac`` to allow a C++ -compiler to be found on :envvar:`!PATH`. diff --git a/Misc/NEWS.d/next/C_API/2026-02-25-13-37-10.gh-issue-145235.-1ySNR.rst b/Misc/NEWS.d/next/C_API/2026-02-25-13-37-10.gh-issue-145235.-1ySNR.rst deleted file mode 100644 index 98a8c268735726..00000000000000 --- a/Misc/NEWS.d/next/C_API/2026-02-25-13-37-10.gh-issue-145235.-1ySNR.rst +++ /dev/null @@ -1,3 +0,0 @@ -Made :c:func:`PyDict_AddWatcher`, :c:func:`PyDict_ClearWatcher`, -:c:func:`PyDict_Watch`, and :c:func:`PyDict_Unwatch` thread-safe on the -:term:`free threaded <free threading>` build. diff --git a/Misc/NEWS.d/next/C_API/2026-05-12-16-47-21.gh-issue-149725.HZLBTZ.rst b/Misc/NEWS.d/next/C_API/2026-05-12-16-47-21.gh-issue-149725.HZLBTZ.rst deleted file mode 100644 index 97721430edbd69..00000000000000 --- a/Misc/NEWS.d/next/C_API/2026-05-12-16-47-21.gh-issue-149725.HZLBTZ.rst +++ /dev/null @@ -1,2 +0,0 @@ -Add :c:func:`PySentinel_CheckExact` for exact :class:`sentinel` type tests -to accompany the existing :c:func:`PySentinel_Check`. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-04-15-15-48-04.gh-issue-148450.2MEVqH.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-04-15-15-48-04.gh-issue-148450.2MEVqH.rst deleted file mode 100644 index 2a7d0d9bb3a7f7..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2026-04-15-15-48-04.gh-issue-148450.2MEVqH.rst +++ /dev/null @@ -1 +0,0 @@ -Fix ``abc.register()`` so it invalidates type version tags for registered classes. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-07-03-18-59.gh-issue-149459.5fhAqP.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-07-03-18-59.gh-issue-149459.5fhAqP.rst deleted file mode 100644 index 4cd0a148df3c70..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-07-03-18-59.gh-issue-149459.5fhAqP.rst +++ /dev/null @@ -1 +0,0 @@ -Fix a crash in the JIT optimizer when a specialized ``LOAD_SPECIAL`` guard deoptimized after inserting the synthetic ``NULL`` stack entry. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-09-15-22-32.gh-issue-144957.u1F2aQ.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-09-15-22-32.gh-issue-144957.u1F2aQ.rst deleted file mode 100644 index 3063f1a3c0e6d3..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-09-15-22-32.gh-issue-144957.u1F2aQ.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix lazy ``from`` imports of module attributes provided by module-level -``__getattr__``. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-10-07-42-36.gh-issue-149642.6ZksML.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-10-07-42-36.gh-issue-149642.6ZksML.rst deleted file mode 100644 index 815a084db69d8d..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-10-07-42-36.gh-issue-149642.6ZksML.rst +++ /dev/null @@ -1,2 +0,0 @@ -Allow imports inside ``exec()`` calls within functions under -``PYTHON_LAZY_IMPORTS=all``. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-10-16-43-50.gh-issue-148829.gscS14.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-10-16-43-50.gh-issue-148829.gscS14.rst deleted file mode 100644 index 3f9b1ccb518787..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-10-16-43-50.gh-issue-148829.gscS14.rst +++ /dev/null @@ -1,2 +0,0 @@ -:class:`sentinel` objects now support a ``repr=`` argument and their -:attr:`~sentinel.__module__` attribute is writable. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-11-14-48-56.gh-issue-149676.6aTrw1.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-11-14-48-56.gh-issue-149676.6aTrw1.rst deleted file mode 100644 index 96f407cf5ad25a..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-11-14-48-56.gh-issue-149676.6aTrw1.rst +++ /dev/null @@ -1 +0,0 @@ -Fix ``frozendict | frozendict`` hash. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-12-16-47-23.gh-issue-139808.iIs7_E.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-12-16-47-23.gh-issue-139808.iIs7_E.rst deleted file mode 100644 index 3e9d930bf1de89..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-12-16-47-23.gh-issue-139808.iIs7_E.rst +++ /dev/null @@ -1,2 +0,0 @@ -Add branch protections for AArch64 (BTI/PAC) in assembly code used by -:option:`-X perf_jit <-X>` (Linux perf profiler integration). diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-13-06-54-41.gh-issue-149738.4BLFoH.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-13-06-54-41.gh-issue-149738.4BLFoH.rst deleted file mode 100644 index e62b681d716650..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-13-06-54-41.gh-issue-149738.4BLFoH.rst +++ /dev/null @@ -1,2 +0,0 @@ -:mod:`sqlite3`: Disallow removing ``row_factory`` and ``text_factory`` attributes -of a connection to prevent a crash on a query. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-14-19-41-03.gh-issue-149807.IwGaCo.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-14-19-41-03.gh-issue-149807.IwGaCo.rst deleted file mode 100644 index a94c737e73619d..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-14-19-41-03.gh-issue-149807.IwGaCo.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix ``hash(frozendict)``: compute the hash of each ``(key, value)`` pair -correctly. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-15-11-31-57.gh-issue-149816.ugN2rx.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-15-11-31-57.gh-issue-149816.ugN2rx.rst deleted file mode 100644 index 016c17dd66b19e..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-15-11-31-57.gh-issue-149816.ugN2rx.rst +++ /dev/null @@ -1 +0,0 @@ -Fix a race condition in :class:`memoryview` with free-threading. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-16-11-03-54.gh-issue-149816.X_gqMT.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-16-11-03-54.gh-issue-149816.X_gqMT.rst deleted file mode 100644 index d35f0857a1aefe..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-16-11-03-54.gh-issue-149816.X_gqMT.rst +++ /dev/null @@ -1 +0,0 @@ -Fix a race condition in ``_PyBytes_FromList`` in free-threading mode. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-18-13-47-17.gh-issue-149590.IPBeQx.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-18-13-47-17.gh-issue-149590.IPBeQx.rst deleted file mode 100644 index 8d3b29d69cc857..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-18-13-47-17.gh-issue-149590.IPBeQx.rst +++ /dev/null @@ -1 +0,0 @@ -Fix crash when faulthandler is imported more than once. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-18-16-54-54.gh-issue-150042.LSr5W8.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-18-16-54-54.gh-issue-150042.LSr5W8.rst deleted file mode 100644 index 18a4fbd9dadd60..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-18-16-54-54.gh-issue-150042.LSr5W8.rst +++ /dev/null @@ -1 +0,0 @@ -Fix refleak in queue.SimpleQueue.put if memory allocation fails. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-18-18-36-28.gh-issue-148587.-RD3z5.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-18-18-36-28.gh-issue-148587.-RD3z5.rst deleted file mode 100644 index 61bfdcdd37362c..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-18-18-36-28.gh-issue-148587.-RD3z5.rst +++ /dev/null @@ -1 +0,0 @@ -``sys.lazy_modules`` is now a set instead of a dict as initially spelled out in PEP 810. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-20-13-06-17.gh-issue-150146.i5m_SL.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-20-13-06-17.gh-issue-150146.i5m_SL.rst deleted file mode 100644 index f373f0bee7023e..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-20-13-06-17.gh-issue-150146.i5m_SL.rst +++ /dev/null @@ -1,5 +0,0 @@ -Fix a crash on a complex type variable substitution. - -``from typing import TypeVar; memoryview[TypeVar("")][*typing.Mapping[..., -...]]`` used to fail due to missing ``NULL`` check on ``_unpack_args`` C -function call. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-22-17-09-28.gh-issue-150107.GD72-D.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-22-17-09-28.gh-issue-150107.GD72-D.rst deleted file mode 100644 index a13f249e48cc02..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-22-17-09-28.gh-issue-150107.GD72-D.rst +++ /dev/null @@ -1,3 +0,0 @@ -:mod:`asyncio`: ``sendfile()`` and ``sock_sendfile()`` event loop methods -now call ``file.seek(offset)`` if *file* has a ``seek()`` method, -even if *offset* is ``0`` (default value). diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-23-22-08-01.gh-issue-149449.2lhQFF.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-23-22-08-01.gh-issue-149449.2lhQFF.rst deleted file mode 100644 index 7d11442468d207..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-23-22-08-01.gh-issue-149449.2lhQFF.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix a use-after-free crash when the :mod:`unicodedata` module was removed -from :data:`sys.modules` and garbage-collected between calls that decode -``\N{...}`` escapes or use the ``namereplace`` codec error handler. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-24-14-45-00.gh-issue-149156.NP73rB.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-24-14-45-00.gh-issue-149156.NP73rB.rst deleted file mode 100644 index 2cb091e2b162f6..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-24-14-45-00.gh-issue-149156.NP73rB.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix an intermittent crash after :func:`os.fork` when perf trampoline -profiling is enabled and the child returns through trampoline frames -inherited from the parent process. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-25-16-00-22.gh-issue-150374.Emu6d8.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-25-16-00-22.gh-issue-150374.Emu6d8.rst deleted file mode 100644 index 7189ca186d2b7e..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-25-16-00-22.gh-issue-150374.Emu6d8.rst +++ /dev/null @@ -1 +0,0 @@ -Fix double release of the import lock on lazy import reification errors. diff --git a/Misc/NEWS.d/next/Library/2021-10-18-13-46-55.bpo-45509.Upwb60.rst b/Misc/NEWS.d/next/Library/2021-10-18-13-46-55.bpo-45509.Upwb60.rst deleted file mode 100644 index 80c38c03f8fe78..00000000000000 --- a/Misc/NEWS.d/next/Library/2021-10-18-13-46-55.bpo-45509.Upwb60.rst +++ /dev/null @@ -1 +0,0 @@ -Gzip headers are now checked for corrupted NAME, COMMENT and HCRC fields. diff --git a/Misc/NEWS.d/next/Library/2024-07-02-20-57-43.gh-issue-121109.Tp6R2s.rst b/Misc/NEWS.d/next/Library/2024-07-02-20-57-43.gh-issue-121109.Tp6R2s.rst deleted file mode 100644 index eca6014e4a0aed..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-07-02-20-57-43.gh-issue-121109.Tp6R2s.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix :mod:`tarfile` performance issue when reading archives in streaming mode -(e.g. ``r|*``). diff --git a/Misc/NEWS.d/next/Library/2024-11-02-02-02-31.gh-issue-107398.uUtA6Q.rst b/Misc/NEWS.d/next/Library/2024-11-02-02-02-31.gh-issue-107398.uUtA6Q.rst deleted file mode 100644 index d5af322d68d309..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-11-02-02-02-31.gh-issue-107398.uUtA6Q.rst +++ /dev/null @@ -1 +0,0 @@ -Fix :mod:`tarfile` stream mode exception when process the file with the gzip extra field. diff --git a/Misc/NEWS.d/next/Library/2025-03-01-13-36-02.gh-issue-128110.9wx_G0.rst b/Misc/NEWS.d/next/Library/2025-03-01-13-36-02.gh-issue-128110.9wx_G0.rst deleted file mode 100644 index b08b1886cff9cf..00000000000000 --- a/Misc/NEWS.d/next/Library/2025-03-01-13-36-02.gh-issue-128110.9wx_G0.rst +++ /dev/null @@ -1,5 +0,0 @@ -Fix bug in the parsing of :mod:`email` address headers that could result in -extraneous spaces in the decoded text when using a modern email policy. -Space between pairs of adjacent :rfc:`2047` encoded-words is now ignored, per -section 6.2 (and consistent with existing parsing of unstructured -headers like *Subject*). diff --git a/Misc/NEWS.d/next/Library/2025-05-19-20-29-35.gh-issue-133998.KmElUw.rst b/Misc/NEWS.d/next/Library/2025-05-19-20-29-35.gh-issue-133998.KmElUw.rst deleted file mode 100644 index 77d92628beefac..00000000000000 --- a/Misc/NEWS.d/next/Library/2025-05-19-20-29-35.gh-issue-133998.KmElUw.rst +++ /dev/null @@ -1,5 +0,0 @@ -Fix :exc:`struct.error` exception when creating a file with -:class:`gzip.GzipFile` or compressing data with :func:`gzip.compress` -if the system time is outside the range 00:00:00 UTC, January 1, 1970 -through 06:28:15 UTC, February 7, 2106, or explicitly passed *mtime* -argument is outside the range ``0`` to ``2**32-1``. diff --git a/Misc/NEWS.d/next/Library/2025-05-19-21-08-25.gh-issue-134261.ravGYm.rst b/Misc/NEWS.d/next/Library/2025-05-19-21-08-25.gh-issue-134261.ravGYm.rst deleted file mode 100644 index bf552fee814acb..00000000000000 --- a/Misc/NEWS.d/next/Library/2025-05-19-21-08-25.gh-issue-134261.ravGYm.rst +++ /dev/null @@ -1 +0,0 @@ -zip: On reproducible builds, ZipFile uses UTC instead of the local time when writing file datetimes to avoid underflows. diff --git a/Misc/NEWS.d/next/Library/2025-08-30-07-44-30.gh-issue-86533.pathlib.rst b/Misc/NEWS.d/next/Library/2025-08-30-07-44-30.gh-issue-86533.pathlib.rst deleted file mode 100644 index 9c32671173e0ad..00000000000000 --- a/Misc/NEWS.d/next/Library/2025-08-30-07-44-30.gh-issue-86533.pathlib.rst +++ /dev/null @@ -1,4 +0,0 @@ -The :func:`os.makedirs` function and :meth:`pathlib.Path.mkdir` method now have -a *parent_mode* parameter to specify the mode for intermediate directories when -creating parent directories. This allows one to match the behavior from Python -3.6 and earlier for :func:`os.makedirs`. diff --git a/Misc/NEWS.d/next/Library/2026-03-26-09-30-00.gh-issue-146452.Y2N6qZ8J.rst b/Misc/NEWS.d/next/Library/2026-03-26-09-30-00.gh-issue-146452.Y2N6qZ8J.rst deleted file mode 100644 index 99f3cce33497a1..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-03-26-09-30-00.gh-issue-146452.Y2N6qZ8J.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix segfault in :mod:`pickle` when pickling a dictionary concurrently -mutated by another thread in the free-threaded build. diff --git a/Misc/NEWS.d/next/Library/2026-04-23-12-50-15.gh-issue-148441.zvpCkR.rst b/Misc/NEWS.d/next/Library/2026-04-23-12-50-15.gh-issue-148441.zvpCkR.rst deleted file mode 100644 index 762815270e4d40..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-04-23-12-50-15.gh-issue-148441.zvpCkR.rst +++ /dev/null @@ -1,4 +0,0 @@ -:mod:`xml.parsers.expat`: prevent a crash in -:meth:`~xml.parsers.expat.xmlparser.CharacterDataHandler` -when the character data size exceeds the parser's -:attr:`buffer size <xml.parsers.expat.xmlparser.buffer_size>`. diff --git a/Misc/NEWS.d/next/Library/2026-04-27-11-12-00.gh-issue-149046.74shDd.rst b/Misc/NEWS.d/next/Library/2026-04-27-11-12-00.gh-issue-149046.74shDd.rst deleted file mode 100644 index b05c4222e30fcd..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-04-27-11-12-00.gh-issue-149046.74shDd.rst +++ /dev/null @@ -1,2 +0,0 @@ -:mod:`io`: Fix :class:`io.StringIO` serialization: no longer call ``str(obj)`` on :class:`str` -subclasses. Patch by Thomas Kowalski. diff --git a/Misc/NEWS.d/next/Library/2026-04-29-08-10-17.gh-issue-149056.jnaD4W.rst b/Misc/NEWS.d/next/Library/2026-04-29-08-10-17.gh-issue-149056.jnaD4W.rst deleted file mode 100644 index 0026d02c876257..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-04-29-08-10-17.gh-issue-149056.jnaD4W.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix :func:`json.load` not forwarding the *array_hook* argument to -:func:`json.loads`. Patch by Thomas Kowalski. diff --git a/Misc/NEWS.d/next/Library/2026-05-07-14-18-47.gh-issue-149489.bX9iHe.rst b/Misc/NEWS.d/next/Library/2026-05-07-14-18-47.gh-issue-149489.bX9iHe.rst deleted file mode 100644 index 1550c893fd7c45..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-05-07-14-18-47.gh-issue-149489.bX9iHe.rst +++ /dev/null @@ -1,5 +0,0 @@ -Fix :mod:`~xml.etree.ElementTree` serialization to HTML. The content of -comments, processing instructions and elements "xmp", "iframe", "noembed", -"noframes", and "plaintext" is no longer escaped. The "plaintext" element no -longer have the closing tag. Add support of empty attributes (with value -``None``). diff --git a/Misc/NEWS.d/next/Library/2026-05-07-21-58-17.gh-issue-149388.DDBPeA.rst b/Misc/NEWS.d/next/Library/2026-05-07-21-58-17.gh-issue-149388.DDBPeA.rst deleted file mode 100644 index 4a1c6f3f5b4e57..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-05-07-21-58-17.gh-issue-149388.DDBPeA.rst +++ /dev/null @@ -1 +0,0 @@ -Make :class:`!asyncio.windows_utils.PipeHandle` closing idempotent. diff --git a/Misc/NEWS.d/next/Library/2026-05-08-09-11-48.gh-issue-149534.Tw7eeY.rst b/Misc/NEWS.d/next/Library/2026-05-08-09-11-48.gh-issue-149534.Tw7eeY.rst deleted file mode 100644 index 0938935a75d8c1..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-05-08-09-11-48.gh-issue-149534.Tw7eeY.rst +++ /dev/null @@ -1 +0,0 @@ -Fix merging of :class:`collections.defaultdict` and :class:`frozendict`. diff --git a/Misc/NEWS.d/next/Library/2026-05-08-15-08-35.gh-issue-112821.t9T1YD.rst b/Misc/NEWS.d/next/Library/2026-05-08-15-08-35.gh-issue-112821.t9T1YD.rst deleted file mode 100644 index cfbcde81493e22..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-05-08-15-08-35.gh-issue-112821.t9T1YD.rst +++ /dev/null @@ -1,4 +0,0 @@ -In the REPL, autocompletion might run arbitrary code in the getter of a -descriptor. If that getter raised an exception, autocompletion would fail to -present any options for the entire object. Autocompletion now works as -expected for these objects. diff --git a/Misc/NEWS.d/next/Library/2026-05-09-21-02-08.gh-issue-149614.U4snj3.rst b/Misc/NEWS.d/next/Library/2026-05-09-21-02-08.gh-issue-149614.U4snj3.rst deleted file mode 100644 index 5169c6c203fc1b..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-05-09-21-02-08.gh-issue-149614.U4snj3.rst +++ /dev/null @@ -1 +0,0 @@ -Fix a regression that broke the ability to deepcopy :class:`argparse.ArgumentParser` instances. diff --git a/Misc/NEWS.d/next/Library/2026-05-10-07-21-51.gh-issue-139489.rS7LTA.rst b/Misc/NEWS.d/next/Library/2026-05-10-07-21-51.gh-issue-139489.rS7LTA.rst deleted file mode 100644 index 40fe7e9fd6a008..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-05-10-07-21-51.gh-issue-139489.rS7LTA.rst +++ /dev/null @@ -1 +0,0 @@ -Add :func:`xml.is_valid_text` to ``xml.__all__``. diff --git a/Misc/NEWS.d/next/Library/2026-05-10-19-26-50.gh-issue-149584.x7Qm9A.rst b/Misc/NEWS.d/next/Library/2026-05-10-19-26-50.gh-issue-149584.x7Qm9A.rst deleted file mode 100644 index 6734250fdd6af3..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-05-10-19-26-50.gh-issue-149584.x7Qm9A.rst +++ /dev/null @@ -1,4 +0,0 @@ -Fix excessive overhead in the Tachyon profiler when inspecting a remote -process by avoiding repeated remote page-cache scans, batching predicted -remote reads, and reusing cached profiler result objects. Patch by Pablo -Galindo and Maurycy Pawłowski-Wieroński. diff --git a/Misc/NEWS.d/next/Library/2026-05-10-23-51-23.gh-issue-149504.pDSCbn.rst b/Misc/NEWS.d/next/Library/2026-05-10-23-51-23.gh-issue-149504.pDSCbn.rst deleted file mode 100644 index 88bf268123bbec..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-05-10-23-51-23.gh-issue-149504.pDSCbn.rst +++ /dev/null @@ -1,5 +0,0 @@ -Fix :func:`site.addsitedir` to allow re-entrant calls from within startup -files. Previously, a ``.pth`` file containing an ``import`` line that -called :func:`site.addsitedir` (or a ``.start`` entry point doing the same) -could crash with ``RuntimeError: dictionary changed size during iteration`` -during site initialization, breaking tools such as ``uv run --with``. diff --git a/Misc/NEWS.d/next/Library/2026-05-12-06-24-54.gh-issue-149701.8v9RTm.rst b/Misc/NEWS.d/next/Library/2026-05-12-06-24-54.gh-issue-149701.8v9RTm.rst deleted file mode 100644 index 676d788cbce62a..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-05-12-06-24-54.gh-issue-149701.8v9RTm.rst +++ /dev/null @@ -1 +0,0 @@ -Fix bad return code from Lib/venv/bin/activate if hashing is disabled diff --git a/Misc/NEWS.d/next/Library/2026-05-12-13-03-45.gh-issue-149718.SaM1NJ.rst b/Misc/NEWS.d/next/Library/2026-05-12-13-03-45.gh-issue-149718.SaM1NJ.rst deleted file mode 100644 index 25344e5a90f022..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-05-12-13-03-45.gh-issue-149718.SaM1NJ.rst +++ /dev/null @@ -1,4 +0,0 @@ -Coalesce consecutive identical stack frames in Tachyon, so aggregating -collectors (pstats, collapsed, flamegraph, gecko) receive one collect. -Improves sample rate 3x, error rate and missed rate drop by 70%. Patch by -Maurycy Pawłowski-Wieroński. diff --git a/Misc/NEWS.d/next/Library/2026-05-13-23-18-39.gh-issue-149801.S_FfGr.rst b/Misc/NEWS.d/next/Library/2026-05-13-23-18-39.gh-issue-149801.S_FfGr.rst deleted file mode 100644 index f9e8538527d204..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-05-13-23-18-39.gh-issue-149801.S_FfGr.rst +++ /dev/null @@ -1,2 +0,0 @@ -Add IANA registered names and aliases with leading zeros before number (like -IBM00858, CP00858, IBM01140, CP01140) for corresponding codecs. diff --git a/Misc/NEWS.d/next/Library/2026-05-14-15-55-28.gh-issue-149816.ZaXQ0q.rst b/Misc/NEWS.d/next/Library/2026-05-14-15-55-28.gh-issue-149816.ZaXQ0q.rst deleted file mode 100644 index 3ea70071ec3c75..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-05-14-15-55-28.gh-issue-149816.ZaXQ0q.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix a race condition in ``_random.Random.__init__`` method in free-threading -mode. diff --git a/Misc/NEWS.d/next/Library/2026-05-15-16-28-00.gh-issue-149819.fixpth.rst b/Misc/NEWS.d/next/Library/2026-05-15-16-28-00.gh-issue-149819.fixpth.rst deleted file mode 100644 index 66e6da0ecf0d87..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-05-15-16-28-00.gh-issue-149819.fixpth.rst +++ /dev/null @@ -1,4 +0,0 @@ -Fix regression in :func:`site.addsitedir` where ``.pth`` files were no -longer processed in Python subprocesses. This happened because -:func:`site.main` seeded ``known_paths`` with entries inherited from -the parent process, causing ``addsitedir`` to skip ``.pth`` processing. diff --git a/Misc/NEWS.d/next/Library/2026-05-15-18-44-20.gh-issue-142349.fHK3v1.rst b/Misc/NEWS.d/next/Library/2026-05-15-18-44-20.gh-issue-142349.fHK3v1.rst deleted file mode 100644 index fa667c4110941e..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-05-15-18-44-20.gh-issue-142349.fHK3v1.rst +++ /dev/null @@ -1 +0,0 @@ -Add :keyword:`lazy` to the list of support topic by :func:`help`. diff --git a/Misc/NEWS.d/next/Library/2026-05-16-21-08-33.gh-issue-149921.I1yNML.rst b/Misc/NEWS.d/next/Library/2026-05-16-21-08-33.gh-issue-149921.I1yNML.rst deleted file mode 100644 index 113bd1a802f799..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-05-16-21-08-33.gh-issue-149921.I1yNML.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix reference leaks in error paths of the :mod:`!_interpchannels` and -:mod:`!_interpqueues` extension modules. diff --git a/Misc/NEWS.d/next/Library/2026-05-17-02-25-56.gh-issue-149571.LNyuWJ.rst b/Misc/NEWS.d/next/Library/2026-05-17-02-25-56.gh-issue-149571.LNyuWJ.rst deleted file mode 100644 index 2b71d9cf2200be..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-05-17-02-25-56.gh-issue-149571.LNyuWJ.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix the C implementation of :meth:`xml.etree.ElementTree.Element.itertext`: -it no longer emits text for comments and processing instructions. diff --git a/Misc/NEWS.d/next/Library/2026-05-17-22-37-02.gh-issue-88726.BAoL6j.rst b/Misc/NEWS.d/next/Library/2026-05-17-22-37-02.gh-issue-88726.BAoL6j.rst deleted file mode 100644 index ba9058d79c9873..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-05-17-22-37-02.gh-issue-88726.BAoL6j.rst +++ /dev/null @@ -1,2 +0,0 @@ -The :mod:`email` package now uses standard MIME charset names "gb2312" and -"big5" instead of non-standard names "eucgb2312_cn" and "big5_tw". diff --git a/Misc/NEWS.d/next/Library/2026-05-18-07-44-46.gh-issue-149995.vvtFHn.rst b/Misc/NEWS.d/next/Library/2026-05-18-07-44-46.gh-issue-149995.vvtFHn.rst deleted file mode 100644 index a8e412b578da37..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-05-18-07-44-46.gh-issue-149995.vvtFHn.rst +++ /dev/null @@ -1 +0,0 @@ -Update various docstrings in :mod:`typing`. diff --git a/Misc/NEWS.d/next/Library/2026-05-18-17-17-20.gh-issue-149189.a8IooK.rst b/Misc/NEWS.d/next/Library/2026-05-18-17-17-20.gh-issue-149189.a8IooK.rst deleted file mode 100644 index bad027f2c71c6f..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-05-18-17-17-20.gh-issue-149189.a8IooK.rst +++ /dev/null @@ -1 +0,0 @@ -Revert the changes to :mod:`pprint` defaults. Patch by Hugo van Kemenade. diff --git a/Misc/NEWS.d/next/Library/2026-05-19-19-00-49.gh-issue-84353.ZU5zaQ.rst b/Misc/NEWS.d/next/Library/2026-05-19-19-00-49.gh-issue-84353.ZU5zaQ.rst deleted file mode 100644 index 84fb12e2abd81a..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-05-19-19-00-49.gh-issue-84353.ZU5zaQ.rst +++ /dev/null @@ -1,5 +0,0 @@ -Preserve non-UTF-8 encoded filenames when appending to a -:class:`zipfile.ZipFile`. Previously, non-ASCII names stored in a legacy -encoding (without the UTF-8 flag bit set) could be corrupted when the -central directory was rewritten: they were decoded as cp437 and then -re-stored as UTF-8. diff --git a/Misc/NEWS.d/next/Library/2026-05-21-11-25-58.gh-issue-150175.8H4Caz.rst b/Misc/NEWS.d/next/Library/2026-05-21-11-25-58.gh-issue-150175.8H4Caz.rst deleted file mode 100644 index 80fc80d4d50a63..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-05-21-11-25-58.gh-issue-150175.8H4Caz.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix race condition in :class:`unittest.mock.ThreadingMock` where -concurrent calls could lose increments to ``call_count`` and other -attributes due to a missing lock in ``_increment_mock_call``. diff --git a/Misc/NEWS.d/next/Library/2026-05-21-20-47-45.gh-issue-150157.ZvmO-bQZ.rst b/Misc/NEWS.d/next/Library/2026-05-21-20-47-45.gh-issue-150157.ZvmO-bQZ.rst deleted file mode 100644 index 3a12e26cf736f7..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-05-21-20-47-45.gh-issue-150157.ZvmO-bQZ.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix a crash in free-threaded builds that occurs when pickling by name -objects without a ``__module__`` attribute while :data:`sys.modules` -is concurrently being modified. diff --git a/Misc/NEWS.d/next/Library/2026-05-25-07-22-05.gh-issue-150372.9hLqhe.rst b/Misc/NEWS.d/next/Library/2026-05-25-07-22-05.gh-issue-150372.9hLqhe.rst deleted file mode 100644 index 7b83bd8fe73f11..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-05-25-07-22-05.gh-issue-150372.9hLqhe.rst +++ /dev/null @@ -1,2 +0,0 @@ -:mod:`readline`: Fix a potential crash during tab completion caused by an -out-of-memory error during module initialization. diff --git a/Misc/NEWS.d/next/Library/2026-05-25-17-00-00.gh-issue-150406.jF3g63.rst b/Misc/NEWS.d/next/Library/2026-05-25-17-00-00.gh-issue-150406.jF3g63.rst deleted file mode 100644 index 230e961abd3f58..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-05-25-17-00-00.gh-issue-150406.jF3g63.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix a possible crash occurring during :mod:`socket` module initialization -when the system is out of memory on platforms without a reentrant -``gethostbyname``. diff --git a/Misc/NEWS.d/next/Library/2026-05-27-11-18-36.gh-issue-150228.pNPiO-.rst b/Misc/NEWS.d/next/Library/2026-05-27-11-18-36.gh-issue-150228.pNPiO-.rst deleted file mode 100644 index 8c03989e90b240..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-05-27-11-18-36.gh-issue-150228.pNPiO-.rst +++ /dev/null @@ -1,11 +0,0 @@ -The new :class:`site.StartupState` class lets callers batch-process -:pep:`829` startup configuration files across multiple site directories -before any startup code runs, with public -:meth:`~site.StartupState.addsitedir`, -:meth:`~site.StartupState.addusersitepackages`, -:meth:`~site.StartupState.addsitepackages`, and -:meth:`~site.StartupState.process` methods. The signature of -:func:`site.addsitedir` is unchanged from Python 3.14. The -:data:`!defer_processing_start_files` argument and the -``process_startup_files()`` function added earlier in the 3.15 cycle have -been removed; use :class:`!site.StartupState` instead. diff --git a/Misc/NEWS.d/next/Library/2026-05-31-17-47-30.gh-issue-150685.EBB2mU.rst b/Misc/NEWS.d/next/Library/2026-05-31-17-47-30.gh-issue-150685.EBB2mU.rst deleted file mode 100644 index eb7f31112d004c..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-05-31-17-47-30.gh-issue-150685.EBB2mU.rst +++ /dev/null @@ -1 +0,0 @@ -Update bundled pip to 26.1.2 diff --git a/Misc/NEWS.d/next/Security/2026-04-26-19-30-45.gh-issue-149018.a9SqWb.rst b/Misc/NEWS.d/next/Security/2026-04-26-19-30-45.gh-issue-149018.a9SqWb.rst deleted file mode 100644 index d1b5b368684e6a..00000000000000 --- a/Misc/NEWS.d/next/Security/2026-04-26-19-30-45.gh-issue-149018.a9SqWb.rst +++ /dev/null @@ -1,3 +0,0 @@ -Improved protection against XML hash-flooding attacks in -:mod:`xml.parsers.expat` and :mod:`xml.etree.ElementTree` when Python is -compiled with libExpat 2.8.0 or later. diff --git a/Misc/NEWS.d/next/Security/2026-04-27-16-36-11.gh-issue-149079.vKl-LM.rst b/Misc/NEWS.d/next/Security/2026-04-27-16-36-11.gh-issue-149079.vKl-LM.rst deleted file mode 100644 index 4ed22b58f7405f..00000000000000 --- a/Misc/NEWS.d/next/Security/2026-04-27-16-36-11.gh-issue-149079.vKl-LM.rst +++ /dev/null @@ -1,5 +0,0 @@ -Fix a potential denial of service in :func:`unicodedata.normalize`. The -canonical ordering step of Unicode normalization used a quadratic-time insertion -sort for reordering combining characters, which could be exploited with -crafted input containing many combining characters in non-canonical order. -Replaced with a linear-time counting sort for long runs. diff --git a/Misc/NEWS.d/next/Security/2026-05-03-21-00-00.gh-issue-149486.tarflt.rst b/Misc/NEWS.d/next/Security/2026-05-03-21-00-00.gh-issue-149486.tarflt.rst deleted file mode 100644 index 7c69edb683cf80..00000000000000 --- a/Misc/NEWS.d/next/Security/2026-05-03-21-00-00.gh-issue-149486.tarflt.rst +++ /dev/null @@ -1,5 +0,0 @@ -:func:`tarfile.data_filter` now validates link targets using the same -normalised value that is written to disk, strips trailing separators from -the member name when resolving a symlink's directory, and rejects link -members that would replace the destination directory itself. This closes -several path-traversal bypasses of the ``data`` extraction filter. diff --git a/Misc/NEWS.d/next/Security/2026-05-08-02-18-54.gh-issue-149474.ujQ-mu.rst b/Misc/NEWS.d/next/Security/2026-05-08-02-18-54.gh-issue-149474.ujQ-mu.rst deleted file mode 100644 index 48e718b95ebe3a..00000000000000 --- a/Misc/NEWS.d/next/Security/2026-05-08-02-18-54.gh-issue-149474.ujQ-mu.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix the binary writer in :mod:`profiling.sampling` not firing the audit -(:pep:`578`) when creating the output file. The writer and the reader now -accept any path-like object. Patch by Maurycy Pawłowski-Wieroński. diff --git a/Misc/NEWS.d/next/Security/2026-05-10-18-05-32.gh-issue-87451.XkKB6M.rst b/Misc/NEWS.d/next/Security/2026-05-10-18-05-32.gh-issue-87451.XkKB6M.rst deleted file mode 100644 index 21a79c3e0e7db7..00000000000000 --- a/Misc/NEWS.d/next/Security/2026-05-10-18-05-32.gh-issue-87451.XkKB6M.rst +++ /dev/null @@ -1,6 +0,0 @@ -The :mod:`ftplib` module's undocumented ``ftpcp`` function no longer trusts -the IPv4 address value returned from the source server in response to the -``PASV`` command by default, completing the fix for CVE-2021-4189. As with -:class:`ftplib.FTP`, the former behavior can be re-enabled by setting the -``trust_server_pasv_ipv4_address`` attribute on the source :class:`ftplib.FTP` -instance to ``True``. Thanks to Qi Deng at Aurascape AI for the report. diff --git a/Misc/NEWS.d/next/Security/2026-05-11-21-15-07.gh-issue-149698.OudOcW.rst b/Misc/NEWS.d/next/Security/2026-05-11-21-15-07.gh-issue-149698.OudOcW.rst deleted file mode 100644 index 3c8671b9a5adc4..00000000000000 --- a/Misc/NEWS.d/next/Security/2026-05-11-21-15-07.gh-issue-149698.OudOcW.rst +++ /dev/null @@ -1,2 +0,0 @@ -Update bundled `libexpat <https://libexpat.github.io/>`_ to version 2.8.1 -for the fix for :cve:`2026-45186`. diff --git a/Misc/NEWS.d/next/Tests/2026-05-13-14-53-23.gh-issue-149776.orqgsn.rst b/Misc/NEWS.d/next/Tests/2026-05-13-14-53-23.gh-issue-149776.orqgsn.rst deleted file mode 100644 index e86a9130ff9bfb..00000000000000 --- a/Misc/NEWS.d/next/Tests/2026-05-13-14-53-23.gh-issue-149776.orqgsn.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix test_socket on Linux kernel 7.1 and newer: skip UDP Lite tests if it's -not supported. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Tests/2026-05-25-15-39-53.gh-issue-150387.yzZ7jq.rst b/Misc/NEWS.d/next/Tests/2026-05-25-15-39-53.gh-issue-150387.yzZ7jq.rst deleted file mode 100644 index 663a357a179204..00000000000000 --- a/Misc/NEWS.d/next/Tests/2026-05-25-15-39-53.gh-issue-150387.yzZ7jq.rst +++ /dev/null @@ -1,5 +0,0 @@ -Fix hang in -``test.test_profiling.test_sampling_profiler.test_live_collector_ui.TestLiveModeErrors.test_run_failed_script_live`` -on slow buildbots. The test now always queues a final ``q`` keystroke so the -live TUI loop exits even when the profiler collects enough samples to enter -the post-finished input loop. diff --git a/Misc/NEWS.d/next/Tools-Demos/2026-05-22-18-51-09.gh-issue-150258.dh8GVK.rst b/Misc/NEWS.d/next/Tools-Demos/2026-05-22-18-51-09.gh-issue-150258.dh8GVK.rst deleted file mode 100644 index 02cad6c4f53d92..00000000000000 --- a/Misc/NEWS.d/next/Tools-Demos/2026-05-22-18-51-09.gh-issue-150258.dh8GVK.rst +++ /dev/null @@ -1 +0,0 @@ -Update the tooltip on the Tachyon flame graph to show both absolute and relative percentages. diff --git a/Misc/NEWS.d/next/Windows/2026-04-26-23-14-45.gh-issue-149029.oPTXP4.rst b/Misc/NEWS.d/next/Windows/2026-04-26-23-14-45.gh-issue-149029.oPTXP4.rst deleted file mode 100644 index 6c4c6403b98984..00000000000000 --- a/Misc/NEWS.d/next/Windows/2026-04-26-23-14-45.gh-issue-149029.oPTXP4.rst +++ /dev/null @@ -1 +0,0 @@ -Update Windows installer to ship with SQLite 3.53.1. diff --git a/Misc/NEWS.d/next/Windows/2026-04-29-14-44-51.gh-issue-138489.234aj6.rst b/Misc/NEWS.d/next/Windows/2026-04-29-14-44-51.gh-issue-138489.234aj6.rst deleted file mode 100644 index 4afb8f737b692e..00000000000000 --- a/Misc/NEWS.d/next/Windows/2026-04-29-14-44-51.gh-issue-138489.234aj6.rst +++ /dev/null @@ -1,4 +0,0 @@ -Windows distributions now include a :file:`build-details.json` file (see -:pep:`739`). The legacy installer does not install it, but all other -distributions from python.org and all preset configurations in the -``PC\layout`` script will include one. diff --git a/Misc/NEWS.d/next/Windows/2026-05-06-21-36-53.gh-issue-124111.m4OBX8.rst b/Misc/NEWS.d/next/Windows/2026-05-06-21-36-53.gh-issue-124111.m4OBX8.rst deleted file mode 100644 index 9a57536f1dc96b..00000000000000 --- a/Misc/NEWS.d/next/Windows/2026-05-06-21-36-53.gh-issue-124111.m4OBX8.rst +++ /dev/null @@ -1 +0,0 @@ -Updated Windows builds to use Tcl/Tk 9.0.3. diff --git a/Misc/NEWS.d/next/Windows/2026-05-14-22-09-46.gh-issue-149786.UI-HZM.rst b/Misc/NEWS.d/next/Windows/2026-05-14-22-09-46.gh-issue-149786.UI-HZM.rst deleted file mode 100644 index 64ca91a01f41af..00000000000000 --- a/Misc/NEWS.d/next/Windows/2026-05-14-22-09-46.gh-issue-149786.UI-HZM.rst +++ /dev/null @@ -1 +0,0 @@ -Fixes virtual environment launchers on Windows free-threaded builds. diff --git a/Misc/NEWS.d/next/macOS/2026-04-26-23-15-09.gh-issue-149029.Lsx--T.rst b/Misc/NEWS.d/next/macOS/2026-04-26-23-15-09.gh-issue-149029.Lsx--T.rst deleted file mode 100644 index 157a70f5e3cefc..00000000000000 --- a/Misc/NEWS.d/next/macOS/2026-04-26-23-15-09.gh-issue-149029.Lsx--T.rst +++ /dev/null @@ -1 +0,0 @@ -Update macOS installer to ship with SQLite version 3.53.1. diff --git a/Misc/NEWS.d/next/macOS/2026-05-31-10-40-00.gh-issue-150644.zLWyjj.rst b/Misc/NEWS.d/next/macOS/2026-05-31-10-40-00.gh-issue-150644.zLWyjj.rst deleted file mode 100644 index 7452a7c765c0a8..00000000000000 --- a/Misc/NEWS.d/next/macOS/2026-05-31-10-40-00.gh-issue-150644.zLWyjj.rst +++ /dev/null @@ -1,3 +0,0 @@ -When system logging is enabled (with ``config.use_system_logger``, messages -are now tagged as public. This allows the macOS 26 system logger to view -messages without special configuration. diff --git a/README.rst b/README.rst index e9dd44382972d5..ac84a8a7d054bd 100644 --- a/README.rst +++ b/README.rst @@ -1,4 +1,4 @@ -This is Python version 3.15.0 beta 1 +This is Python version 3.15.0 beta 2 ==================================== .. image:: https://github.com/python/cpython/actions/workflows/build.yml/badge.svg?branch=main&event=push From fd0a7fd5ba19986bbb9bb22c5d80811e648f7396 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 2 Jun 2026 17:31:56 +0200 Subject: [PATCH 208/818] [3.15] gh-101913: changed wording of docstring for _parsedate_tz (GH-134446) (#150796) Fixed incorrect word. (cherry picked from commit f7e0fb60cfaf31373c0b78e6eb954a0351e92f09) Co-authored-by: Gustaf <79180496+gostak-dd@users.noreply.github.com> Co-authored-by: Gustaf <79180496+GGyll@users.noreply.github.com> --- Lib/email/_parseaddr.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/email/_parseaddr.py b/Lib/email/_parseaddr.py index 6a7c5fa06d20b6..e311948cb09a7d 100644 --- a/Lib/email/_parseaddr.py +++ b/Lib/email/_parseaddr.py @@ -59,7 +59,7 @@ def _parsedate_tz(data): The last (additional) element is the time zone offset in seconds, except if the timezone was specified as -0000. In that case the last element is - None. This indicates a UTC timestamp that explicitly declaims knowledge of + None. This indicates a UTC timestamp that explicitly disclaims knowledge of the source timezone, as opposed to a +0000 timestamp that indicates the source timezone really was UTC. From a1387695946b17002c2b97b7690e14dc6efc5924 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> Date: Tue, 2 Jun 2026 20:34:33 +0300 Subject: [PATCH 209/818] Post 3.15.0b2 --- Include/patchlevel.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Include/patchlevel.h b/Include/patchlevel.h index 649609136fec80..e474c56e101e1b 100644 --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -27,7 +27,7 @@ #define PY_RELEASE_SERIAL 2 /* Version as a string */ -#define PY_VERSION "3.15.0b2" +#define PY_VERSION "3.15.0b2+dev" /*--end constants--*/ From 0aa9f434ad878bbbdf50e66ad484bae1a2085e92 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 2 Jun 2026 21:20:49 +0200 Subject: [PATCH 210/818] [3.15] Fix description of the function parameter of shutil.register_archive_format() (GH-145087) (GH-150804) (cherry picked from commit 18c6d3ccc32232a28a5288708818ef9c4fecba1a) Co-authored-by: Brian Schubert <brianm.schubert@gmail.com> --- Doc/library/shutil.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/shutil.rst b/Doc/library/shutil.rst index e0300a38e2f357..6a734966d1e0a4 100644 --- a/Doc/library/shutil.rst +++ b/Doc/library/shutil.rst @@ -696,7 +696,7 @@ provided. They rely on the :mod:`zipfile` and :mod:`tarfile` modules. Register an archiver for the format *name*. - *function* is the callable that will be used to unpack archives. The callable + *function* is the callable that will be used to create archives. The callable will receive the *base_name* of the file to create, followed by the *base_dir* (which defaults to :data:`os.curdir`) to start archiving from. Further arguments are passed as keyword arguments: *owner*, *group*, From d5f93ce15601d887bb6fd562ea33fd48dad33960 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 2 Jun 2026 21:23:15 +0200 Subject: [PATCH 211/818] [3.15] gh-141627: Fix BufferedRandom inheritance documentation (GH-141629) (GH-150801) BufferedRandom does not inherit from BufferedReader and BufferedWriter in the C implementation. (cherry picked from commit 551bc2cb5ed4719c35ca3ea0f320167dd750389e) Co-authored-by: Mohsin Mehmood <55545648+mohsinm-dev@users.noreply.github.com> --- Doc/library/io.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/library/io.rst b/Doc/library/io.rst index 494e57fe1c0474..8c0eed592dd49e 100644 --- a/Doc/library/io.rst +++ b/Doc/library/io.rst @@ -824,9 +824,9 @@ than raw I/O does. .. class:: BufferedRandom(raw, buffer_size=DEFAULT_BUFFER_SIZE) - A buffered binary stream providing higher-level access to a seekable - :class:`RawIOBase` raw binary stream. It inherits from :class:`BufferedReader` - and :class:`BufferedWriter`. + A buffered binary stream implementing :class:`BufferedIOBase` interfaces + providing higher-level access to a seekable :class:`RawIOBase` raw binary + stream. The constructor creates a reader and writer for a seekable raw stream, given in the first argument. If the *buffer_size* is omitted it defaults to From 1c2daa08fb8b802e6057378d78e8e2b38b14abdb Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 2 Jun 2026 22:40:52 +0200 Subject: [PATCH 212/818] [3.15] gh-150319: Replace all documentation which says "See PEP 585" (GH-150325) (#150808) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gh-150319: Replace all documentation which says "See PEP 585" (GH-150325) * Replace all documentation which says "See PEP 585" The following classes in the stdlib get simple updates: - array.array - asyncio.Future - asyncio.Task - collections.defaultdict - collections.deque - contextvars.ContextVar - contextvars.Token - ctypes.Array - os.DirEntry - re.Match - re.Pattern - string.templatelib.Interpolation - string.templatelib.Template - types.MappingProxyType - queue.SimpleQueue - weakref.ref The following classes are documented publicly as functions, and are therefore updated internally (`__class_getitem__.__doc__`) but not in the public docs: - functools.partial - itertools.chain The following builtin types have updates to `__class_getitem__.__doc__` but not to any documentation pages: - BaseExceptionGroup - coroutines (from generators) - dict - enumerate - frozendict - frozenset - generators (and async generators) - list - memoryview - set - slice - tuple Special cases: - union objects are now documented as "supporting class-level []", rather than anything to do with generics. - Templates might be generic over a single type (union, in theory) or over a TypeVarTuple. As this is not currently fully settled, it is marked with a comment and a mild hint that it is a single type is used (namely, "type" is singular rather than "types", plural) * Apply suggestions from code review * Correct several class getitem docs And expand the text for tuples. * Add notes on generic typing of builtins * Fix typo in tuple.__class_getitem__ docstring * Typo fix: malformed refs Fix `generic` links which weren't marked as `:ref:`. * Strike unnecessary docs on generic-ness * Apply suggestions from code review These are applied at both the originally indicated locations and in the corresponding docstring definitions. * Update Doc/library/re.rst * Update Objects/enumobject.c * Remove tuple generic doc in 'stdtypes' page This is covered in more detail in the cross-linked typing documentation. The other copy of this documentation -- in the docstring for `tuple.__class_getitem__` -- is left in place. * Fix whitespace around new doc of generics Per review, do not introduce or remove whitespace such that section breaks are altered by the introduction of doc on various generic types. In most cases, this is a removal of an extra line. In one case (Arrays), it is the reintroduction of a line. Additionally, two other minor fixes are included: - incorrect indent on 'defaultdicts' - make `mappingproxy.__class_getitem__.__doc__` consistent with other mapping type generic docs * Move placement of memoryview generic note Previous placement was at the end of the main docstring, which is consistent with other types but places it after a section on various methods (which makes it read somewhat inconsistently). Moving it up helps resolve. * Ensure sphinxdoc does not start sentences lowercase Lowercase class names at the start of sentences are marked out with the `class` role. In the case of `deque`, documentation already refers to these as `Deques`, so this form is preferred. * Apply suggestions from code review * Fix line endings and wrap more tightly Line endings fixed by pre-commit ; also re-wrapped the MappingProxyType text which was too long. * Use 'ContextVars' style in sphinx doc --------- (cherry picked from commit 50fe49c879af352914da3baa40c7fd1fb170028c) Co-authored-by: Stephen Rosen <sirosen@globus.org> Co-authored-by: Jelle Zijlstra <jelle.zijlstra@gmail.com> Co-authored-by: Jelle Zijlstra <906600+JelleZijlstra@users.noreply.github.com> Co-authored-by: Alex Waygood <66076021+AlexWaygood@users.noreply.github.com> Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com> Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com> --- Doc/c-api/typehints.rst | 2 +- Doc/library/array.rst | 2 ++ Doc/library/asyncio-future.rst | 2 ++ Doc/library/asyncio-task.rst | 3 +++ Doc/library/collections.rst | 5 +++++ Doc/library/contextvars.rst | 6 ++++++ Doc/library/ctypes.rst | 2 ++ Doc/library/exceptions.rst | 3 +++ Doc/library/os.rst | 3 +++ Doc/library/queue.rst | 2 ++ Doc/library/re.rst | 6 ++++++ Doc/library/stdtypes.rst | 17 +++++++++++++++++ Doc/library/string.templatelib.rst | 2 ++ Doc/library/types.rst | 4 ++++ Doc/library/weakref.rst | 3 +++ Doc/reference/datamodel.rst | 3 +++ ...26-05-23-17-27-41.gh-issue-150319.ol9tWK.rst | 2 ++ Modules/_asynciomodule.c | 6 ++++-- Modules/_collectionsmodule.c | 10 ++++++++-- Modules/_ctypes/_ctypes.c | 2 +- Modules/_functoolsmodule.c | 3 ++- Modules/_queuemodule.c | 2 +- Modules/_sre/sre.c | 4 ++-- Modules/arraymodule.c | 3 ++- Modules/itertoolsmodule.c | 6 +++++- Modules/posixmodule.c | 2 +- Objects/descrobject.c | 2 +- Objects/dictobject.c | 6 ++++-- Objects/enumobject.c | 2 +- Objects/exceptions.c | 3 ++- Objects/genobject.c | 8 +++++--- Objects/interpolationobject.c | 2 +- Objects/listobject.c | 3 ++- Objects/memoryobject.c | 3 ++- Objects/setobject.c | 6 ++++-- Objects/sliceobject.c | 3 ++- Objects/templateobject.c | 6 +++++- Objects/tupleobject.c | 8 +++++++- Objects/unionobject.c | 3 ++- Objects/weakrefobject.c | 3 ++- Python/context.c | 6 ++++-- 41 files changed, 136 insertions(+), 33 deletions(-) create mode 100644 Misc/NEWS.d/next/Documentation/2026-05-23-17-27-41.gh-issue-150319.ol9tWK.rst diff --git a/Doc/c-api/typehints.rst b/Doc/c-api/typehints.rst index 98fe68737deb81..ec2fba6da8b043 100644 --- a/Doc/c-api/typehints.rst +++ b/Doc/c-api/typehints.rst @@ -31,7 +31,7 @@ two types exist -- :ref:`GenericAlias <types-genericalias>` and static PyMethodDef my_obj_methods[] = { // Other methods. ... - {"__class_getitem__", Py_GenericAlias, METH_O|METH_CLASS, "See PEP 585"} + {"__class_getitem__", Py_GenericAlias, METH_O|METH_CLASS, "my_obj is generic over its contained type"} ... } diff --git a/Doc/library/array.rst b/Doc/library/array.rst index ca7c055285aa82..da9b3fa2fe8a5d 100644 --- a/Doc/library/array.rst +++ b/Doc/library/array.rst @@ -134,6 +134,8 @@ The module defines the following type: :exc:`TypeError` is raised. Array objects also implement the buffer interface, and may be used wherever :term:`bytes-like objects <bytes-like object>` are supported. + Arrays are :ref:`generic <generics>` over the type of their contents. + .. audit-event:: array.__new__ typecode,initializer array.array diff --git a/Doc/library/asyncio-future.rst b/Doc/library/asyncio-future.rst index 43977de273e61f..195d99123dbd36 100644 --- a/Doc/library/asyncio-future.rst +++ b/Doc/library/asyncio-future.rst @@ -101,6 +101,8 @@ Future Object implementations can inject their own optimized implementations of a Future object. + Futures are :ref:`generic <generics>` over the type of their results. + .. versionchanged:: 3.7 Added support for the :mod:`contextvars` module. diff --git a/Doc/library/asyncio-task.rst b/Doc/library/asyncio-task.rst index cc833b80d52542..64f0810777e41b 100644 --- a/Doc/library/asyncio-task.rst +++ b/Doc/library/asyncio-task.rst @@ -1230,6 +1230,9 @@ Task object blocks. If the coroutine returns or raises without blocking, the task will be finished eagerly and will skip scheduling to the event loop. + Tasks are :ref:`generic <generics>` over the return type of their wrapped + coroutines. + .. versionchanged:: 3.7 Added support for the :mod:`contextvars` module. diff --git a/Doc/library/collections.rst b/Doc/library/collections.rst index e42bdc06be09ff..25e4a71b03c6c8 100644 --- a/Doc/library/collections.rst +++ b/Doc/library/collections.rst @@ -484,6 +484,8 @@ or subtracting from an empty counter. Unix. They are also useful for tracking transactions and other pools of data where only the most recent activity is of interest. + Deques are :ref:`generic <generics>` over the type of their contents. + Deque objects support the following methods: @@ -739,6 +741,9 @@ stack manipulations such as ``dup``, ``drop``, ``swap``, ``over``, ``pick``, as if they were passed to the :class:`dict` constructor, including keyword arguments. + :class:`!defaultdict`\s are :ref:`generic <generics>` over two types, + signifying (respectively) the types of the dictionary's keys and values. + :class:`defaultdict` objects support the following method in addition to the standard :class:`dict` operations: diff --git a/Doc/library/contextvars.rst b/Doc/library/contextvars.rst index 93d0c0d34bf039..b0cc0be8e911bf 100644 --- a/Doc/library/contextvars.rst +++ b/Doc/library/contextvars.rst @@ -42,6 +42,9 @@ Context Variables references to context variables which prevents context variables from being properly garbage collected. + :class:`!ContextVar`\s are :ref:`generic <generics>` over the type of + their contained value. + .. attribute:: ContextVar.name The name of the variable. This is a read-only property. @@ -130,6 +133,9 @@ Context Variables Tokens support the :ref:`context manager protocol <context-managers>` to automatically reset context variables. See :meth:`ContextVar.set`. + Tokens are :ref:`generic <generics>` over the same type as the + :class:`ContextVar` which created them. + .. versionadded:: 3.14 Added support for usage as a context manager. diff --git a/Doc/library/ctypes.rst b/Doc/library/ctypes.rst index 618ae89921c348..46b8dd8ef18814 100644 --- a/Doc/library/ctypes.rst +++ b/Doc/library/ctypes.rst @@ -3178,6 +3178,8 @@ Arrays and pointers subscript and slice accesses; for slice reads, the resulting object is *not* itself an :class:`Array`. + Arrays are :ref:`generic <generics>` over the type of their elements. + .. attribute:: _length_ diff --git a/Doc/library/exceptions.rst b/Doc/library/exceptions.rst index 7fc6055aa9a881..3775d5ac81a273 100644 --- a/Doc/library/exceptions.rst +++ b/Doc/library/exceptions.rst @@ -984,6 +984,9 @@ their subgroups based on the types of the contained exceptions. raises a :exc:`TypeError` if any contained exception is not an :exc:`Exception` subclass. + Exception groups are :ref:`generic <generics>` over the type of their + contained exceptions. + .. impl-detail:: The ``excs`` parameter may be any sequence, but lists and tuples are diff --git a/Doc/library/os.rst b/Doc/library/os.rst index 27a032a8a97c63..f2c9b3914f36e6 100644 --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -2982,6 +2982,9 @@ features: To be directly usable as a :term:`path-like object`, ``os.DirEntry`` implements the :class:`PathLike` interface. + :class:`!DirEntry` objects are :ref:`generic <generics>` over the type of the + path (:class:`str` or :class:`bytes`). + Attributes and methods on a ``os.DirEntry`` instance are as follows: .. attribute:: name diff --git a/Doc/library/queue.rst b/Doc/library/queue.rst index 5ac72ef7604d50..f5326aff7236bd 100644 --- a/Doc/library/queue.rst +++ b/Doc/library/queue.rst @@ -76,6 +76,8 @@ The :mod:`!queue` module defines the following classes and exceptions: Constructor for an unbounded :abbr:`FIFO (first-in, first-out)` queue. Simple queues lack advanced functionality such as task tracking. + Simple queues are :ref:`generic <generics>` over the type of their items. + .. versionadded:: 3.7 diff --git a/Doc/library/re.rst b/Doc/library/re.rst index a46fd42458158c..4745c1b98a4554 100644 --- a/Doc/library/re.rst +++ b/Doc/library/re.rst @@ -1257,6 +1257,9 @@ Regular expression objects Compiled regular expression object returned by :func:`re.compile`. + Patterns are :ref:`generic <generics>` over the type of string they handle + (:class:`str` or :class:`bytes`). + .. versionchanged:: 3.9 :py:class:`re.Pattern` supports ``[]`` to indicate a Unicode (str) or bytes pattern. See :ref:`types-genericalias`. @@ -1419,6 +1422,9 @@ when there is no match, you can test whether there was a match with a simple Match object returned by successful ``match``\ es and ``search``\ es. + Matches are :ref:`generic <generics>` over the type of string which was + matched (:class:`str` or :class:`bytes`). + .. versionchanged:: 3.9 :py:class:`re.Match` supports ``[]`` to indicate a Unicode (str) or bytes match. See :ref:`types-genericalias`. diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index b0388c4e1f0bd4..c8f2cca484ab31 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -1403,6 +1403,8 @@ application). Many other operations also produce lists, including the :func:`sorted` built-in. + Lists are :ref:`generic <generics>` over the types of their items. + Lists implement all of the :ref:`common <typesseq-common>` and :ref:`mutable <typesseq-mutable>` sequence operations. Lists also provide the following additional method: @@ -1494,6 +1496,10 @@ homogeneous data is needed (such as allowing storage in a :class:`set` or Tuples implement all of the :ref:`common <typesseq-common>` sequence operations. + Tuples are :ref:`generic <generics>` over the types of their contents. + For more information, refer to + :ref:`the typing documentation on annotating tuples <annotating-tuples>`. + For heterogeneous collections of data where access by name is clearer than access by index, :func:`collections.namedtuple` may be a more appropriate choice than a simple tuple object. @@ -4586,6 +4592,9 @@ copying. types such as :class:`bytes` and :class:`bytearray`, an element is a single byte, but other types such as :class:`array.array` may have bigger elements. + :class:`!memoryview`\s are :ref:`generic <generics>` over the type of their + underlying data. + ``len(view)`` is equal to the length of :meth:`~memoryview.tolist`, which is the nested list representation of the view. If ``view.ndim = 1``, this is equal to the number of elements in the view. @@ -5279,6 +5288,8 @@ Note, the *elem* argument to the :meth:`~object.__contains__`, :meth:`~set.discard` methods may be a set. To support searching for an equivalent frozenset, a temporary one is created from *elem*. +Sets and frozensets are :ref:`generic <generics>` over the type of their elements. + .. seealso:: For detailed information on thread-safety guarantees for :class:`set` @@ -5382,6 +5393,9 @@ can be used interchangeably to index the same dictionary entry. Dictionary order is guaranteed to be insertion order. This behavior was an implementation detail of CPython from 3.6. + Dictionaries are :ref:`generic <generics>` over two types, signifying + (respectively) the types of the dictionary's keys and values. + These are the operations that dictionaries support (and therefore, custom mapping types should support too): @@ -5719,6 +5733,9 @@ Frozen dictionaries :class:`!frozendict` is not a :class:`!dict` subclass but inherits directly from ``object``. + Like dictionaries, frozendicts are :ref:`generic <generics>` over two types, + signifying (respectively) the types of the frozendict's keys and values. + .. versionadded:: 3.15 diff --git a/Doc/library/string.templatelib.rst b/Doc/library/string.templatelib.rst index a5b2d796aaf4b8..6e91850fdf59ca 100644 --- a/Doc/library/string.templatelib.rst +++ b/Doc/library/string.templatelib.rst @@ -245,6 +245,8 @@ Types ... 3.0 | 1. + 2. | None | .2f + Interpolations are :ref:`generic <generics>` over the types of their values. + .. rubric:: Attributes .. attribute:: value diff --git a/Doc/library/types.rst b/Doc/library/types.rst index 9f7b7579519052..38a77119769d72 100644 --- a/Doc/library/types.rst +++ b/Doc/library/types.rst @@ -386,6 +386,10 @@ Standard names are defined for the following types: entries, which means that when the mapping changes, the view reflects these changes. + :class:`!MappingProxyType`\s are :ref:`generic <generics>` over two types, + signifying (respectively) the types of the underlying mapping's keys and + values. + .. versionadded:: 3.3 .. versionchanged:: 3.9 diff --git a/Doc/library/weakref.rst b/Doc/library/weakref.rst index 318da931fc314c..fcb9e0199fad69 100644 --- a/Doc/library/weakref.rst +++ b/Doc/library/weakref.rst @@ -120,6 +120,9 @@ See :ref:`__slots__ documentation <slots>` for details. This is a subclassable type rather than a factory function. + Weak references are :ref:`generic <generics>` over the type of the object they + reference. + .. attribute:: __callback__ This read-only attribute returns the callback currently associated to the diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst index e13b2c9db490a1..a8614128c85dad 100644 --- a/Doc/reference/datamodel.rst +++ b/Doc/reference/datamodel.rst @@ -3868,6 +3868,9 @@ Coroutines also have the methods listed below, which are analogous to those of generators (see :ref:`generator-methods`). However, unlike generators, coroutines do not directly support iteration. +Coroutines are :ref:`generic <generics>` over the types of their yield, send, +and return values, respectively. + .. versionchanged:: 3.5.2 It is a :exc:`RuntimeError` to await on a coroutine more than once. diff --git a/Misc/NEWS.d/next/Documentation/2026-05-23-17-27-41.gh-issue-150319.ol9tWK.rst b/Misc/NEWS.d/next/Documentation/2026-05-23-17-27-41.gh-issue-150319.ol9tWK.rst new file mode 100644 index 00000000000000..d56ccbce2fa325 --- /dev/null +++ b/Misc/NEWS.d/next/Documentation/2026-05-23-17-27-41.gh-issue-150319.ol9tWK.rst @@ -0,0 +1,2 @@ +Generic builtin and standard library types now document the meaning of their +type parameters. diff --git a/Modules/_asynciomodule.c b/Modules/_asynciomodule.c index 7fa415a08b1551..6620ee26449b16 100644 --- a/Modules/_asynciomodule.c +++ b/Modules/_asynciomodule.c @@ -1742,7 +1742,8 @@ static PyMethodDef FutureType_methods[] = { _ASYNCIO_FUTURE_DONE_METHODDEF _ASYNCIO_FUTURE_GET_LOOP_METHODDEF _ASYNCIO_FUTURE__MAKE_CANCELLED_ERROR_METHODDEF - {"__class_getitem__", Py_GenericAlias, METH_O|METH_CLASS, PyDoc_STR("See PEP 585")}, + {"__class_getitem__", Py_GenericAlias, METH_O|METH_CLASS, + PyDoc_STR("Futures are generic over the type of their results")}, {NULL, NULL} /* Sentinel */ }; @@ -2927,7 +2928,8 @@ static PyMethodDef TaskType_methods[] = { _ASYNCIO_TASK_SET_NAME_METHODDEF _ASYNCIO_TASK_GET_CORO_METHODDEF _ASYNCIO_TASK_GET_CONTEXT_METHODDEF - {"__class_getitem__", Py_GenericAlias, METH_O|METH_CLASS, PyDoc_STR("See PEP 585")}, + {"__class_getitem__", Py_GenericAlias, METH_O|METH_CLASS, + PyDoc_STR("Tasks are generic over the return type of their wrapped coroutines")}, {NULL, NULL} /* Sentinel */ }; diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c index 541ca48633bb56..c5d4879312bc8a 100644 --- a/Modules/_collectionsmodule.c +++ b/Modules/_collectionsmodule.c @@ -1855,7 +1855,7 @@ static PyMethodDef deque_methods[] = { DEQUE_ROTATE_METHODDEF DEQUE___SIZEOF___METHODDEF {"__class_getitem__", Py_GenericAlias, - METH_O|METH_CLASS, PyDoc_STR("See PEP 585")}, + METH_O|METH_CLASS, PyDoc_STR("deques are generic over the type of their contents")}, {NULL, NULL} /* sentinel */ }; @@ -2331,6 +2331,12 @@ defdict_reduce(PyObject *op, PyObject *Py_UNUSED(dummy)) return result; } + +PyDoc_STRVAR(defdict_class_getitem_doc, +"defaultdicts are generic over two types, signifying (respectively) the types \ +of the dictionary's keys and values"); + + static PyMethodDef defdict_methods[] = { {"__missing__", defdict_missing, METH_O, defdict_missing_doc}, @@ -2341,7 +2347,7 @@ static PyMethodDef defdict_methods[] = { {"__reduce__", defdict_reduce, METH_NOARGS, reduce_doc}, {"__class_getitem__", Py_GenericAlias, METH_O|METH_CLASS, - PyDoc_STR("See PEP 585")}, + defdict_class_getitem_doc}, {NULL} }; diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c index 09eae97dd21a36..e891249668c20f 100644 --- a/Modules/_ctypes/_ctypes.c +++ b/Modules/_ctypes/_ctypes.c @@ -5305,7 +5305,7 @@ Array_length(PyObject *myself) static PyMethodDef Array_methods[] = { {"__class_getitem__", Py_GenericAlias, - METH_O|METH_CLASS, PyDoc_STR("See PEP 585")}, + METH_O|METH_CLASS, PyDoc_STR("Arrays are generic over the type of their elements")}, { NULL, NULL } }; diff --git a/Modules/_functoolsmodule.c b/Modules/_functoolsmodule.c index 393b59883e89f3..b4595c55d519b9 100644 --- a/Modules/_functoolsmodule.c +++ b/Modules/_functoolsmodule.c @@ -860,7 +860,8 @@ static PyMethodDef partial_methods[] = { {"__reduce__", partial_reduce, METH_NOARGS}, {"__setstate__", partial_setstate, METH_O}, {"__class_getitem__", Py_GenericAlias, - METH_O|METH_CLASS, PyDoc_STR("See PEP 585")}, + METH_O|METH_CLASS, + PyDoc_STR("partial is generic over the wrapped function's return type")}, {NULL, NULL} /* sentinel */ }; diff --git a/Modules/_queuemodule.c b/Modules/_queuemodule.c index 7205c095cc87b8..af54e42a6af584 100644 --- a/Modules/_queuemodule.c +++ b/Modules/_queuemodule.c @@ -550,7 +550,7 @@ static PyMethodDef simplequeue_methods[] = { _QUEUE_SIMPLEQUEUE_QSIZE_METHODDEF _QUEUE_SIMPLEQUEUE___SIZEOF___METHODDEF {"__class_getitem__", Py_GenericAlias, - METH_O|METH_CLASS, PyDoc_STR("See PEP 585")}, + METH_O|METH_CLASS, PyDoc_STR("SimpleQueues are generic over the type of their contents")}, {NULL, NULL} /* sentinel */ }; diff --git a/Modules/_sre/sre.c b/Modules/_sre/sre.c index 7a07ed1d7aca20..d372d6a03ab4ee 100644 --- a/Modules/_sre/sre.c +++ b/Modules/_sre/sre.c @@ -3180,7 +3180,7 @@ static PyMethodDef pattern_methods[] = { _SRE_SRE_PATTERN___DEEPCOPY___METHODDEF _SRE_SRE_PATTERN__FAIL_AFTER_METHODDEF {"__class_getitem__", Py_GenericAlias, METH_O|METH_CLASS, - PyDoc_STR("See PEP 585")}, + PyDoc_STR("Patterns are generic over the type of string they handle (str or bytes)")}, {NULL, NULL} }; @@ -3236,7 +3236,7 @@ static PyMethodDef match_methods[] = { _SRE_SRE_MATCH___COPY___METHODDEF _SRE_SRE_MATCH___DEEPCOPY___METHODDEF {"__class_getitem__", Py_GenericAlias, METH_O|METH_CLASS, - PyDoc_STR("See PEP 585")}, + PyDoc_STR("Matches are generic over the type of string which was matched (str or bytes)")}, {NULL, NULL} }; diff --git a/Modules/arraymodule.c b/Modules/arraymodule.c index 7f367d639983ae..aefdfe0edc0e1e 100644 --- a/Modules/arraymodule.c +++ b/Modules/arraymodule.c @@ -2676,7 +2676,8 @@ static PyMethodDef array_methods[] = { ARRAY_ARRAY_TOBYTES_METHODDEF ARRAY_ARRAY_TOUNICODE_METHODDEF ARRAY_ARRAY___SIZEOF___METHODDEF - {"__class_getitem__", Py_GenericAlias, METH_O|METH_CLASS, PyDoc_STR("See PEP 585")}, + {"__class_getitem__", Py_GenericAlias, METH_O|METH_CLASS, + PyDoc_STR("Arrays are generic over the type of their elements")}, {NULL, NULL} /* sentinel */ }; diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c index 68ac810eaad237..0dd31dfbc5a346 100644 --- a/Modules/itertoolsmodule.c +++ b/Modules/itertoolsmodule.c @@ -1952,10 +1952,14 @@ Return a chain object whose .__next__() method returns elements from the\n\ first iterable until it is exhausted, then elements from the next\n\ iterable, until all of the iterables are exhausted."); +PyDoc_STRVAR(chain_class_getitem_doc, +"chain is generic over the type of its contents.\n\ +This is the union of the types of the input iterable contents."); + static PyMethodDef chain_methods[] = { ITERTOOLS_CHAIN_FROM_ITERABLE_METHODDEF {"__class_getitem__", Py_GenericAlias, - METH_O|METH_CLASS, PyDoc_STR("See PEP 585")}, + METH_O|METH_CLASS, chain_class_getitem_doc}, {NULL, NULL} /* sentinel */ }; diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 4f745c504a066a..214c4ab8602be7 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -16528,7 +16528,7 @@ static PyMethodDef DirEntry_methods[] = { OS_DIRENTRY_INODE_METHODDEF OS_DIRENTRY___FSPATH___METHODDEF {"__class_getitem__", Py_GenericAlias, - METH_O|METH_CLASS, PyDoc_STR("See PEP 585")}, + METH_O|METH_CLASS, PyDoc_STR("DirEntry is generic over the type of the path (str or bytes)")}, {NULL} }; diff --git a/Objects/descrobject.c b/Objects/descrobject.c index a5926616eeb3cb..30444b7d677424 100644 --- a/Objects/descrobject.c +++ b/Objects/descrobject.c @@ -1178,7 +1178,7 @@ static PyMethodDef mappingproxy_methods[] = { {"copy", mappingproxy_copy, METH_NOARGS, PyDoc_STR("D.copy() -> a shallow copy of D")}, {"__class_getitem__", Py_GenericAlias, METH_O|METH_CLASS, - PyDoc_STR("See PEP 585")}, + PyDoc_STR("mappingproxy objects are generic over two types, signifying (respectively) the types of their keys and values")}, {"__reversed__", mappingproxy_reversed, METH_NOARGS, PyDoc_STR("D.__reversed__() -> reverse iterator")}, {0} diff --git a/Objects/dictobject.c b/Objects/dictobject.c index 66546b72130dd0..e279c8765dd464 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -5130,7 +5130,8 @@ static PyMethodDef mapp_methods[] = { DICT_CLEAR_METHODDEF DICT_COPY_METHODDEF DICT___REVERSED___METHODDEF - {"__class_getitem__", Py_GenericAlias, METH_O|METH_CLASS, PyDoc_STR("See PEP 585")}, + {"__class_getitem__", Py_GenericAlias, METH_O|METH_CLASS, + PyDoc_STR("dicts are generic over two types, signifying (respectively) the types of their keys and values")}, {NULL, NULL} /* sentinel */ }; @@ -8198,7 +8199,8 @@ static PyMethodDef frozendict_methods[] = { DICT_FROMKEYS_METHODDEF FROZENDICT_COPY_METHODDEF DICT___REVERSED___METHODDEF - {"__class_getitem__", Py_GenericAlias, METH_O|METH_CLASS, PyDoc_STR("See PEP 585")}, + {"__class_getitem__", Py_GenericAlias, METH_O|METH_CLASS, + PyDoc_STR("frozendicts are generic over two types, signifying (respectively) the types of the frozendict's keys and values")}, {"__getnewargs__", frozendict_getnewargs, METH_NOARGS}, {NULL, NULL} /* sentinel */ }; diff --git a/Objects/enumobject.c b/Objects/enumobject.c index 364d508dd01822..fc53f1bfee8dde 100644 --- a/Objects/enumobject.c +++ b/Objects/enumobject.c @@ -290,7 +290,7 @@ PyDoc_STRVAR(reduce_doc, "Return state information for pickling."); static PyMethodDef enum_methods[] = { {"__reduce__", enum_reduce, METH_NOARGS, reduce_doc}, {"__class_getitem__", Py_GenericAlias, - METH_O|METH_CLASS, PyDoc_STR("See PEP 585")}, + METH_O|METH_CLASS, PyDoc_STR("'enumerate' objects are generic over the type of their values")}, {NULL, NULL} /* sentinel */ }; diff --git a/Objects/exceptions.c b/Objects/exceptions.c index 5e5e87cd6d7559..10d100384be7aa 100644 --- a/Objects/exceptions.c +++ b/Objects/exceptions.c @@ -1743,7 +1743,8 @@ static PyMemberDef BaseExceptionGroup_members[] = { static PyMethodDef BaseExceptionGroup_methods[] = { {"__class_getitem__", Py_GenericAlias, - METH_O|METH_CLASS, PyDoc_STR("See PEP 585")}, + METH_O|METH_CLASS, + PyDoc_STR("Exception groups are generic over the type of their contained exceptions")}, BASEEXCEPTIONGROUP_DERIVE_METHODDEF BASEEXCEPTIONGROUP_SPLIT_METHODDEF BASEEXCEPTIONGROUP_SUBGROUP_METHODDEF diff --git a/Objects/genobject.c b/Objects/genobject.c index 8c5d720c0b9035..38d493343454fc 100644 --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -1023,7 +1023,8 @@ static PyMethodDef gen_methods[] = { {"throw", _PyCFunction_CAST(gen_throw), METH_FASTCALL, throw_doc}, {"close", gen_close, METH_NOARGS, close_doc}, {"__sizeof__", gen_sizeof, METH_NOARGS, sizeof__doc__}, - {"__class_getitem__", Py_GenericAlias, METH_O|METH_CLASS, PyDoc_STR("See PEP 585")}, + {"__class_getitem__", Py_GenericAlias, METH_O|METH_CLASS, + PyDoc_STR("generators are generic over the types of their yield, send, and return values")}, {NULL, NULL} /* Sentinel */ }; @@ -1374,7 +1375,8 @@ static PyMethodDef coro_methods[] = { {"throw",_PyCFunction_CAST(gen_throw), METH_FASTCALL, coro_throw_doc}, {"close", gen_close, METH_NOARGS, coro_close_doc}, {"__sizeof__", gen_sizeof, METH_NOARGS, sizeof__doc__}, - {"__class_getitem__", Py_GenericAlias, METH_O|METH_CLASS, PyDoc_STR("See PEP 585")}, + {"__class_getitem__", Py_GenericAlias, METH_O|METH_CLASS, + PyDoc_STR("coroutines are generic over the types of their yield, send, and return values")}, {NULL, NULL} /* Sentinel */ }; @@ -1820,7 +1822,7 @@ static PyMethodDef async_gen_methods[] = { {"aclose", async_gen_aclose, METH_NOARGS, async_aclose_doc}, {"__sizeof__", gen_sizeof, METH_NOARGS, sizeof__doc__}, {"__class_getitem__", Py_GenericAlias, - METH_O|METH_CLASS, PyDoc_STR("See PEP 585")}, + METH_O|METH_CLASS, PyDoc_STR("async generators are generic over the types of their yield and send values")}, {NULL, NULL} /* Sentinel */ }; diff --git a/Objects/interpolationobject.c b/Objects/interpolationobject.c index b58adb693f0cae..e37724fb7852a2 100644 --- a/Objects/interpolationobject.c +++ b/Objects/interpolationobject.c @@ -138,7 +138,7 @@ static PyMethodDef interpolation_methods[] = { {"__reduce__", interpolation_reduce, METH_NOARGS, PyDoc_STR("__reduce__() -> (cls, state)")}, {"__class_getitem__", Py_GenericAlias, - METH_O|METH_CLASS, PyDoc_STR("See PEP 585")}, + METH_O|METH_CLASS, PyDoc_STR("Interpolations are generic over the types of their values")}, {NULL, NULL}, }; diff --git a/Objects/listobject.c b/Objects/listobject.c index 38dc38dd277b97..8a9c9bda68269b 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -3610,7 +3610,8 @@ static PyMethodDef list_methods[] = { LIST_COUNT_METHODDEF LIST_REVERSE_METHODDEF LIST_SORT_METHODDEF - {"__class_getitem__", Py_GenericAlias, METH_O|METH_CLASS, PyDoc_STR("See PEP 585")}, + {"__class_getitem__", Py_GenericAlias, METH_O|METH_CLASS, + PyDoc_STR("lists are generic over the type of their contents")}, {NULL, NULL} /* sentinel */ }; diff --git a/Objects/memoryobject.c b/Objects/memoryobject.c index 3cfee04d80bb74..a05d3c3b7a7f46 100644 --- a/Objects/memoryobject.c +++ b/Objects/memoryobject.c @@ -3579,7 +3579,8 @@ static PyMethodDef memory_methods[] = { MEMORYVIEW_INDEX_METHODDEF {"__enter__", memory_enter, METH_NOARGS, NULL}, {"__exit__", memory_exit, METH_VARARGS, memory_exit_doc}, - {"__class_getitem__", Py_GenericAlias, METH_O|METH_CLASS, PyDoc_STR("See PEP 585")}, + {"__class_getitem__", Py_GenericAlias, METH_O|METH_CLASS, + PyDoc_STR("memoryviews are generic over the type of their underlying data")}, {NULL, NULL} }; diff --git a/Objects/setobject.c b/Objects/setobject.c index 642baef3544d36..7644ea0baf73dd 100644 --- a/Objects/setobject.c +++ b/Objects/setobject.c @@ -2792,7 +2792,8 @@ static PyMethodDef set_methods[] = { SET_SYMMETRIC_DIFFERENCE_UPDATE_METHODDEF SET_UNION_METHODDEF SET_UPDATE_METHODDEF - {"__class_getitem__", Py_GenericAlias, METH_O|METH_CLASS, PyDoc_STR("See PEP 585")}, + {"__class_getitem__", Py_GenericAlias, METH_O|METH_CLASS, + PyDoc_STR("sets are generic over the type of their elements")}, {NULL, NULL} /* sentinel */ }; @@ -2896,7 +2897,8 @@ static PyMethodDef frozenset_methods[] = { SET___SIZEOF___METHODDEF SET_SYMMETRIC_DIFFERENCE_METHODDEF SET_UNION_METHODDEF - {"__class_getitem__", Py_GenericAlias, METH_O|METH_CLASS, PyDoc_STR("See PEP 585")}, + {"__class_getitem__", Py_GenericAlias, METH_O|METH_CLASS, + PyDoc_STR("frozensets are generic over the type of their elements")}, {NULL, NULL} /* sentinel */ }; diff --git a/Objects/sliceobject.c b/Objects/sliceobject.c index dbb509b06ecbba..0d05eb7a47bb1d 100644 --- a/Objects/sliceobject.c +++ b/Objects/sliceobject.c @@ -572,7 +572,8 @@ PyDoc_STRVAR(reduce_doc, "Return state information for pickling."); static PyMethodDef slice_methods[] = { {"indices", slice_indices, METH_O, slice_indices_doc}, {"__reduce__", slice_reduce, METH_NOARGS, reduce_doc}, - {"__class_getitem__", Py_GenericAlias, METH_O|METH_CLASS, "See PEP 585"}, + {"__class_getitem__", Py_GenericAlias, METH_O|METH_CLASS, + "slices are generic over the types of their start, end, and step values"}, {NULL, NULL} }; diff --git a/Objects/templateobject.c b/Objects/templateobject.c index a05208e4c8fc8e..1609e82b444516 100644 --- a/Objects/templateobject.c +++ b/Objects/templateobject.c @@ -372,7 +372,11 @@ template_reduce(PyObject *op, PyObject *Py_UNUSED(dummy)) static PyMethodDef template_methods[] = { {"__reduce__", template_reduce, METH_NOARGS, NULL}, {"__class_getitem__", Py_GenericAlias, - METH_O|METH_CLASS, PyDoc_STR("See PEP 585")}, + METH_O|METH_CLASS, + // note that this is not supported in typeshed, and it is not clear if the + // type for this is a simple TypeVar or a TypeVarTuple + // for details, see: https://github.com/python/typeshed/issues/14878 + PyDoc_STR("Template supports [] for generic usage")}, {NULL, NULL}, }; diff --git a/Objects/tupleobject.c b/Objects/tupleobject.c index 6de9487432a398..5aa5188905305a 100644 --- a/Objects/tupleobject.c +++ b/Objects/tupleobject.c @@ -954,11 +954,17 @@ tuple___getnewargs___impl(PyTupleObject *self) return Py_BuildValue("(N)", tuple_slice(self, 0, Py_SIZE(self))); } + +PyDoc_STRVAR(tuple_class_getitem_doc, +"Tuples are generic over the types of their contents.\n\n\ +For example, use ``tuple[int, str]`` for a pair whose first element is an int and second element is a string.\n\n\ +Tuples also support the form ``tuple[T, ...]`` to indicate an arbitrary length tuple of elements of type T."); + static PyMethodDef tuple_methods[] = { TUPLE___GETNEWARGS___METHODDEF TUPLE_INDEX_METHODDEF TUPLE_COUNT_METHODDEF - {"__class_getitem__", Py_GenericAlias, METH_O|METH_CLASS, PyDoc_STR("See PEP 585")}, + {"__class_getitem__", Py_GenericAlias, METH_O|METH_CLASS, tuple_class_getitem_doc}, {NULL, NULL} /* sentinel */ }; diff --git a/Objects/unionobject.c b/Objects/unionobject.c index 0f6b1e44bc2402..1dc2927b6e6ac7 100644 --- a/Objects/unionobject.c +++ b/Objects/unionobject.c @@ -518,7 +518,8 @@ union_mro_entries(PyObject *self, PyObject *args) static PyMethodDef union_methods[] = { {"__mro_entries__", union_mro_entries, METH_O}, - {"__class_getitem__", union_class_getitem, METH_O|METH_CLASS, PyDoc_STR("See PEP 585")}, + {"__class_getitem__", union_class_getitem, METH_O|METH_CLASS, + PyDoc_STR("Create a union containing the given types")}, {0} }; diff --git a/Objects/weakrefobject.c b/Objects/weakrefobject.c index 61fa3ddad0bfd8..8446a2dbcf7559 100644 --- a/Objects/weakrefobject.c +++ b/Objects/weakrefobject.c @@ -491,7 +491,8 @@ static PyMemberDef weakref_members[] = { static PyMethodDef weakref_methods[] = { {"__class_getitem__", Py_GenericAlias, - METH_O|METH_CLASS, PyDoc_STR("See PEP 585")}, + METH_O|METH_CLASS, + PyDoc_STR("Weakrefs are generic over the type of the referenced object.")}, {NULL} /* Sentinel */ }; diff --git a/Python/context.c b/Python/context.c index 3170018da8c1c9..593e6ef90037cf 100644 --- a/Python/context.c +++ b/Python/context.c @@ -1100,7 +1100,8 @@ static PyMethodDef PyContextVar_methods[] = { _CONTEXTVARS_CONTEXTVAR_SET_METHODDEF _CONTEXTVARS_CONTEXTVAR_RESET_METHODDEF {"__class_getitem__", Py_GenericAlias, - METH_O|METH_CLASS, PyDoc_STR("See PEP 585")}, + METH_O|METH_CLASS, + PyDoc_STR("ContextVars are generic over the type of their contained values")}, {NULL, NULL} }; @@ -1266,7 +1267,8 @@ token_exit_impl(PyContextToken *self, PyObject *type, PyObject *val, static PyMethodDef PyContextTokenType_methods[] = { {"__class_getitem__", Py_GenericAlias, - METH_O|METH_CLASS, PyDoc_STR("See PEP 585")}, + METH_O|METH_CLASS, + PyDoc_STR("Tokens are generic over the same type as the ContextVar which created them.")}, TOKEN_ENTER_METHODDEF TOKEN_EXIT_METHODDEF {NULL} From 53e7f2400a74fc81b741371aaedec7e7b43e6a1b Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 3 Jun 2026 02:41:24 +0200 Subject: [PATCH 213/818] [3.15] gh-150723: Fix perf jitdump files on macOS (GH-150728) (#150832) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gh-150723: Fix perf jitdump files on macOS (GH-150728) The perf jitdump format defines the thread id field of the JR_CODE_LOAD record as a 32-bit value, but on macOS it was declared as a uint64_t (since pthread_threadid_np() returns a uint64_t). Those extra 8 bytes plus alignment padding shifted every following field, so parsers reading the file by the spec misread code_size as the code address and failed to resolve any Python frames. Declare thread_id as uint32_t on all platforms and truncate the macOS thread id when writing the record. The value is only informational. Symbols are resolved by address, and not thread ids so truncation is safe here. * Use mach_absolute_time for macOS jitdump timestamps On macOS the jitdump file is consumed by profilers such as samply, which timestamp their samples using mach_absolute_time(). The jitdump events were stamped with clock_gettime(CLOCK_MONOTONIC), a different clock domain that keeps advancing while the system is asleep, so the JIT code mappings could be off by days relative to the samples and no Python frame would resolve. Stamp jitdump events with mach_absolute_time() on macOS so they share the sampler's clock domain. Linux continues to use CLOCK_MONOTONIC to stay aligned with perf. Exercise the -Xperf_jit (jitdump) backend through samply and assert that Python frames resolve, exercising the binary jitdump path end to end. Skipped when samply is not installed. (cherry picked from commit 494f2e3c92cc1b7774cca16fca5c7d1ff18c0de2) Co-authored-by: Nazım Can Altınova <canaltinova@gmail.com> --- Lib/test/test_samply_profiler.py | 24 +++++++++++++++ ...-06-01-19-21-01.gh-issue-150723.Hb3JDG.rst | 4 +++ ...-06-01-19-24-12.gh-issue-150723.WlcL_-.rst | 4 +++ Python/perf_jit_trampoline.c | 29 +++++++++++++++---- 4 files changed, 56 insertions(+), 5 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-01-19-21-01.gh-issue-150723.Hb3JDG.rst create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-01-19-24-12.gh-issue-150723.WlcL_-.rst diff --git a/Lib/test/test_samply_profiler.py b/Lib/test/test_samply_profiler.py index ec0ed37ffd047b..f9ab9207c3c23d 100644 --- a/Lib/test/test_samply_profiler.py +++ b/Lib/test/test_samply_profiler.py @@ -240,5 +240,29 @@ def compile_trampolines_for_all_functions(): self.assertIn(line, child_perf_file_contents) +@unittest.skipUnless(samply_command_works(), "samply command doesn't work") +class TestSamplyProfilerWithJitDump(unittest.TestCase, TestSamplyProfilerMixin): + # Regression test for gh-150723: exercises the binary jitdump backend + # (-Xperf_jit) end to end through samply, unlike TestSamplyProfiler which + # uses the textual perf-map backend (-Xperf). + def run_samply(self, script_dir, script, activate_trampoline=True): + if activate_trampoline: + return run_samply(script_dir, sys.executable, "-Xperf_jit", script) + return run_samply(script_dir, sys.executable, script) + + def setUp(self): + super().setUp() + self.jit_files = set(pathlib.Path("/tmp/").glob("jit-*.dump")) + self.jit_files |= set(pathlib.Path("/tmp/").glob("jitted-*.so")) + + def tearDown(self) -> None: + super().tearDown() + files_to_delete = set(pathlib.Path("/tmp/").glob("jit-*.dump")) + files_to_delete |= set(pathlib.Path("/tmp/").glob("jitted-*.so")) + files_to_delete -= self.jit_files + for file in files_to_delete: + file.unlink() + + if __name__ == "__main__": unittest.main() diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-01-19-21-01.gh-issue-150723.Hb3JDG.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-01-19-21-01.gh-issue-150723.Hb3JDG.rst new file mode 100644 index 00000000000000..1920c8cdfce4f4 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-01-19-21-01.gh-issue-150723.Hb3JDG.rst @@ -0,0 +1,4 @@ +Fix malformed perf jitdump thread ids on macOS. The ``thread_id`` field of the +``JR_CODE_LOAD`` record was written as a 64-bit value instead of the 32-bit +value required by the jitdump format, which shifted every following field and +prevented profilers from resolving Python frames. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-01-19-24-12.gh-issue-150723.WlcL_-.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-01-19-24-12.gh-issue-150723.WlcL_-.rst new file mode 100644 index 00000000000000..78c896b669c239 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-01-19-24-12.gh-issue-150723.WlcL_-.rst @@ -0,0 +1,4 @@ +Fix perf jitdump timestamps on macOS. Events were stamped using +``CLOCK_MONOTONIC``, but macOS profilers timestamp their samples with +``mach_absolute_time()``. The mismatch prevented the JIT code mappings from +lining up with the samples, so no Python frame could be resolved. diff --git a/Python/perf_jit_trampoline.c b/Python/perf_jit_trampoline.c index 0c460282feceef..32b147199544cf 100644 --- a/Python/perf_jit_trampoline.c +++ b/Python/perf_jit_trampoline.c @@ -82,6 +82,9 @@ #if defined(__linux__) # include <sys/syscall.h> // System call interface #endif +#if defined(__APPLE__) +# include <mach/mach_time.h> // mach_absolute_time, mach_timebase_info +#endif // ============================================================================= // CONSTANTS AND CONFIGURATION @@ -217,11 +220,7 @@ struct BaseEvent { typedef struct { struct BaseEvent base; // Common event header uint32_t process_id; // Process ID where code was generated -#if defined(__APPLE__) - uint64_t thread_id; // Thread ID where code was generated -#else uint32_t thread_id; // Thread ID where code was generated -#endif uint64_t vma; // Virtual memory address where code is loaded uint64_t code_address; // Address of the actual machine code uint64_t code_size; // Size of the machine code in bytes @@ -295,7 +294,9 @@ static PerfMapJitState perf_jit_map_state; // ============================================================================= /* Time conversion constant */ +#if !defined(__APPLE__) static const intptr_t nanoseconds_per_second = 1000000000; +#endif /* * Get current monotonic time in nanoseconds @@ -307,6 +308,18 @@ static const intptr_t nanoseconds_per_second = 1000000000; * Returns: Current monotonic time in nanoseconds since an arbitrary epoch */ static int64_t get_current_monotonic_ticks(void) { +#if defined(__APPLE__) + // On macOS the jitdump file is consumed by profilers (such as samply) that + // timestamp their samples using mach_absolute_time(). The jitdump event + // timestamps must use the same clock domain, otherwise the JIT code + // mappings cannot be lined up with the samples. + static mach_timebase_info_data_t timebase = {0, 0}; + if (timebase.denom == 0) { + (void)mach_timebase_info(&timebase); + } + uint64_t ticks = mach_absolute_time(); + return (int64_t)(ticks * timebase.numer / timebase.denom); +#else struct timespec ts; if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) { Py_UNREACHABLE(); // Should never fail on supported systems @@ -318,6 +331,7 @@ static int64_t get_current_monotonic_ticks(void) { result *= nanoseconds_per_second; result += ts.tv_nsec; return result; +#endif } /* @@ -652,7 +666,12 @@ static void perf_map_jit_write_entry_with_name( ev.base.time_stamp = get_current_monotonic_ticks(); ev.process_id = getpid(); #if defined(__APPLE__) - pthread_threadid_np(NULL, &ev.thread_id); + // The jitdump format defines the thread id field as a 32-bit value, but + // pthread_threadid_np() returns a 64-bit id. Truncate it to 32 bits to + // keep the record layout identical to other platforms. + uint64_t thread_id = 0; + pthread_threadid_np(NULL, &thread_id); + ev.thread_id = (uint32_t)thread_id; #else ev.thread_id = syscall(SYS_gettid); // Get thread ID via system call #endif From accc0c8315dc53a639748b2dcd6094c3300eeb08 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 3 Jun 2026 10:36:50 +0200 Subject: [PATCH 214/818] [3.15] gh-148587: Document `sys.lazy_modules` (GH-150742) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (cherry picked from commit e3fa52d953492772d36f5a4397262483bcf67641) Co-authored-by: Bartosz Sławecki <bartosz@ilikepython.com> --- Doc/library/sys.rst | 15 +++++++++++++++ Misc/NEWS.d/3.15.0a8.rst | 2 +- Misc/NEWS.d/3.15.0b2.rst | 2 +- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst index 6946eb6eeaa5fa..4683fc03f843a2 100644 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -1483,6 +1483,21 @@ always available. Unless explicitly noted otherwise, all variables are read-only They hold the legacy representation of ``sys.last_exc``, as returned from :func:`exc_info` above. + +.. data:: lazy_modules + + A :class:`set` of fully qualified module name strings that have been lazily + imported in the current interpreter but not yet loaded. When a + lazily imported module is accessed for the first time, its name is removed + from this set. + + This attribute is intended for debugging and introspection. + + See also :func:`set_lazy_imports` and :pep:`810`. + + .. versionadded:: 3.15 + + .. data:: maxsize An integer giving the maximum value a variable of type :c:type:`Py_ssize_t` can diff --git a/Misc/NEWS.d/3.15.0a8.rst b/Misc/NEWS.d/3.15.0a8.rst index ff7930aeb292d6..3c6da8b6ab48e3 100644 --- a/Misc/NEWS.d/3.15.0a8.rst +++ b/Misc/NEWS.d/3.15.0a8.rst @@ -350,7 +350,7 @@ Fix :func:`repr` for lists and tuples containing ``NULL``\ s. .. nonce: aB3xKm .. section: Core and Builtins -Fixed ``sys.lazy_modules`` to include lazy modules without submodules. Patch +Fixed :py:attr:`sys.lazy_modules` to include lazy modules without submodules. Patch by Bartosz Sławecki. .. diff --git a/Misc/NEWS.d/3.15.0b2.rst b/Misc/NEWS.d/3.15.0b2.rst index 24fef1907d5122..afbdd4e072ed7d 100644 --- a/Misc/NEWS.d/3.15.0b2.rst +++ b/Misc/NEWS.d/3.15.0b2.rst @@ -132,7 +132,7 @@ function call. .. nonce: -RD3z5 .. section: Core and Builtins -``sys.lazy_modules`` is now a set instead of a dict as initially spelled out +:py:attr:`sys.lazy_modules` is now a set instead of a dict as initially spelled out in PEP 810. .. From f8cea98b4e449f9a2ed00d8eef4d2b05ed7448d8 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 3 Jun 2026 10:39:22 +0200 Subject: [PATCH 215/818] [3.15] gh-149805: Fix `SystemError` when compiling `__classdict__` class annotation (GH-149806) (cherry picked from commit c52d2b16ddda3995f0f935b1a3815f1aac498da6) Co-authored-by: Stan Ulbrych <stan@python.org> --- Lib/test/test_type_annotations.py | 7 +++++++ .../2026-05-13-21-26-26.gh-issue-149805.IG6cza.rst | 2 ++ Python/symtable.c | 1 + 3 files changed, 10 insertions(+) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-05-13-21-26-26.gh-issue-149805.IG6cza.rst diff --git a/Lib/test/test_type_annotations.py b/Lib/test/test_type_annotations.py index d459f497e333e6..b751f825bb97d5 100644 --- a/Lib/test/test_type_annotations.py +++ b/Lib/test/test_type_annotations.py @@ -485,6 +485,13 @@ def test_comprehension_in_annotation(self): ns = run_code("x: [y for y in range(10)]") self.assertEqual(ns["__annotate__"](1), {"x": list(range(10))}) + def test_class_annotation_dunder_classdict(self): + ns = run_code(""" + class C: + __classdict__: int + """) + self.assertEqual(ns["C"].__annotations__, {"__classdict__": int}) + def test_future_annotations(self): code = """ from __future__ import annotations diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-13-21-26-26.gh-issue-149805.IG6cza.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-13-21-26-26.gh-issue-149805.IG6cza.rst new file mode 100644 index 00000000000000..02d050840ee1f9 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-13-21-26-26.gh-issue-149805.IG6cza.rst @@ -0,0 +1,2 @@ +Fix a :exc:`SystemError` when compiling a compiling ``__classdict__`` class +annotation. Found by OSS-Fuzz in :oss-fuzz:`512907042`. diff --git a/Python/symtable.c b/Python/symtable.c index 2263a2d8db9097..9a2e278caaf9e2 100644 --- a/Python/symtable.c +++ b/Python/symtable.c @@ -2870,6 +2870,7 @@ symtable_visit_annotation(struct symtable *st, expr_ty annotation, void *key) int future_annotations = st->st_future->ff_features & CO_FUTURE_ANNOTATIONS; if (current_type == ClassBlock && !future_annotations) { st->st_cur->ste_can_see_class_scope = 1; + parent_ste->ste_needs_classdict = 1; if (!symtable_add_def(st, &_Py_ID(__classdict__), USE, LOCATION(annotation))) { return 0; } From c69521fdecd03ea76cbbdfa4b26ae672a4276c18 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 3 Jun 2026 14:27:56 +0200 Subject: [PATCH 216/818] [3.15] Fix a typo in `SSLSocket` docs (GH-150839) (GH-150848) Fix a typo in `SSLSocket` docs (GH-150839) (cherry picked from commit 5553e003ca56ecc67340962b2d0f7ca561d64197) Co-authored-by: Robsdedude <dev@rouvenbauer.de> --- Doc/library/ssl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/ssl.rst b/Doc/library/ssl.rst index c0f3757e583e95..41a101e84ac4d7 100644 --- a/Doc/library/ssl.rst +++ b/Doc/library/ssl.rst @@ -1121,7 +1121,7 @@ SSL sockets :meth:`SSLContext.wrap_socket` to wrap a socket. .. versionchanged:: 3.7 - :class:`SSLSocket` instances must to created with + :class:`SSLSocket` instances must be created with :meth:`~SSLContext.wrap_socket`. In earlier versions, it was possible to create instances directly. This was never documented or officially supported. From 0f08c550bcf26ca62ddf9bc221a461746638ceb3 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 3 Jun 2026 14:44:34 +0200 Subject: [PATCH 217/818] [3.15] gh-141004: Document unstable perf map functions in `ceval.h` (GH-143492) (GH-150849) gh-141004: Document unstable perf map functions in `ceval.h` (GH-143492) (cherry picked from commit 6453065db9ff31e3f737240030f8311d2b087851) Co-authored-by: Yashraj <yashrajpala8@gmail.com> --- Doc/c-api/perfmaps.rst | 40 ++++++++++++++++++++++++ Tools/check-c-api-docs/ignored_c_api.txt | 4 --- 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/Doc/c-api/perfmaps.rst b/Doc/c-api/perfmaps.rst index bd05e628faaaa1..a962c4ee09ad77 100644 --- a/Doc/c-api/perfmaps.rst +++ b/Doc/c-api/perfmaps.rst @@ -49,3 +49,43 @@ Note that holding an :term:`attached thread state` is not required for these API This is called by the runtime itself during interpreter shut-down. In general, there shouldn't be a reason to explicitly call this, except to handle specific scenarios such as forking. + +.. c:function:: int PyUnstable_CopyPerfMapFile(const char *parent_filename) + + Open the ``/tmp/perf-$pid.map`` file and append the content of *parent_filename* + to it. + + This function is available on all platforms but only generates output on platforms + that support perf maps (currently only Linux). On other platforms, it does nothing. + + .. versionadded:: 3.13 + +.. c:function:: int PyUnstable_PerfTrampoline_CompileCode(PyCodeObject *code) + + Compile the given code object using the current perf trampoline. + + The "current" trampoline is the one set by the runtime or the most recent + :c:func:`PyUnstable_PerfTrampoline_SetPersistAfterFork` call. + + If no trampoline is set, falls back to normal compilation (no perf map entry). + + :param code: The code object to compile. + :return: 0 on success, -1 on failure. + + .. versionadded:: 3.13 + +.. c:function:: int PyUnstable_PerfTrampoline_SetPersistAfterFork(int enable) + + Set whether the perf trampoline should persist after a fork. + + * If ``enable`` is true (non-zero): perf map file remains open/valid post-fork. + Child process inherits all existing perf map entries. + * If ``enable`` is false (zero): perf map closes post-fork. + Child process gets empty perf map. + + Default: false (clears on fork). + + :param enable: 1 to enable, 0 to disable. + :return: 0 on success, -1 on failure. + + .. versionadded:: 3.13 diff --git a/Tools/check-c-api-docs/ignored_c_api.txt b/Tools/check-c-api-docs/ignored_c_api.txt index dfec0524cfe016..fa53b205c4ff6a 100644 --- a/Tools/check-c-api-docs/ignored_c_api.txt +++ b/Tools/check-c-api-docs/ignored_c_api.txt @@ -43,10 +43,6 @@ PyDescr_TYPE PyWrapperFlag_KEYWORDS # cpython/fileobject.h Py_UniversalNewlineFgets -# cpython/ceval.h -PyUnstable_CopyPerfMapFile -PyUnstable_PerfTrampoline_CompileCode -PyUnstable_PerfTrampoline_SetPersistAfterFork # cpython/pyframe.h PyUnstable_EXECUTABLE_KINDS PyUnstable_EXECUTABLE_KIND_BUILTIN_FUNCTION From 21a4ac77be597c7f8b799672e1c65276eda1c3db Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 3 Jun 2026 15:12:46 +0200 Subject: [PATCH 218/818] [3.15] gh-91099: fix[imaplib]: call Exception with string instance (GH-31823) (#150811) * bpo-46943: fix[imaplib]: call Exception with string instance Adjust the behavior of 'login' to be similar to `authenticate()`, where self.error is called with a str() instance. (cherry picked from commit 29805f00a1b65163230d17584c30e2b955086abb) Co-authored-by: Florian Best <spaceone@users.noreply.github.com> Co-authored-by: Oleg Iarygin <oleg@arhadthedev.net> --- Lib/imaplib.py | 2 +- Lib/test/test_imaplib.py | 10 ++++++++++ .../2023-02-26-14-07-18.gh-issue-91099._QPbEL.rst | 2 ++ 3 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2023-02-26-14-07-18.gh-issue-91099._QPbEL.rst diff --git a/Lib/imaplib.py b/Lib/imaplib.py index 2fafd9322c609e..497b5a60cecb08 100644 --- a/Lib/imaplib.py +++ b/Lib/imaplib.py @@ -712,7 +712,7 @@ def login(self, user, password): """ typ, dat = self._simple_command('LOGIN', user, self._quote(password)) if typ != 'OK': - raise self.error(dat[-1]) + raise self.error(dat[-1].decode('UTF-8', 'replace')) self.state = 'AUTH' return typ, dat diff --git a/Lib/test/test_imaplib.py b/Lib/test/test_imaplib.py index 0b704d62655762..fb256fb7cbcd34 100644 --- a/Lib/test/test_imaplib.py +++ b/Lib/test/test_imaplib.py @@ -434,6 +434,16 @@ def cmd_AUTHENTICATE(self, tag, args): r'\[AUTHENTICATIONFAILED\] invalid'): client.authenticate('MYAUTH', lambda x: b'fake') + def test_invalid_login(self): + class MyServer(SimpleIMAPHandler): + def cmd_LOGIN(self, tag, args): + self.server.logged = args[0] + self._send_tagged(tag, 'NO', '[LOGIN] failed') + client, _ = self._setup(MyServer) + with self.assertRaisesRegex(imaplib.IMAP4.error, + r'\[LOGIN\] failed'): + client.login('user', 'wrongpass') + def test_valid_authentication_bytes(self): class MyServer(SimpleIMAPHandler): def cmd_AUTHENTICATE(self, tag, args): diff --git a/Misc/NEWS.d/next/Library/2023-02-26-14-07-18.gh-issue-91099._QPbEL.rst b/Misc/NEWS.d/next/Library/2023-02-26-14-07-18.gh-issue-91099._QPbEL.rst new file mode 100644 index 00000000000000..d886e8ac6032a4 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-02-26-14-07-18.gh-issue-91099._QPbEL.rst @@ -0,0 +1,2 @@ +:meth:`imaplib.IMAP4.login` now raises exceptions with :class:`str` instead of +:class:`bytes`. Patch by Florian Best. From 381bda939592b3bc8341b544de163e0a19888c29 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> Date: Wed, 3 Jun 2026 16:49:58 +0300 Subject: [PATCH 219/818] [3.15] Docs: Replace hardcoded `SOURCE_URI` with `patchlevel` check (GH-150850) (#150855) --- Doc/conf.py | 12 +++++++----- Doc/tools/extensions/pyspecific.py | 11 +---------- 2 files changed, 8 insertions(+), 15 deletions(-) diff --git a/Doc/conf.py b/Doc/conf.py index e2dff74538a342..a766bac7063255 100644 --- a/Doc/conf.py +++ b/Doc/conf.py @@ -8,15 +8,13 @@ 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')) sys.path.append(os.path.abspath('includes')) -# Python specific content from Doc/Tools/extensions/pyspecific.py -from pyspecific import SOURCE_URI +from patchlevel import get_header_version_info, get_version_info # General configuration # --------------------- @@ -78,7 +76,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 = import_module('patchlevel').get_version_info() +version, release = get_version_info() rst_epilog = f""" .. |python_version_literal| replace:: ``Python {version}`` @@ -557,16 +555,20 @@ r'https://unix.org/version2/whatsnew/lp64_wp.html', ] + # Options for sphinx.ext.extlinks # ------------------------------- +v = get_header_version_info() +branch = "main" if v.releaselevel == "alpha" else f"{v.major}.{v.minor}" + # This config is a dictionary of external sites, # mapping unique short aliases to a base URL and a prefix. # https://www.sphinx-doc.org/en/master/usage/extensions/extlinks.html extlinks = { "oss-fuzz": ("https://issues.oss-fuzz.com/issues/%s", "#%s"), "pypi": ("https://pypi.org/project/%s/", "%s"), - "source": (SOURCE_URI, "%s"), + "source": (f"https://github.com/python/cpython/tree/{branch}/%s", "%s"), } extlinks_detect_hardcoded_links = True diff --git a/Doc/tools/extensions/pyspecific.py b/Doc/tools/extensions/pyspecific.py index 85e7f5454252d2..9b335f2976a2fa 100644 --- a/Doc/tools/extensions/pyspecific.py +++ b/Doc/tools/extensions/pyspecific.py @@ -10,19 +10,10 @@ """ import re -import io -from os import getenv, path -from docutils import nodes -from docutils.parsers.rst import directives -from docutils.utils import unescape from sphinx import addnodes -from sphinx.domains.python import PyFunction, PyMethod, PyModule -from sphinx.locale import _ as sphinx_gettext -from sphinx.util.docutils import SphinxDirective +from sphinx.domains.python import PyFunction, PyMethod -# Used in conf.py and updated here by python/release-tools/run_release.py -SOURCE_URI = 'https://github.com/python/cpython/tree/3.15/%s' class PyAwaitableMixin(object): def handle_signature(self, sig, signode): From 24f5d3d59847fa68cc04d8d60bf9bf1374a5311d Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 3 Jun 2026 16:55:35 +0200 Subject: [PATCH 220/818] [3.15] gh-146636: Add Free-threaded Stable ABI migration guide (GH-150580) (#150844) Co-authored-by: Petr Viktorin <encukou@gmail.com> Co-authored-by: Charlie Lin <tuug@gmx.us> Co-authored-by: da-woods <dw-git@d-woods.co.uk> Co-authored-by: Stan Ulbrych <stan@python.org> Co-authored-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> --- Doc/bugs.rst | 3 + Doc/howto/abi3t-migration.rst | 614 ++++++++++++++++++++++++++ Doc/howto/index.rst | 2 + Doc/tools/extensions/c_annotations.py | 2 +- Doc/whatsnew/3.15.rst | 7 +- 5 files changed, 623 insertions(+), 5 deletions(-) create mode 100644 Doc/howto/abi3t-migration.rst diff --git a/Doc/bugs.rst b/Doc/bugs.rst index 254a22f2622bd8..a6ea0a72e76f9d 100644 --- a/Doc/bugs.rst +++ b/Doc/bugs.rst @@ -12,6 +12,9 @@ It can be sometimes faster to fix bugs yourself and contribute patches to Python as it streamlines the process and involves fewer people. Learn how to :ref:`contribute <contributing-to-python>`. + +.. _reporting-documentation-bugs: + Documentation bugs ================== diff --git a/Doc/howto/abi3t-migration.rst b/Doc/howto/abi3t-migration.rst new file mode 100644 index 00000000000000..ed7a324c4af6f0 --- /dev/null +++ b/Doc/howto/abi3t-migration.rst @@ -0,0 +1,614 @@ +.. highlight:: c + +.. _abi3t-migration-howto: + +****************************************************** +Migrating to Stable ABI for free threading (``abi3t``) +****************************************************** + +Starting with the 3.15 release, CPython supports a variant of the Stable ABI +that supports :term:`free-threaded <free threading>` Python: +Stable ABI for Free-Threaded Builds, or ``abi3t`` for short. +This document describes how to adapt C API extensions to support free threading. + +Why do this +=========== + +The typical reason to use Stable ABI is to reduce the number of artifacts that +you need to build and distribute for each version of your library. + +Without the Stable ABI, you must build a separate shared library, and typically +a *wheel* distribution, for each feature version of CPython you wish +to support. +For example, each tag in the following table represents a separate +library/wheel: + ++-----------------+-----------------------+------------------------+ +| CPython version | Non-free-threaded | Free-threaded | ++=================+=======================+========================+ +| 3.12 | ``cpython-312`` | --- | ++-----------------+-----------------------+------------------------+ +| 3.13 | ``cpython-313`` | ``cpython-313t`` | ++-----------------+-----------------------+------------------------+ +| 3.14 | ``cpython-314`` | ``cpython-314t`` | ++-----------------+-----------------------+------------------------+ +| 3.15 | ``cpython-315`` | ``cpython-315t`` | ++-----------------+-----------------------+------------------------+ +| 3.16 | ``cpython-316`` | ``cpython-316t`` | ++-----------------+-----------------------+------------------------+ +| Later versions | :samp:`cpython-3{XX}` | :samp:`cpython-3{XX}t` | ++-----------------+-----------------------+------------------------+ + +That's a lot of builds, especially when multiplied by the number +of supported platforms. + +With the Stable ABI (``abi3``, introduced in CPython 3.2), a single extension +(per platform) can cover all *non-free-threaded* builds of CPython: + ++-----------------+-------------------+------------------------+ +| CPython version | Non-free-threaded | Free-threaded | ++=================+===================+========================+ +| 3.12 | ``abi3`` | --- | ++-----------------+ +------------------------+ +| 3.13 | | ``cpython-313t`` | ++-----------------+ +------------------------+ +| 3.14 | | ``cpython-314t`` | ++-----------------+ +------------------------+ +| 3.15 | | ``cpython-315t`` | ++-----------------+ +------------------------+ +| 3.16 | | ``cpython-316t`` | ++-----------------+ +------------------------+ +| Later versions | | :samp:`cpython-3{XX}t` | ++-----------------+-------------------+------------------------+ + +The Stable ABI for free-threaded builds (``abi3t``), introduced in +CPython 3.15, does the same for free-threaded builds. +And it's compatible with non-free-threaded ones as well: + ++-----------------+-------------------+------------------+ +| CPython version | Non-free-threaded | Free-threaded | ++=================+===================+==================+ +| 3.12 | ``abi3`` * | --- | ++-----------------+ +------------------+ +| 3.13 | | ``cpython-313t`` | ++-----------------+ +------------------+ +| 3.14 | | ``cpython-314t`` | ++-----------------+-------------------+------------------+ +| 3.15 | ``abi3t`` | ++-----------------+ + +| 3.16 | | ++-----------------+ + +| Later versions | | ++-----------------+-------------------+------------------+ + +\* (As above, the ``abi3`` extension is compatible with all non-free-threaded +builds; even the 3.15+ ones that this table "attributes" to ``abi3t``.) + +Why *not* do this +----------------- + +There are two main downsides to Stable ABI. + +First, you extension may become slower, since Stable ABI prioritizes +compatibility over performance. +The difference is usually not noticeable, and often can be mitigated by +using the same source to build both a Stable ABI build and a few +version-specific ones for "tier 1" CPython versions. + +Second, not all of the C API is available. +Extensions need to be ported to build for Stable ABI, which may be difficult +or, in rare cases, impossible. + +Specifically, ``abi3t`` requires APIs added in CPython 3.15. +If you want to build your extension for older versions of CPython from the +same source, you have two main options: + +- Use preprocessor conditionals. + + When following this guide, use ``#ifdef Py_TARGET_ABI3T`` blocks whenever + you are told to do a change that breaks the build on CPython versions you + care about. Keep the pre-existing code in ``#else`` blocks. + + For hand-written C extensions, this approach is reasonable down to + CPython 3.12, due to additions introduced in :pep:`697`. + Keeping compatibility with 3.11 and below may be worth it for code + generators (for example, Cython). + +- Do not port to ``abi3t``, and continue building separate extensions for + each version of CPython, until you can drop support for the older versions. + + This is a valid approach. Not all extensions need to switch to ``abi3t`` + right now. + + +Prerequisites +============= + +This guide assumes that you have an extension written directly in C (or C++), +which you want to port to ``abi3t``. + +If your extenstion uses a code generator (like Cython) or language binding +(like PyO3), it's best to wait until that tool has support for ``abi3t``. +If you maintain such a tool, you might be able to adapt the instructions +here for your tool. + +Non-free-threaded Stable ABI +---------------------------- + +Your extension should support the Stable ABI (``abi3t``). +If not, either port it first, or follow this guide but be prepared to fix +issues it does not mention. + +Free-threading support +---------------------- + +While it's technically not a hard prerequisite, you will most likely want to +prepare your extension for free threading before you port it to ``abi3t``. +See :ref:`freethreading-extensions-howto` for instructions. + +.. seealso:: + + `Porting Extension Modules to Support Free-Threading + <https://py-free-threading.github.io/porting/>`__: + A community-maintained porting guide for extension authors. + +Isolating extension modules +--------------------------- + +Your module should use :ref:`multi-phase initialization <multi-phase-initialization>`, +and it should either be isolated or limit itself to be loaded at most once +per process. +If it is not your case, follow :ref:`isolating-extensions-howto` first. +(See the :ref:`opt-out section <isolating-extensions-optout>` for a shortcut.) + +Avoiding variable-sized types +----------------------------- + +If your extension defines variable-sized types (using :c:macro:`Py_tp_itemsize` +or :c:member:`PyTypeObject.tp_itemsize`), it cannot be ported to +``abi3t`` 3.15. + + +Setting up the build +==================== + +If you use a build tool (such as setuptools, meson-python, scikit-build-core), +search its documentation for a way to select ``abi3t``. +At the time of writing, not all of them have this; but if your tool does, +use it. +You may want to verify that it set the right flag by temporarily adding the +following just after ``#include <Python.h>``:: + + #if Py_TARGET_ABI3T+0 <= 0x30f0000 + #error "abi3t define is not set!" + #endif + +This should result in a different error than "``abt3t`` define is not set". + +.. note:: + + If your build tool doesn't support ``abi3t`` yet, set the following macro + before including ``Python.h``:: + + #define Py_TARGET_ABI3T 0x30f0000 + + or specify it as a compiler flag, for example:: + + -DPy_TARGET_ABI3T=0x30f0000 + + Once your extension builds with this setting, it will be compatible with + CPython 3.15 and above. + + If you set this macro manually, you will later need to name and tag the + resulting extension manually as well. + This is covered in :ref:`abi3t-migration-tagging` below. + +This guide will ask you to make a series of changes. +After each one, verify that your extension still builds in the original +(non-``abi3t``) configuration, and ideally run tests on all Python +versions you support. +This will ensure that nothing breaks as you are porting. + + +Module export hook +================== + +Unless you've done this step already, your extension module defines a +:ref:`module initialization function <extension-pyinit>` +named :samp:`PyInit_{<module_name>}`. +You will need to port it to a :ref:`module export hook <extension-export-hook>`, +:samp:`PyModExport_{<module name>}`, a feature added in CPython 3.15 in +:pep:`793`. + +Your existing init function should look like this (with your own names +for ``<modname>`` and ``<moddef>``): + +.. code-block:: + :class: bad + + PyMODINIT_FUNC + PyInit_<modname>(void) + { + return PyModuleDef_Init(&<moddef>); + } + +If there is some code before the ``return``, move it to +a :c:macro:`Py_mod_create` or :c:macro:`Py_mod_exec` slot function. +See the :ref:`PyInit documentation <extension-pyinit>` for related information. + +The function references a ``PyModuleDef`` object (``<moddef>`` in the code +above). +Its definition should be similar to the following, with different values +and perhaps some fields unnnamed or left out: + +.. code-block:: + :class: bad + + static PyModuleDef <moddef> = { + PyModuleDef_HEAD_INIT, + .m_name = "my_module", + .m_doc = "my docstring", + .m_size = sizeof(my_state_struct), + .m_methods = my_methods, + .m_slots = my_slots, + .m_traverse = my_traverse, + .m_clear = my_clear, + .m_free = my_free, + }; + +Remove this definition and the ``PyInit`` function (or put them in +an ``#ifndef Py_TARGET_ABI3T`` block, to retain backwards compatibility), +and replace them with the following: + +.. code-block:: + :class: good + + PyABIInfo_VAR(abi_info); + + static PySlot my_slot_array[] = { + PySlot_STATIC_DATA(Py_mod_abi, &abi_info), + PySlot_STATIC_DATA(Py_mod_name, "my_module"), + PySlot_STATIC_DATA(Py_mod_doc, "my docstring"), + PySlot_SIZE(Py_mod_state_size, sizeof(my_state_struct)), + PySlot_STATIC_DATA(Py_mod_methods, my_methods), + PySlot_STATIC_DATA(Py_mod_slots, my_slots), + PySlot_FUNC(Py_mod_state_traverse, my_traverse), + PySlot_FUNC(Py_mod_state_clear, my_clear), + PySlot_FUNC(Py_mod_state_free, my_free), + PySlot_END + }; + + PyMODEXPORT_FUNC + PyModExport_<modname>(void) + { + return my_slot_array; + } + +Leave out any fields that were missing (except the new :c:macro:`Py_mod_abi`), +and substitute your own values. + +See the :c:type:`PySlot` and :c:ref:`export hook <extension-export-hook>` +documentation for details on this API. + +Associated ``PyModuleDef`` +-------------------------- + +Since the new API does not use a :c:type:`!PyModuleDef` structure, a definition +will not be associated with the resulting module. +This changes the behavior of the following functions: + +- :c:func:`PyModule_GetDef` +- :c:func:`PyType_GetModuleByDef` + +Check your code for these. +If you do not use them, you can skip this section. + +These functions are typically used for two purposes: + +1. To get the definition the module was created with. + This is no longer possible using the new API. + Modules no longer keep a reference to the definition, so you will need to + figure out a different way to pass the relevant data around. + +.. _abi3t-migration-module-token: + +2. To check if a given module object is “yours”. + This use case is now served by :ref:`module tokens <ext-module-token>` -- + opaque pointers that identify a module. + To use a token, declare (or reuse) a unique static variable, for example: + + .. code-block:: + :class: good + + static char my_token; + + and add a pointer to it in a new entry to your module's ``PySlot`` array: + + .. code-block:: + :class: good + :emphasize-lines: 3 + + static PySlot my_slot_array[] = { + ... + PySlot_STATIC_DATA(Py_mod_token, &my_token), + PySlot_END + } + + Then, switch from :c:func:`PyModule_GetDef` calls such as: + + .. code-block:: + :class: bad + + PyModuleDef *def = PyModule_GetDef(module); + + to :c:func:`PyModule_GetToken` (which uses an output argument and may fail + with an exception): + + .. code-block:: + :class: good + + void *token; + if (PyModule_GetToken(module, &token) < 0) { + /* handle error */ + } + + and from :c:func:`PyType_GetModuleByDef` calls such as: + + .. code-block:: + :class: bad + + PyObject *module = PyType_GetModuleByDef(type, my_def); + /* handle error; use module */ + + to :c:func:`PyType_GetModuleByToken` (which returns a strong reference): + + .. code-block:: + :class: good + + PyObject *module = PyType_GetModuleByToken(type, my_token); + /* handle error; use module */ + Py_XDECREF(module); + +``PyObject`` opaqueness +======================= + +The :c:type:`PyObject` and :c:type:`PyVarObject` structures are opaque +in ``abi3t``. + +Accessing their members is prohibited. +If you do this, switch to getter/setter functions mentioned in +their documentation: + +- :c:member:`PyObject.ob_type` +- :c:member:`PyObject.ob_refcnt` +- :c:member:`PyVarObject.ob_size` + +Also, the *size* of the :c:type:`PyObject` structures is +unknown to the compiler. +It can -- and *does* -- change between different CPython builds. + +.. note:: + + While the size is available at runtime (for example as + ``sys.getsizeof(object())`` in Python code), you should resist the + temptation to calculate pointer offsets from it. + The object memory layout is subject to change in future + ``abi3t`` implementations. + + +Custom type definitions +----------------------- + +Since :c:type:`!PyObject` is opaque, the traditional way of defining +custom types no longer works: + +.. code-block:: + :class: bad + + typedef struct { + PyObject_HEAD // expands to `PyObject ob_base;` which has unknown size + + int my_data; + } CustomObject; + + static PyType_Spec CustomType_spec = { + ... + .basicsize = sizeof(CustomObject), + ... + }; + +Most likely, all your class definitions, *and* all code that accesses +your classes' data, will need to be rewritten. +This will probably be the biggest change you need to support ``abi3t``. + +For each such type, instead of defining a ``struct`` for the entire instance, +define one with only the “additional” fields -- ones specific to your class, +not its superclasses: + +.. code-block:: + :class: good + + typedef struct { + int my_data; + } CustomObjectData; + +Change the name. +Almost all code that uses the struct will need to change +(notably, pointers to the new structure cannot be cast to/from ``PyObject*``), +and changing the name will highlight the usages as compiler errors. +(If you use ``typeof``, C++ ``auto``, or similar ways to avoid +typing the type name, this won't work. Be extra careful, and consider running +tools to detect undefined behavior.) + +Then, to create the class, use *negative* ``basicsize`` to indicate +“extra” storage space rather than *total* instance size: + +.. code-block:: + :class: good + + static PyType_Spec CustomType_spec = { + ... + .basicsize = -sizeof(CustomObjectData), /* note the minus sign */ + ... + }; + +If you use :c:macro:`Py_tp_members`, set the :c:macro:`Py_RELATIVE_OFFSET` +flag on each member and specify the :c:member:`~PyMemberDef.offset` +relative to your new struct. + + +Custom type data access +----------------------- + +Then comes the hard part: in all code that needs to access this struct, +you will need an additional :c:func:`PyObject_GetTypeData` call to +retrieve a ``CustomObjectData *`` pointer from ``PyObject *``: + +.. code-block:: + :class: good + + PyObject *obj = ...; + CustomObjectData *data = PyObject_GetTypeData(obj, cls); + +Note that this call requires the *type object* for your class (``cls``). + +If your class is not subclassable (that is, it does not use the +:c:macro:`Py_TPFLAGS_BASETYPE` flag), ``cls`` will be ``Py_TYPE(obj)``. +Otherwise, **DO NOT USE** ``Py_TYPE`` with :c:func:`!PyObject_GetTypeData`: +it might return memory reserved to an unrelated subclass! +For example, if a user makes a subclass like this: + +.. code-block:: python + + class Sub(YourCustomClass): + __slots__ = ('a', 'b') + +then ``Py_TYPE(obj)`` is ``YourCustomClass``, and the underlying memory may +look like this: + +.. code-block:: text + + ╭─ PyObject *obj + │ ╭─ the pointer you want + │ │ ╭─ PyObject_GetTypeData(obj, Py_TYPE(obj)) + ▼ ▼ ▼ + ┌──────────┬───┬────────────────┬───┬─────────────┬───┬─────────────┐ + │ PyObject │...│ CustomTypeData │...│ PyObject *a │...│ PyObject *b │ + └──────────┴───┴────────────────┴───┴─────────────┴───┴─────────────┘ + +(Ellipses indicate possible padding. +Note that this memory layout is not guaranteed: future versions of Python may +add different padding or even switch the order of the structures.) + +There are two main ways to get the right class: + +- In instance methods, your implementation may use the :c:type:`PyCMethod` + signature (and the :c:macro:`METH_METHOD` bit in + :c:member:`PyMethodDef.ml_flags`), + and get the class as the ``defining_class`` argument. +- Otherwise, give your class a unique static token using the + :c:macro:`Py_tp_token` slot, and use: + + .. code-block:: + :class: good + + PyTypeObject cls; + if (PyType_GetBaseByToken(Py_TYPE(obj), my_tp_token, &cls) < 0) { + /* handle error */ + } + CustomObjectData *data = PyObject_GetTypeData(obj, cls); + + Type tokens work similarly to module tokens covered :ref:`earlier in this + guide <abi3t-migration-module-token>`. + + + +Avoid build-time conditionals +============================= + +Check your code for API that identifies the version of Python used to +*build* your extension. +This no longer corresponds to the Python your extension runs on, so code +that uses this information often needs changing. +The macros to check for are: + +- :c:macro:`PY_VERSION_HEX`, :c:macro:`PY_MAJOR_VERSION`, + :c:macro:`PY_MINOR_VERSION`: + + - to get the run-time version, use :c:data:`Py_Version`; + - to determine what C API is available, use :c:macro:`Py_TARGET_ABI3T`. + This macro is set to the minimum supported version. + +- :c:macro:`Py_GIL_DISABLED`: under ``abi3t``, this macro is always defined. + Code that works with free-threaded Python *should* also work with + the GIL enabled (since the GIL can be enabled at run time), + and usually *does* (unless it, for some reason, requires more than one + :term:`attached thread state <attached thread state>` at one time). + + +Further code changes +==================== + +If you are still left with compiler errors or warnings, find a way to fix them. +Alas, this guide is limited, and cannot cover all possible code +changes extensions may need. + +If you find a problem that other extension authors might run into, +consider :ref:`reporting an issue <reporting-documentation-bugs>` (or sending +a pull request) for this guide. + +It is possible your issue cannot be fixed for the current version of ``abi3t``. +In that case, reporting it may help it get prioritized for the next version +of CPython. + + +.. _abi3t-migration-tagging: + +Tagging and distribution +======================== + +If you are using a build tool with ``abi3t`` support, your extension is ready, +but you might want to check that it was built correctly. + +Extensions built with ``abi3t`` should have the following extension: + +- On Windows: ``.pyd`` (like any other extension); +- Linux, macOS, and other systems that use the ``.so`` suffix: ``.abi3t.so`` + (**not** ``.cpython-315t.so`` or ``.abi3.so``). + Note that both free-threaded and non-free-threaded builds will + load ``.abi3t.so`` extensions; +- Other systems: consult your distributor, and perhaps update this guide. + +If you distribute the extension as a *wheel*, use the following tags: + +* Python tag: :samp:`cp3{XX}`, where *XX* is the minimum Python version + the extension is built for. + (For example, ``cp315`` if you set ``Py_TARGET_ABI3T`` to ``0x30f0000``. + See :ref:`abi3-compiling` for more values.) +* ABI tag: ``abi3.abi3t``. This is a *compressed tag set* that indicates + support for both non-free-threaded and free-threaded builds. + +For example, the wheel filename may look like this: + +.. code-block:: text + + myproject-1.0-cp315-abi3.abi3t-macosx_11_0_arm64.whl + +.. seealso:: `Platform Compatibility Tags <https://packaging.python.org/en/latest/specifications/platform-compatibility-tags/>`__ in the PyPA package distribution metadata. + +If the filename or tags are incorrect, fix them. + + +Testing +======= + +Note that when you build an extension compatible with multiple versions of +CPython, you should always *test* it with each version it supports (for +example, 3.15, 3.16, and so on). +Stable ABI only guarantees *ABI* compatibility; there may also be behavior +changes -- both intentional ones (covered by :pep:`387`) and bugs. + +Be sure to run tests on both free-threaded and non-free-threaded builds +of CPython. + +If they pass, congratulations! You have an ``abi3t`` extension. diff --git a/Doc/howto/index.rst b/Doc/howto/index.rst index 81fc7e63f35bd7..57e2d6e0752447 100644 --- a/Doc/howto/index.rst +++ b/Doc/howto/index.rst @@ -37,6 +37,7 @@ Python Library Reference. mro.rst free-threading-python.rst free-threading-extensions.rst + abi3t-migration.rst remote_debugging.rst General: @@ -61,6 +62,7 @@ Advanced development: * :ref:`freethreading-python-howto` * :ref:`freethreading-extensions-howto` * :ref:`isolating-extensions-howto` +* :ref:`abi3t-migration-howto` * :ref:`python_2.3_mro` * :ref:`socket-howto` * :ref:`timerfd-howto` diff --git a/Doc/tools/extensions/c_annotations.py b/Doc/tools/extensions/c_annotations.py index 1409c77aed9c6b..0e762042979c2b 100644 --- a/Doc/tools/extensions/c_annotations.py +++ b/Doc/tools/extensions/c_annotations.py @@ -394,7 +394,7 @@ def run(self) -> list[nodes.Node]: current_minor = int(self.config.version.removeprefix('3.')) for minor in range(current_minor - 5, current_minor + 1): value = (3 << 24) | (minor << 16) - content.append(f' {value:#x} /* Py_PACK_VERSION(3.{minor}) */') + content.append(f' {value:#x} /* Py_PACK_VERSION(3,{minor}) */') node = nodes.paragraph() self.state.nested_parse(StringList(content), 0, node) return [node] diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst index 99c5a9478e2460..7d20805c4c5775 100644 --- a/Doc/whatsnew/3.15.rst +++ b/Doc/whatsnew/3.15.rst @@ -514,10 +514,6 @@ specifically: purpose in :pep:`793`, with a new :c:type:`PySlot` structure introduced in :pep:`820`. -The reference documentation for these features is complete, but currently -aimed at early adopters. -A migration guide is planned for an upcoming beta release. - Note that Stable ABI does not offer all the functionality that CPython has to offer. Extensions that cannot switch to ``abi3t`` should continue to build for @@ -533,6 +529,9 @@ If not using a build tool -- or when writing such a tool -- you can select ``abi3t`` by setting the macro :c:macro:`!Py_TARGET_ABI3T` as discussed in :ref:`abi3-compiling`. +A practical :ref:`migration guide <abi3t-migration-howto>` for switching to +``abi3t`` is available. + .. seealso:: :pep:`803` for further details. From 54bd7c0258c52e25f7e5afe6ab6afb7915e4944e Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 3 Jun 2026 17:26:36 +0200 Subject: [PATCH 221/818] [3.15] gh-132467: Document and test that generic aliases are not classes (GH-133504) (#150854) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gh-132467: Document and test that generic aliases are not classes (GH-133504) (cherry picked from commit 5915a1fb9d8499387e371c6801b40c55cf126dbf) Co-authored-by: Abduaziz π <mail@ziyodov.uz> Co-authored-by: Jelle Zijlstra <jelle.zijlstra@gmail.com> --- Doc/library/stdtypes.rst | 9 ++++ Lib/test/test_typing.py | 21 ++++++++ Lib/typing.py | 112 ++++++++++++++++++++------------------- 3 files changed, 88 insertions(+), 54 deletions(-) diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index c8f2cca484ab31..ba896212925d89 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -5927,6 +5927,15 @@ creation:: >>> type(l) <class 'list'> + +Instances of ``GenericAlias`` are not classes at runtime, even though they behave like classes (they can be instantiated and subclassed):: + + >>> import inspect + >>> inspect.isclass(list[int]) + False + +This is true for :ref:`user-defined generics <user-defined-generics>` also. + Calling :func:`repr` or :func:`str` on a generic shows the parameterized type:: >>> repr(list[int]) diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index ad644bb3128809..042604ed7c1a42 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -5848,6 +5848,27 @@ def foo(x: T): foo(42) + def test_genericalias_instance_isclass(self): + # test against user-defined generic classes + T = TypeVar('T') + + class Node(Generic[T]): + def __init__(self, label: T, + left: 'Node[T] | None' = None, + right: 'Node[T] | None' = None): + self.label = label + self.left = left + self.right = right + + self.assertTrue(inspect.isclass(Node)) + self.assertFalse(inspect.isclass(Node[int])) + self.assertFalse(inspect.isclass(Node[str])) + + # test against standard generic classes + self.assertFalse(inspect.isclass(set[int])) + self.assertFalse(inspect.isclass(list[bytes])) + self.assertFalse(inspect.isclass(dict[str, str])) + def test_implicit_any(self): T = TypeVar('T') diff --git a/Lib/typing.py b/Lib/typing.py index bd1f6448894e8f..6011b62cd26944 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -1356,32 +1356,35 @@ def __dir__(self): class _GenericAlias(_BaseGenericAlias, _root=True): - # The type of parameterized generics. - # - # That is, for example, `type(List[int])` is `_GenericAlias`. - # - # Objects which are instances of this class include: - # * Parameterized container types, e.g. `Tuple[int]`, `List[int]`. - # * Note that native container types, e.g. `tuple`, `list`, use - # `types.GenericAlias` instead. - # * Parameterized classes: - # class C[T]: pass - # # C[int] is a _GenericAlias - # * `Callable` aliases, generic `Callable` aliases, and - # parameterized `Callable` aliases: - # T = TypeVar('T') - # # _CallableGenericAlias inherits from _GenericAlias. - # A = Callable[[], None] # _CallableGenericAlias - # B = Callable[[T], None] # _CallableGenericAlias - # C = B[int] # _CallableGenericAlias - # * Parameterized `Final`, `ClassVar`, `TypeForm`, `TypeGuard`, and `TypeIs`: - # # All _GenericAlias - # Final[int] - # ClassVar[float] - # TypeForm[bytes] - # TypeGuard[bool] - # TypeIs[range] - + """The type of parameterized generics. + + That is, for example, `type(List[int])` is `_GenericAlias`. + + Objects which are instances of this class include: + * Parameterized container types, e.g. `Tuple[int]`, `List[int]`. + * Note that native container types, e.g. `tuple`, `list`, use + `types.GenericAlias` instead. + * Parameterized classes: + class C[T]: pass + # C[int] is a _GenericAlias + * `Callable` aliases, generic `Callable` aliases, and + parameterized `Callable` aliases: + T = TypeVar('T') + # _CallableGenericAlias inherits from _GenericAlias. + A = Callable[[], None] # _CallableGenericAlias + B = Callable[[T], None] # _CallableGenericAlias + C = B[int] # _CallableGenericAlias + * Parameterized `Final`, `ClassVar`, `TypeForm`, `TypeGuard`, and `TypeIs`: + # All _GenericAlias + Final[int] + ClassVar[float] + TypeForm[bytearray] + TypeGuard[bool] + TypeIs[range] + + Note that instances of this class are not classes (e.g by `inspect.isclass`), + even though they behave like them. + """ def __init__(self, origin, args, *, inst=True, name=None): super().__init__(origin, inst=inst, name=name) if not isinstance(args, tuple): @@ -1413,20 +1416,21 @@ def __ror__(self, left): @_tp_cache def __getitem__(self, args): - # Parameterizes an already-parameterized object. - # - # For example, we arrive here doing something like: - # T1 = TypeVar('T1') - # T2 = TypeVar('T2') - # T3 = TypeVar('T3') - # class A(Generic[T1]): pass - # B = A[T2] # B is a _GenericAlias - # C = B[T3] # Invokes _GenericAlias.__getitem__ - # - # We also arrive here when parameterizing a generic `Callable` alias: - # T = TypeVar('T') - # C = Callable[[T], None] - # C[int] # Invokes _GenericAlias.__getitem__ + """Parameterizes an already-parameterized object. + + For example, we arrive here doing something like: + T1 = TypeVar('T1') + T2 = TypeVar('T2') + T3 = TypeVar('T3') + class A(Generic[T1]): pass + B = A[T2] # B is a _GenericAlias + C = B[T3] # Invokes _GenericAlias.__getitem__ + + We also arrive here when parameterizing a generic `Callable` alias: + T = TypeVar('T') + C = Callable[[T], None] + C[int] # Invokes _GenericAlias.__getitem__ + """ if self.__origin__ in (Generic, Protocol): # Can't subscript Generic[...] or Protocol[...]. @@ -1443,20 +1447,20 @@ def __getitem__(self, args): return r def _determine_new_args(self, args): - # Determines new __args__ for __getitem__. - # - # For example, suppose we had: - # T1 = TypeVar('T1') - # T2 = TypeVar('T2') - # class A(Generic[T1, T2]): pass - # T3 = TypeVar('T3') - # B = A[int, T3] - # C = B[str] - # `B.__args__` is `(int, T3)`, so `C.__args__` should be `(int, str)`. - # Unfortunately, this is harder than it looks, because if `T3` is - # anything more exotic than a plain `TypeVar`, we need to consider - # edge cases. - + """Determines new __args__ for __getitem__. + + For example, suppose we had: + T1 = TypeVar('T1') + T2 = TypeVar('T2') + class A(Generic[T1, T2]): pass + T3 = TypeVar('T3') + B = A[int, T3] + C = B[str] + `B.__args__` is `(int, T3)`, so `C.__args__` should be `(int, str)`. + Unfortunately, this is harder than it looks, because if `T3` is + anything more exotic than a plain `TypeVar`, we need to consider + edge cases. + """ params = self.__parameters__ # In the example above, this would be {T3: str} for param in params: From e26ad524ecfcaed34a615f9d6329c1a34d5c07eb Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 4 Jun 2026 02:20:08 +0200 Subject: [PATCH 222/818] [3.15] gh-145177: Fix Emscripten help text (GH-150874) (#150894) Removes some stray commas in help text. (cherry picked from commit 57d444612d9c8a0eab66543d5bf8539103a59b47) Co-authored-by: Hood Chatham <roberthoodchatham@gmail.com> --- Platforms/emscripten/__main__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Platforms/emscripten/__main__.py b/Platforms/emscripten/__main__.py index c1eac8005474fd..c2fb1c4c36e608 100644 --- a/Platforms/emscripten/__main__.py +++ b/Platforms/emscripten/__main__.py @@ -650,7 +650,7 @@ def add_cross_build_dir_option(subcommand): help=( "Path to the cross-build directory " f"(default: {DEFAULT_CROSS_BUILD_DIR}). " - "Can also be set with the CROSS_BUILD_DIR environment variable.", + "Can also be set with the CROSS_BUILD_DIR environment variable." ), ) @@ -743,7 +743,7 @@ def main(): nargs=argparse.REMAINDER, help=( "Arguments to pass to the emscripten Python " - "(use '--' to separate from run options)", + "(use '--' to separate from run options)" ), ) add_cross_build_dir_option(run) From d7505294dfdc3894ee8fb06016e038233660f89f Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 4 Jun 2026 09:13:46 +0200 Subject: [PATCH 223/818] [3.15] gh-148613: Fix race in `gc_set_threshold` and `gc_get_threshold` (GH-150356) (#150841) gh-148613: Fix race in `gc_set_threshold` and `gc_get_threshold` (GH-150356) (cherry picked from commit 41eb8ee2bb8cfd4129736e1f6068e702b8bdba6c) Co-authored-by: Edward Xu <xuxiangad@gmail.com> --- Lib/test/test_free_threading/test_gc.py | 30 +++++++++++++++++++ ...-05-24-22-46-49.gh-issue-148613.PLpmyd.rst | 2 ++ Modules/gcmodule.c | 3 ++ 3 files changed, 35 insertions(+) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-05-24-22-46-49.gh-issue-148613.PLpmyd.rst diff --git a/Lib/test/test_free_threading/test_gc.py b/Lib/test/test_free_threading/test_gc.py index 8b45b6e2150c28..cc1888dae48bc0 100644 --- a/Lib/test/test_free_threading/test_gc.py +++ b/Lib/test/test_free_threading/test_gc.py @@ -94,6 +94,36 @@ def evil(): thread.start() thread.join() + def test_set_threshold(self): + # GH-148613: Setting the GC threshold from another thread could cause a + # race between the `gc_should_collect` and `gc_set_threshold` functions. + NUM_THREADS = 8 + NUM_ITERS = 100_000 + barrier = threading.Barrier(NUM_THREADS) + + class CyclicReference: + def __init__(self): + self.r = self + + def allocator(): + barrier.wait() + for _ in range(NUM_ITERS): + CyclicReference() + + def setter(): + barrier.wait() + for i in range(NUM_ITERS): + gc.set_threshold(100 + (i % 100), 10 + (i % 10), 10 + (i % 10)) + + current_threshold = gc.get_threshold() + try: + threads = [Thread(target=allocator) for _ in range(NUM_THREADS - 1)] + threads.append(Thread(target=setter)) + with threading_helper.start_threads(threads): + pass + finally: + gc.set_threshold(*current_threshold) + if __name__ == "__main__": unittest.main() diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-24-22-46-49.gh-issue-148613.PLpmyd.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-24-22-46-49.gh-issue-148613.PLpmyd.rst new file mode 100644 index 00000000000000..71a701bf3eb355 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-24-22-46-49.gh-issue-148613.PLpmyd.rst @@ -0,0 +1,2 @@ +Fix a data race in the free-threaded build between :func:`gc.set_threshold` +and garbage collection scheduling during object allocation. diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c index 12f93ac0fdea14..8762e592b25810 100644 --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -167,6 +167,8 @@ gc_set_threshold_impl(PyObject *module, int threshold0, int group_right_1, gcstate->generations[2].threshold = threshold2; } #else + PyInterpreterState *interp = _PyInterpreterState_GET(); + _PyEval_StopTheWorld(interp); gcstate->young.threshold = threshold0; if (group_right_1) { gcstate->old[0].threshold = threshold1; @@ -174,6 +176,7 @@ gc_set_threshold_impl(PyObject *module, int threshold0, int group_right_1, if (group_right_2) { gcstate->old[1].threshold = threshold2; } + _PyEval_StartTheWorld(interp); #endif Py_RETURN_NONE; } From 624384d97405f071da94321505ef160c987cac50 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 4 Jun 2026 10:31:47 +0200 Subject: [PATCH 224/818] [3.15] gh-149521: Do not update `last_profiled_frame` if it's not changed (GH-149522) (#149542) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Maurycy Pawłowski-Wieroński <maurycy@maurycy.com> --- Modules/_remote_debugging/threads.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/Modules/_remote_debugging/threads.c b/Modules/_remote_debugging/threads.c index 5176c4cf0671bb..81735e85395ac9 100644 --- a/Modules/_remote_debugging/threads.c +++ b/Modules/_remote_debugging/threads.c @@ -534,12 +534,14 @@ unwind_stack_for_thread( set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to collect frames"); goto error; } - // Update last_profiled_frame for next sample - uintptr_t lpf_addr = - *current_tstate + (uintptr_t)unwinder->debug_offsets.thread_state.last_profiled_frame; - if (_Py_RemoteDebug_WriteRemoteMemory(&unwinder->handle, lpf_addr, - sizeof(uintptr_t), &frame_addr) < 0) { - PyErr_Clear(); // Non-fatal + // Update last_profiled_frame for next sample if it changed + if (frame_addr != ctx.last_profiled_frame) { + uintptr_t lpf_addr = + *current_tstate + (uintptr_t)unwinder->debug_offsets.thread_state.last_profiled_frame; + if (_Py_RemoteDebug_WriteRemoteMemory(&unwinder->handle, lpf_addr, + sizeof(uintptr_t), &frame_addr) < 0) { + PyErr_Clear(); // Non-fatal + } } } else { // No caching - process entire frame chain with base_frame validation From 6b46aac7d629e83e34fd2539ba71c015234a4f37 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 4 Jun 2026 10:46:08 +0200 Subject: [PATCH 225/818] [3.15] gh-150436: Skip subprocess test on STATUS_DLL_INIT_FAILED (GH-150704) (#150713) gh-150436: Skip subprocess test on STATUS_DLL_INIT_FAILED (GH-150704) If a subprocess spawned with CREATE_NEW_CONSOLE creation flag fails with STATUS_DLL_INIT_FAILED return code, skip the test. It's likely a memory allocation failure in the desktop heap memory which caused the DLL init failure. (cherry picked from commit e8034dd841808416e243a4b2f8e08f0edf9caff3) Co-authored-by: Victor Stinner <vstinner@python.org> --- Lib/test/support/__init__.py | 15 +++++++++++++++ Lib/test/test_cmd_line.py | 2 ++ Lib/test/test_msvcrt.py | 9 +++++++-- Lib/test/test_subprocess.py | 10 +++++++--- 4 files changed, 31 insertions(+), 5 deletions(-) diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index 2cac70f4ab2afb..f9601655dfe157 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -3323,3 +3323,18 @@ def control_characters_c0() -> list[str]: _ROOT_IN_POSIX = hasattr(os, 'geteuid') and os.geteuid() == 0 requires_root_user = unittest.skipUnless(_ROOT_IN_POSIX, "test needs root privilege") requires_non_root_user = unittest.skipIf(_ROOT_IN_POSIX, "test needs non-root account") + + +STATUS_DLL_INIT_FAILED = 0xC0000142 +def skip_on_low_desktop_heap_memory_subprocess(returncode): + if sys.platform not in ('win32', 'cygwin'): + return + # On Windows, STATUS_DLL_INIT_FAILED is a generic error code that could + # come from any of the DLLs being loaded when a new Python process is + # created. In practice, it's likely a memory allocation failure in the + # desktop heap memory which caused the DLL init failure, especially on + # process created with CREATE_NEW_CONSOLE creation flag. See the article: + # https://learn.microsoft.com/en-us/troubleshoot/windows-server/performance/desktop-heap-limitation-out-of-memory + if returncode == STATUS_DLL_INIT_FAILED: + raise unittest.SkipTest('gh-150436: DLL init failed, likely because ' + 'of low desktop heap memory') diff --git a/Lib/test/test_cmd_line.py b/Lib/test/test_cmd_line.py index 7f9e44d70001b7..3b556ec31445df 100644 --- a/Lib/test/test_cmd_line.py +++ b/Lib/test/test_cmd_line.py @@ -1036,6 +1036,7 @@ def test_python_legacy_windows_stdio(self): p = subprocess.run([sys.executable, "-c", code], creationflags=subprocess.CREATE_NEW_CONSOLE, env=env) + support.skip_on_low_desktop_heap_memory_subprocess(p.returncode) self.assertEqual(p.returncode, 0) # Then test that FIleIO is used when PYTHONLEGACYWINDOWSSTDIO is set. @@ -1044,6 +1045,7 @@ def test_python_legacy_windows_stdio(self): p = subprocess.run([sys.executable, "-c", code], creationflags=subprocess.CREATE_NEW_CONSOLE, env=env) + support.skip_on_low_desktop_heap_memory_subprocess(p.returncode) self.assertEqual(p.returncode, 0) @unittest.skipIf("-fsanitize" in sysconfig.get_config_vars().get('PY_CFLAGS', ()), diff --git a/Lib/test/test_msvcrt.py b/Lib/test/test_msvcrt.py index 1c6905bd1ee586..fef86ce323e54d 100644 --- a/Lib/test/test_msvcrt.py +++ b/Lib/test/test_msvcrt.py @@ -4,6 +4,7 @@ import unittest from textwrap import dedent +from test import support from test.support import os_helper, requires_resource from test.support.os_helper import TESTFN, TESTFN_ASCII @@ -67,8 +68,12 @@ def run_in_separated_process(self, code): # Run test in a separated process to avoid stdin conflicts. # See: gh-110147 cmd = [sys.executable, '-c', code] - subprocess.run(cmd, check=True, capture_output=True, - creationflags=subprocess.CREATE_NEW_CONSOLE) + try: + subprocess.run(cmd, check=True, capture_output=True, + creationflags=subprocess.CREATE_NEW_CONSOLE) + except subprocess.CalledProcessError as exc: + support.skip_on_low_desktop_heap_memory_subprocess(exc.returncode) + raise def test_kbhit(self): code = dedent(''' diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py index 1a3db527d3d5b8..f944084aaa6d6a 100644 --- a/Lib/test/test_subprocess.py +++ b/Lib/test/test_subprocess.py @@ -3765,13 +3765,17 @@ def test_startupinfo_copy(self): self.assertEqual(startupinfo.wShowWindow, subprocess.SW_HIDE) self.assertEqual(startupinfo.lpAttributeList, {"handle_list": []}) + # CREATE_NEW_CONSOLE creates a "popup" window. + @support.requires_resource('gui') def test_creationflags(self): # creationflags argument CREATE_NEW_CONSOLE = 16 sys.stderr.write(" a DOS box should flash briefly ...\n") - subprocess.call(sys.executable + - ' -c "import time; time.sleep(0.25)"', - creationflags=CREATE_NEW_CONSOLE) + rc = subprocess.call(sys.executable + + ' -c "import time; time.sleep(0.25)"', + creationflags=CREATE_NEW_CONSOLE) + support.skip_on_low_desktop_heap_memory_subprocess(rc) + self.assertEqual(rc, 0) def test_invalid_args(self): # invalid arguments should raise ValueError From 0ad93968feecb9d717b2d76cc01a665ea8870a52 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 4 Jun 2026 10:47:38 +0200 Subject: [PATCH 226/818] [3.15] gh-149473: Emit audit event on calling os.environ.clear() (GH-149768) (#150094) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gh-149473: Emit audit event on calling os.environ.clear() (GH-149768) (cherry picked from commit 29415c071f368e34b504e5efab9d0a795e7c6222) Co-authored-by: Victor Stinner <vstinner@python.org> Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com> --- Doc/library/os.rst | 12 ++++++++++++ .../2026-05-13-12-16-54.gh-issue-149473.nOQZqn.rst | 2 ++ Modules/posixmodule.c | 4 ++++ 3 files changed, 18 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2026-05-13-12-16-54.gh-issue-149473.nOQZqn.rst diff --git a/Doc/library/os.rst b/Doc/library/os.rst index f2c9b3914f36e6..b65dbb4623af2a 100644 --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -219,6 +219,14 @@ process and user. :data:`os.environ`, and when one of the :meth:`~dict.pop` or :meth:`~dict.clear` methods is called. + If the :manpage:`clearenv(3)` function is available, the :meth:`~dict.clear` method + uses it and emits a single ``os._clearenv`` audit event. Otherwise, it emits + an ``os.unsetenv`` event on each deleted variable. + + .. audit-event:: os.unsetenv key os.unsetenv + + .. audit-event:: os._clearenv "" os._clearenv + .. seealso:: The :func:`os.reload_environ` function. @@ -226,6 +234,10 @@ process and user. .. versionchanged:: 3.9 Updated to support :pep:`584`'s merge (``|``) and update (``|=``) operators. + .. versionchanged:: 3.15 + The :meth:`~dict.clear` method can now emit an ``os._clearenv`` audit + event. + .. data:: environb diff --git a/Misc/NEWS.d/next/Library/2026-05-13-12-16-54.gh-issue-149473.nOQZqn.rst b/Misc/NEWS.d/next/Library/2026-05-13-12-16-54.gh-issue-149473.nOQZqn.rst new file mode 100644 index 00000000000000..db624aba31a9de --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-05-13-12-16-54.gh-issue-149473.nOQZqn.rst @@ -0,0 +1,2 @@ +Calling ``os.environ.clear()`` now emits ``os._clearenv`` auditing event. +Patch by Victor Stinner. diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 214c4ab8602be7..60695cf116a41d 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -13678,6 +13678,10 @@ static PyObject * os__clearenv_impl(PyObject *module) /*[clinic end generated code: output=2d6705d62c014b51 input=47d2fa7f323c43ca]*/ { + if (PySys_Audit("os._clearenv", NULL) < 0) { + return NULL; + } + errno = 0; int err = clearenv(); if (err) { From 5a83d1bb7f6a2cc867c64e543dd78d76833cddb5 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 4 Jun 2026 11:50:39 +0200 Subject: [PATCH 227/818] [3.15] Correct Stable ABI documentation for METH_FASTCALL (GH-149593) (GH-150853) The current documentation says: > > METH_FASTCALL > Part of the Stable ABI since version 3.7. > > [...] > > Added in version 3.7. > > Changed in version 3.10: METH_FASTCALL is now part of the stable ABI. so is contradictory about when it was added to the Stable ABI. Looking at the header it seems like 3.10 is right. (cherry picked from commit 58beae7319c58d850184d621d6635de23f71a229) Co-authored-by: da-woods <dw-git@d-woods.co.uk> --- Doc/data/stable_abi.dat | 2 +- Misc/stable_abi.toml | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Doc/data/stable_abi.dat b/Doc/data/stable_abi.dat index 2d4278c9d97c85..86080fac716383 100644 --- a/Doc/data/stable_abi.dat +++ b/Doc/data/stable_abi.dat @@ -1,7 +1,7 @@ role,name,added,ifdef_note,struct_abi_kind macro,METH_CLASS,3.2,, macro,METH_COEXIST,3.2,, -macro,METH_FASTCALL,3.7,, +macro,METH_FASTCALL,3.10,, macro,METH_METHOD,3.7,, macro,METH_NOARGS,3.2,, macro,METH_O,3.2,, diff --git a/Misc/stable_abi.toml b/Misc/stable_abi.toml index 8fd7aba09241e6..d59a7c788fa9e0 100644 --- a/Misc/stable_abi.toml +++ b/Misc/stable_abi.toml @@ -1813,7 +1813,6 @@ [const.METH_COEXIST] added = '3.2' # METH_STACKLESS is undocumented -# METH_FASTCALL is not part of limited API. # The following are defined in private headers, but historically # they were exported as part of the stable ABI. @@ -2149,8 +2148,6 @@ # New method flags in 3.7 (PEP 590): -[const.METH_FASTCALL] - added = '3.7' [const.METH_METHOD] added = '3.7' @@ -2300,6 +2297,10 @@ [data.PyStructSequence_UnnamedField] added = '3.11' +# Added in 3.7 but in the Stable ABI from 3.10 +[const.METH_FASTCALL] + added = '3.10' + # Add stable Py_buffer API in Python 3.11 (https://bugs.python.org/issue45459) [struct.Py_buffer] added = '3.11' From f3956c659aace9e0be25ab497ea07d2adaef3c21 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 4 Jun 2026 11:51:34 +0200 Subject: [PATCH 228/818] [3.15] Fix 2 broken links in documentation (GH-150892) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (cherry picked from commit cb064e746de210fea8639b986c8d2a573b71c48f) Co-authored-by: Miro Hrončok <miro@hroncok.cz> Co-authored-by: Stan Ulbrych <stan@python.org> --- Doc/c-api/complex.rst | 2 +- Doc/extending/first-extension-module.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/c-api/complex.rst b/Doc/c-api/complex.rst index 629312bd771beb..10f96c7cb75e88 100644 --- a/Doc/c-api/complex.rst +++ b/Doc/c-api/complex.rst @@ -130,7 +130,7 @@ rather than dereferencing them through pointers. Please note, that these functions are :term:`soft deprecated` since Python 3.15. Avoid using this API in a new code to do complex arithmetic: either use -the `Number Protocol <number>`_ API or use native complex types, like +the :ref:`Number Protocol <number>` API or use native complex types, like :c:expr:`double complex`. diff --git a/Doc/extending/first-extension-module.rst b/Doc/extending/first-extension-module.rst index 894f5bdbb8f09c..55a772e2aca24f 100644 --- a/Doc/extending/first-extension-module.rst +++ b/Doc/extending/first-extension-module.rst @@ -164,7 +164,7 @@ Then, create ``meson.build`` containing the following: .. note:: - See `meson-python documentation <meson-python>`_ for details on + See the `meson-python documentation <meson-python_>`_ for details on configuration. Now, build install the *project in the current directory* (``.``) via ``pip``: From 253c51837fa0dd0adb7499583d66d726ac921749 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 4 Jun 2026 15:23:33 +0200 Subject: [PATCH 229/818] [3.15] gh-106318: Add doctest role and a 'See also' to the `str.split()` docs (GH-144367) (cherry picked from commit a96cba5c4aa3cf859a9cacab590fc1a51d6efbbb) Co-authored-by: Adorilson Bezerra <adorilson@gmail.com> --- Doc/library/stdtypes.rst | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index ba896212925d89..f770809dfb4006 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -2616,7 +2616,9 @@ expression support in the :mod:`re` module). :func:`re.split`). Splitting an empty string with a specified separator returns ``['']``. - For example:: + For example: + + .. doctest:: >>> '1,2,3'.split(',') ['1', '2', '3'] @@ -2634,7 +2636,9 @@ expression support in the :mod:`re` module). string or a string consisting of just whitespace with a ``None`` separator returns ``[]``. - For example:: + For example: + + .. doctest:: >>> '1 2 3'.split() ['1', '2', '3'] @@ -2646,7 +2650,9 @@ expression support in the :mod:`re` module). If *sep* is not specified or is ``None`` and *maxsplit* is ``0``, only leading runs of consecutive whitespace are considered. - For example:: + For example: + + .. doctest:: >>> "".split(None, 0) [] @@ -2655,7 +2661,7 @@ expression support in the :mod:`re` module). >>> " foo ".split(maxsplit=0) ['foo '] - See also :meth:`join`. + See also :meth:`join` and :meth:`rsplit`. .. index:: From 42a41cc69ff01239b2cc65f19fbe31417a176445 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 4 Jun 2026 15:58:59 +0200 Subject: [PATCH 230/818] [3.15] gh-150750: Fix a race condition in `deque.index` with free-threading (GH-150779) (#150920) gh-150750: Fix a race condition in `deque.index` with free-threading (GH-150779) (cherry picked from commit d83d50b5b735cb58e175280d1c27d40c43d535b5) Co-authored-by: sobolevn <mail@sobolevn.me> --- Lib/test/test_deque.py | 16 +++++++++++++ .../test_free_threading/test_collections.py | 24 +++++++++++++++++++ ...-06-02-14-21-46.gh-issue-150750.SVS2o0.rst | 1 + Modules/_collectionsmodule.c | 15 ++++++------ Modules/clinic/_collectionsmodule.c.h | 4 ++-- Modules/posixmodule.c | 4 ++-- 6 files changed, 53 insertions(+), 11 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-06-02-14-21-46.gh-issue-150750.SVS2o0.rst diff --git a/Lib/test/test_deque.py b/Lib/test/test_deque.py index 4e1a489205a685..3c45032cda9138 100644 --- a/Lib/test/test_deque.py +++ b/Lib/test/test_deque.py @@ -287,6 +287,22 @@ def test_index(self): else: self.assertEqual(d.index(element, start, stop), target) + # Test stop argument + for elem in d: + index = d.index(elem) + self.assertEqual( + index, + d.index(elem, 0), + ) + self.assertEqual( + index, + d.index(elem, 0, len(d)), + ) + self.assertEqual( + index, + d.index(elem, 0, len(d) + 100), + ) + # Test large start argument d = deque(range(0, 10000, 10)) for step in range(100): diff --git a/Lib/test/test_free_threading/test_collections.py b/Lib/test/test_free_threading/test_collections.py index 3a413ccf396d4b..849b0480e232fc 100644 --- a/Lib/test/test_free_threading/test_collections.py +++ b/Lib/test/test_free_threading/test_collections.py @@ -24,6 +24,30 @@ def copy_loop(): threading_helper.run_concurrently([mutate, copy_loop]) + def test_index_race_in_ac(self): + # gh-150750: There was a c_default specified as `Py_SIZE(self)`, + # it was used without a critical section. + + d = deque(range(100)) + + def index(): + for _ in range(10000): + try: + d.index(50) + except ValueError: + pass + + def mutate(): + for _ in range(10000): + d.append(0) + d.clear() + d.extend(range(100)) + d.appendleft(-1) + + threading_helper.run_concurrently( + [index, *[mutate for _ in range(3)]], + ) + if __name__ == "__main__": unittest.main() diff --git a/Misc/NEWS.d/next/Library/2026-06-02-14-21-46.gh-issue-150750.SVS2o0.rst b/Misc/NEWS.d/next/Library/2026-06-02-14-21-46.gh-issue-150750.SVS2o0.rst new file mode 100644 index 00000000000000..bda500383e7cda --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-02-14-21-46.gh-issue-150750.SVS2o0.rst @@ -0,0 +1 @@ +Fix a race condition in :meth:`collections.deque.index` with free-threading. diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c index c5d4879312bc8a..5ca6362406a78b 100644 --- a/Modules/_collectionsmodule.c +++ b/Modules/_collectionsmodule.c @@ -1251,7 +1251,7 @@ _collections.deque.index as deque_index deque: dequeobject value as v: object start: object(converter='_PyEval_SliceIndexNotNone', type='Py_ssize_t', c_default='0') = NULL - stop: object(converter='_PyEval_SliceIndexNotNone', type='Py_ssize_t', c_default='Py_SIZE(deque)') = NULL + stop: object(converter='_PyEval_SliceIndexNotNone', type='Py_ssize_t', c_default='PY_SSIZE_T_MAX') = NULL / Return first index of value. @@ -1262,7 +1262,7 @@ Raises ValueError if the value is not present. static PyObject * deque_index_impl(dequeobject *deque, PyObject *v, Py_ssize_t start, Py_ssize_t stop) -/*[clinic end generated code: output=df45132753175ef9 input=90f48833a91e1743]*/ +/*[clinic end generated code: output=df45132753175ef9 input=1c3b19632cf3484f]*/ { Py_ssize_t i, n; PyObject *item; @@ -1270,22 +1270,23 @@ deque_index_impl(dequeobject *deque, PyObject *v, Py_ssize_t start, Py_ssize_t index = deque->leftindex; size_t start_state = deque->state; int cmp; + Py_ssize_t size = Py_SIZE(deque); if (start < 0) { - start += Py_SIZE(deque); + start += size; if (start < 0) start = 0; } if (stop < 0) { - stop += Py_SIZE(deque); + stop += size; if (stop < 0) stop = 0; } - if (stop > Py_SIZE(deque)) - stop = Py_SIZE(deque); + if (stop > size) + stop = size; if (start > stop) start = stop; - assert(0 <= start && start <= stop && stop <= Py_SIZE(deque)); + assert(0 <= start && start <= stop && stop <= size); for (i=0 ; i < start - BLOCKLEN ; i += BLOCKLEN) { b = b->rightlink; diff --git a/Modules/clinic/_collectionsmodule.c.h b/Modules/clinic/_collectionsmodule.c.h index b5c315c680e782..6c60678a6fbd51 100644 --- a/Modules/clinic/_collectionsmodule.c.h +++ b/Modules/clinic/_collectionsmodule.c.h @@ -340,7 +340,7 @@ deque_index(PyObject *deque, PyObject *const *args, Py_ssize_t nargs) PyObject *return_value = NULL; PyObject *v; Py_ssize_t start = 0; - Py_ssize_t stop = Py_SIZE(deque); + Py_ssize_t stop = PY_SSIZE_T_MAX; if (!_PyArg_CheckPositional("index", nargs, 1, 3)) { goto exit; @@ -632,4 +632,4 @@ tuplegetter_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) exit: return return_value; } -/*[clinic end generated code: output=b9d4d647c221cb9f input=a9049054013a1b77]*/ +/*[clinic end generated code: output=f5a388add99d3d15 input=a9049054013a1b77]*/ diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 60695cf116a41d..4b6b5196173169 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -3123,7 +3123,7 @@ class path_t_converter(CConverter): impl_by_reference = True parse_by_reference = True default_type = () - c_init_default = "<placeholder>" # overridden in pre_render(() + c_init_default = "<placeholder>" # overridden in pre_render() converter = 'path_converter' @@ -3266,7 +3266,7 @@ class confname_converter(CConverter): """, argname=argname, converter=self.converter, table=self.table) [python start generated code]*/ -/*[python end generated code: output=da39a3ee5e6b4b0d input=d58f18bdf3bd3565]*/ +/*[python end generated code: output=da39a3ee5e6b4b0d input=ddbf3ac90a981122]*/ /*[clinic input] From c6d64cc60df359a45522ded4fca9076837678836 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 4 Jun 2026 16:10:30 +0200 Subject: [PATCH 231/818] [3.15] gh-150913: Fix sqlite3.Blob validation for empty slice assignment (GH-150915) (GH-150923) ass_subscript_slice() returned early when the computed slice length was zero, bypassing validation performed for non-empty slices. (cherry picked from commit fc9c4db1302f8be7527e70cf0938b629985a1d72) Co-authored-by: Jiseok CHOI <jiseok.dev@gmail.com> --- Lib/test/test_sqlite3/test_dbapi.py | 12 ++++++++++++ ...26-06-04-21-49-18.gh-issue-150913.EmptyBl.rst | 3 +++ Modules/_sqlite/blob.c | 16 ++++++++++------ 3 files changed, 25 insertions(+), 6 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-06-04-21-49-18.gh-issue-150913.EmptyBl.rst diff --git a/Lib/test/test_sqlite3/test_dbapi.py b/Lib/test/test_sqlite3/test_dbapi.py index 73b40e82a96811..5f6cb527955ca1 100644 --- a/Lib/test/test_sqlite3/test_dbapi.py +++ b/Lib/test/test_sqlite3/test_dbapi.py @@ -1400,6 +1400,18 @@ def test_blob_set_empty_slice(self): self.blob[0:0] = b"" self.assertEqual(self.blob[:], self.data) + def test_blob_set_empty_slice_wrong_type(self): + with self.assertRaises(TypeError): + self.blob[5:5] = None + + def test_blob_set_empty_slice_wrong_size(self): + with self.assertRaisesRegex(IndexError, "wrong size"): + self.blob[5:5] = b"123" + + def test_blob_set_empty_slice_correct(self): + self.blob[5:5] = b"" + self.assertEqual(self.blob[:], self.data) + def test_blob_set_slice_with_skip(self): self.blob[0:10:2] = b"12345" actual = self.cx.execute("select b from test").fetchone()[0] diff --git a/Misc/NEWS.d/next/Library/2026-06-04-21-49-18.gh-issue-150913.EmptyBl.rst b/Misc/NEWS.d/next/Library/2026-06-04-21-49-18.gh-issue-150913.EmptyBl.rst new file mode 100644 index 00000000000000..f95a6ee6ee15bf --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-04-21-49-18.gh-issue-150913.EmptyBl.rst @@ -0,0 +1,3 @@ +Fix :class:`sqlite3.Blob` slice assignment to raise +:exc:`TypeError` and :exc:`IndexError` for type and size mismatches +respectively, even when the target slice is empty. diff --git a/Modules/_sqlite/blob.c b/Modules/_sqlite/blob.c index 2cc62751054278..d81784409e5d91 100644 --- a/Modules/_sqlite/blob.c +++ b/Modules/_sqlite/blob.c @@ -531,21 +531,25 @@ ass_subscript_slice(pysqlite_Blob *self, PyObject *item, PyObject *value) return -1; } - if (len == 0) { - return 0; - } - Py_buffer vbuf; if (PyObject_GetBuffer(value, &vbuf, PyBUF_SIMPLE) < 0) { return -1; } - int rc = -1; if (vbuf.len != len) { PyErr_SetString(PyExc_IndexError, "Blob slice assignment is wrong size"); + PyBuffer_Release(&vbuf); + return -1; } - else if (step == 1) { + + if (len == 0) { + PyBuffer_Release(&vbuf); + return 0; + } + + int rc = -1; + if (step == 1) { rc = inner_write(self, vbuf.buf, len, start); } else { From 1e1a9d9b41411e2670c2869ae396d898bffeba90 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 4 Jun 2026 22:45:28 +0200 Subject: [PATCH 232/818] [3.15] Add shebang documentation for PyManager 26.3b1 (GH-150931) (cherry picked from commit e28a2f493044ecfc0f76fe78ff6dde8e395504a9) Co-authored-by: Steve Dower <steve.dower@python.org> --- Doc/using/windows.rst | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/Doc/using/windows.rst b/Doc/using/windows.rst index eea1e2f64a468d..5b715d4614dad8 100644 --- a/Doc/using/windows.rst +++ b/Doc/using/windows.rst @@ -455,6 +455,12 @@ customization. Python runtimes, or false to prevent it. By default, true. + * - ``shebang_templates`` + - (none) + - Mapping from shebang line template to alternative command, such as + ``py -V:<tag>`` or a substitute string. + See :ref:`pymanager-shebang` for more details. + * - ``log_level`` - ``PYMANAGER_VERBOSE``, ``PYMANAGER_DEBUG`` - Set the default level of output (0-50). @@ -568,6 +574,30 @@ which the path to the script and any additional arguments will be appended. This functionality may be disabled by the ``shebang_can_run_anything`` configuration option. +Since version 26.3 of the Python install manager, custom shebang templates may +be added to your configuration file. Add the ``shebang_templates`` object with +one member for each template (the string to match) and the command to use when +the template is matched. Most commands should be ``py -V:<tag>`` (or ``pyw``) to +launch one of your installed runtimes. The ``py -3.<version>`` form is also +allowed, as is a plain ``py`` to launch the default. No other arguments are +supported. + +.. code:: json5 + + { + "shebang_templates": { + "/usr/bin/python": "py", + "/usr/bin/my_custom_python": "py -V:MyCustomPython/3" + } + } + +If the substitute command is not ``py`` or ``pyw``, it will be written back into +the shebang and regular handling continues. If launching arbitrary executables +is permitted, then providing a full path will allow you to redirect from Python +to any executable. The template should match either the entire line (ignoring +leading and trailing whitespace), or up to the first space in the shebang line. + + .. note:: The behaviour of shebangs in the Python install manager is subtly different From a13fd39832dd8992ad88fe859824c8ccb5965e2a Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 5 Jun 2026 08:25:21 +0200 Subject: [PATCH 233/818] [3.15] gh-145177: Bump emscripten version to 4.0.19 (GH-150926) (#150939) Bumps the emscripten version to 4.0.19. (cherry picked from commit c83d3d789eec9db1fc5ce00d1a320afe20d725fa) Co-authored-by: Hood Chatham <roberthoodchatham@gmail.com> --- Lib/test/test_platform.py | 2 +- Platforms/emscripten/config.toml | 2 +- Platforms/emscripten/streams.mjs | 6 +++++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_platform.py b/Lib/test/test_platform.py index 9ee97b922ad48e..63c130813ec497 100644 --- a/Lib/test/test_platform.py +++ b/Lib/test/test_platform.py @@ -534,7 +534,7 @@ def test_ios_ver(self): def test_libc_ver(self): if support.is_emscripten: - assert platform.libc_ver() == ("emscripten", "4.0.12") + assert platform.libc_ver() == ("emscripten", "4.0.19") return # check that libc_ver(executable) doesn't raise an exception if os.path.isdir(sys.executable) and \ diff --git a/Platforms/emscripten/config.toml b/Platforms/emscripten/config.toml index ba2dc8f4a482bf..401e9396ddbb00 100644 --- a/Platforms/emscripten/config.toml +++ b/Platforms/emscripten/config.toml @@ -1,7 +1,7 @@ # Any data that can vary between Python versions is to be kept in this file. # This allows for blanket copying of the Emscripten build code between supported # Python versions. -emscripten-version = "4.0.12" +emscripten-version = "4.0.19" node-version = "24" test-args = [ "-m", "test", diff --git a/Platforms/emscripten/streams.mjs b/Platforms/emscripten/streams.mjs index 76ad79f9247f4c..1b121d48d4e76c 100644 --- a/Platforms/emscripten/streams.mjs +++ b/Platforms/emscripten/streams.mjs @@ -112,7 +112,7 @@ const prepareBuffer = (buffer, offset, length) => const TTY_OPS = { ioctl_tiocgwinsz(tty) { - return tty.devops.ioctl_tiocgwinsz?.(); + return tty.devops.ioctl_tiocgwinsz?.() ?? [24, 80]; }, }; @@ -188,6 +188,10 @@ class NodeReader { fsync() { nodeFsync(this.nodeStream.fd); } + + ioctl_tiocgwinsz() { + return [this.nodeStream.rows ?? 24, this.nodeStream.columns ?? 80]; + } } class NodeWriter { From b48c208bb03ec50e5f41672037aa5fd0adbdb987 Mon Sep 17 00:00:00 2001 From: sobolevn <mail@sobolevn.me> Date: Fri, 5 Jun 2026 11:43:27 +0300 Subject: [PATCH 234/818] [3.15] gh-150899: Do not reset custom `-Xlazy_imports` mode in `test_lazy_imports` (GH-150900) (#150947) (cherry picked from commit 2f064fbc0b427f0e1c83fe9b9036531ed16e95e8) --- Lib/test/test_lazy_import/__init__.py | 230 ++++---------------------- 1 file changed, 32 insertions(+), 198 deletions(-) diff --git a/Lib/test/test_lazy_import/__init__.py b/Lib/test/test_lazy_import/__init__.py index 4340efd31095ea..2a82ac78fb90fb 100644 --- a/Lib/test/test_lazy_import/__init__.py +++ b/Lib/test/test_lazy_import/__init__.py @@ -21,8 +21,10 @@ _testcapi = None -class LazyImportTests(unittest.TestCase): - """Tests for basic lazy import functionality.""" +class LazyImportTestCase(unittest.TestCase): + def setUp(self): + self.lazy_imports_filter = sys.get_lazy_imports_filter() + self.lazy_imports = sys.get_lazy_imports() def tearDown(self): """Clean up any test modules from sys.modules.""" @@ -30,10 +32,14 @@ def tearDown(self): if key.startswith('test.test_lazy_import.data'): del sys.modules[key] - sys.set_lazy_imports_filter(None) - sys.set_lazy_imports("normal") + sys.set_lazy_imports_filter(self.lazy_imports_filter) + sys.set_lazy_imports(self.lazy_imports) sys.lazy_modules.clear() + +class LazyImportTests(LazyImportTestCase): + """Tests for basic lazy import functionality.""" + def test_basic_unused(self): """Lazy imported module should not be loaded if never accessed.""" import test.test_lazy_import.data.basic_unused @@ -162,17 +168,9 @@ def test_from_import_with_imported_module_getattr(self): assert_python_ok("-c", code) -class GlobalLazyImportModeTests(unittest.TestCase): +class GlobalLazyImportModeTests(LazyImportTestCase): """Tests for sys.set_lazy_imports() global mode control.""" - def tearDown(self): - for key in list(sys.modules.keys()): - if key.startswith('test.test_lazy_import.data'): - del sys.modules[key] - - sys.set_lazy_imports_filter(None) - sys.set_lazy_imports("normal") - def test_global_off(self): """Mode 'none' should disable lazy imports entirely.""" import test.test_lazy_import.data.global_off @@ -204,17 +202,9 @@ def test_global_filter_from_true(self): self.assertNotIn("test.test_lazy_import.data.basic2", sys.modules) -class CompatibilityModeTests(unittest.TestCase): +class CompatibilityModeTests(LazyImportTestCase): """Tests for __lazy_modules__ compatibility mode.""" - def tearDown(self): - for key in list(sys.modules.keys()): - if key.startswith('test.test_lazy_import.data'): - del sys.modules[key] - - sys.set_lazy_imports_filter(None) - sys.set_lazy_imports("normal") - def test_compatibility_mode(self): """__lazy_modules__ should enable lazy imports for listed modules.""" import test.test_lazy_import.data.basic_compatibility_mode @@ -241,17 +231,9 @@ def test_compatibility_mode_relative(self): self.assertNotIn("test.test_lazy_import.data.basic2", sys.modules) -class ModuleIntrospectionTests(unittest.TestCase): +class ModuleIntrospectionTests(LazyImportTestCase): """Tests for module dict and getattr behavior with lazy imports.""" - def tearDown(self): - for key in list(sys.modules.keys()): - if key.startswith('test.test_lazy_import.data'): - del sys.modules[key] - - sys.set_lazy_imports_filter(None) - sys.set_lazy_imports("normal") - def test_modules_dict(self): """Accessing module.__dict__ should not trigger reification.""" import test.test_lazy_import.data.modules_dict @@ -268,17 +250,9 @@ def test_modules_getattr_other(self): self.assertNotIn("test.test_lazy_import.data.basic2", sys.modules) -class LazyImportTypeTests(unittest.TestCase): +class LazyImportTypeTests(LazyImportTestCase): """Tests for the LazyImportType and its resolve() method.""" - def tearDown(self): - for key in list(sys.modules.keys()): - if key.startswith('test.test_lazy_import.data'): - del sys.modules[key] - - sys.set_lazy_imports_filter(None) - sys.set_lazy_imports("normal") - def test_lazy_value_resolve(self): """resolve() method should force the lazy import to load.""" import test.test_lazy_import.data.lazy_get_value @@ -304,17 +278,9 @@ def test_lazy_import_type_attributes_accessible(self): self.assertIn(b"<built-in method resolve of lazy_import object at", proc.out) -class SyntaxRestrictionTests(unittest.TestCase): +class SyntaxRestrictionTests(LazyImportTestCase): """Tests for syntax restrictions on lazy imports.""" - def tearDown(self): - for key in list(sys.modules.keys()): - if key.startswith('test.test_lazy_import.data'): - del sys.modules[key] - - sys.set_lazy_imports_filter(None) - sys.set_lazy_imports("normal") - def test_lazy_try_except(self): """lazy import inside try/except should raise SyntaxError.""" with self.assertRaises(SyntaxError): @@ -383,17 +349,9 @@ def test_lazy_import_exec_at_module_level(self): self.assertIn("OK", result.stdout) -class EagerImportInLazyModeTests(unittest.TestCase): +class EagerImportInLazyModeTests(LazyImportTestCase): """Tests for imports that should remain eager even in lazy mode.""" - def tearDown(self): - for key in list(sys.modules.keys()): - if key.startswith('test.test_lazy_import.data'): - del sys.modules[key] - - sys.set_lazy_imports_filter(None) - sys.set_lazy_imports("normal") - def test_try_except_eager(self): """Imports in try/except should be eager even with mode='all'.""" sys.set_lazy_imports("all") @@ -459,17 +417,9 @@ class C: del globals()["__lazy_modules__"] -class WithStatementTests(unittest.TestCase): +class WithStatementTests(LazyImportTestCase): """Tests for lazy imports in with statement context.""" - def tearDown(self): - for key in list(sys.modules.keys()): - if key.startswith('test.test_lazy_import.data'): - del sys.modules[key] - - sys.set_lazy_imports_filter(None) - sys.set_lazy_imports("normal") - def test_lazy_with(self): """lazy import with 'with' statement should work.""" import test.test_lazy_import.data.lazy_with @@ -481,17 +431,9 @@ def test_lazy_with_from(self): self.assertNotIn("test.test_lazy_import.data.basic2", sys.modules) -class PackageTests(unittest.TestCase): +class PackageTests(LazyImportTestCase): """Tests for lazy imports with packages.""" - def tearDown(self): - for key in list(sys.modules.keys()): - if key.startswith('test.test_lazy_import.data'): - del sys.modules[key] - - sys.set_lazy_imports_filter(None) - sys.set_lazy_imports("normal") - def test_lazy_import_pkg(self): """lazy import of package submodule should load the package.""" out = io.StringIO() @@ -600,17 +542,9 @@ def test_package_from_import_with_module_getattr(self): assert_python_ok("-c", code) -class DunderLazyImportTests(unittest.TestCase): +class DunderLazyImportTests(LazyImportTestCase): """Tests for __lazy_import__ builtin function.""" - def tearDown(self): - for key in list(sys.modules.keys()): - if key.startswith('test.test_lazy_import.data'): - del sys.modules[key] - - sys.set_lazy_imports_filter(None) - sys.set_lazy_imports("normal") - def test_dunder_lazy_import(self): """__lazy_import__ should create lazy import proxy.""" import test.test_lazy_import.data.dunder_lazy_import @@ -645,17 +579,9 @@ def test_dunder_lazy_import_builtins(self): self.assertEqual(dunder_lazy_import_builtins.basic.basic2, 42) -class SysLazyImportsAPITests(unittest.TestCase): +class SysLazyImportsAPITests(LazyImportTestCase): """Tests for sys lazy imports API functions.""" - def tearDown(self): - for key in list(sys.modules.keys()): - if key.startswith('test.test_lazy_import.data'): - del sys.modules[key] - - sys.set_lazy_imports_filter(None) - sys.set_lazy_imports("normal") - def test_set_lazy_imports_requires_string(self): """set_lazy_imports should reject non-string arguments.""" with self.assertRaises(TypeError): @@ -723,21 +649,13 @@ def test_lazy_modules_tracks_lazy_imports(self): @support.requires_subprocess() -class ErrorHandlingTests(unittest.TestCase): +class ErrorHandlingTests(LazyImportTestCase): """Tests for error handling during lazy import reification. PEP 810: Errors during reification should show exception chaining with both the lazy import definition location and the access location. """ - def tearDown(self): - for key in list(sys.modules.keys()): - if key.startswith('test.test_lazy_import.data'): - del sys.modules[key] - - sys.set_lazy_imports_filter(None) - sys.set_lazy_imports("normal") - def test_import_error_shows_chained_traceback(self): """Accessing a nonexistent lazy submodule via parent attr raises AttributeError.""" code = textwrap.dedent(""" @@ -870,7 +788,7 @@ def hello(): @support.requires_subprocess() -class GlobalsAndDictTests(unittest.TestCase): +class GlobalsAndDictTests(LazyImportTestCase): """Tests for globals() and __dict__ behavior with lazy imports. PEP 810: "Calling globals() or accessing a module's __dict__ does not trigger @@ -878,14 +796,6 @@ class GlobalsAndDictTests(unittest.TestCase): through that dictionary still returns lazy proxy objects." """ - def tearDown(self): - for key in list(sys.modules.keys()): - if key.startswith('test.test_lazy_import.data'): - del sys.modules[key] - - sys.set_lazy_imports_filter(None) - sys.set_lazy_imports("normal") - def test_globals_returns_lazy_proxy_when_accessed_from_function(self): """globals() accessed from a function should return lazy proxy without reification. @@ -1040,7 +950,7 @@ def f(): @support.requires_subprocess() -class MultipleNameFromImportTests(unittest.TestCase): +class MultipleNameFromImportTests(LazyImportTestCase): """Tests for lazy from ... import with multiple names. PEP 810: "When using lazy from ... import, each imported name is bound to a @@ -1049,14 +959,6 @@ class MultipleNameFromImportTests(unittest.TestCase): Other names remain as lazy proxies until they are accessed." """ - def tearDown(self): - for key in list(sys.modules.keys()): - if key.startswith('test.test_lazy_import.data'): - del sys.modules[key] - - sys.set_lazy_imports_filter(None) - sys.set_lazy_imports("normal") - def test_accessing_one_name_leaves_others_as_proxies(self): """Accessing one name from multi-name import should leave others lazy.""" code = textwrap.dedent(""" @@ -1121,20 +1023,12 @@ def test_all_names_reified_after_all_accessed(self): @support.requires_subprocess() -class SysLazyModulesTrackingTests(unittest.TestCase): +class SysLazyModulesTrackingTests(LazyImportTestCase): """Tests for sys.lazy_modules tracking behavior. PEP 810: "When the module is reified, it's removed from sys.lazy_modules" """ - def tearDown(self): - for key in list(sys.modules.keys()): - if key.startswith('test.test_lazy_import.data'): - del sys.modules[key] - - sys.set_lazy_imports_filter(None) - sys.set_lazy_imports("normal") - def test_module_added_to_lazy_modules_on_lazy_import(self): """Module should be added to sys.lazy_modules when lazily imported.""" # PEP 810 states lazy_modules tracks modules that have been lazily imported @@ -1433,20 +1327,12 @@ def test_sys_set_lazy_imports_overrides_cli(self): @support.requires_subprocess() -class FilterFunctionSignatureTests(unittest.TestCase): +class FilterFunctionSignatureTests(LazyImportTestCase): """Tests for the filter function signature per PEP 810. PEP 810: func(importer: str, name: str, fromlist: tuple[str, ...] | None) -> bool """ - def tearDown(self): - for key in list(sys.modules.keys()): - if key.startswith('test.test_lazy_import.data'): - del sys.modules[key] - - sys.set_lazy_imports_filter(None) - sys.set_lazy_imports("normal") - def _run_subprocess_with_modules(self, code, files): with tempfile.TemporaryDirectory() as tmpdir: for relpath, contents in files.items(): @@ -1716,17 +1602,9 @@ def my_filter(importer, name, fromlist): self.assertIn("OK", result.stdout) -class AdditionalSyntaxRestrictionTests(unittest.TestCase): +class AdditionalSyntaxRestrictionTests(LazyImportTestCase): """Additional syntax restriction tests per PEP 810.""" - def tearDown(self): - for key in list(sys.modules.keys()): - if key.startswith('test.test_lazy_import.data'): - del sys.modules[key] - - sys.set_lazy_imports_filter(None) - sys.set_lazy_imports("normal") - def test_lazy_import_inside_class_raises_syntax_error(self): """lazy import inside class body should raise SyntaxError.""" # PEP 810: "The soft keyword is only allowed at the global (module) level, @@ -1736,7 +1614,7 @@ def test_lazy_import_inside_class_raises_syntax_error(self): @support.requires_subprocess() -class MixedLazyEagerImportTests(unittest.TestCase): +class MixedLazyEagerImportTests(LazyImportTestCase): """Tests for mixing lazy and eager imports of the same module. PEP 810: "If module foo is imported both lazily and eagerly in the same @@ -1744,14 +1622,6 @@ class MixedLazyEagerImportTests(unittest.TestCase): the same module object." """ - def tearDown(self): - for key in list(sys.modules.keys()): - if key.startswith('test.test_lazy_import.data'): - del sys.modules[key] - - sys.set_lazy_imports_filter(None) - sys.set_lazy_imports("normal") - def test_eager_import_before_lazy_resolves_to_same_module(self): """Eager import before lazy should make lazy resolve to same module.""" code = textwrap.dedent(""" @@ -1797,17 +1667,9 @@ def test_lazy_import_before_eager_resolves_to_same_module(self): self.assertIn("OK", result.stdout) -class RelativeImportTests(unittest.TestCase): +class RelativeImportTests(LazyImportTestCase): """Tests for relative imports with lazy keyword.""" - def tearDown(self): - for key in list(sys.modules.keys()): - if key.startswith('test.test_lazy_import.data'): - del sys.modules[key] - - sys.set_lazy_imports_filter(None) - sys.set_lazy_imports("normal") - def test_relative_lazy_import(self): """lazy from . import submodule should work.""" from test.test_lazy_import.data import relative_lazy @@ -1832,21 +1694,13 @@ def test_relative_lazy_from_import(self): self.assertIn("test.test_lazy_import.data.basic2", sys.modules) -class LazyModulesCompatibilityFromImportTests(unittest.TestCase): +class LazyModulesCompatibilityFromImportTests(LazyImportTestCase): """Tests for __lazy_modules__ with from imports. PEP 810: "When a module is made lazy this way, from-imports using that module are also lazy" """ - def tearDown(self): - for key in list(sys.modules.keys()): - if key.startswith('test.test_lazy_import.data'): - del sys.modules[key] - - sys.set_lazy_imports_filter(None) - sys.set_lazy_imports("normal") - def test_lazy_modules_makes_from_imports_lazy(self): """__lazy_modules__ should make from imports of listed modules lazy.""" from test.test_lazy_import.data import lazy_compat_from @@ -1861,7 +1715,7 @@ def test_lazy_modules_makes_from_imports_lazy(self): @support.requires_subprocess() -class ImportStateAtReificationTests(unittest.TestCase): +class ImportStateAtReificationTests(LazyImportTestCase): """Tests for import system state at reification time. PEP 810: "Reification still calls __import__ to resolve the import, which uses @@ -1870,14 +1724,6 @@ class ImportStateAtReificationTests(unittest.TestCase): statement was evaluated." """ - def tearDown(self): - for key in list(sys.modules.keys()): - if key.startswith('test.test_lazy_import.data'): - del sys.modules[key] - - sys.set_lazy_imports_filter(None) - sys.set_lazy_imports("normal") - def test_sys_path_at_reification_time_is_used(self): """sys.path changes after lazy import should affect reification.""" code = textwrap.dedent(""" @@ -1920,17 +1766,9 @@ def test_sys_path_at_reification_time_is_used(self): @support.requires_subprocess() -class ThreadSafetyTests(unittest.TestCase): +class ThreadSafetyTests(LazyImportTestCase): """Tests for thread-safety of lazy imports.""" - def tearDown(self): - for key in list(sys.modules.keys()): - if key.startswith('test.test_lazy_import.data'): - del sys.modules[key] - - sys.set_lazy_imports_filter(None) - sys.set_lazy_imports("normal") - def test_concurrent_lazy_import_reification(self): """Multiple threads racing to reify the same lazy import should succeed.""" from test.test_lazy_import.data import basic_unused @@ -2192,11 +2030,7 @@ def test_normal_import_dis(self): @unittest.skipIf(_testcapi is None, 'need the _testcapi module') -class LazyCApiTests(unittest.TestCase): - def tearDown(self): - sys.set_lazy_imports("normal") - sys.set_lazy_imports_filter(None) - +class LazyCApiTests(LazyImportTestCase): def test_set_matches_sys(self): self.assertEqual(_testcapi.PyImport_GetLazyImportsMode(), sys.get_lazy_imports()) for mode in ("normal", "all", "none"): From 675ed8a7490f221f228d7bc75263e4195e6139a4 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 5 Jun 2026 13:41:22 +0200 Subject: [PATCH 235/818] [3.15] gh-62825: Fix encoding aliases "KS_C_5601-1987", "KS X 1001", etc (GH-150933) (GH-150946) They are now aliases of CP949 instead of EUC-KR. (cherry picked from commit 45562c6f4f469e278a9c03c31c2cdadf8100d101) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> --- Lib/encodings/aliases.py | 12 ++++++------ .../2026-06-04-23-10-31.gh-issue-62825.BtG_yQ.rst | 2 ++ 2 files changed, 8 insertions(+), 6 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-06-04-23-10-31.gh-issue-62825.BtG_yQ.rst diff --git a/Lib/encodings/aliases.py b/Lib/encodings/aliases.py index e5e50630f33d14..df4c230fbf9c4e 100644 --- a/Lib/encodings/aliases.py +++ b/Lib/encodings/aliases.py @@ -226,6 +226,12 @@ # cp949 codec '949' : 'cp949', + 'korean' : 'cp949', + 'ksc5601' : 'cp949', + 'ks_c_5601' : 'cp949', + 'ks_c_5601_1987' : 'cp949', + 'ksx1001' : 'cp949', + 'ks_x_1001' : 'cp949', 'ms949' : 'cp949', 'uhc' : 'cp949', @@ -248,12 +254,6 @@ # euc_kr codec 'euckr' : 'euc_kr', - 'korean' : 'euc_kr', - 'ksc5601' : 'euc_kr', - 'ks_c_5601' : 'euc_kr', - 'ks_c_5601_1987' : 'euc_kr', - 'ksx1001' : 'euc_kr', - 'ks_x_1001' : 'euc_kr', 'cseuckr' : 'euc_kr', # gb18030 codec diff --git a/Misc/NEWS.d/next/Library/2026-06-04-23-10-31.gh-issue-62825.BtG_yQ.rst b/Misc/NEWS.d/next/Library/2026-06-04-23-10-31.gh-issue-62825.BtG_yQ.rst new file mode 100644 index 00000000000000..95a4fb1c61d4c3 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-04-23-10-31.gh-issue-62825.BtG_yQ.rst @@ -0,0 +1,2 @@ +Encodings "KS_C_5601-1987", "KS X 1001", etc are now aliases of "CP949" +instead of "EUC-KR". From d8af158eb6e16ee5494b6e16c800f9fe7eee9295 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 5 Jun 2026 14:09:13 +0200 Subject: [PATCH 236/818] [3.15] gh-129011: Update docs for Raw I/O read, readinto, and write (GH-135328) (#150957) gh-129011: Update docs for Raw I/O read, readinto, and write (GH-135328) Update `RawIOBase` and `FileIO` documentation to match implementation behavior around `.read`, `.readinto`, `.readall` and `.write`. In particular: - They may make more than one system call (PEP-475) - Add warnings if `.write()` requires a wrapping retry loop (see: gh-126606) - "Raw I/O" `.write`` may not write all bytes - `buffering=0` example results in a "Raw I/O" (cherry picked from commit e4db68b9c990ed1bb7562094bee2e73f4450d42b) Co-authored-by: Cody Maloney <cmaloney@users.noreply.github.com> Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Victor Stinner <vstinner@python.org> --- Doc/library/io.rst | 50 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 41 insertions(+), 9 deletions(-) diff --git a/Doc/library/io.rst b/Doc/library/io.rst index 8c0eed592dd49e..d47b74efe22de9 100644 --- a/Doc/library/io.rst +++ b/Doc/library/io.rst @@ -38,6 +38,7 @@ will raise a :exc:`TypeError`. So will giving a :class:`bytes` object to the Operations that used to raise :exc:`IOError` now raise :exc:`OSError`, since :exc:`IOError` is now an alias of :exc:`OSError`. +.. _text-io: Text I/O ^^^^^^^^ @@ -65,6 +66,7 @@ In-memory text streams are also available as :class:`StringIO` objects:: The text stream API is described in detail in the documentation of :class:`TextIOBase`. +.. _binary-io: Binary I/O ^^^^^^^^^^ @@ -103,6 +105,13 @@ stream by opening a file in binary mode with buffering disabled:: The raw stream API is described in detail in the docs of :class:`RawIOBase`. +.. warning:: + Raw I/O is a low-level interface and methods generally must have their return + values checked and be explicitly retried to ensure an operation completes. + For instance :meth:`~RawIOBase.write` returns the number of bytes written + which may be less than the number of bytes provided (a partial write). + High-level I/O objects like :ref:`binary-io` and :ref:`text-io` implement + retry behavior. .. _io-text-encoding: @@ -478,8 +487,11 @@ I/O Base Classes Read up to *size* bytes from the object and return them. As a convenience, if *size* is unspecified or -1, all bytes until EOF are returned. - Otherwise, only one system call is ever made. Fewer than *size* bytes may - be returned if the operating system call returns fewer than *size* bytes. + + Attempts to make only one system call but will retry if interrupted and + the signal handler does not raise an exception (see :pep:`475` for the + rationale). This means fewer than *size* bytes may be returned if the + operating system call returns fewer than *size* bytes. If 0 bytes are returned, and *size* was not 0, this indicates end of file. If the object is in non-blocking mode and no bytes are available, @@ -493,13 +505,19 @@ I/O Base Classes Read and return all the bytes from the stream until EOF, using multiple calls to the stream if necessary. + If ``0`` bytes are returned this indicates end of file. If the object is in + non-blocking mode and the underlying :meth:`read` returns ``None`` + indicating no bytes are available, ``None`` is returned. + .. method:: readinto(b, /) Read bytes into a pre-allocated, writable :term:`bytes-like object` *b*, and return the number of bytes read. For example, *b* might be a :class:`bytearray`. - If the object is in non-blocking mode and no bytes - are available, ``None`` is returned. + + If ``0`` is returned and ``len(b)`` is not ``0``, this indicates end of file. If + the object is in non-blocking mode and no bytes are available, ``None`` is + returned. .. method:: write(b, /) @@ -513,6 +531,13 @@ I/O Base Classes this method returns, so the implementation should only access *b* during the method call. + .. warning:: + + This function does not ensure all bytes are written or an exception is + thrown. Callers may implement that behavior by checking the return + value and, if it is less than the length of *b*, looping with additional + write calls until all unwritten bytes are written. High-level I/O + objects like :ref:`binary-io` and :ref:`text-io` implement retry behavior. .. class:: BufferedIOBase @@ -641,7 +666,11 @@ Raw File I/O .. class:: FileIO(name, mode='r', closefd=True, opener=None) A raw binary stream representing an OS-level file containing bytes data. It - inherits from :class:`RawIOBase`. + inherits from :class:`RawIOBase` and implements its low-level access design. + This means :meth:`~RawIOBase.write` does not guarantee all bytes are written + and :meth:`~RawIOBase.read` may read less bytes than requested even when more + bytes may be present in the underlying file. To get "write all" and + "read at least" behavior, use :ref:`binary-io`. The *name* can be one of two things: @@ -661,10 +690,6 @@ Raw File I/O implies writing, so this mode behaves in a similar way to ``'w'``. Add a ``'+'`` to the mode to allow simultaneous reading and writing. - The :meth:`~RawIOBase.read` (when called with a positive argument), - :meth:`~RawIOBase.readinto` and :meth:`~RawIOBase.write` methods on this - class will only make one system call. - A custom opener can be used by passing a callable as *opener*. The underlying file descriptor for the file object is then obtained by calling *opener* with (*name*, *flags*). *opener* must return an open file descriptor (passing @@ -676,6 +701,13 @@ Raw File I/O See the :func:`open` built-in function for examples on using the *opener* parameter. + .. warning:: + :class:`FileIO` is a low-level I/O object and members, such as + :meth:`~RawIOBase.read` and :meth:`~RawIOBase.write`, need to have their + return values checked explicitly in a retry loop to implement "write all" + and "read at least" behavior. High-level I/O objects :ref:`binary-io` and + :ref:`text-io` implement retry behavior. + .. versionchanged:: 3.3 The *opener* parameter was added. The ``'x'`` mode was added. From 85e75a73d4f8e3cf28db97fe15ffdf28eb1f5641 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 5 Jun 2026 14:41:19 +0200 Subject: [PATCH 237/818] [3.15] gh-150907: Fix dynamic_annotations.h when built with C++ and Valgrind (GH-150914) (#150962) gh-150907: Fix dynamic_annotations.h when built with C++ and Valgrind (GH-150914) Add extern "C++" scope for the C++ template. Fix test_cppext when Python is built with --with-valgrind. (cherry picked from commit c32501261aeeb0cc1ad1c53b6be9790ff1d23215) Co-authored-by: Victor Stinner <vstinner@python.org> --- Include/dynamic_annotations.h | 3 +++ .../next/C_API/2026-06-04-14-26-17.gh-issue-150907.CA91_B.rst | 2 ++ 2 files changed, 5 insertions(+) create mode 100644 Misc/NEWS.d/next/C_API/2026-06-04-14-26-17.gh-issue-150907.CA91_B.rst diff --git a/Include/dynamic_annotations.h b/Include/dynamic_annotations.h index 4d4def9bf8983e..5290319dd762c5 100644 --- a/Include/dynamic_annotations.h +++ b/Include/dynamic_annotations.h @@ -461,6 +461,7 @@ int RunningOnValgrind(void); #if DYNAMIC_ANNOTATIONS_ENABLED != 0 && defined(__cplusplus) +extern "C++" { /* _Py_ANNOTATE_UNPROTECTED_READ is the preferred way to annotate racey reads. Instead of doing @@ -476,6 +477,8 @@ int RunningOnValgrind(void); _Py_ANNOTATE_IGNORE_READS_END(); return res; } +} + /* Apply _Py_ANNOTATE_BENIGN_RACE_SIZED to a static variable. */ #define _Py_ANNOTATE_BENIGN_RACE_STATIC(static_var, description) \ namespace { \ diff --git a/Misc/NEWS.d/next/C_API/2026-06-04-14-26-17.gh-issue-150907.CA91_B.rst b/Misc/NEWS.d/next/C_API/2026-06-04-14-26-17.gh-issue-150907.CA91_B.rst new file mode 100644 index 00000000000000..f58b248f3a0b98 --- /dev/null +++ b/Misc/NEWS.d/next/C_API/2026-06-04-14-26-17.gh-issue-150907.CA91_B.rst @@ -0,0 +1,2 @@ +Fix ``dynamic_annotations.h`` header file when built with C++ and Valgrind: +add ``extern "C++" scope`` for the C++ template. Patch by Victor Stinner. From e8384cf1a0349871a7ec1d857b8e3c7037d727e9 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 5 Jun 2026 14:45:22 +0200 Subject: [PATCH 238/818] [3.15] gh-149891: Add more encoding aliases (GH-149892) (GH-150961) Support all aliases officially registered in IANA, except Extended_UNIX_Code_Packed_Format_for_Japanese. New names: KSC_5601, KS_C_5601-1989, iso-ir-149, GB_2312-80, windows-936, mac, CCSID00858, CCSID01140, and a number of "cs"-prefixed names. Fix csHPRoman8, which was not normalized. (cherry picked from commit 49f4ecfb08e6192ddc9f782553c775ccbdc2dfdb) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> --- Lib/encodings/aliases.py | 57 +++++++++++++++++-- ...-05-15-19-52-41.gh-issue-149891.BJUIGB.rst | 1 + 2 files changed, 53 insertions(+), 5 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-05-15-19-52-41.gh-issue-149891.BJUIGB.rst diff --git a/Lib/encodings/aliases.py b/Lib/encodings/aliases.py index df4c230fbf9c4e..ef51168d755ba9 100644 --- a/Lib/encodings/aliases.py +++ b/Lib/encodings/aliases.py @@ -43,6 +43,7 @@ # big5hkscs codec 'big5_hkscs' : 'big5hkscs', + 'csbig5hkscs' : 'big5hkscs', 'hkscs' : 'big5hkscs', # bz2_codec codec @@ -71,6 +72,7 @@ # cp1140 codec '1140' : 'cp1140', + 'ccsid01140' : 'cp1140', 'cp01140' : 'cp1140', 'csibm01140' : 'cp1140', 'ebcdic_us_37_euro' : 'cp1140', @@ -79,38 +81,47 @@ # cp1250 codec '1250' : 'cp1250', + 'cswindows1250' : 'cp1250', 'windows_1250' : 'cp1250', # cp1251 codec '1251' : 'cp1251', + 'cswindows1251' : 'cp1251', 'windows_1251' : 'cp1251', # cp1252 codec '1252' : 'cp1252', + 'cswindows1252' : 'cp1252', 'windows_1252' : 'cp1252', # cp1253 codec '1253' : 'cp1253', + 'cswindows1253' : 'cp1253', 'windows_1253' : 'cp1253', # cp1254 codec '1254' : 'cp1254', + 'cswindows1254' : 'cp1254', 'windows_1254' : 'cp1254', # cp1255 codec '1255' : 'cp1255', + 'cswindows1255' : 'cp1255', 'windows_1255' : 'cp1255', # cp1256 codec '1256' : 'cp1256', + 'cswindows1256' : 'cp1256', 'windows_1256' : 'cp1256', # cp1257 codec '1257' : 'cp1257', + 'cswindows1257' : 'cp1257', 'windows_1257' : 'cp1257', # cp1258 codec '1258' : 'cp1258', + 'cswindows1258' : 'cp1258', 'windows_1258' : 'cp1258', # cp273 codec @@ -163,6 +174,7 @@ # cp858 codec '858' : 'cp858', + 'ccsid00858' : 'cp858', 'cp00858' : 'cp858', 'csibm00858' : 'cp858', 'csibm858' : 'cp858', @@ -214,11 +226,13 @@ # cp874 codec '874' : 'cp874', + 'cswindows874' : 'cp874', 'ms874' : 'cp874', 'windows_874' : 'cp874', # cp932 codec '932' : 'cp932', + 'cswindows31j' : 'cp932', 'ms932' : 'cp932', 'mskanji' : 'cp932', 'ms_kanji' : 'cp932', @@ -226,10 +240,14 @@ # cp949 codec '949' : 'cp949', + 'csksc56011987' : 'cp949', + 'iso_ir_149' : 'cp949', 'korean' : 'cp949', + 'ks_c_5601_1987' : 'cp949', + 'ks_c_5601_1989' : 'cp949', 'ksc5601' : 'cp949', 'ks_c_5601' : 'cp949', - 'ks_c_5601_1987' : 'cp949', + 'ksc_5601' : 'cp949', 'ksx1001' : 'cp949', 'ks_x_1001' : 'cp949', 'ms949' : 'cp949', @@ -248,41 +266,47 @@ 'eucjisx0213' : 'euc_jisx0213', # euc_jp codec + 'cseucpkdfmtjapanese' : 'euc_jp', 'eucjp' : 'euc_jp', 'ujis' : 'euc_jp', 'u_jis' : 'euc_jp', # euc_kr codec - 'euckr' : 'euc_kr', 'cseuckr' : 'euc_kr', + 'euckr' : 'euc_kr', # gb18030 codec + 'csgb18030' : 'gb18030', 'gb18030_2000' : 'gb18030', # gb2312 codec 'chinese' : 'gb2312', + 'csgb2312' : 'gb2312', 'csiso58gb231280' : 'gb2312', 'euc_cn' : 'gb2312', 'euccn' : 'gb2312', 'eucgb2312_cn' : 'gb2312', 'gb2312_1980' : 'gb2312', 'gb2312_80' : 'gb2312', + 'gb_2312_80' : 'gb2312', 'iso_ir_58' : 'gb2312', # gbk codec '936' : 'gbk', 'cp936' : 'gbk', + 'csgbk' : 'gbk', 'ms936' : 'gbk', + 'windows_936' : 'gbk', # hex_codec codec 'hex' : 'hex_codec', # hp_roman8 codec - 'roman8' : 'hp_roman8', - 'r8' : 'hp_roman8', - 'csHPRoman8' : 'hp_roman8', 'cp1051' : 'hp_roman8', + 'cshproman8' : 'hp_roman8', 'ibm1051' : 'hp_roman8', + 'r8' : 'hp_roman8', + 'roman8' : 'hp_roman8', # hz codec 'hzgb' : 'hz', @@ -299,6 +323,7 @@ 'iso_2022_jp_1' : 'iso2022_jp_1', # iso2022_jp_2 codec + 'csiso2022jp2' : 'iso2022_jp_2', 'iso2022jp_2' : 'iso2022_jp_2', 'iso_2022_jp_2' : 'iso2022_jp_2', @@ -334,12 +359,14 @@ 'iso_8859_11_2001' : 'iso8859_11', # iso8859_13 codec + 'csiso885913' : 'iso8859_13', 'iso_8859_13' : 'iso8859_13', 'l7' : 'iso8859_13', 'latin7' : 'iso8859_13', 'latin_7' : 'iso8859_13', # iso8859_14 codec + 'csiso885914' : 'iso8859_14', 'iso_8859_14' : 'iso8859_14', 'iso_8859_14_1998' : 'iso8859_14', 'iso_celtic' : 'iso8859_14', @@ -349,12 +376,14 @@ 'latin_8' : 'iso8859_14', # iso8859_15 codec + 'csiso885915' : 'iso8859_15', 'iso_8859_15' : 'iso8859_15', 'l9' : 'iso8859_15', 'latin9' : 'iso8859_15', 'latin_9' : 'iso8859_15', # iso8859_16 codec + 'csiso885916' : 'iso8859_16', 'iso_8859_16' : 'iso8859_16', 'iso_8859_16_2001' : 'iso8859_16', 'iso_ir_226' : 'iso8859_16', @@ -416,6 +445,8 @@ 'iso_ir_126' : 'iso8859_7', # iso8859_8 codec + 'csiso88598e' : 'iso8859_8', + 'csiso88598i' : 'iso8859_8', 'csisolatinhebrew' : 'iso8859_8', 'hebrew' : 'iso8859_8', 'iso_8859_8' : 'iso8859_8', @@ -440,7 +471,11 @@ # koi8_r codec 'cskoi8r' : 'koi8_r', + # koi8_u codec + 'cskoi8u' : 'koi8_u', + # kz1048 codec + 'cskz1048' : 'kz1048', 'kz_1048' : 'kz1048', 'rk1048' : 'kz1048', 'strk1048_2002' : 'kz1048', @@ -480,7 +515,9 @@ 'maclatin2' : 'mac_latin2', # mac_roman codec + 'csmacintosh' : 'mac_roman', 'macintosh' : 'mac_roman', + 'mac' : 'mac_roman', 'macroman' : 'mac_roman', # mac_turkish codec @@ -521,6 +558,7 @@ 's_jisx0213' : 'shift_jisx0213', # tis_620 codec + 'cstis620' : 'tis_620', 'tis620' : 'tis_620', 'tis_620_0' : 'tis_620', 'tis_620_2529_0' : 'tis_620', @@ -528,33 +566,42 @@ 'iso_ir_166' : 'tis_620', # utf_16 codec + 'csutf16' : 'utf_16', 'u16' : 'utf_16', 'utf16' : 'utf_16', # utf_16_be codec + 'csutf16be' : 'utf_16_be', 'unicodebigunmarked' : 'utf_16_be', 'utf_16be' : 'utf_16_be', # utf_16_le codec + 'csutf16le' : 'utf_16_le', 'unicodelittleunmarked' : 'utf_16_le', 'utf_16le' : 'utf_16_le', # utf_32 codec + 'csutf32' : 'utf_32', 'u32' : 'utf_32', 'utf32' : 'utf_32', # utf_32_be codec + 'csutf32be' : 'utf_32_be', 'utf_32be' : 'utf_32_be', # utf_32_le codec + 'csutf32le' : 'utf_32_le', 'utf_32le' : 'utf_32_le', # utf_7 codec + 'csunicode11utf7' : 'utf_7', + 'csutf7' : 'utf_7', 'u7' : 'utf_7', 'utf7' : 'utf_7', 'unicode_1_1_utf_7' : 'utf_7', # utf_8 codec + 'csutf8' : 'utf_8', 'u8' : 'utf_8', 'utf' : 'utf_8', 'utf8' : 'utf_8', diff --git a/Misc/NEWS.d/next/Library/2026-05-15-19-52-41.gh-issue-149891.BJUIGB.rst b/Misc/NEWS.d/next/Library/2026-05-15-19-52-41.gh-issue-149891.BJUIGB.rst new file mode 100644 index 00000000000000..f8bc28659533af --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-05-15-19-52-41.gh-issue-149891.BJUIGB.rst @@ -0,0 +1 @@ +Add support for more encoding aliases `officially registered in IANA <https://www.iana.org/assignments/character-sets/character-sets.xhtml>`__. From 68f814eb7151d7bd3e0780c78fcd9571f0312496 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 5 Jun 2026 15:22:33 +0200 Subject: [PATCH 239/818] [3.15] gh-53144: Improve charset support in the email package (GH-149942) (GH-150967) Defer to the codecs module for all aliases. Use MIME/IANA names for all IANA registered charsets. Fix email.contentmanager.set_text_content(). (cherry picked from commit c195a046f81d986dce22743d85e2500fe282e8a9) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> --- Lib/email/charset.py | 104 ++++++++++---- Lib/email/contentmanager.py | 6 +- Lib/test/test_email/test_asian_codecs.py | 6 +- Lib/test/test_email/test_contentmanager.py | 13 ++ Lib/test/test_email/test_email.py | 127 ++++++++++++++++++ ...6-05-17-12-37-59.gh-issue-53144.c5tr1p.rst | 2 + 6 files changed, 223 insertions(+), 35 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-05-17-12-37-59.gh-issue-53144.c5tr1p.rst diff --git a/Lib/email/charset.py b/Lib/email/charset.py index c4b246455f86c6..5981791820e740 100644 --- a/Lib/email/charset.py +++ b/Lib/email/charset.py @@ -9,6 +9,7 @@ 'add_codec', ] +import codecs from functools import partial import email.base64mime @@ -58,37 +59,71 @@ 'shift_jis': (BASE64, None, 'iso-2022-jp'), 'iso-2022-jp': (BASE64, None, None), 'koi8-r': (BASE64, BASE64, None), - 'utf-8': (SHORTEST, BASE64, 'utf-8'), } -# Aliases for other commonly-used names for character sets. Map -# them to the real ones used in email. +# Map Python codec names to their corresponding MIME/IANA names. ALIASES = { - 'latin_1': 'iso-8859-1', - 'latin-1': 'iso-8859-1', - 'latin_2': 'iso-8859-2', - 'latin-2': 'iso-8859-2', - 'latin_3': 'iso-8859-3', - 'latin-3': 'iso-8859-3', - 'latin_4': 'iso-8859-4', - 'latin-4': 'iso-8859-4', - 'latin_5': 'iso-8859-9', - 'latin-5': 'iso-8859-9', - 'latin_6': 'iso-8859-10', - 'latin-6': 'iso-8859-10', - 'latin_7': 'iso-8859-13', - 'latin-7': 'iso-8859-13', - 'latin_8': 'iso-8859-14', - 'latin-8': 'iso-8859-14', - 'latin_9': 'iso-8859-15', - 'latin-9': 'iso-8859-15', - 'latin_10':'iso-8859-16', - 'latin-10':'iso-8859-16', - 'cp949': 'ks_c_5601-1987', - 'euc_jp': 'euc-jp', - 'euc_kr': 'euc-kr', - 'ascii': 'us-ascii', - } + 'ascii': 'us-ascii', + 'big5hkscs': 'big5-hkscs', + 'cp037': 'ibm037', + 'cp1026': 'ibm1026', + 'cp1140': 'ibm01140', + 'cp1250': 'windows-1250', + 'cp1251': 'windows-1251', + 'cp1252': 'windows-1252', + 'cp1253': 'windows-1253', + 'cp1254': 'windows-1254', + 'cp1255': 'windows-1255', + 'cp1256': 'windows-1256', + 'cp1257': 'windows-1257', + 'cp1258': 'windows-1258', + 'cp273': 'ibm273', + 'cp424': 'ibm424', + 'cp437': 'ibm437', + 'cp500': 'ibm500', + 'cp775': 'ibm775', + 'cp850': 'ibm850', + 'cp852': 'ibm852', + 'cp855': 'ibm855', + 'cp857': 'ibm857', + 'cp858': 'ibm00858', + 'cp860': 'ibm860', + 'cp861': 'ibm861', + 'cp862': 'ibm862', + 'cp863': 'ibm863', + 'cp864': 'ibm864', + 'cp865': 'ibm865', + 'cp866': 'ibm866', + 'cp869': 'ibm869', + 'cp874': 'windows-874', + 'euc_jp': 'euc-jp', + 'euc_kr': 'euc-kr', + 'hz': 'hz-gb-2312', + 'iso2022_jp': 'iso-2022-jp', + 'iso2022_jp_2': 'iso-2022-jp-2', + 'iso2022_kr': 'iso-2022-kr', + 'iso8859-1': 'iso-8859-1', + 'iso8859-10': 'iso-8859-10', + 'iso8859-11': 'iso-8859-11', + 'iso8859-13': 'iso-8859-13', + 'iso8859-14': 'iso-8859-14', + 'iso8859-15': 'iso-8859-15', + 'iso8859-16': 'iso-8859-16', + 'iso8859-2': 'iso-8859-2', + 'iso8859-3': 'iso-8859-3', + 'iso8859-4': 'iso-8859-4', + 'iso8859-5': 'iso-8859-5', + 'iso8859-6': 'iso-8859-6', + 'iso8859-7': 'iso-8859-7', + 'iso8859-8': 'iso-8859-8-i', + 'iso8859-9': 'iso-8859-9', + 'kz1048': 'kz-1048', + 'mac-roman': 'macintosh', + + # CP949 is not registered in IANA. KS_C_5601-1987 is not the same, + # but the closest registered option. + 'cp949': 'ks_c_5601-1987', +} # Map charsets to their Unicode codec strings. @@ -215,7 +250,18 @@ def __init__(self, input_charset=DEFAULT_CHARSET): raise errors.CharsetError(input_charset) input_charset = input_charset.lower() # Set the input charset after filtering through the aliases - self.input_charset = ALIASES.get(input_charset, input_charset) + # For backward compatibility, try ALIASES first to let the user + # override it. + if input_charset in ALIASES: + input_charset = ALIASES[input_charset] + else: + try: + input_codec = codecs.lookup(input_charset).name + except LookupError: + pass + else: + input_charset = ALIASES.get(input_codec, input_codec) + self.input_charset = input_charset # We can try to guess which encoding and conversion to use by the # charset_map dictionary. Try that first, but let the user override # it. diff --git a/Lib/email/contentmanager.py b/Lib/email/contentmanager.py index 13fcb9787f1f32..faf2626bccce65 100644 --- a/Lib/email/contentmanager.py +++ b/Lib/email/contentmanager.py @@ -173,11 +173,11 @@ def set_text_content(msg, string, subtype="plain", charset='utf-8', cte=None, disposition=None, filename=None, cid=None, params=None, headers=None): _prepare_set(msg, 'text', subtype, headers) + + charset = email.charset.Charset(charset).input_charset cte, payload = _encode_text(string, charset, cte, msg.policy) msg.set_payload(payload) - msg.set_param('charset', - email.charset.ALIASES.get(charset, charset), - replace=True) + msg.set_param('charset', charset, replace=True) msg['Content-Transfer-Encoding'] = cte _finalize_set(msg, disposition, filename, cid, params) raw_data_manager.add_set_handler(str, set_text_content) diff --git a/Lib/test/test_email/test_asian_codecs.py b/Lib/test/test_email/test_asian_codecs.py index 85979ffd8169a7..59013f087199e3 100644 --- a/Lib/test/test_email/test_asian_codecs.py +++ b/Lib/test/test_email/test_asian_codecs.py @@ -83,15 +83,15 @@ def test_chinese_codecs(self): h.append(s, Charset('big5hkscs')) eq(h.encode(), """\ Chinese =?gb2312?b?1tDOxA==?= =?gbk?b?1tDOxA==?= =?gb18030?b?1tDOxA==?= - =?hz?b?fntWUE5Efn0=?= =?big5?b?pKSk5Q==?= =?big5hkscs?b?pKSk5Q==?=""") + =?hz-gb-2312?b?fntWUE5Efn0=?= =?big5?b?pKSk5Q==?= =?big5-hkscs?b?pKSk5Q==?=""") eq(decode_header(h.encode()), [(b'Chinese ', None), (b'\xd6\xd0\xce\xc4', 'gb2312'), (b'\xd6\xd0\xce\xc4', 'gbk'), (b'\xd6\xd0\xce\xc4', 'gb18030'), - (b'~{VPND~}', 'hz'), + (b'~{VPND~}', 'hz-gb-2312'), (b'\xa4\xa4\xa4\xe5', 'big5'), - (b'\xa4\xa4\xa4\xe5', 'big5hkscs'), + (b'\xa4\xa4\xa4\xe5', 'big5-hkscs'), ]) def test_korean_codecs(self): diff --git a/Lib/test/test_email/test_contentmanager.py b/Lib/test/test_email/test_contentmanager.py index dceb54f15e48f4..bc0e5d35618159 100644 --- a/Lib/test/test_email/test_contentmanager.py +++ b/Lib/test/test_email/test_contentmanager.py @@ -342,6 +342,19 @@ def test_set_text_charset_latin_1(self): self.assertEqual(m.get_payload(decode=True).decode('utf-8'), content) self.assertEqual(m.get_content(), content) + def test_set_text_charset_cp949(self): + m = self._make_message() + content = "\ud55c\uad6d\uc5b4\n\uac02\n" + raw_data_manager.set_content(m, content, charset='cp949') + self.assertEqual(str(m), textwrap.dedent("""\ + Content-Type: text/plain; charset="ks_c_5601-1987" + Content-Transfer-Encoding: base64 + + x9Gxub7uCoFBCg== + """)) + self.assertEqual(m.get_payload(decode=True).decode('ks_c_5601-1987'), content) + self.assertEqual(m.get_content(), content) + def test_set_text_plain_long_line_heuristics(self): m = self._make_message() content = ("Simple but long message that is over 78 characters" diff --git a/Lib/test/test_email/test_email.py b/Lib/test/test_email/test_email.py index d2c2261edbe04e..19555d87085e17 100644 --- a/Lib/test/test_email/test_email.py +++ b/Lib/test/test_email/test_email.py @@ -4970,6 +4970,128 @@ def tearDown(self): except KeyError: pass + def test_attributes(self): + from email import charset + c = Charset() + self.assertEqual(c.input_charset, 'us-ascii') + self.assertEqual(c.header_encoding, None) + self.assertEqual(c.body_encoding, None) + self.assertEqual(c.output_charset, 'us-ascii') + self.assertEqual(c.input_codec, None) + self.assertEqual(c.output_codec, None) + + c = Charset('us-ascii') + self.assertEqual(c.input_charset, 'us-ascii') + self.assertEqual(c.header_encoding, None) + self.assertEqual(c.body_encoding, None) + self.assertEqual(c.output_charset, 'us-ascii') + self.assertEqual(c.input_codec, None) + self.assertEqual(c.output_codec, None) + + c = Charset('utf8') + self.assertEqual(c.input_charset, 'utf-8') + self.assertEqual(c.header_encoding, charset.SHORTEST) + self.assertEqual(c.body_encoding, charset.BASE64) + self.assertEqual(c.output_charset, 'utf-8') + self.assertEqual(c.input_codec, 'utf-8') + self.assertEqual(c.output_codec, 'utf-8') + + c = Charset('latin1') + self.assertEqual(c.input_charset, 'iso-8859-1') + self.assertEqual(c.header_encoding, charset.QP) + self.assertEqual(c.body_encoding, charset.QP) + self.assertEqual(c.output_charset, 'iso-8859-1') + self.assertEqual(c.input_codec, 'iso-8859-1') + self.assertEqual(c.output_codec, 'iso-8859-1') + + c = Charset('latin9') + self.assertEqual(c.input_charset, 'iso-8859-15') + self.assertEqual(c.header_encoding, charset.QP) + self.assertEqual(c.body_encoding, charset.QP) + self.assertEqual(c.output_charset, 'iso-8859-15') + self.assertEqual(c.input_codec, 'iso-8859-15') + self.assertEqual(c.output_codec, 'iso-8859-15') + + c = Charset('cyrillic') + self.assertEqual(c.input_charset, 'iso-8859-5') + self.assertEqual(c.header_encoding, charset.SHORTEST) + self.assertEqual(c.body_encoding, charset.BASE64) + self.assertEqual(c.output_charset, 'iso-8859-5') + self.assertEqual(c.input_codec, 'iso-8859-5') + self.assertEqual(c.output_codec, 'iso-8859-5') + + c = Charset('cp1251') + self.assertEqual(c.input_charset, 'windows-1251') + self.assertEqual(c.header_encoding, charset.SHORTEST) + self.assertEqual(c.body_encoding, charset.BASE64) + self.assertEqual(c.output_charset, 'windows-1251') + self.assertEqual(c.input_codec, 'windows-1251') + self.assertEqual(c.output_codec, 'windows-1251') + + c = Charset('cp1252') + self.assertEqual(c.input_charset, 'windows-1252') + self.assertEqual(c.header_encoding, charset.QP) + self.assertEqual(c.body_encoding, charset.QP) + self.assertEqual(c.output_charset, 'windows-1252') + self.assertEqual(c.input_codec, 'windows-1252') + self.assertEqual(c.output_codec, 'windows-1252') + + c = Charset('eucjp') + self.assertEqual(c.input_charset, 'euc-jp') + self.assertEqual(c.header_encoding, charset.BASE64) + self.assertEqual(c.body_encoding, None) + self.assertEqual(c.output_charset, 'iso-2022-jp') + self.assertEqual(c.input_codec, 'euc-jp') + self.assertEqual(c.output_codec, 'iso-2022-jp') + + c = Charset('cp949') + self.assertEqual(c.input_charset, 'ks_c_5601-1987') + self.assertEqual(c.header_encoding, charset.SHORTEST) + self.assertEqual(c.body_encoding, charset.BASE64) + self.assertEqual(c.output_charset, 'ks_c_5601-1987') + self.assertEqual(c.input_codec, 'ks_c_5601-1987') + self.assertEqual(c.output_codec, 'ks_c_5601-1987') + + c = Charset('gb2312') + self.assertEqual(c.input_charset, 'gb2312') + self.assertEqual(c.header_encoding, charset.BASE64) + self.assertEqual(c.body_encoding, charset.BASE64) + self.assertEqual(c.output_charset, 'gb2312') + self.assertEqual(c.input_codec, 'gb2312') + self.assertEqual(c.output_codec, 'gb2312') + + c = Charset('big5') + self.assertEqual(c.input_charset, 'big5') + self.assertEqual(c.header_encoding, charset.BASE64) + self.assertEqual(c.body_encoding, charset.BASE64) + self.assertEqual(c.output_charset, 'big5') + self.assertEqual(c.input_codec, 'big5') + self.assertEqual(c.output_codec, 'big5') + + def test_user_charsets(self): + from email import charset + c = Charset('fake0') + self.assertEqual(c.input_charset, 'fake0') + self.assertEqual(c.header_encoding, charset.SHORTEST) + self.assertEqual(c.body_encoding, charset.BASE64) + self.assertEqual(c.output_charset, 'fake0') + self.assertEqual(c.input_codec, 'fake0') + self.assertEqual(c.output_codec, 'fake0') + + charset.add_alias('fake1', 'mime-fake') + charset.add_alias('output-mime-fake', 'output-mime-fake-alias') + charset.add_codec('mime-fake', 'fakecodec') + charset.add_codec('output-mime-fake-alias', 'outputfakecodec') + charset.add_charset('mime-fake', charset.QP, None, 'output-mime-fake') + + c = Charset('fake1') + self.assertEqual(c.input_charset, 'mime-fake') + self.assertEqual(c.header_encoding, charset.QP) + self.assertEqual(c.body_encoding, None) + self.assertEqual(c.output_charset, 'output-mime-fake-alias') + self.assertEqual(c.input_codec, 'fakecodec') + self.assertEqual(c.output_codec, 'outputfakecodec') + def test_codec_encodeable(self): eq = self.assertEqual # Make sure us-ascii = no Unicode conversion @@ -5010,6 +5132,11 @@ def test_unicode_charset_name(self): self.assertEqual(str(charset), 'us-ascii') self.assertRaises(errors.CharsetError, Charset, 'asc\xffii') + def test_bytes_charset_name(self): + charset = Charset(b'us-ascii') + self.assertEqual(str(charset), 'us-ascii') + self.assertRaises(errors.CharsetError, Charset, b'asc\xffii') + # Test multilingual MIME headers. diff --git a/Misc/NEWS.d/next/Library/2026-05-17-12-37-59.gh-issue-53144.c5tr1p.rst b/Misc/NEWS.d/next/Library/2026-05-17-12-37-59.gh-issue-53144.c5tr1p.rst new file mode 100644 index 00000000000000..283a5ba44d1f19 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-05-17-12-37-59.gh-issue-53144.c5tr1p.rst @@ -0,0 +1,2 @@ +The :mod:`email` package now supports all aliases of Python codecs and uses +MIME/IANA names for all IANA registered charsets. From 06ffcde725c6ee30c4717bd2c2375f6019d172c1 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 5 Jun 2026 16:11:37 +0200 Subject: [PATCH 240/818] [3.15] gh-146527: Fix memory leak in _PyGC_Fini() (GH-150969) (#150970) gh-146527: Fix memory leak in _PyGC_Fini() (GH-150969) Free generation_stats allocated by _PyGC_Init(). Fix Python/gc.c: Python/gc_free_threading.c was already fixed. (cherry picked from commit 0036565e81b9580d645862bcc6249e2ae4f1fd03) Co-authored-by: Victor Stinner <vstinner@python.org> --- Python/gc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Python/gc.c b/Python/gc.c index 54ac1b089e503d..201c621bcc3cb9 100644 --- a/Python/gc.c +++ b/Python/gc.c @@ -1876,6 +1876,8 @@ _PyGC_Fini(PyInterpreterState *interp) GCState *gcstate = &interp->gc; Py_CLEAR(gcstate->garbage); Py_CLEAR(gcstate->callbacks); + PyMem_RawFree(gcstate->generation_stats); + gcstate->generation_stats = NULL; /* Prevent a subtle bug that affects sub-interpreters that use basic * single-phase init extensions (m_size == -1). Those extensions cause objects From d0a263d6d6c94272249d76e139ce80f749103bfe Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 5 Jun 2026 17:46:57 +0200 Subject: [PATCH 241/818] [3.15] gh-149977: Fix extra output of `-m test test_lazy_import`, again (GH-150965) (#150975) gh-149977: Fix extra output of `-m test test_lazy_import`, again (GH-150965) (cherry picked from commit 9b4090c48e0b5e51f15ca0c52f7c173de71e3ba6) Co-authored-by: sobolevn <mail@sobolevn.me> --- Lib/test/test_lazy_import/__init__.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_lazy_import/__init__.py b/Lib/test/test_lazy_import/__init__.py index 2a82ac78fb90fb..aeb275b958ec5e 100644 --- a/Lib/test/test_lazy_import/__init__.py +++ b/Lib/test/test_lazy_import/__init__.py @@ -447,11 +447,15 @@ def test_lazy_import_pkg(self): def test_lazy_submodule_stored_in_parent_dict(self): """Accessing a lazy submodule should store it in the parent's __dict__.""" - import test.test_lazy_import.data.lazy_import_pkg + out = io.StringIO() + + with contextlib.redirect_stdout(out): + import test.test_lazy_import.data.lazy_import_pkg pkg = sys.modules["test.test_lazy_import.data.pkg"] self.assertIn("bar", pkg.__dict__) self.assertIs(pkg.__dict__["bar"], sys.modules["test.test_lazy_import.data.pkg.bar"]) + self.assertIn("BAR_MODULE_LOADED", out.getvalue()) def test_lazy_import_pkg_cross_import(self): """Cross-imports within package should preserve lazy imports.""" From 4a3d6f9793fe7bfab3576f08a722c5003fb8b89e Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 6 Jun 2026 00:59:30 +0200 Subject: [PATCH 242/818] [3.15] Use `time.monotonic` in OrderedDict LRU cache example (GH-150986) (#150991) Use `time.monotonic` in OrderedDict LRU cache example (GH-150986) (cherry picked from commit ea4c85552bb7883e1d6c808281c1f46aca86aeab) Co-authored-by: Ilya Nikolaev <65247719+ilya-nikolaev@users.noreply.github.com> --- Doc/library/collections.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/library/collections.rst b/Doc/library/collections.rst index 25e4a71b03c6c8..0c727b71cf4d4b 100644 --- a/Doc/library/collections.rst +++ b/Doc/library/collections.rst @@ -1233,7 +1233,7 @@ variants of :func:`functools.lru_cache`: .. testcode:: from collections import OrderedDict - from time import time + from time import monotonic class TimeBoundedLRU: "LRU Cache that invalidates and refreshes old entries." @@ -1248,10 +1248,10 @@ variants of :func:`functools.lru_cache`: if args in self.cache: self.cache.move_to_end(args) timestamp, result = self.cache[args] - if time() - timestamp <= self.maxage: + if monotonic() - timestamp <= self.maxage: return result result = self.func(*args) - self.cache[args] = time(), result + self.cache[args] = monotonic(), result if len(self.cache) > self.maxsize: self.cache.popitem(last=False) return result From 934ae3ed153bc01ac44d43c5ad0fc3e01027f98f Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 6 Jun 2026 04:46:55 +0200 Subject: [PATCH 243/818] [3.15] gh-150207: Raise MemoryError on tokenizer allocation failure instead of crashing (GH-150275) (#150996) gh-150207: Raise MemoryError on tokenizer allocation failure instead of crashing (GH-150275) (cherry picked from commit 262625fa30e5a1b5cf33c9dbce5d2b713093c7be) Co-authored-by: Grant Herman <grantlouisherman041@gmail.com> --- .../2026-05-22-21-52-38.gh-issue-150207.l2BUtI.rst | 1 + Parser/lexer/state.c | 5 ++++- Parser/tokenizer/file_tokenizer.c | 1 + Parser/tokenizer/helpers.c | 2 ++ Parser/tokenizer/readline_tokenizer.c | 1 + 5 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-05-22-21-52-38.gh-issue-150207.l2BUtI.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-22-21-52-38.gh-issue-150207.l2BUtI.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-22-21-52-38.gh-issue-150207.l2BUtI.rst new file mode 100644 index 00000000000000..12fbffcd170684 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-22-21-52-38.gh-issue-150207.l2BUtI.rst @@ -0,0 +1 @@ +Fix a crash when a memory allocation fails during tokenizer initialization. A proper :exc:`MemoryError` is now raised instead. diff --git a/Parser/lexer/state.c b/Parser/lexer/state.c index 3663dc3eb7f9f6..5cf9b4d768c3eb 100644 --- a/Parser/lexer/state.c +++ b/Parser/lexer/state.c @@ -15,8 +15,11 @@ _PyTokenizer_tok_new(void) struct tok_state *tok = (struct tok_state *)PyMem_Calloc( 1, sizeof(struct tok_state)); - if (tok == NULL) + if (tok == NULL) { + PyErr_NoMemory(); return NULL; + } + tok->buf = tok->cur = tok->inp = NULL; tok->fp_interactive = 0; tok->interactive_src_start = NULL; diff --git a/Parser/tokenizer/file_tokenizer.c b/Parser/tokenizer/file_tokenizer.c index 8c836a3f725829..a11702557a07af 100644 --- a/Parser/tokenizer/file_tokenizer.c +++ b/Parser/tokenizer/file_tokenizer.c @@ -378,6 +378,7 @@ _PyTokenizer_FromFile(FILE *fp, const char* enc, return NULL; if ((tok->buf = (char *)PyMem_Malloc(BUFSIZ)) == NULL) { _PyTokenizer_Free(tok); + PyErr_NoMemory(); return NULL; } tok->cur = tok->inp = tok->buf; diff --git a/Parser/tokenizer/helpers.c b/Parser/tokenizer/helpers.c index 9542969ad3127b..c69e66d0ab9b7a 100644 --- a/Parser/tokenizer/helpers.c +++ b/Parser/tokenizer/helpers.c @@ -193,6 +193,7 @@ _PyTokenizer_new_string(const char *s, Py_ssize_t len, struct tok_state *tok) char* result = (char *)PyMem_Malloc(len + 1); if (!result) { tok->done = E_NOMEM; + PyErr_NoMemory(); return NULL; } memcpy(result, s, len); @@ -221,6 +222,7 @@ _PyTokenizer_translate_newlines(const char *s, int exec_input, int preserve_crlf buf = PyMem_Malloc(needed_length); if (buf == NULL) { tok->done = E_NOMEM; + PyErr_NoMemory(); return NULL; } for (current = buf; *s; s++, current++) { diff --git a/Parser/tokenizer/readline_tokenizer.c b/Parser/tokenizer/readline_tokenizer.c index 0f7769aeb8fd57..917f7b40cfbbfe 100644 --- a/Parser/tokenizer/readline_tokenizer.c +++ b/Parser/tokenizer/readline_tokenizer.c @@ -114,6 +114,7 @@ _PyTokenizer_FromReadline(PyObject* readline, const char* enc, return NULL; if ((tok->buf = (char *)PyMem_Malloc(BUFSIZ)) == NULL) { _PyTokenizer_Free(tok); + PyErr_NoMemory(); return NULL; } tok->cur = tok->inp = tok->buf; From 0a2e7af44bba26265ba9932fd9637bf1954d1806 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 6 Jun 2026 12:29:57 +0200 Subject: [PATCH 244/818] [3.15] gh-149835: Use realpath() instead of abspath() in shutil.move() (GH-149986) (GH-151009) (cherry picked from commit fab449bddbc4ff03677d49448cf6ea1f9d6a319f) Co-authored-by: Thomas Kowalski <thom.kowa@gmail.com> --- Lib/shutil.py | 4 ++-- Lib/test/test_shutil.py | 17 +++++++++++++++++ ...26-05-18-17-46-00.gh-issue-149835.EebFlk.rst | 3 +++ 3 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Security/2026-05-18-17-46-00.gh-issue-149835.EebFlk.rst diff --git a/Lib/shutil.py b/Lib/shutil.py index 45cbe4c855b462..d3ac5dc5c50a73 100644 --- a/Lib/shutil.py +++ b/Lib/shutil.py @@ -940,8 +940,8 @@ def move(src, dst, copy_function=copy2): return real_dst def _destinsrc(src, dst): - src = os.path.abspath(src) - dst = os.path.abspath(dst) + src = os.path.realpath(src) + dst = os.path.realpath(dst) if not src.endswith(os.path.sep): src += os.path.sep if not dst.endswith(os.path.sep): diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py index 13a3487382dfcf..c2485e20a19903 100644 --- a/Lib/test/test_shutil.py +++ b/Lib/test/test_shutil.py @@ -2914,6 +2914,23 @@ def test_destinsrc_false_positive(self): finally: os_helper.rmtree(TESTFN) + @os_helper.skip_unless_symlink + def test_destinsrc_symlink_bypass(self): + tmp = self.mkdtemp() + src = os.path.join(tmp, 'src') + os.makedirs(src) + # tmp/link -> tmp (one level up) + link = os.path.join(tmp, 'link') + os.symlink(tmp, link) + # raw path: tmp/link/src/sub - no src prefix in string space + # real path: tmp/src/sub - physically inside src + dst = os.path.join(link, 'src', 'sub') + self.assertTrue( + shutil._destinsrc(src, dst), + msg='_destinsrc failed to detect dst inside src via symlink ' + '(dst=%s, src=%s)' % (dst, src), + ) + @os_helper.skip_unless_symlink @mock_rename def test_move_file_symlink(self): diff --git a/Misc/NEWS.d/next/Security/2026-05-18-17-46-00.gh-issue-149835.EebFlk.rst b/Misc/NEWS.d/next/Security/2026-05-18-17-46-00.gh-issue-149835.EebFlk.rst new file mode 100644 index 00000000000000..20cab736552486 --- /dev/null +++ b/Misc/NEWS.d/next/Security/2026-05-18-17-46-00.gh-issue-149835.EebFlk.rst @@ -0,0 +1,3 @@ +:func:`shutil.move` now resolves symlinks via :func:`os.path.realpath` +when checking whether the destination is inside the source directory, +preventing a symlink-based bypass of that guard. From 3c1c9ba285ccfac4ae67f13312b118aefbad3d48 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 6 Jun 2026 13:59:53 +0200 Subject: [PATCH 245/818] [3.15] Delete mention encoding and errors for importlib.resources.path() (GH-143111) (GH-151014) (cherry picked from commit fded34d6fe8c300f5625b7fddb86a4c56ecc35c5) Co-authored-by: Alexander Shadchin <shadchin@yandex-team.com> --- Doc/library/importlib.resources.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/Doc/library/importlib.resources.rst b/Doc/library/importlib.resources.rst index 653fa61420be86..72db66f9f06f89 100644 --- a/Doc/library/importlib.resources.rst +++ b/Doc/library/importlib.resources.rst @@ -240,7 +240,6 @@ For all the following functions: .. versionchanged:: 3.13 Multiple *path_names* are accepted. - *encoding* and *errors* must be given as keyword arguments. .. function:: is_resource(anchor, *path_names) From ec9b40d740ef1f261ff19152505ad9c0d859b105 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 6 Jun 2026 14:06:37 +0200 Subject: [PATCH 246/818] [3.15] Doc: fix order of PyLong_FromUnsignedLongLong (GH-150937) (GH-151012) (cherry picked from commit 4833b2031edc97a79f44afacd2a8f40f51a9b2c5) Co-authored-by: Inada Naoki <songofacandy@gmail.com> --- Doc/c-api/long.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Doc/c-api/long.rst b/Doc/c-api/long.rst index 60e3ae4a064e72..874e422d4701dd 100644 --- a/Doc/c-api/long.rst +++ b/Doc/c-api/long.rst @@ -71,6 +71,12 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. on failure. +.. c:function:: PyObject* PyLong_FromUnsignedLongLong(unsigned long long v) + + Return a new :c:type:`PyLongObject` object from a C :c:expr:`unsigned long long`, + or ``NULL`` on failure. + + .. c:function:: PyObject* PyLong_FromInt32(int32_t value) PyObject* PyLong_FromInt64(int64_t value) @@ -81,12 +87,6 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. .. versionadded:: 3.14 -.. c:function:: PyObject* PyLong_FromUnsignedLongLong(unsigned long long v) - - Return a new :c:type:`PyLongObject` object from a C :c:expr:`unsigned long long`, - or ``NULL`` on failure. - - .. c:function:: PyObject* PyLong_FromUInt32(uint32_t value) PyObject* PyLong_FromUInt64(uint64_t value) From ad8a3d33be021288dbcb17ab3c8e1d01e31386da Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 6 Jun 2026 14:45:53 +0200 Subject: [PATCH 247/818] [3.15] gh-150662: Stop unbounded memory growth in Tachyon `--gecko` collector (GH-150845) (#151000) --- Lib/profiling/sampling/gecko_collector.py | 379 +++++++++++++----- .../test_sampling_profiler/test_collectors.py | 203 ++++++++-- ...-06-03-13-51-29.gh-issue-150662.ELT8Vg.rst | 4 + 3 files changed, 454 insertions(+), 132 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-06-03-13-51-29.gh-issue-150662.ELT8Vg.rst diff --git a/Lib/profiling/sampling/gecko_collector.py b/Lib/profiling/sampling/gecko_collector.py index 54392af9500008..361f6037f216fd 100644 --- a/Lib/profiling/sampling/gecko_collector.py +++ b/Lib/profiling/sampling/gecko_collector.py @@ -1,8 +1,10 @@ import itertools +import io import json import os import platform import sys +import tempfile import threading import time @@ -61,6 +63,77 @@ PROCESS_TYPE_MAIN = 0 STACKWALK_DISABLED = 0 +# In-memory buffer before spilling to disk +DEFAULT_SPILL_BUFFER_BYTES = 128 * 1024 +_JSON_SEPARATORS = (",", ":") +_JSON_ENCODER = json.JSONEncoder( + separators=_JSON_SEPARATORS, allow_nan=False +) + + +class SpillColumn: + def __init__(self, directory, basename, *, + buffer_bytes=None): + self.path = os.path.join(directory, basename) + self.buffer = bytearray() + self._buffer_bytes = ( + DEFAULT_SPILL_BUFFER_BYTES if buffer_bytes is None + else buffer_bytes + ) + + def append(self, value): + self.buffer += (_JSON_ENCODER.encode(value) + "\n").encode("utf-8") + if len(self.buffer) >= self._buffer_bytes: + self.flush() + + def flush(self): + with open(self.path, "ab") as file: + file.write(self.buffer) + self.buffer.clear() + + def iter_tokens(self): + with open(self.path, encoding="utf-8") as file: + for line in file: + yield line.rstrip("\n") + + +class GeckoThreadSpill: + _COLUMNS = ( + ("samples_stack", "samples-stack.json"), + ("samples_time", "samples-time.json"), + ("markers_name", "markers-name.json"), + ("markers_start_time", "markers-start-time.json"), + ("markers_end_time", "markers-end-time.json"), + ("markers_phase", "markers-phase.json"), + ("markers_category", "markers-category.json"), + ("markers_data", "markers-data.json"), + ) + + def __init__(self, directory, tid): + prefix = f"thread-{tid}-" + for attr, basename in self._COLUMNS: + setattr(self, attr, SpillColumn(directory, prefix + basename)) + self.sample_count = 0 + self.marker_count = 0 + + def append_sample(self, stack_index, time_ms): + self.samples_stack.append(stack_index) + self.samples_time.append(time_ms) + self.sample_count += 1 + + def append_marker(self, name_idx, start_time, end_time, phase, category, data): + self.markers_name.append(name_idx) + self.markers_start_time.append(start_time) + self.markers_end_time.append(end_time) + self.markers_phase.append(phase) + self.markers_category.append(category) + self.markers_data.append(data) + self.marker_count += 1 + + def prepare_read(self): + for attr, _basename in self._COLUMNS: + getattr(self, attr).flush() + class GeckoCollector(Collector): aggregating = True @@ -77,6 +150,8 @@ def __init__(self, sample_interval_usec, *, skip_idle=False, opcodes=False): # Per-thread data structures self.threads = {} # tid -> thread data + self.spill_dir = None + self.exported = False # Global tables self.libs = [] @@ -151,6 +226,9 @@ def collect(self, stack_frames, timestamps_us=None): stack_frames: List of interpreter/thread frame info timestamps_us: List of timestamps in microseconds (None for live sampling) """ + if self.exported: + raise RuntimeError("cannot append to GeckoCollector after export") + # Handle live sampling (no timestamps provided) if timestamps_us is None: current_time = (time.monotonic() * 1000) - self.start_time @@ -259,15 +337,9 @@ def collect(self, stack_frames, timestamps_us=None): stack_index = self._process_stack(thread_data, frames) # Add samples with timestamps - samples = thread_data["samples"] - samples_stack = samples["stack"] - samples_time = samples["time"] - samples_delay = samples["eventDelay"] - + thread_spill = thread_data["_spill"] for t in times: - samples_stack.append(stack_index) - samples_time.append(t) - samples_delay.append(None) + thread_spill.append_sample(stack_index, t) # Handle opcodes if self.opcodes_enabled and frames: @@ -294,6 +366,8 @@ def collect(self, stack_frames, timestamps_us=None): def _create_thread(self, tid, is_main_thread): """Create a new thread structure with processed profile format.""" + if self.spill_dir is None: + self.spill_dir = tempfile.TemporaryDirectory() thread = { "name": f"Thread-{tid}", @@ -307,15 +381,6 @@ def _create_thread(self, tid, is_main_thread): "tid": tid, "processType": "default", "processName": "Python Process", - # Sample data - processed format with direct arrays - "samples": { - "stack": [], - "time": [], - "eventDelay": [], - "weight": None, - "weightType": "samples", - "length": 0, # Will be updated on export - }, # Stack table - processed format "stackTable": { "frame": [], @@ -366,21 +431,12 @@ def _create_thread(self, tid, is_main_thread): "functionSize": [], "length": 0, }, - # Markers - processed format (arrays) - "markers": { - "data": [], - "name": [], - "startTime": [], - "endTime": [], - "phase": [], - "category": [], - "length": 0, - }, # Caches for deduplication "_stackCache": {}, "_frameCache": {}, "_funcCache": {}, "_resourceCache": {}, + "_spill": GeckoThreadSpill(self.spill_dir.name, tid), } return thread @@ -405,51 +461,42 @@ def _add_marker(self, tid, name, start_time, end_time, category): if tid not in self.threads: return - thread_data = self.threads[tid] duration = end_time - start_time name_idx = self._intern_string(name) - markers = thread_data["markers"] - markers["name"].append(name_idx) - markers["startTime"].append(start_time) - markers["endTime"].append(end_time) - markers["phase"].append(1) # 1 = interval marker - markers["category"].append(category) - markers["data"].append({ - "type": name.replace(" ", ""), - "duration": duration, - "tid": tid - }) - - def _add_opcode_interval_marker(self, tid, opcode, lineno, col_offset, funcname, start_time, end_time): + self.threads[tid]["_spill"].append_marker( + name_idx, start_time, end_time, 1, category, { + "type": name.replace(" ", ""), + "duration": duration, + "tid": tid, + } + ) + + def _add_opcode_interval_marker(self, tid, opcode, lineno, col_offset, + funcname, start_time, end_time): """Add an interval marker for opcode execution span.""" if tid not in self.threads or opcode is None: return - thread_data = self.threads[tid] opcode_info = get_opcode_info(opcode) # Use formatted opcode name (with base opcode for specialized ones) formatted_opname = format_opcode(opcode) name_idx = self._intern_string(formatted_opname) - markers = thread_data["markers"] - markers["name"].append(name_idx) - markers["startTime"].append(start_time) - markers["endTime"].append(end_time) - markers["phase"].append(1) # 1 = interval marker - markers["category"].append(CATEGORY_OPCODES) - markers["data"].append({ - "type": "Opcode", - "opcode": opcode, - "opname": formatted_opname, - "base_opname": opcode_info["base_opname"], - "is_specialized": opcode_info["is_specialized"], - "line": lineno, - "column": col_offset if col_offset >= 0 else None, - "function": funcname, - "duration": end_time - start_time, - }) + self.threads[tid]["_spill"].append_marker( + name_idx, start_time, end_time, 1, CATEGORY_OPCODES, { + "type": "Opcode", + "opcode": opcode, + "opname": formatted_opname, + "base_opname": opcode_info["base_opname"], + "is_specialized": opcode_info["is_specialized"], + "line": lineno, + "column": col_offset if col_offset >= 0 else None, + "function": funcname, + "duration": end_time - start_time, + } + ) def _process_stack(self, thread_data, frames): """Process a stack and return the stack index.""" @@ -660,7 +707,6 @@ def _finalize_markers(self): def export(self, filename): """Export the profile to a Gecko JSON file.""" - if self.sample_count > 0 and self.last_sample_time > 0: self.interval = self.last_sample_time / self.sample_count @@ -681,19 +727,30 @@ def spin(): spinner_thread = threading.Thread(target=spin, daemon=True) spinner_thread.start() + temp_path = None + replaced = False try: - # Finalize any open markers before building profile - self._finalize_markers() - - profile = self._build_profile() - - with open(filename, "w") as f: - json.dump(profile, f, separators=(",", ":")) + self._prepare_for_serialization() + output_dir = os.path.dirname(os.path.abspath(filename)) or "." + with tempfile.NamedTemporaryFile( + "w", dir=output_dir, delete=False + ) as file: + temp_path = file.name + self._stream_profile(file) + os.replace(temp_path, filename) + replaced = True finally: + self.exported = True stop_spinner.set() spinner_thread.join(timeout=1.0) # Small delay to ensure the clear happens time.sleep(0.01) + if temp_path is not None and not replaced: + try: + os.unlink(temp_path) + except FileNotFoundError: + pass + self._cleanup_spills() print(f"Gecko profile written to {filename}") print( @@ -727,34 +784,17 @@ def _build_marker_schema(self): def _build_profile(self): """Build the complete profile structure in processed format.""" - # Convert thread data to final format - threads = [] - - for tid, thread_data in self.threads.items(): - # Update lengths - samples = thread_data["samples"] - stack_table = thread_data["stackTable"] - frame_table = thread_data["frameTable"] - func_table = thread_data["funcTable"] - resource_table = thread_data["resourceTable"] - - samples["length"] = len(samples["stack"]) - stack_table["length"] = len(stack_table["frame"]) - frame_table["length"] = len(frame_table["func"]) - func_table["length"] = len(func_table["name"]) - resource_table["length"] = len(resource_table["name"]) - thread_data["markers"]["length"] = len(thread_data["markers"]["name"]) - - # Clean up internal caches - del thread_data["_stackCache"] - del thread_data["_frameCache"] - del thread_data["_funcCache"] - del thread_data["_resourceCache"] - - threads.append(thread_data) - - # Main profile structure in processed format - profile = { + try: + self._prepare_for_serialization() + file = io.StringIO() + self._stream_profile(file) + return json.loads(file.getvalue()) + finally: + self.exported = True + self._cleanup_spills() + + def _profile_head(self): + return { "meta": { "interval": self.interval, "startTime": self.start_time, @@ -784,7 +824,10 @@ def _build_profile(self): }, }, "libs": self.libs, - "threads": threads, + } + + def _profile_tail(self): + return { "pages": [], "shared": { "stringArray": self.global_strings, @@ -792,4 +835,146 @@ def _build_profile(self): }, } - return profile + def _prepare_for_serialization(self): + if self.exported: + raise RuntimeError("GeckoCollector has already been exported") + self._finalize_markers() + for thread_data in self.threads.values(): + thread_data["_spill"].prepare_read() + thread_data["stackTable"]["length"] = len(thread_data["stackTable"]["frame"]) + thread_data["frameTable"]["length"] = len(thread_data["frameTable"]["func"]) + thread_data["funcTable"]["length"] = len(thread_data["funcTable"]["name"]) + thread_data["resourceTable"]["length"] = len(thread_data["resourceTable"]["name"]) + + def _cleanup_spills(self): + if self.spill_dir is not None: + self.spill_dir.cleanup() + self.spill_dir = None + + def _stream_profile(self, file): + file.write("{") + first = True + for key, value in self._profile_head().items(): + first = _write_json_member(file, key, value, first) + + first = _write_member_name(file, "threads", first) + file.write("[") + for index, (tid, thread_data) in enumerate(self.threads.items()): + if index: + file.write(",") + self._stream_thread(file, tid, thread_data) + file.write("]") + + for key, value in self._profile_tail().items(): + first = _write_json_member(file, key, value, first) + file.write("}") + + def _stream_thread(self, file, tid, thread_data): + spill = thread_data["_spill"] + metadata = { + "name": thread_data["name"], + "isMainThread": thread_data["isMainThread"], + "processStartupTime": thread_data["processStartupTime"], + "processShutdownTime": thread_data["processShutdownTime"], + "registerTime": thread_data["registerTime"], + "unregisterTime": thread_data["unregisterTime"], + "pausedRanges": thread_data["pausedRanges"], + "pid": thread_data["pid"], + "tid": thread_data["tid"], + "processType": thread_data["processType"], + "processName": thread_data["processName"], + } + file.write("{") + first = True + for key, value in metadata.items(): + first = _write_json_member(file, key, value, first) + + first = _write_member_name(file, "samples", first) + self._stream_samples(file, spill) + for key in ( + "stackTable", + "frameTable", + "funcTable", + "resourceTable", + "nativeSymbols", + ): + first = _write_json_member(file, key, thread_data[key], first) + first = _write_member_name(file, "markers", first) + self._stream_markers(file, spill) + file.write("}") + + def _stream_samples(self, file, spill): + _stream_column_table( + file, + ( + ("stack", spill.samples_stack.iter_tokens()), + ("time", spill.samples_time.iter_tokens()), + ("eventDelay", ("null" for _ in range(spill.sample_count))), + ), + spill.sample_count, + ( + ("weight", None), + ("weightType", "samples"), + ("length", spill.sample_count), + ), + ) + + def _stream_markers(self, file, spill): + _stream_column_table( + file, + ( + ("data", spill.markers_data.iter_tokens()), + ("name", spill.markers_name.iter_tokens()), + ("startTime", spill.markers_start_time.iter_tokens()), + ("endTime", spill.markers_end_time.iter_tokens()), + ("phase", spill.markers_phase.iter_tokens()), + ("category", spill.markers_category.iter_tokens()), + ), + spill.marker_count, + (("length", spill.marker_count),), + ) + + +def _write_json(file, value): + for chunk in _JSON_ENCODER.iterencode(value): + file.write(chunk) + + +def _write_member_name(file, name, first): + if not first: + file.write(",") + _write_json(file, name) + file.write(":") + return False + + +def _write_json_member(file, name, value, first): + first = _write_member_name(file, name, first) + _write_json(file, value) + return first + + +def _stream_column_table(file, columns, expected_count, trailing_members=()): + file.write("{") + first = True + for name, token_iter in columns: + first = _write_member_name(file, name, first) + _stream_array(file, token_iter, expected_count, name) + for name, value in trailing_members: + first = _write_json_member(file, name, value, first) + file.write("}") + + +def _stream_array(file, token_iter, expected_count, label="array"): + file.write("[") + count = 0 + for token in token_iter: + if count: + file.write(",") + file.write(token) + count += 1 + if count != expected_count: + raise RuntimeError( + f"streamed {count} {label} items, expected {expected_count}" + ) + file.write("]") diff --git a/Lib/test/test_profiling/test_sampling_profiler/test_collectors.py b/Lib/test/test_profiling/test_sampling_profiler/test_collectors.py index 390a1479fdd297..1ab31af67fec52 100644 --- a/Lib/test/test_profiling/test_sampling_profiler/test_collectors.py +++ b/Lib/test/test_profiling/test_sampling_profiler/test_collectors.py @@ -11,6 +11,7 @@ try: import _remote_debugging # noqa: F401 + from profiling.sampling import gecko_collector from profiling.sampling.pstats_collector import PstatsCollector from profiling.sampling.stack_collector import ( CollapsedStackCollector, @@ -59,6 +60,42 @@ def find_child_by_name(children, strings, substr): return None +def export_gecko_profile(testcase, collector): + gecko_out = tempfile.NamedTemporaryFile(suffix=".json", delete=False) + testcase.addCleanup(close_and_unlink, gecko_out) + # We cannot overwrite an open file on Windows. + gecko_out.close() + + with captured_stdout(), captured_stderr(): + collector.export(gecko_out.name) + + testcase.assertGreater(os.path.getsize(gecko_out.name), 0) + with open(gecko_out.name, encoding="utf-8") as file: + return json.load(file) + + +def assert_gecko_column_lengths(testcase, table, columns): + expected = table["length"] + for column in columns: + testcase.assertEqual( + len(table[column]), expected, + f"{column!r} has wrong length", + ) + + +def gecko_marker_names(profile, markers): + string_array = profile["shared"]["stringArray"] + return [string_array[idx] for idx in markers["name"]] + + +def gecko_opcode_marker_data(profile): + markers = profile["threads"][0]["markers"] + return [ + data for data in markers["data"] + if data.get("type") == "Opcode" + ] + + class TestSampleProfilerComponents(unittest.TestCase): """Unit tests for individual profiler components.""" @@ -583,9 +620,10 @@ def test_gecko_collector_basic(self): # Verify samples samples = thread_data["samples"] - self.assertEqual(len(samples["stack"]), 1) - self.assertEqual(len(samples["time"]), 1) self.assertEqual(samples["length"], 1) + assert_gecko_column_lengths( + self, samples, ("stack", "time", "eventDelay") + ) # Verify function table structure and content func_table = thread_data["funcTable"] @@ -622,9 +660,6 @@ def test_gecko_collector_basic(self): @unittest.skipIf(is_emscripten, "threads not available") def test_gecko_collector_export(self): """Test Gecko profile export functionality.""" - gecko_out = tempfile.NamedTemporaryFile(suffix=".json", delete=False) - self.addCleanup(close_and_unlink, gecko_out) - collector = GeckoCollector(1000) test_frames1 = [ @@ -657,17 +692,7 @@ def test_gecko_collector_export(self): collector.collect(test_frames2) collector.collect(test_frames3) - # Export gecko profile - with captured_stdout(), captured_stderr(): - collector.export(gecko_out.name) - - # Verify file was created and contains valid data - self.assertTrue(os.path.exists(gecko_out.name)) - self.assertGreater(os.path.getsize(gecko_out.name), 0) - - # Check file contains valid JSON - with open(gecko_out.name, "r") as f: - profile_data = json.load(f) + profile_data = export_gecko_profile(self, collector) # Should be valid Gecko profile format self.assertIn("meta", profile_data) @@ -688,6 +713,100 @@ def test_gecko_collector_export(self): self.assertIn("func2", string_array) self.assertIn("other_func", string_array) + thread_data = profile_data["threads"][0] + assert_gecko_column_lengths( + self, thread_data["samples"], ("stack", "time", "eventDelay") + ) + + @unittest.skipIf(is_emscripten, "threads not available") + def test_gecko_collector_export_after_spill_flush(self): + """Test Gecko profile export after spill buffers flush to disk.""" + old_buffer_bytes = gecko_collector.DEFAULT_SPILL_BUFFER_BYTES + gecko_collector.DEFAULT_SPILL_BUFFER_BYTES = 1 + self.addCleanup( + setattr, gecko_collector, "DEFAULT_SPILL_BUFFER_BYTES", + old_buffer_bytes + ) + + collector = GeckoCollector(1000) + test_frames = [ + MockInterpreterInfo( + 0, + [ + MockThreadInfo( + 1, + [MockFrameInfo("file.py", 10, "func")], + status=THREAD_STATUS_HAS_GIL, + ) + ], + ) + ] + collector.collect(test_frames, timestamps_us=[1000, 2000, 3000]) + + profile_data = export_gecko_profile(self, collector) + samples = profile_data["threads"][0]["samples"] + self.assertEqual(samples["length"], 3) + assert_gecko_column_lengths( + self, samples, ("stack", "time", "eventDelay") + ) + + @unittest.skipIf(is_emscripten, "threads not available") + def test_gecko_collector_rejects_collect_after_export(self): + collector = GeckoCollector(1000) + test_frames = [ + MockInterpreterInfo( + 0, + [ + MockThreadInfo( + 1, + [MockFrameInfo("file.py", 10, "func")], + status=THREAD_STATUS_HAS_GIL, + ) + ], + ) + ] + collector.collect(test_frames) + export_gecko_profile(self, collector) + + with self.assertRaisesRegex(RuntimeError, "after export"): + collector.collect(test_frames) + + @unittest.skipIf(is_emscripten, "threads not available") + def test_gecko_collector_export_failure_keeps_existing_file(self): + collector = GeckoCollector(1000) + test_frames = [ + MockInterpreterInfo( + 0, + [ + MockThreadInfo( + 1, + [MockFrameInfo("file.py", 10, "func")], + status=THREAD_STATUS_HAS_GIL, + ) + ], + ) + ] + collector.collect(test_frames) + + with tempfile.TemporaryDirectory() as temp_dir: + filename = os.path.join(temp_dir, "profile.json") + with open(filename, "w", encoding="utf-8") as file: + file.write("existing") + + before = set(os.listdir(temp_dir)) + + def fail(file): + raise OSError("boom") + + collector._stream_profile = fail + with captured_stdout(), captured_stderr(): + with self.assertRaisesRegex(OSError, "boom"): + collector.export(filename) + + with open(filename, encoding="utf-8") as file: + self.assertEqual(file.read(), "existing") + self.assertEqual(set(os.listdir(temp_dir)), before) + def test_gecko_collector_markers(self): """Test Gecko profile markers for GIL and CPU state tracking.""" collector = GeckoCollector(1000) @@ -771,21 +890,16 @@ def test_gecko_collector_markers(self): self.assertIn("markers", thread_data) markers = thread_data["markers"] - # Should have marker arrays - self.assertIn("name", markers) - self.assertIn("startTime", markers) - self.assertIn("endTime", markers) - self.assertIn("category", markers) self.assertGreater( markers["length"], 0, "Should have generated markers" ) - - # Get marker names from string table - string_array = profile_data["shared"]["stringArray"] - marker_names = [string_array[idx] for idx in markers["name"]] + assert_gecko_column_lengths( + self, markers, + ("data", "name", "startTime", "endTime", "phase", "category"), + ) # Verify we have different marker types - marker_name_set = set(marker_names) + marker_name_set = set(gecko_marker_names(profile_data, markers)) # Should have "Has GIL" markers (when thread had GIL) self.assertIn( @@ -2659,6 +2773,7 @@ def test_gecko_collector_opcodes_enabled(self): def test_gecko_opcode_state_tracking(self): """Test that GeckoCollector tracks opcode state changes.""" collector = GeckoCollector(sample_interval_usec=1000, opcodes=True) + self.addCleanup(collector._cleanup_spills) # First sample with opcode 90 (RAISE_VARARGS) frame1 = MockFrameInfo("test.py", 10, "func", opcode=90) @@ -2702,10 +2817,28 @@ def test_gecko_opcode_state_change_emits_marker(self): collector.collect(frames2) # Should have emitted a marker for the first opcode - thread_data = collector.threads[1] - markers = thread_data["markers"] - # At least one marker should have been added - self.assertGreater(len(markers["name"]), 0) + profile = collector._build_profile() + markers = profile["threads"][0]["markers"] + assert_gecko_column_lengths( + self, markers, + ("data", "name", "startTime", "endTime", "phase", "category"), + ) + opcode_markers = gecko_opcode_marker_data(profile) + self.assertIn( + { + "opcode": 90, + "line": 10, + "function": "func", + }, + [ + { + "opcode": marker["opcode"], + "line": marker["line"], + "function": marker["function"], + } + for marker in opcode_markers + ], + ) def test_gecko_opcode_markers_not_emitted_when_disabled(self): """Test that no opcode markers when opcodes=False.""" @@ -2729,8 +2862,9 @@ def test_gecko_opcode_markers_not_emitted_when_disabled(self): ] collector.collect(frames2) - # opcode_state should not be tracked - self.assertEqual(len(collector.opcode_state), 0) + profile = collector._build_profile() + self.assertEqual(gecko_opcode_marker_data(profile), []) + self.assertEqual(profile["meta"]["markerSchema"], []) def test_gecko_opcode_with_none_opcode(self): """Test that None opcode doesn't cause issues.""" @@ -2746,9 +2880,8 @@ def test_gecko_opcode_with_none_opcode(self): ] collector.collect(frames) - # Should track the state but opcode is None - self.assertIn(1, collector.opcode_state) - self.assertIsNone(collector.opcode_state[1][0]) + profile = collector._build_profile() + self.assertEqual(gecko_opcode_marker_data(profile), []) class TestCollectorFrameFormat(unittest.TestCase): diff --git a/Misc/NEWS.d/next/Library/2026-06-03-13-51-29.gh-issue-150662.ELT8Vg.rst b/Misc/NEWS.d/next/Library/2026-06-03-13-51-29.gh-issue-150662.ELT8Vg.rst new file mode 100644 index 00000000000000..42ed6ad7cd3c65 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-03-13-51-29.gh-issue-150662.ELT8Vg.rst @@ -0,0 +1,4 @@ +Fix the ``--gecko`` collector in :mod:`profiling.sampling` that kept every +sample in memory. It now writes sample and marker data to temporary files +and reads them back, ultimately building the output file at the end. Patch +by Pablo Galindo and Maurycy Pawłowski-Wieroński. From 9352936b4ec21a0237df09a8e416dca2401d7921 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 6 Jun 2026 15:13:52 +0200 Subject: [PATCH 248/818] [3.15] gh-149083: Use sentinel for urllib.parse._UNSPECIFIED (GH-149612) (#151017) This was added in 3.15; let's use a real sentinel instead of an ad-hoc list object. (cherry picked from commit 884ac3e3ec02347301939ff1f124972d4973f015) Co-authored-by: Jelle Zijlstra <jelle.zijlstra@gmail.com> --- Lib/urllib/parse.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/urllib/parse.py b/Lib/urllib/parse.py index d64f678d235b6f..82b95adbdc283e 100644 --- a/Lib/urllib/parse.py +++ b/Lib/urllib/parse.py @@ -277,7 +277,7 @@ def _hostinfo(self): return hostname, port -_UNSPECIFIED = ['not specified'] +_UNSPECIFIED = sentinel("_UNSPECIFIED", repr="<not specified>") _MISSING_AS_NONE_DEFAULT = False class _ResultBase: From 96073736a40f80c419e7bc62fd6da86a3dc25277 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 6 Jun 2026 23:11:55 +0200 Subject: [PATCH 249/818] [3.15] gh-50948: IDLE: Warn if saving a file will overwrite a newer version (GH-17578) (GH-151026) (cherry picked from commit 69851a64076cc240513b834d87d654064f7ac597) Co-authored-by: Zackery Spytz <zspytz@gmail.com> Co-authored-by: Guilherme Polo <ggpolo@gmail.com> Co-authored-by: Priya Pappachan <priyapappachan010@gmail.com> Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> --- Lib/idlelib/iomenu.py | 27 +++++++++++++++++++ .../2019-12-12-03-18-02.bpo-6699.1CqJFG.rst | 1 + 2 files changed, 28 insertions(+) create mode 100644 Misc/NEWS.d/next/IDLE/2019-12-12-03-18-02.bpo-6699.1CqJFG.rst diff --git a/Lib/idlelib/iomenu.py b/Lib/idlelib/iomenu.py index 464126e2df0668..fc502f7fde1780 100644 --- a/Lib/idlelib/iomenu.py +++ b/Lib/idlelib/iomenu.py @@ -61,6 +61,7 @@ def set_filename_change_hook(self, hook): self.filename_change_hook = hook filename = None + file_timestamp = None dirname = None def set_filename(self, filename): @@ -127,6 +128,7 @@ def loadfile(self, filename): chars = f.read() fileencoding = f.encoding eol_convention = f.newlines + file_timestamp = self.getmtime(filename) converted = False except (UnicodeDecodeError, SyntaxError): # Wait for the editor window to appear @@ -142,6 +144,7 @@ def loadfile(self, filename): chars = f.read() fileencoding = f.encoding eol_convention = f.newlines + file_timestamp = self.getmtime(filename) converted = True except OSError as err: messagebox.showerror("I/O Error", str(err), parent=self.text) @@ -170,6 +173,7 @@ def loadfile(self, filename): self.text.insert("1.0", chars) self.reset_undo() self.set_filename(filename) + self.file_timestamp = file_timestamp if converted: # We need to save the conversion results first # before being able to execute the code @@ -206,7 +210,26 @@ def save(self, event): if not self.filename: self.save_as(event) else: + # Check the time of most recent content modification so the + # user doesn't accidentally overwrite a newer version of the file. + try: + file_timestamp = self.getmtime(self.filename) + except OSError: + pass + else: + if self.file_timestamp != file_timestamp: + confirm = messagebox.askokcancel( + title="File has changed", + message=( + "The file has changed on disk since reading it!\n\n" + "Do you really want to overwrite it?"), + default=messagebox.CANCEL, + parent=self.text) + if not confirm: + return "break" + if self.writefile(self.filename): + self.file_timestamp = self.getmtime(self.filename) self.set_saved(True) try: self.editwin.store_file_breaks() @@ -219,6 +242,7 @@ def save_as(self, event): filename = self.asksavefile() if filename: if self.writefile(filename): + self.file_timestamp = self.getmtime(filename) self.set_filename(filename) self.set_saved(1) try: @@ -251,6 +275,9 @@ def writefile(self, filename): parent=self.text) return False + def getmtime(self, filename): + return os.stat(filename).st_mtime + def fixnewlines(self): """Return text with os eols. diff --git a/Misc/NEWS.d/next/IDLE/2019-12-12-03-18-02.bpo-6699.1CqJFG.rst b/Misc/NEWS.d/next/IDLE/2019-12-12-03-18-02.bpo-6699.1CqJFG.rst new file mode 100644 index 00000000000000..e7fb9bf1b3bdf6 --- /dev/null +++ b/Misc/NEWS.d/next/IDLE/2019-12-12-03-18-02.bpo-6699.1CqJFG.rst @@ -0,0 +1 @@ +Warn the user if a file will be overwritten when saving. From d7aef33bd794c3b1d9bccfe3c923d460cd46b7c5 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 7 Jun 2026 09:52:40 +0200 Subject: [PATCH 250/818] [3.15] gh-148954: Escape methodname in xmlrpc.client.dumps() to prevent XML injection (GH-148968) (GH-151033) (cherry picked from commit ab930175e7e909aaa3ec7e761bfdbb886677bebb) Co-authored-by: Sanyam Kumat <124618873+sanyamk23@users.noreply.github.com> --- Lib/test/test_xmlrpc.py | 11 +++++++++++ Lib/xmlrpc/client.py | 2 +- .../2026-04-24-19-54-00.gh-issue-148954.v1.rst | 1 + 3 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2026-04-24-19-54-00.gh-issue-148954.v1.rst diff --git a/Lib/test/test_xmlrpc.py b/Lib/test/test_xmlrpc.py index 2803c6d45c27bf..ee0e24f6e86ae3 100644 --- a/Lib/test/test_xmlrpc.py +++ b/Lib/test/test_xmlrpc.py @@ -208,6 +208,17 @@ def test_dump_encoding(self): self.assertEqual(xmlrpclib.loads(strg)[0][0], value) self.assertEqual(xmlrpclib.loads(strg)[1], methodname) + def test_dump_escape_methodname(self): + payload = 'foo</methodName><injected attr="evil"/><methodName>bar' + s = xmlrpclib.dumps((), methodname=payload) + self.assertIn( + '<methodName>foo&lt;/methodName&gt;&lt;injected attr="evil"/&gt;' + '&lt;methodName&gt;bar</methodName>', s + ) + self.assertNotIn('<injected attr="evil"/>', s) + load, m = xmlrpclib.loads(s) + self.assertEqual(m, payload) + def test_dump_bytes(self): sample = b"my dog has fleas" self.assertEqual(sample, xmlrpclib.Binary(sample)) diff --git a/Lib/xmlrpc/client.py b/Lib/xmlrpc/client.py index f441376d09c4aa..84e4e4d11a7319 100644 --- a/Lib/xmlrpc/client.py +++ b/Lib/xmlrpc/client.py @@ -965,7 +965,7 @@ def dumps(params, methodname=None, methodresponse=None, encoding=None, data = ( xmlheader, "<methodCall>\n" - "<methodName>", methodname, "</methodName>\n", + "<methodName>", escape(methodname), "</methodName>\n", data, "</methodCall>\n" ) diff --git a/Misc/NEWS.d/next/Library/2026-04-24-19-54-00.gh-issue-148954.v1.rst b/Misc/NEWS.d/next/Library/2026-04-24-19-54-00.gh-issue-148954.v1.rst new file mode 100644 index 00000000000000..6245af7e362e92 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-04-24-19-54-00.gh-issue-148954.v1.rst @@ -0,0 +1 @@ +Fix XML injection vulnerability in :func:`xmlrpc.client.dumps` where the ``methodname`` was not being escaped before interpolation into the XML body. From a642d1ab38cb3199c16898875e86cd13a99b687a Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 7 Jun 2026 15:27:26 +0200 Subject: [PATCH 251/818] [3.15] gh-151021: Fix mmap empty searches past the end (GH-151023) (GH-151041) (cherry picked from commit f2cab7b0cf019fcc3112018db5e20c00976f33d4) Co-authored-by: esadomer <54475303+esadomer@users.noreply.github.com> --- Lib/test/test_mmap.py | 2 ++ .../Library/2026-06-06-15-20-54.gh-issue-151021.J4qk2A.rst | 3 +++ Modules/mmapmodule.c | 2 -- 3 files changed, 5 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-06-06-15-20-54.gh-issue-151021.J4qk2A.rst diff --git a/Lib/test/test_mmap.py b/Lib/test/test_mmap.py index 177fe45e8d9749..2e2ac147968dd4 100644 --- a/Lib/test/test_mmap.py +++ b/Lib/test/test_mmap.py @@ -354,6 +354,8 @@ def test_find_end(self): self.assertEqual(m.find(b'one', 1, -1), 8) self.assertEqual(m.find(b'one', 1, -2), -1) self.assertEqual(m.find(bytearray(b'one')), 0) + self.assertEqual(m.find(b'', n + 1), -1) + self.assertEqual(m.rfind(b'', n + 1), -1) for i in range(-n-1, n+1): for j in range(-n-1, n+1): diff --git a/Misc/NEWS.d/next/Library/2026-06-06-15-20-54.gh-issue-151021.J4qk2A.rst b/Misc/NEWS.d/next/Library/2026-06-06-15-20-54.gh-issue-151021.J4qk2A.rst new file mode 100644 index 00000000000000..0617fa068c844d --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-06-15-20-54.gh-issue-151021.J4qk2A.rst @@ -0,0 +1,3 @@ +Fix :meth:`mmap.mmap.find` and :meth:`~mmap.mmap.rfind` to return ``-1`` +when searching for an empty subsequence with a start position past the end +of the mapping. diff --git a/Modules/mmapmodule.c b/Modules/mmapmodule.c index a30afe91f8fa17..6fb04ba7bd47c6 100644 --- a/Modules/mmapmodule.c +++ b/Modules/mmapmodule.c @@ -620,8 +620,6 @@ mmap_gfind_lock_held(mmap_object *self, Py_buffer *view, PyObject *start_obj, start += self->size; if (start < 0) start = 0; - else if (start > self->size) - start = self->size; if (end < 0) end += self->size; From d3ca26983dfbccdf609f24ff5877dc3118e4702d Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 7 Jun 2026 18:48:30 +0200 Subject: [PATCH 252/818] [3.15] gh-150599: Prevent bz2 decompressor reuse after errors (GH-150600) (cherry picked from commit 5755d0f083949ff3c5bf3a37e673e24e306b036e) Co-authored-by: Stan Ulbrych <stan@python.org> --- Lib/test/test_bz2.py | 15 +++++++++++++++ ...6-05-30-09-36-20.gh-issue-150599.nlHqU-.rst | 3 +++ Modules/_bz2module.c | 18 +++++++++++++++--- 3 files changed, 33 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Security/2026-05-30-09-36-20.gh-issue-150599.nlHqU-.rst diff --git a/Lib/test/test_bz2.py b/Lib/test/test_bz2.py index d8e3b671ec229f..64293d757331d7 100644 --- a/Lib/test/test_bz2.py +++ b/Lib/test/test_bz2.py @@ -1032,6 +1032,21 @@ def test_failure(self): # Previously, a second call could crash due to internal inconsistency self.assertRaises(Exception, bzd.decompress, self.BAD_DATA * 30) + def test_decompress_after_data_error(self): + data = bytes.fromhex( + "425a6839314159265359000000000000007fffff000000000000000000000000" + "00000000000000000000000000000000000000e0370000000000000000000000" + "000000000000000000000000000000000000000000000000000083f3" + ) + bzd = BZ2Decompressor() + with self.assertRaisesRegex(OSError, "Invalid data stream"): + bzd.decompress(data) + # Previously, a second call could crash due to internal inconsistency + self.assertFalse(bzd.needs_input) + self.assertFalse(bzd.eof) + with self.assertRaisesRegex(ValueError, "previous error"): + bzd.decompress(b'\x00' * 18) + @support.refcount_test def test_refleaks_in___init__(self): gettotalrefcount = support.get_attribute(sys, 'gettotalrefcount') diff --git a/Misc/NEWS.d/next/Security/2026-05-30-09-36-20.gh-issue-150599.nlHqU-.rst b/Misc/NEWS.d/next/Security/2026-05-30-09-36-20.gh-issue-150599.nlHqU-.rst new file mode 100644 index 00000000000000..a37d86cf423f82 --- /dev/null +++ b/Misc/NEWS.d/next/Security/2026-05-30-09-36-20.gh-issue-150599.nlHqU-.rst @@ -0,0 +1,3 @@ +Fix a possible stack buffer overflow in :mod:`bz2` when a +:class:`bz2.BZ2Decompressor` is reused after a decompression error. +The decompressor now becomes unusable after libbz2 reports an error. diff --git a/Modules/_bz2module.c b/Modules/_bz2module.c index 4cf8beed9ee3eb..9db3ac39da5209 100644 --- a/Modules/_bz2module.c +++ b/Modules/_bz2module.c @@ -108,6 +108,7 @@ typedef struct { typedef struct { PyObject_HEAD bz_stream bzs; + int bzerror; char eof; /* Py_T_BOOL expects a char */ PyObject *unused_data; char needs_input; @@ -435,8 +436,11 @@ decompress_buf(BZ2Decompressor *d, Py_ssize_t max_length) d->bzs_avail_in_real += bzs->avail_in; - if (catch_bz2_error(bzret)) + if (catch_bz2_error(bzret)) { + d->bzerror = bzret; + FT_ATOMIC_STORE_CHAR_RELAXED(d->needs_input, 0); goto error; + } if (bzret == BZ_STREAM_END) { FT_ATOMIC_STORE_CHAR_RELAXED(d->eof, 1); break; @@ -607,10 +611,17 @@ _bz2_BZ2Decompressor_decompress_impl(BZ2Decompressor *self, Py_buffer *data, PyObject *result = NULL; PyMutex_Lock(&self->mutex); - if (self->eof) + if (self->eof) { PyErr_SetString(PyExc_EOFError, "End of stream already reached"); - else + } + else if (self->bzerror) { + // Re-entering BZ2_bzDecompress() after an error can write out of bounds. + PyErr_SetString(PyExc_ValueError, + "Decompressor is unusable after a previous error"); + } + else { result = decompress(self, data->buf, data->len, max_length); + } PyMutex_Unlock(&self->mutex); return result; } @@ -638,6 +649,7 @@ _bz2_BZ2Decompressor_impl(PyTypeObject *type) } self->mutex = (PyMutex){0}; + self->bzerror = 0; self->needs_input = 1; self->bzs_avail_in_real = 0; self->input_buffer = NULL; From 2185b73dff8fa317dfa620cfaa52c007a3f6ea5a Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 7 Jun 2026 19:25:37 +0200 Subject: [PATCH 253/818] [3.15] Update an error message in the 'Functional Programming HOWTO' (GH-151047) (cherry picked from commit 81965c1683d7129a70e3fde22ea8a02b9398e227) Co-authored-by: saber-bit <bryanventura0324@gmail.com> --- Doc/howto/functional.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/howto/functional.rst b/Doc/howto/functional.rst index 552514063c95ab..ebc7a100d91a64 100644 --- a/Doc/howto/functional.rst +++ b/Doc/howto/functional.rst @@ -1042,7 +1042,7 @@ first calculation. :: >>> functools.reduce(operator.concat, []) Traceback (most recent call last): ... - TypeError: reduce() of empty sequence with no initial value + TypeError: reduce() of empty iterable with no initial value >>> functools.reduce(operator.mul, [1, 2, 3], 1) 6 >>> functools.reduce(operator.mul, [], 1) From 550d9b62dd5ce8ff3df17053dbcfb78f23d522ec Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 8 Jun 2026 11:47:41 +0200 Subject: [PATCH 254/818] [3.15] Docs: Fix missing colon in `bisect` example function (GH-151061) (GH-151067) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Docs: Fix missing colon in `bisect` example function (GH-151061) (cherry picked from commit 16ede813ebad81e41874f1c0a1b3c83fc98a38ca) Co-authored-by: Sergio López Gómez <sergiolopezgmz.dam@gmail.com> --- Doc/library/bisect.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/bisect.rst b/Doc/library/bisect.rst index 2c29a5ec992737..f532aa462565e4 100644 --- a/Doc/library/bisect.rst +++ b/Doc/library/bisect.rst @@ -200,7 +200,7 @@ example uses :py:func:`~bisect.bisect` to look up a letter grade for an exam sco based on a set of ordered numeric breakpoints: 90 and up is an 'A', 80 to 89 is a 'B', and so on:: - >>> def grade(score) + >>> def grade(score): ... i = bisect([60, 70, 80, 90], score) ... return "FDCBA"[i] ... From 1f3ee9248a5ccdc0265d165d3a2595b0173a4add Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 8 Jun 2026 12:32:43 +0200 Subject: [PATCH 255/818] [3.15] gh-101100: Fix Sphinx warnings in 'Buffer Object Structures' documentation (GH-151058) (cherry picked from commit a1873300eebe9c634f59592c3333035768f09de9) Co-authored-by: Christian Zinck <christian.zinck@gmail.com> --- Doc/c-api/typeobj.rst | 10 +++++----- Doc/tools/.nitignore | 1 - 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/Doc/c-api/typeobj.rst b/Doc/c-api/typeobj.rst index 38db69e5c6db96..dcc9e243c2f314 100644 --- a/Doc/c-api/typeobj.rst +++ b/Doc/c-api/typeobj.rst @@ -2975,13 +2975,13 @@ Buffer Object Structures steps: (1) Check if the request can be met. If not, raise :exc:`BufferError`, - set :c:expr:`view->obj` to ``NULL`` and return ``-1``. + set ``view->obj`` to ``NULL`` and return ``-1``. (2) Fill in the requested fields. (3) Increment an internal counter for the number of exports. - (4) Set :c:expr:`view->obj` to *exporter* and increment :c:expr:`view->obj`. + (4) Set ``view->obj`` to *exporter* and increment ``view->obj``. (5) Return ``0``. @@ -3007,10 +3007,10 @@ Buffer Object Structures schemes can be used: * Re-export: Each member of the tree acts as the exporting object and - sets :c:expr:`view->obj` to a new reference to itself. + sets ``view->obj`` to a new reference to itself. * Redirect: The buffer request is redirected to the root object of the - tree. Here, :c:expr:`view->obj` will be a new reference to the root + tree. Here, ``view->obj`` will be a new reference to the root object. The individual fields of *view* are described in section @@ -3064,7 +3064,7 @@ Buffer Object Structures *view* argument. - This function MUST NOT decrement :c:expr:`view->obj`, since that is + This function MUST NOT decrement ``view->obj``, since that is done automatically in :c:func:`PyBuffer_Release` (this scheme is useful for breaking reference cycles). diff --git a/Doc/tools/.nitignore b/Doc/tools/.nitignore index 189173a5f8a75f..31173134dd5019 100644 --- a/Doc/tools/.nitignore +++ b/Doc/tools/.nitignore @@ -5,7 +5,6 @@ Doc/c-api/init_config.rst Doc/c-api/intro.rst Doc/c-api/stable.rst -Doc/c-api/typeobj.rst Doc/library/ast.rst Doc/library/asyncio-extending.rst Doc/library/email.charset.rst From 0f964f46796751babad96f1676b52fcb3404bdbf Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 8 Jun 2026 13:47:55 +0200 Subject: [PATCH 256/818] [3.15] Mention `frozendict` in `object.__hash__()` documentation (GH-148867) (#151077) (cherry picked from commit e3762114e514f7790e9b4cf3a7b9478f2f306901) Co-authored-by: Jonathan Dung <jonathandung@yahoo.com> --- Doc/reference/datamodel.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst index a8614128c85dad..780e0e0eca3c22 100644 --- a/Doc/reference/datamodel.rst +++ b/Doc/reference/datamodel.rst @@ -2230,12 +2230,12 @@ Basic customization pair: built-in function; hash Called by built-in function :func:`hash` and for operations on members of - hashed collections including :class:`set`, :class:`frozenset`, and - :class:`dict`. The ``__hash__()`` method should return an integer. The only required - property is that objects which compare equal have the same hash value; it is - advised to mix together the hash values of the components of the object that - also play a part in comparison of objects by packing them into a tuple and - hashing the tuple. Example:: + hashed collections including :class:`set`, :class:`frozenset`, :class:`dict`, + and :class:`frozendict`. The ``__hash__()`` method should return an integer. + The only required property is that objects which compare equal have the same + hash value; it is advised to mix together the hash values of the components + of the object that also play a part in comparison of objects by packing them + into a tuple and hashing the tuple. Example:: def __hash__(self): return hash((self.name, self.nick, self.color)) From 39f232219e78b37caf9079bcc91026d0d4736ec9 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 8 Jun 2026 14:21:22 +0200 Subject: [PATCH 257/818] [3.15] gh-141623: Clarify operator function descriptions (GH-141846) (cherry picked from commit bd5fa31c5ff47866f0f93ef2a674e78d56d2e44c) Co-authored-by: Doron Behar <doron.behar@gmail.com> --- Doc/library/operator.rst | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/Doc/library/operator.rst b/Doc/library/operator.rst index c0dab83977e427..3d1c8cda13be38 100644 --- a/Doc/library/operator.rst +++ b/Doc/library/operator.rst @@ -110,7 +110,7 @@ The mathematical and bitwise operations are the most numerous: .. function:: and_(a, b) __and__(a, b) - Return the bitwise and of *a* and *b*. + Return ``a & b``. .. function:: floordiv(a, b) @@ -134,13 +134,13 @@ The mathematical and bitwise operations are the most numerous: __inv__(obj) __invert__(obj) - Return the bitwise inverse of the number *obj*. This is equivalent to ``~obj``. + Return ``~obj``. .. function:: lshift(a, b) __lshift__(a, b) - Return *a* shifted left by *b*. + Return ``a << b``. .. function:: mod(a, b) @@ -152,7 +152,7 @@ The mathematical and bitwise operations are the most numerous: .. function:: mul(a, b) __mul__(a, b) - Return ``a * b``, for *a* and *b* numbers. + Return ``a * b``. .. function:: matmul(a, b) @@ -172,25 +172,25 @@ The mathematical and bitwise operations are the most numerous: .. function:: or_(a, b) __or__(a, b) - Return the bitwise or of *a* and *b*. + Return ``a | b``. .. function:: pos(obj) __pos__(obj) - Return *obj* positive (``+obj``). + Return ``+obj``. .. function:: pow(a, b) __pow__(a, b) - Return ``a ** b``, for *a* and *b* numbers. + Return ``a ** b``. .. function:: rshift(a, b) __rshift__(a, b) - Return *a* shifted right by *b*. + Return ``a >> b``. .. function:: sub(a, b) @@ -209,7 +209,7 @@ The mathematical and bitwise operations are the most numerous: .. function:: xor(a, b) __xor__(a, b) - Return the bitwise exclusive or of *a* and *b*. + Return ``a ^ b``. Operations which work with sequences (some of them with mappings too) include: @@ -403,13 +403,18 @@ Python syntax and the functions in the :mod:`!operator` module. +-----------------------+-------------------------+---------------------------------------+ | Division | ``a // b`` | ``floordiv(a, b)`` | +-----------------------+-------------------------+---------------------------------------+ -| Bitwise And | ``a & b`` | ``and_(a, b)`` | +| Bitwise And, or | ``a & b`` | ``and_(a, b)`` | +| Intersection | | | +-----------------------+-------------------------+---------------------------------------+ -| Bitwise Exclusive Or | ``a ^ b`` | ``xor(a, b)`` | +| Bitwise Exclusive Or, | ``a ^ b`` | ``xor(a, b)`` | +| or Symmetric | | | +| Difference | | | +-----------------------+-------------------------+---------------------------------------+ -| Bitwise Inversion | ``~ a`` | ``invert(a)`` | +| Bitwise Inversion, or | ``~ a`` | ``invert(a)`` | +| Complement | | | +-----------------------+-------------------------+---------------------------------------+ -| Bitwise Or | ``a | b`` | ``or_(a, b)`` | +| Bitwise Or, or | ``a | b`` | ``or_(a, b)`` | +| Union | | | +-----------------------+-------------------------+---------------------------------------+ | Exponentiation | ``a ** b`` | ``pow(a, b)`` | +-----------------------+-------------------------+---------------------------------------+ From 86e291e6627a6eee2912c4f6ec6848b7e4866029 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 8 Jun 2026 14:59:46 +0200 Subject: [PATCH 258/818] [3.15] gh-106318: Add examples to the `str.isdigit()` method docs (GH-144721) (cherry picked from commit f051c68923b4060b03566d0ea1df06d911ebe238) Co-authored-by: Adorilson Bezerra <adorilson@gmail.com> Co-authored-by: Stan Ulbrych <stan@python.org> --- Doc/library/stdtypes.rst | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index f770809dfb4006..9ad4b27cf2fc87 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -2174,9 +2174,25 @@ expression support in the :mod:`re` module). character, ``False`` otherwise. Digits include decimal characters and digits that need special handling, such as the compatibility superscript digits. This covers digits which cannot be used to form numbers in base 10, - like the Kharosthi numbers. Formally, a digit is a character that has the + like the `Kharosthi numbers <https://en.wikipedia.org/wiki/Kharosthi#Numerals>`__. + Formally, a digit is a character that has the property value Numeric_Type=Digit or Numeric_Type=Decimal. + For example: + + .. doctest:: + + >>> '0123456789'.isdigit() + True + >>> '٠١٢٣٤٥٦٧٨٩'.isdigit() # Arabic-Indic digits zero to nine + True + >>> '⅕'.isdigit() # Vulgar fraction one fifth + False + >>> '²'.isdecimal(), '²'.isdigit(), '²'.isnumeric() + (False, True, True) + + See also :meth:`isdecimal` and :meth:`isnumeric`. + .. method:: str.isidentifier() @@ -2217,15 +2233,14 @@ expression support in the :mod:`re` module). >>> '0123456789'.isnumeric() True - >>> '٠١٢٣٤٥٦٧٨٩'.isnumeric() # Arabic-indic digit zero to nine + >>> '٠١٢٣٤٥٦٧٨٩'.isnumeric() # Arabic-Indic digits zero to nine True >>> '⅕'.isnumeric() # Vulgar fraction one fifth True >>> '²'.isdecimal(), '²'.isdigit(), '²'.isnumeric() (False, True, True) - See also :meth:`isdecimal` and :meth:`isdigit`. Numeric characters are - a superset of decimal numbers. + See also :meth:`isdecimal` and :meth:`isdigit`. .. method:: str.isprintable() From 199751ea6a4637d0445fc16af84c3072a30f29f2 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 8 Jun 2026 19:25:50 +0200 Subject: [PATCH 259/818] [3.15] gh-151019: Fix test_os on 32-bit FreeBSD (GH-151087) (#151093) gh-151019: Fix test_os on 32-bit FreeBSD (GH-151087) Remove references to server.handler_instance. This attribute has been removed in 2022 by commit 3ae975f1ac880c47d51cca6c9e305547bd365be7. (cherry picked from commit a9002349cbe3f2243fe53a9fcadd02318dd0caf9) Co-authored-by: Victor Stinner <vstinner@python.org> --- Lib/test/test_os/test_os.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/Lib/test/test_os/test_os.py b/Lib/test/test_os/test_os.py index 6fcf94fc825385..fef4f495fa5679 100644 --- a/Lib/test/test_os/test_os.py +++ b/Lib/test/test_os/test_os.py @@ -3789,7 +3789,6 @@ async def test_trailers(self): @requires_headers_trailers @requires_32b async def test_headers_overflow_32bits(self): - self.server.handler_instance.accumulate = False with self.assertRaises(OSError) as cm: await self.async_sendfile(self.sockno, self.fileno, 0, 0, headers=[b"x" * 2**16] * 2**15) @@ -3798,7 +3797,6 @@ async def test_headers_overflow_32bits(self): @requires_headers_trailers @requires_32b async def test_trailers_overflow_32bits(self): - self.server.handler_instance.accumulate = False with self.assertRaises(OSError) as cm: await self.async_sendfile(self.sockno, self.fileno, 0, 0, trailers=[b"x" * 2**16] * 2**15) From 99979753b38f64a6cdbe37990eaaeb2af440e140 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 8 Jun 2026 20:01:31 +0200 Subject: [PATCH 260/818] [3.15] gh-149816: Fix SNI callback callable race (GH-150018) (GH-150099) (cherry picked from commit 8b31d08e62b9714cf8dd1d8b19afa5ecbad2414a) Co-authored-by: Kirill Ignatev <kiri11@users.noreply.github.com> Co-authored-by: Petr Viktorin <encukou@gmail.com> --- Lib/test/test_ssl.py | 53 +++++++++++++++++++ ...-05-18-22-45-54.gh-issue-149816.T68vc_.rst | 1 + Modules/_ssl.c | 36 +++++++------ 3 files changed, 74 insertions(+), 16 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-05-18-22-45-54.gh-issue-149816.T68vc_.rst diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py index b51fc3cf09ff8a..f41262d81a8290 100644 --- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py @@ -1606,6 +1606,59 @@ def dummycallback(sock, servername, ctx, cycle=ctx): gc.collect() self.assertIs(wr(), None) + @unittest.skipUnless(support.Py_GIL_DISABLED, + "test is only useful if the GIL is disabled") + @threading_helper.requires_working_threading() + def test_sni_callback_race(self): + # Replacing sni_callback while handshakes are in-flight must not + # crash (use-after-free on the callback in free-threaded builds). + client_ctx, server_ctx, hostname = testing_context() + + server_ctx.sni_callback = lambda *a: None + done = threading.Event() + + def do_handshakes(): + while not done.is_set(): + c_in = ssl.MemoryBIO() + c_out = ssl.MemoryBIO() + s_in = ssl.MemoryBIO() + s_out = ssl.MemoryBIO() + client = client_ctx.wrap_bio( + c_in, c_out, server_hostname=hostname) + server = server_ctx.wrap_bio(s_in, s_out, server_side=True) + for _ in range(50): + try: + client.do_handshake() + except ssl.SSLWantReadError: + pass + except ssl.SSLError: + break + if c_out.pending: + s_in.write(c_out.read()) + try: + server.do_handshake() + except ssl.SSLWantReadError: + pass + except ssl.SSLError: + break + if s_out.pending: + c_in.write(s_out.read()) + + def toggle_callback(): + while not done.is_set(): + server_ctx.sni_callback = lambda *a: None + server_ctx.sni_callback = None + + workers = max(4, (os.cpu_count() or 4) * 2) + threads = [threading.Thread(target=do_handshakes) + for _ in range(workers)] + threads.append(threading.Thread(target=toggle_callback)) + + with threading_helper.catch_threading_exception() as cm: + with threading_helper.start_threads(threads): + done.set() + self.assertIsNone(cm.exc_value) + def test_cert_store_stats(self): ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) self.assertEqual(ctx.cert_store_stats(), diff --git a/Misc/NEWS.d/next/Library/2026-05-18-22-45-54.gh-issue-149816.T68vc_.rst b/Misc/NEWS.d/next/Library/2026-05-18-22-45-54.gh-issue-149816.T68vc_.rst new file mode 100644 index 00000000000000..9996cc7ec0e866 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-05-18-22-45-54.gh-issue-149816.T68vc_.rst @@ -0,0 +1 @@ +Fix race condition in :attr:`ssl.SSLContext.sni_callback` diff --git a/Modules/_ssl.c b/Modules/_ssl.c index 69472ae01a5016..f451c0ce7364ab 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -26,6 +26,7 @@ #define OPENSSL_NO_DEPRECATED 1 #include "Python.h" +#include "pycore_critical_section.h" // Py_BEGIN_CRITICAL_SECTION() #include "pycore_fileutils.h" // _PyIsSelectable_fd() #include "pycore_long.h" // _PyLong_UnsignedLongLong_Converter() #include "pycore_pyerrors.h" // _PyErr_ChainExceptions1() @@ -5151,12 +5152,15 @@ _servername_callback(SSL *s, int *al, void *args) PyObject *result; /* The high-level ssl.SSLSocket object */ PyObject *ssl_socket; + PyObject *sni_cb; const char *servername = SSL_get_servername(s, TLSEXT_NAMETYPE_host_name); PyGILState_STATE gstate = PyGILState_Ensure(); - if (sslctx->set_sni_cb == NULL) { - /* remove race condition in this the call back while if removing the - * callback is in progress */ + Py_BEGIN_CRITICAL_SECTION(sslctx); + sni_cb = Py_XNewRef(sslctx->set_sni_cb); + Py_END_CRITICAL_SECTION(); + + if (sni_cb == NULL) { PyGILState_Release(gstate); return SSL_TLSEXT_ERR_OK; } @@ -5183,7 +5187,7 @@ _servername_callback(SSL *s, int *al, void *args) goto error; if (servername == NULL) { - result = PyObject_CallFunctionObjArgs(sslctx->set_sni_cb, ssl_socket, + result = PyObject_CallFunctionObjArgs(sni_cb, ssl_socket, Py_None, sslctx, NULL); } else { @@ -5210,7 +5214,7 @@ _servername_callback(SSL *s, int *al, void *args) } Py_DECREF(servername_bytes); result = PyObject_CallFunctionObjArgs( - sslctx->set_sni_cb, ssl_socket, servername_str, + sni_cb, ssl_socket, servername_str, sslctx, NULL); Py_DECREF(servername_str); } @@ -5220,7 +5224,7 @@ _servername_callback(SSL *s, int *al, void *args) PyErr_FormatUnraisable("Exception ignored " "in ssl servername callback " "while calling set SNI callback %R", - sslctx->set_sni_cb); + sni_cb); *al = SSL_AD_HANDSHAKE_FAILURE; ret = SSL_TLSEXT_ERR_ALERT_FATAL; } @@ -5245,11 +5249,13 @@ _servername_callback(SSL *s, int *al, void *args) Py_DECREF(result); } + Py_DECREF(sni_cb); PyGILState_Release(gstate); return ret; error: Py_XDECREF(ssl_socket); + Py_XDECREF(sni_cb); *al = SSL_AD_INTERNAL_ERROR; ret = SSL_TLSEXT_ERR_ALERT_FATAL; PyGILState_Release(gstate); @@ -5298,20 +5304,18 @@ _ssl__SSLContext_sni_callback_set_impl(PySSLContext *self, PyObject *value) "sni_callback cannot be set on TLS_CLIENT context"); return -1; } - Py_CLEAR(self->set_sni_cb); - if (value == Py_None) { + if (!PyCallable_Check(value)) { SSL_CTX_set_tlsext_servername_callback(self->ctx, NULL); - } - else { - if (!PyCallable_Check(value)) { - SSL_CTX_set_tlsext_servername_callback(self->ctx, NULL); - PyErr_SetString(PyExc_TypeError, - "not a callable object"); + Py_CLEAR(self->set_sni_cb); + if (value != Py_None) { + PyErr_SetString(PyExc_TypeError, "not a callable object"); return -1; } - self->set_sni_cb = Py_NewRef(value); - SSL_CTX_set_tlsext_servername_callback(self->ctx, _servername_callback); + } + else { + Py_XSETREF(self->set_sni_cb, Py_NewRef(value)); SSL_CTX_set_tlsext_servername_arg(self->ctx, self); + SSL_CTX_set_tlsext_servername_callback(self->ctx, _servername_callback); } return 0; } From e795bd4be7c0304b678beb5af7dc3e634af818ea Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 8 Jun 2026 20:01:52 +0200 Subject: [PATCH 261/818] [3.15] gh-119949: Refactor test_exc() helper in test_format.py (GH-135452) (GH-150329) Use assertRaisesRegex() context and fix https://github.com/python/cpython/pull/119781#pullrequestreview-2088240959 (cherry picked from commit 0851700a9d99ca4bebd8d5f9d73c8c9ab1084405) Co-authored-by: Sergey B Kirpichev <skirpichev@gmail.com> --- Lib/test/test_format.py | 38 ++++++++++++++------------------------ 1 file changed, 14 insertions(+), 24 deletions(-) diff --git a/Lib/test/test_format.py b/Lib/test/test_format.py index 00f1ab44b0a8fa..5d322cb444cfb6 100644 --- a/Lib/test/test_format.py +++ b/Lib/test/test_format.py @@ -68,33 +68,20 @@ def testcommon(formatstr, args, output=None, limit=None, overflowok=False): testformat(b_format, args, b_output, limit, overflowok) testformat(ba_format, args, ba_output, limit, overflowok) -def test_exc(formatstr, args, exception, excmsg): - try: - testformat(formatstr, args) - except exception as exc: - if str(exc) == excmsg: - if verbose: - print("yes") - else: - if verbose: print('no') - print('Unexpected ', exception, ':', repr(str(exc))) - raise - except: - if verbose: print('no') - print('Unexpected exception') - raise - else: - raise TestFailed('did not get expected exception: %s' % excmsg) - -def test_exc_common(formatstr, args, exception, excmsg): - # test str and bytes - test_exc(formatstr, args, exception, excmsg) - if isinstance(args, dict): - args = {k.encode('ascii'): v for k, v in args.items()} - test_exc(formatstr.encode('ascii'), args, exception, excmsg) class FormatTest(unittest.TestCase): + def check_exc(self, formatstr, args, exception, excmsg): + with self.assertRaisesRegex(exception, re.escape(excmsg)): + testformat(formatstr, args) + + def check_exc_common(self, formatstr, args, exception, excmsg): + # test str and bytes + self.check_exc(formatstr, args, exception, excmsg) + if isinstance(args, dict): + args = {k.encode('ascii'): v for k, v in args.items()} + self.check_exc(formatstr.encode('ascii'), args, exception, excmsg) + def test_common_format(self): # test the format identifiers that work the same across # str, bytes, and bytearrays (integer, float, oct, hex) @@ -271,6 +258,7 @@ def test_common_format(self): if verbose: print('Testing exceptions') + test_exc_common = self.check_exc_common test_exc_common('abc %', (), ValueError, "stray % at position 4") test_exc_common('abc % %s', 1, ValueError, "stray % at position 4 or unexpected format character '%' at position 6") @@ -365,6 +353,7 @@ def test_str_format(self): # Test exception for unknown format characters, etc. if verbose: print('Testing exceptions') + test_exc = self.check_exc test_exc('abc %b', 1, ValueError, "unsupported format %b at position 4") test_exc("abc %\nd", 1, ValueError, @@ -468,6 +457,7 @@ def __bytes__(self): # Test exception for unknown format characters, etc. if verbose: print('Testing exceptions') + test_exc = self.check_exc test_exc(b"abc %\nd", 1, ValueError, "stray % at position 4 or unexpected format character with code 0x0a at position 5") test_exc(b"abc %'d", 1, ValueError, From 5751633facde4e217c805a95dd679caa4e760d28 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 8 Jun 2026 20:58:11 +0200 Subject: [PATCH 262/818] [3.15] gh-150633: Properly handle null characters in the name when importing frozen modules (GH-150634) (GH-151100) (cherry picked from commit 54de5475cd753e2519692c3e54af0f150e0a8b62) Co-authored-by: Thomas Kowalski <thom.kowa@gmail.com> --- Lib/test/test_import/__init__.py | 9 +++++++++ .../2026-05-30-20-19-35.gh-issue-150633.XkNul0.rst | 3 +++ Python/import.c | 2 +- 3 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-05-30-20-19-35.gh-issue-150633.XkNul0.rst diff --git a/Lib/test/test_import/__init__.py b/Lib/test/test_import/__init__.py index c905c0da0a1232..f8e77fc7c532c4 100644 --- a/Lib/test/test_import/__init__.py +++ b/Lib/test/test_import/__init__.py @@ -364,6 +364,15 @@ def test_import_raises_ModuleNotFoundError(self): with self.assertRaises(ModuleNotFoundError): import something_that_should_not_exist_anywhere + def test_import_null_byte_in_name_raises_ModuleNotFoundError(self): + # gh-150633: module names containing null bytes should not + # lead to duplicates in sys.modules + before = set(sys.modules.keys()) + with self.assertRaises(ModuleNotFoundError): + __import__('zipimport\x00junk') + + self.assertEqual(set(sys.modules.keys()), before) + def test_from_import_missing_module_raises_ModuleNotFoundError(self): with self.assertRaises(ModuleNotFoundError): from something_that_should_not_exist_anywhere import blah diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-30-20-19-35.gh-issue-150633.XkNul0.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-30-20-19-35.gh-issue-150633.XkNul0.rst new file mode 100644 index 00000000000000..c397ad61f086c1 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-30-20-19-35.gh-issue-150633.XkNul0.rst @@ -0,0 +1,3 @@ +Fix the frozen importer accepting module names with embedded null bytes, which +caused it to bypass the :data:`sys.modules` cache and create duplicate module +objects. diff --git a/Python/import.c b/Python/import.c index fc1b3f1acbe063..63021208a23d3b 100644 --- a/Python/import.c +++ b/Python/import.c @@ -3168,7 +3168,7 @@ find_frozen(PyObject *nameobj, struct frozen_info *info) if (nameobj == NULL || nameobj == Py_None) { return FROZEN_BAD_NAME; } - const char *name = PyUnicode_AsUTF8(nameobj); + const char *name = _PyUnicode_AsUTF8NoNUL(nameobj); if (name == NULL) { // Note that this function previously used // _PyUnicode_EqualToASCIIString(). We clear the error here From fd4f9fa18635a4e354b946bc20128980e35aab0d Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 8 Jun 2026 21:47:05 +0200 Subject: [PATCH 263/818] [3.15] gh-151070: Fix class referencing typo in collections.abc docs (GH-151088) (GH-151110) (cherry picked from commit 29a920e80e21490b5bdb7178373f80fe606a4403) Co-authored-by: Arshal Aromal <arshalaromal19@gmail.com> --- Doc/library/collections.abc.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/collections.abc.rst b/Doc/library/collections.abc.rst index 51853725b1b297..10e3790717ed6e 100644 --- a/Doc/library/collections.abc.rst +++ b/Doc/library/collections.abc.rst @@ -456,7 +456,7 @@ Notes on using :class:`Set` and :class:`MutableSet` as a mixin: The :class:`Set` mixin provides a :meth:`!_hash` method to compute a hash value for the set; however, :meth:`~object.__hash__` is not defined because not all sets are :term:`hashable` or immutable. To add set hashability using mixins, - inherit from both :meth:`Set` and :meth:`Hashable`, then define + inherit from both :class:`Set` and :class:`Hashable`, then define ``__hash__ = Set._hash``. .. seealso:: From eeba22190522a26d3847da1383e976871adff6ca Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 8 Jun 2026 22:04:02 +0200 Subject: [PATCH 264/818] [3.15] gh-150633: Minor improvement of a newly added test (GH-151103) (#151106) gh-150633: Minor improvement of a newly added test (GH-151103) Minor improvement of a newly added test. (cherry picked from commit fccf67a35449920484ea11d8a16566b58b0c4519) Co-authored-by: Barry Warsaw <barry@python.org> --- Lib/test/test_import/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_import/__init__.py b/Lib/test/test_import/__init__.py index f8e77fc7c532c4..9f3df8010d3233 100644 --- a/Lib/test/test_import/__init__.py +++ b/Lib/test/test_import/__init__.py @@ -367,11 +367,11 @@ def test_import_raises_ModuleNotFoundError(self): def test_import_null_byte_in_name_raises_ModuleNotFoundError(self): # gh-150633: module names containing null bytes should not # lead to duplicates in sys.modules - before = set(sys.modules.keys()) + before = set(sys.modules) with self.assertRaises(ModuleNotFoundError): __import__('zipimport\x00junk') - self.assertEqual(set(sys.modules.keys()), before) + self.assertEqual(set(sys.modules), before) def test_from_import_missing_module_raises_ModuleNotFoundError(self): with self.assertRaises(ModuleNotFoundError): From fd252e80f5a1a40eb8ed05ea47a36c33f8eec760 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 9 Jun 2026 00:04:06 +0200 Subject: [PATCH 265/818] [3.15] gh-148932: Fix `profiling.sampling` on Windows virtual environments (GH-150541) (#151097) gh-148932: Fix `profiling.sampling` on Windows virtual environments (GH-150541) (cherry picked from commit 5c1321731403031d933ca469977e4bb3859c8680) Co-authored-by: Eduardo Villalpando Mello <eduardovil@microsoft.com> --- Doc/library/profiling.sampling.rst | 5 --- Lib/profiling/sampling/sample.py | 35 ++++++++++++++++--- ...-05-27-23-47-31.gh-issue-148932.Y1xmvA.rst | 1 + 3 files changed, 31 insertions(+), 10 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-05-27-23-47-31.gh-issue-148932.Y1xmvA.rst diff --git a/Doc/library/profiling.sampling.rst b/Doc/library/profiling.sampling.rst index 39b6ea4e31cde7..aeb1a429b58515 100644 --- a/Doc/library/profiling.sampling.rst +++ b/Doc/library/profiling.sampling.rst @@ -387,11 +387,6 @@ This requires one of: On Windows, the profiler requires administrative privileges or the ``SeDebugPrivilege`` privilege to read another process's memory. -*Note*: On Windows, ``python -m profiling.sampling`` fails inside a virtual -environment because the venv's ``python.exe`` is just a launcher shim that -re-executes the base interpreter as a child process. The shim itself isn't -a Python process and has no ``PyRuntime`` section to attach to. Instead, -run it from the global Python installation. Version compatibility --------------------- diff --git a/Lib/profiling/sampling/sample.py b/Lib/profiling/sampling/sample.py index 2d379e1e16a35e..50ccc57566d70d 100644 --- a/Lib/profiling/sampling/sample.py +++ b/Lib/profiling/sampling/sample.py @@ -50,9 +50,38 @@ def _pause_threads(unwinder, blocking): # Maximum number of consecutive identical samples to keep before flushing. MAX_PENDING_SAMPLES = 8192 + +def _resolve_python_pid(pid): + """On Windows, if pid is a venvlauncher process, return the child Python PID. + + The venvlauncher (used as python.exe in venvs) spawns the real Python + interpreter as a child process via CreateProcessW. The RemoteUnwinder + needs the child's PID, not the launcher's. + + Returns the original pid if not on Windows, not a venv launcher, + or no child process is found. + """ + if os.name != "nt" or sys.prefix == sys.base_prefix: + return pid + try: + children = _remote_debugging.get_child_pids(pid, recursive=False) + python_children = [ + child for child in children + if _remote_debugging.is_python_process(child) + ] + if len(python_children) == 1: + return python_children[0] + except (OSError, RuntimeError) as err: + raise SystemExit( + f"Failed to initialize profiler from virtualenv: {err}\n" + f"Try running with the base interpreter: {sys._base_executable}" + ) from err + return pid + + class SampleProfiler: def __init__(self, pid, sample_interval_usec, all_threads, *, mode=PROFILING_MODE_WALL, native=False, gc=True, opcodes=False, skip_non_matching_threads=True, collect_stats=False, blocking=False): - self.pid = pid + self.pid = _resolve_python_pid(pid) self.sample_interval_usec = sample_interval_usec self.all_threads = all_threads self.mode = mode # Store mode for later use @@ -61,10 +90,6 @@ def __init__(self, pid, sample_interval_usec, all_threads, *, mode=PROFILING_MOD try: self.unwinder = self._new_unwinder(native, gc, opcodes, skip_non_matching_threads) except RuntimeError as err: - if os.name == "nt" and sys.executable.endswith("python.exe"): - raise SystemExit( - "Running profiling.sampling from virtualenv on Windows platform is not supported" - ) from err raise SystemExit(err) from err # Track sample intervals and total sample count self.sample_intervals = deque(maxlen=100) diff --git a/Misc/NEWS.d/next/Library/2026-05-27-23-47-31.gh-issue-148932.Y1xmvA.rst b/Misc/NEWS.d/next/Library/2026-05-27-23-47-31.gh-issue-148932.Y1xmvA.rst new file mode 100644 index 00000000000000..a0b7a9740cd518 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-05-27-23-47-31.gh-issue-148932.Y1xmvA.rst @@ -0,0 +1 @@ +Fix ``profiling.sampling`` on Windows virtual environments to resolve the actual Python PID from a virtual environment shim. From 83e26a43a7598ef55a4f9b0bd793b029071d3ed4 Mon Sep 17 00:00:00 2001 From: Pablo Galindo Salgado <Pablogsal@gmail.com> Date: Mon, 8 Jun 2026 23:55:57 +0100 Subject: [PATCH 266/818] [3.15] gh-149321: Remove lazy_imports=none startup mode (GH-149389) (#150129) --- Doc/c-api/import.rst | 5 - Doc/data/python3.15.abi | 1 - Doc/library/sys.rst | 4 - Doc/reference/simple_stmts.rst | 4 - Doc/tools/removed-ids.txt | 3 + Doc/using/cmdline.rst | 14 +- Doc/whatsnew/3.15.rst | 9 +- Include/import.h | 3 +- Lib/test/test_lazy_import/__init__.py | 160 ++++-------------- Lib/test/test_lazy_import/data/global_off.py | 5 - Misc/NEWS.d/3.15.0a8.rst | 10 -- ...-issue-149321.remove-lazy-imports-none.rst | 1 + Modules/_testcapi/import.c | 4 - Python/ceval.c | 18 +- Python/clinic/sysmodule.c.h | 4 +- Python/initconfig.c | 15 +- Python/pylifecycle.c | 14 +- Python/sysmodule.c | 15 +- 18 files changed, 71 insertions(+), 218 deletions(-) delete mode 100644 Lib/test/test_lazy_import/data/global_off.py create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-05-05-12-00-00.gh-issue-149321.remove-lazy-imports-none.rst diff --git a/Doc/c-api/import.rst b/Doc/c-api/import.rst index e2d363b911a87c..ec9462931d56c2 100644 --- a/Doc/c-api/import.rst +++ b/Doc/c-api/import.rst @@ -393,11 +393,6 @@ Importing Modules Make all imports lazy by default. - .. c:enumerator:: PyImport_LAZY_NONE - - Disable lazy imports entirely. Even explicit ``lazy`` statements become - eager imports. - .. versionadded:: 3.15 .. c:function:: PyObject* PyImport_CreateModuleFromInitfunc(PyObject *spec, PyObject* (*initfunc)(void)) diff --git a/Doc/data/python3.15.abi b/Doc/data/python3.15.abi index aea9ff48a62763..d769d6a764c62e 100644 --- a/Doc/data/python3.15.abi +++ b/Doc/data/python3.15.abi @@ -26840,7 +26840,6 @@ <underlying-type type-id='type-id-45'/> <enumerator name='PyImport_LAZY_NORMAL' value='0'/> <enumerator name='PyImport_LAZY_ALL' value='1'/> - <enumerator name='PyImport_LAZY_NONE' value='2'/> </enum-decl> <typedef-decl name='PyImport_LazyImportsMode' type-id='type-id-1652' filepath='./Include/import.h' line='95' column='1' id='type-id-1651'/> <typedef-decl name='conversion_func' type-id='type-id-1456' filepath='./Include/internal/pycore_ceval.h' line='282' column='1' id='type-id-1653'/> diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst index 4683fc03f843a2..b4f410a020f86e 100644 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -919,8 +919,6 @@ always available. Unless explicitly noted otherwise, all variables are read-only * ``"normal"``: Only imports explicitly marked with the ``lazy`` keyword are lazy * ``"all"``: All top-level imports are potentially lazy - * ``"none"``: All lazy imports are suppressed (even explicitly marked - ones) See also :func:`set_lazy_imports` and :pep:`810`. @@ -1772,8 +1770,6 @@ always available. Unless explicitly noted otherwise, all variables are read-only * ``"normal"``: Only imports explicitly marked with the ``lazy`` keyword are lazy * ``"all"``: All top-level imports become potentially lazy - * ``"none"``: All lazy imports are suppressed (even explicitly marked - ones) This function is intended for advanced users who need to control lazy imports across their entire application. Library developers should diff --git a/Doc/reference/simple_stmts.rst b/Doc/reference/simple_stmts.rst index f8e54aa0a108c8..0f134604b5d922 100644 --- a/Doc/reference/simple_stmts.rst +++ b/Doc/reference/simple_stmts.rst @@ -965,10 +965,6 @@ Imports inside functions, class bodies, or :keyword:`try`/:keyword:`except`/:keyword:`finally` blocks are always eager, regardless of :attr:`!__lazy_modules__`. -Setting ``-X lazy_imports=none`` (or the :envvar:`PYTHON_LAZY_IMPORTS` -environment variable to ``none``) overrides :attr:`!__lazy_modules__` and -forces all imports to be eager. - .. versionadded:: 3.15 .. _future: diff --git a/Doc/tools/removed-ids.txt b/Doc/tools/removed-ids.txt index 2d5917f4d240f5..474376f4bd7bae 100644 --- a/Doc/tools/removed-ids.txt +++ b/Doc/tools/removed-ids.txt @@ -6,6 +6,9 @@ c-api/file.html: deprecated-api library/asyncio-task.html: terminating-a-task-group +# Removed APIs +c-api/import.html: c.PyImport_LazyImportsMode.PyImport_LAZY_NONE + ## Old names for grammar tokens reference/expressions.html: grammar-token-python-grammar-comp_for reference/expressions.html: grammar-token-python-grammar-comp_if diff --git a/Doc/using/cmdline.rst b/Doc/using/cmdline.rst index d84cd42062a678..19997eb5fed963 100644 --- a/Doc/using/cmdline.rst +++ b/Doc/using/cmdline.rst @@ -705,10 +705,9 @@ Miscellaneous options .. versionadded:: 3.14 - * :samp:`-X lazy_imports={all,none,normal}` controls lazy import behavior. - ``all`` makes all imports lazy by default, ``none`` disables lazy imports - entirely (even explicit ``lazy`` statements become eager), and ``normal`` - (the default) respects the ``lazy`` keyword in source code. + * :samp:`-X lazy_imports={all,normal}` controls lazy import behavior. + ``all`` makes all imports lazy by default, and ``normal`` (the default) + respects the ``lazy`` keyword in source code. See also :envvar:`PYTHON_LAZY_IMPORTS`. .. versionadded:: 3.15 @@ -1416,10 +1415,9 @@ conflict. .. envvar:: PYTHON_LAZY_IMPORTS - Controls lazy import behavior. Accepts three values: ``all`` makes all - imports lazy by default, ``none`` disables lazy imports entirely (even - explicit ``lazy`` statements become eager), and ``normal`` (the default) - respects the ``lazy`` keyword in source code. + Controls lazy import behavior. Accepts two values: ``all`` makes all + imports lazy by default, and ``normal`` (the default) respects the + ``lazy`` keyword in source code. See also the :option:`-X lazy_imports <-X>` command-line option. diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst index 7d20805c4c5775..36a18f15a3deb2 100644 --- a/Doc/whatsnew/3.15.rst +++ b/Doc/whatsnew/3.15.rst @@ -157,11 +157,10 @@ making it straightforward to diagnose and debug the failure. For cases where you want to enable lazy loading globally without modifying source code, Python provides the :option:`-X lazy_imports <-X>` command-line option and the :envvar:`PYTHON_LAZY_IMPORTS` environment variable. Both -accept three values: ``all`` makes all imports lazy by default, ``none`` -disables lazy imports entirely (even explicit ``lazy`` statements become -eager), and ``normal`` (the default) respects the ``lazy`` keyword in source -code. The :func:`sys.set_lazy_imports` and :func:`sys.get_lazy_imports` -functions allow changing and querying this mode at runtime. +accept two values: ``all`` makes all imports lazy by default, and ``normal`` +(the default) respects the ``lazy`` keyword in source code. The +:func:`sys.set_lazy_imports` and :func:`sys.get_lazy_imports` functions allow +changing and querying this mode at runtime. For more selective control, :func:`sys.set_lazy_imports_filter` accepts a callable that determines whether a specific module should be loaded lazily. diff --git a/Include/import.h b/Include/import.h index 6f1c13787b8569..c062e46bff46bf 100644 --- a/Include/import.h +++ b/Include/import.h @@ -90,8 +90,7 @@ PyAPI_FUNC(int) PyImport_AppendInittab( typedef enum { PyImport_LAZY_NORMAL, - PyImport_LAZY_ALL, - PyImport_LAZY_NONE + PyImport_LAZY_ALL } PyImport_LazyImportsMode; #ifndef Py_LIMITED_API diff --git a/Lib/test/test_lazy_import/__init__.py b/Lib/test/test_lazy_import/__init__.py index aeb275b958ec5e..c99c22491028d3 100644 --- a/Lib/test/test_lazy_import/__init__.py +++ b/Lib/test/test_lazy_import/__init__.py @@ -171,10 +171,18 @@ def test_from_import_with_imported_module_getattr(self): class GlobalLazyImportModeTests(LazyImportTestCase): """Tests for sys.set_lazy_imports() global mode control.""" - def test_global_off(self): - """Mode 'none' should disable lazy imports entirely.""" - import test.test_lazy_import.data.global_off - self.assertIn("test.test_lazy_import.data.basic2", sys.modules) + def tearDown(self): + for key in list(sys.modules.keys()): + if key.startswith('test.test_lazy_import.data'): + del sys.modules[key] + + sys.set_lazy_imports_filter(None) + sys.set_lazy_imports("normal") + + def test_global_off_rejected(self): + """Mode 'none' is not supported.""" + with self.assertRaises(ValueError): + sys.set_lazy_imports("none") def test_global_on(self): """Mode 'all' should make regular imports lazy.""" @@ -612,9 +620,6 @@ def test_get_lazy_imports_returns_string(self): sys.set_lazy_imports("all") self.assertEqual(sys.get_lazy_imports(), "all") - sys.set_lazy_imports("none") - self.assertEqual(sys.get_lazy_imports(), "none") - def test_get_lazy_imports_filter_default(self): """get_lazy_imports_filter should return None by default.""" sys.set_lazy_imports_filter(None) @@ -1111,68 +1116,16 @@ def test_cli_lazy_imports_all_makes_regular_imports_lazy(self): self.assertEqual(result.returncode, 0, f"stderr: {result.stderr}") self.assertIn("LAZY", result.stdout) - def test_cli_lazy_imports_none_forces_all_imports_eager(self): - """-X lazy_imports=none should force all imports to be eager.""" - code = textwrap.dedent(""" - import sys - # Even explicit lazy imports should be eager in 'none' mode - lazy import json - if 'json' in sys.modules: - print("EAGER") - else: - print("LAZY") - """) + def test_cli_lazy_imports_none_is_rejected(self): + """-X lazy_imports=none should be rejected.""" result = subprocess.run( - [sys.executable, "-X", "lazy_imports=none", "-c", code], + [sys.executable, "-X", "lazy_imports=none", "-c", "pass"], capture_output=True, text=True ) - self.assertEqual(result.returncode, 0, f"stderr: {result.stderr}") - self.assertIn("EAGER", result.stdout) - - @support.requires_resource("cpu") - def test_cli_lazy_imports_modes_import_stdlib_modules(self): - """-X lazy_imports modes should import available stdlib modules.""" - # Do not smoke-test modules with intentional import-time effects. - import_side_effect_modules = {"antigravity", "this"} - importable = [] - - for module in sorted(sys.stdlib_module_names): - if module in import_side_effect_modules: - continue - - with self.subTest(module=module): - code = f"import {module}; print({module})" - baseline = subprocess.run( - [sys.executable, "-I", "-c", code], - capture_output=True, - text=True, - timeout=60, - ) - if baseline.returncode: - # sys.stdlib_module_names includes modules for other - # platforms and optional extension modules not built here. - continue - importable.append(module) - - for mode in ("normal", "none"): - with self.subTest(module=module, mode=mode): - result = subprocess.run( - [ - sys.executable, - "-I", - "-X", - f"lazy_imports={mode}", - "-c", - code, - ], - capture_output=True, - text=True, - timeout=60, - ) - self.assertEqual(result.returncode, 0, result.stderr) - - self.assertGreater(len(importable), 100) + self.assertNotEqual(result.returncode, 0) + self.assertIn("-X lazy_imports: invalid value", result.stderr) + self.assertIn("expected 'all' or 'normal'", result.stderr) def test_cli_lazy_imports_normal_respects_lazy_keyword_only(self): """-X lazy_imports=normal should respect lazy keyword only.""" @@ -1221,77 +1174,27 @@ def test_env_var_lazy_imports_all_enables_global_lazy(self): self.assertEqual(result.returncode, 0, f"stderr: {result.stderr}") self.assertIn("LAZY", result.stdout) - def test_env_var_lazy_imports_none_disables_all_lazy(self): - """PYTHON_LAZY_IMPORTS=none should disable all lazy imports.""" - code = textwrap.dedent(""" - import sys - lazy import json - if 'json' in sys.modules: - print("EAGER") - else: - print("LAZY") - """) + def test_env_var_lazy_imports_none_is_rejected(self): + """PYTHON_LAZY_IMPORTS=none should be rejected.""" import os env = os.environ.copy() env["PYTHON_LAZY_IMPORTS"] = "none" result = subprocess.run( - [sys.executable, "-c", code], + [sys.executable, "-c", "pass"], capture_output=True, text=True, env=env ) - self.assertEqual(result.returncode, 0, f"stderr: {result.stderr}") - self.assertIn("EAGER", result.stdout) - - def test_cli_lazy_imports_none_disables_dunder_lazy_modules(self): - """-X lazy_imports=none should override __lazy_modules__.""" - code = textwrap.dedent(""" - import sys - __lazy_modules__ = ["json"] - import json - if 'json' in sys.modules: - print("EAGER") - else: - print("LAZY") - """) - result = subprocess.run( - [sys.executable, "-X", "lazy_imports=none", "-c", code], - capture_output=True, - text=True, - ) - self.assertEqual(result.returncode, 0, f"stderr: {result.stderr}") - self.assertIn("EAGER", result.stdout) - - def test_env_var_lazy_imports_none_disables_dunder_lazy_modules(self): - """PYTHON_LAZY_IMPORTS=none should override __lazy_modules__.""" - code = textwrap.dedent(""" - import sys - __lazy_modules__ = ["json"] - import json - if 'json' in sys.modules: - print("EAGER") - else: - print("LAZY") - """) - import os - - env = os.environ.copy() - env["PYTHON_LAZY_IMPORTS"] = "none" - result = subprocess.run( - [sys.executable, "-c", code], - capture_output=True, - text=True, - env=env, - ) - self.assertEqual(result.returncode, 0, f"stderr: {result.stderr}") - self.assertIn("EAGER", result.stdout) + self.assertNotEqual(result.returncode, 0) + self.assertIn("PYTHON_LAZY_IMPORTS: invalid value", result.stderr) + self.assertIn("expected 'all' or 'normal'", result.stderr) def test_cli_overrides_env_var(self): """Command-line option should take precedence over environment variable.""" # PEP 810: -X lazy_imports takes precedence over PYTHON_LAZY_IMPORTS code = textwrap.dedent(""" import sys - lazy import json + import json if 'json' in sys.modules: print("EAGER") else: @@ -1299,23 +1202,23 @@ def test_cli_overrides_env_var(self): """) import os env = os.environ.copy() - env["PYTHON_LAZY_IMPORTS"] = "all" # env says all + env["PYTHON_LAZY_IMPORTS"] = "all" # env says all imports are lazy result = subprocess.run( - [sys.executable, "-X", "lazy_imports=none", "-c", code], # CLI says none + [sys.executable, "-X", "lazy_imports=normal", "-c", code], capture_output=True, text=True, env=env ) self.assertEqual(result.returncode, 0, f"stderr: {result.stderr}") - # CLI should win - imports should be eager + # CLI should win, so a regular import should stay eager. self.assertIn("EAGER", result.stdout) def test_sys_set_lazy_imports_overrides_cli(self): """sys.set_lazy_imports() should take precedence over CLI option.""" code = textwrap.dedent(""" import sys - sys.set_lazy_imports("none") # Override CLI - lazy import json + sys.set_lazy_imports("normal") # Override CLI + import json if 'json' in sys.modules: print("EAGER") else: @@ -2037,9 +1940,10 @@ def test_normal_import_dis(self): class LazyCApiTests(LazyImportTestCase): def test_set_matches_sys(self): self.assertEqual(_testcapi.PyImport_GetLazyImportsMode(), sys.get_lazy_imports()) - for mode in ("normal", "all", "none"): + for mode in ("normal", "all"): _testcapi.PyImport_SetLazyImportsMode(mode) self.assertEqual(_testcapi.PyImport_GetLazyImportsMode(), sys.get_lazy_imports()) + self.assertRaises(ValueError, _testcapi.PyImport_SetLazyImportsMode, "none") def test_filter_matches_sys(self): self.assertEqual(_testcapi.PyImport_GetLazyImportsFilter(), sys.get_lazy_imports_filter()) diff --git a/Lib/test/test_lazy_import/data/global_off.py b/Lib/test/test_lazy_import/data/global_off.py deleted file mode 100644 index 95d1511dd93223..00000000000000 --- a/Lib/test/test_lazy_import/data/global_off.py +++ /dev/null @@ -1,5 +0,0 @@ -import sys - -sys.set_lazy_imports("none") - -lazy import test.test_lazy_import.data.basic2 as basic2 diff --git a/Misc/NEWS.d/3.15.0a8.rst b/Misc/NEWS.d/3.15.0a8.rst index 3c6da8b6ab48e3..28e9ca85166620 100644 --- a/Misc/NEWS.d/3.15.0a8.rst +++ b/Misc/NEWS.d/3.15.0a8.rst @@ -180,16 +180,6 @@ dealing with contradictions in ``make_bottom``. .. -.. date: 2026-03-24-13-06-52 -.. gh-issue: 146369 -.. nonce: 6wDI6S -.. section: Core and Builtins - -Ensure ``-X lazy_imports=none`` and ``PYTHON_LAZY_IMPORTS=none`` override -:attr:`~module.__lazy_modules__`. Patch by Hugo van Kemenade. - -.. - .. date: 2026-03-22-19-30-00 .. gh-issue: 146308 .. nonce: AxnRVA diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-05-12-00-00.gh-issue-149321.remove-lazy-imports-none.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-05-12-00-00.gh-issue-149321.remove-lazy-imports-none.rst new file mode 100644 index 00000000000000..44e96ce7be0bfb --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-05-12-00-00.gh-issue-149321.remove-lazy-imports-none.rst @@ -0,0 +1 @@ +Do not support ``none`` as a lazy imports mode. diff --git a/Modules/_testcapi/import.c b/Modules/_testcapi/import.c index ebb1032fdd1c32..384a8f52da4b98 100644 --- a/Modules/_testcapi/import.c +++ b/Modules/_testcapi/import.c @@ -41,8 +41,6 @@ pyimport_setlazyimportsmode(PyObject *self, PyObject *args) PyImport_SetLazyImportsMode(PyImport_LAZY_NORMAL); } else if (strcmp(PyUnicode_AsUTF8(mode), "all") == 0) { PyImport_SetLazyImportsMode(PyImport_LAZY_ALL); - } else if (strcmp(PyUnicode_AsUTF8(mode), "none") == 0) { - PyImport_SetLazyImportsMode(PyImport_LAZY_NONE); } else { PyErr_SetString(PyExc_ValueError, "invalid mode"); return NULL; @@ -59,8 +57,6 @@ pyimport_getlazyimportsmode(PyObject *self, PyObject *args) return PyUnicode_FromString("normal"); case PyImport_LAZY_ALL: return PyUnicode_FromString("all"); - case PyImport_LAZY_NONE: - return PyUnicode_FromString("none"); default: PyErr_SetString(PyExc_ValueError, "unknown mode"); return NULL; diff --git a/Python/ceval.c b/Python/ceval.c index a080ae42b93766..5661200e74d0a5 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -3072,12 +3072,8 @@ _PyEval_LazyImportName(PyThreadState *tstate, PyObject *builtins, PyObject *fromlist, PyObject *level, int lazy) { PyObject *res = NULL; - PyImport_LazyImportsMode mode = PyImport_GetLazyImportsMode(); // Check if global policy overrides the local syntax - switch (mode) { - case PyImport_LAZY_NONE: - lazy = 0; - break; + switch (PyImport_GetLazyImportsMode()) { case PyImport_LAZY_ALL: if (!lazy) { lazy = is_lazy_import_module_level(); @@ -3087,11 +3083,15 @@ _PyEval_LazyImportName(PyThreadState *tstate, PyObject *builtins, break; } - if (!lazy && mode != PyImport_LAZY_NONE && is_lazy_import_module_level()) { + if (!lazy) { // See if __lazy_modules__ forces this to be lazy. - lazy = check_lazy_import_compatibility(tstate, globals, name, level); - if (lazy < 0) { - return NULL; + // __lazy_modules__ only applies at module level; exec() inside + // functions or classes should remain eager. + if (is_lazy_import_module_level()) { + lazy = check_lazy_import_compatibility(tstate, globals, name, level); + if (lazy < 0) { + return NULL; + } } } diff --git a/Python/clinic/sysmodule.c.h b/Python/clinic/sysmodule.c.h index 75ce493f8688d6..067b0b0a1fb035 100644 --- a/Python/clinic/sysmodule.c.h +++ b/Python/clinic/sysmodule.c.h @@ -1915,7 +1915,6 @@ PyDoc_STRVAR(sys_set_lazy_imports__doc__, "\n" "The mode parameter must be one of the following strings:\n" "- \"all\": All top-level imports become potentially lazy\n" -"- \"none\": All lazy imports are suppressed (even explicitly marked ones)\n" "- \"normal\": Only explicitly marked imports (with \'lazy\' keyword) are\n" " lazy\n" "\n" @@ -1981,7 +1980,6 @@ PyDoc_STRVAR(sys_get_lazy_imports__doc__, "Gets the global lazy imports mode.\n" "\n" "Returns \"all\" if all top level imports are potentially lazy.\n" -"Returns \"none\" if all explicitly marked lazy imports are suppressed.\n" "Returns \"normal\" if only explicitly marked imports are lazy."); #define SYS_GET_LAZY_IMPORTS_METHODDEF \ @@ -2123,4 +2121,4 @@ _jit_is_active(PyObject *module, PyObject *Py_UNUSED(ignored)) #ifndef SYS_GETANDROIDAPILEVEL_METHODDEF #define SYS_GETANDROIDAPILEVEL_METHODDEF #endif /* !defined(SYS_GETANDROIDAPILEVEL_METHODDEF) */ -/*[clinic end generated code: output=94838be2d96b4522 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=3ccdb73f733fc82c input=a9049054013a1b77]*/ diff --git a/Python/initconfig.c b/Python/initconfig.c index a996fb117aab9d..bebadcc76111b7 100644 --- a/Python/initconfig.c +++ b/Python/initconfig.c @@ -455,7 +455,7 @@ static const char usage_xoptions[] = " log imports of already-loaded modules; also #e{PYTHONPROFILEIMPORTTIME}\n" "#s{-X} #L{int_max_str_digits}#b{=N}: limit the size of int<->str conversions;\n" " 0 disables the limit; also #e{PYTHONINTMAXSTRDIGITS}\n" -"#s{-X} #L{lazy_imports}#b{=[all|none|normal]}: control global lazy imports;\n" +"#s{-X} #L{lazy_imports}#b{=[all|normal]}: control global lazy imports;\n" " default is #B{normal}; also #e{PYTHON_LAZY_IMPORTS}\n" "#s{-X} #L{no_debug_ranges}: don't include extra location information in code objects;\n" " also #e{PYTHONNODEBUGRANGES}\n" @@ -1065,7 +1065,8 @@ config_check_consistency(const PyConfig *config) assert(config->int_max_str_digits >= 0); // cpu_count can be -1 if the user doesn't override it. assert(config->cpu_count != 0); - // lazy_imports can be -1 (default), 0 (off), or 1 (on). + // lazy_imports can be -1 (default) or 1 (on). 0 is rejected later + // for embedders with an error message. assert(config->lazy_imports >= -1 && config->lazy_imports <= 1); // config->use_frozen_modules is initialized later // by _PyConfig_InitImportConfig(). @@ -2437,15 +2438,12 @@ config_init_lazy_imports(PyConfig *config) if (strcmp(env, "all") == 0) { lazy_imports = 1; } - else if (strcmp(env, "none") == 0) { - lazy_imports = 0; - } else if (strcmp(env, "normal") == 0) { lazy_imports = -1; } else { return _PyStatus_ERR("PYTHON_LAZY_IMPORTS: invalid value; " - "expected 'all', 'none', or 'normal'"); + "expected 'all' or 'normal'"); } config->lazy_imports = lazy_imports; } @@ -2455,15 +2453,12 @@ config_init_lazy_imports(PyConfig *config) if (wcscmp(x_value, L"all") == 0) { lazy_imports = 1; } - else if (wcscmp(x_value, L"none") == 0) { - lazy_imports = 0; - } else if (wcscmp(x_value, L"normal") == 0) { lazy_imports = -1; } else { return _PyStatus_ERR("-X lazy_imports: invalid value; " - "expected 'all', 'none', or 'normal'"); + "expected 'all' or 'normal'"); } config->lazy_imports = lazy_imports; } diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index f8d9836d90ba78..0bdc7ddd92dc82 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -1486,15 +1486,11 @@ init_interp_main(PyThreadState *tstate) // Initialize lazy imports based on configuration. Do this after site // module is imported to avoid circular imports during startup. - if (config->lazy_imports != -1) { - PyImport_LazyImportsMode lazy_mode; - if (config->lazy_imports == 1) { - lazy_mode = PyImport_LAZY_ALL; - } - else { - lazy_mode = PyImport_LAZY_NONE; - } - if (PyImport_SetLazyImportsMode(lazy_mode) < 0) { + if (config->lazy_imports == 0) { + return _PyStatus_ERR("PyConfig.lazy_imports=0 is not supported"); + } + if (config->lazy_imports == 1) { + if (PyImport_SetLazyImportsMode(PyImport_LAZY_ALL) < 0) { return _PyStatus_ERR("failed to set lazy imports mode"); } } diff --git a/Python/sysmodule.c b/Python/sysmodule.c index b2f33d4e809d26..b79ebf56371ff2 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -2845,7 +2845,6 @@ Sets the global lazy imports mode. The mode parameter must be one of the following strings: - "all": All top-level imports become potentially lazy -- "none": All lazy imports are suppressed (even explicitly marked ones) - "normal": Only explicitly marked imports (with 'lazy' keyword) are lazy @@ -2856,12 +2855,12 @@ provided to sys.set_lazy_imports_filter static PyObject * sys_set_lazy_imports_impl(PyObject *module, PyObject *mode) -/*[clinic end generated code: output=1ff34ba6c4feaf73 input=cb6df28a51844a31]*/ +/*[clinic end generated code: output=1ff34ba6c4feaf73 input=db3242f0ff6e5dcc]*/ { PyImport_LazyImportsMode lazy_mode; if (!PyUnicode_Check(mode)) { PyErr_SetString(PyExc_TypeError, - "mode must be a string: 'normal', 'all', or 'none'"); + "mode must be a string: 'normal' or 'all'"); return NULL; } if (PyUnicode_CompareWithASCIIString(mode, "normal") == 0) { @@ -2870,12 +2869,9 @@ sys_set_lazy_imports_impl(PyObject *module, PyObject *mode) else if (PyUnicode_CompareWithASCIIString(mode, "all") == 0) { lazy_mode = PyImport_LAZY_ALL; } - else if (PyUnicode_CompareWithASCIIString(mode, "none") == 0) { - lazy_mode = PyImport_LAZY_NONE; - } else { PyErr_SetString(PyExc_ValueError, - "mode must be 'normal', 'all', or 'none'"); + "mode must be 'normal' or 'all'"); return NULL; } @@ -2891,22 +2887,19 @@ sys.get_lazy_imports Gets the global lazy imports mode. Returns "all" if all top level imports are potentially lazy. -Returns "none" if all explicitly marked lazy imports are suppressed. Returns "normal" if only explicitly marked imports are lazy. [clinic start generated code]*/ static PyObject * sys_get_lazy_imports_impl(PyObject *module) -/*[clinic end generated code: output=4147dec48c51ae99 input=8cb574f1e4e3003c]*/ +/*[clinic end generated code: output=4147dec48c51ae99 input=6f8dd4f2c82893f2]*/ { switch (PyImport_GetLazyImportsMode()) { case PyImport_LAZY_NORMAL: return PyUnicode_FromString("normal"); case PyImport_LAZY_ALL: return PyUnicode_FromString("all"); - case PyImport_LAZY_NONE: - return PyUnicode_FromString("none"); default: PyErr_SetString(PyExc_RuntimeError, "unknown lazy imports mode"); return NULL; From 8a2bf2a072ee2482a22eaed96af3016a6f627303 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 9 Jun 2026 12:33:02 +0200 Subject: [PATCH 267/818] [3.15] gh-151126: Fix missing `PyErr_NoMemory()` in `remove_unused_consts` (GH-151127) (#151134) gh-151126: Fix missing `PyErr_NoMemory()` in `remove_unused_consts` (GH-151127) (cherry picked from commit 3186547c1ec76e1afab82ec32271ec5b9467fdeb) Co-authored-by: sobolevn <mail@sobolevn.me> --- .../2026-06-09-10-28-30.gh-issue-151126.DKa6Sl.rst | 3 +++ Python/flowgraph.c | 2 ++ 2 files changed, 5 insertions(+) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-09-10-28-30.gh-issue-151126.DKa6Sl.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-09-10-28-30.gh-issue-151126.DKa6Sl.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-09-10-28-30.gh-issue-151126.DKa6Sl.rst new file mode 100644 index 00000000000000..3f699a50d7a42b --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-09-10-28-30.gh-issue-151126.DKa6Sl.rst @@ -0,0 +1,3 @@ +Fix a crash, when there's no memory left on a device, +which happened in code compilation. +Now it raises a proper :exc:`MemoryError`. diff --git a/Python/flowgraph.c b/Python/flowgraph.c index 224426b7aa44bc..b63906818e2d6c 100644 --- a/Python/flowgraph.c +++ b/Python/flowgraph.c @@ -3273,6 +3273,7 @@ remove_unused_consts(basicblock *entryblock, PyObject *consts) index_map = PyMem_Malloc(nconsts * sizeof(Py_ssize_t)); if (index_map == NULL) { + PyErr_NoMemory(); goto end; } for (Py_ssize_t i = 1; i < nconsts; i++) { @@ -3325,6 +3326,7 @@ remove_unused_consts(basicblock *entryblock, PyObject *consts) /* adjust const indices in the bytecode */ reverse_index_map = PyMem_Malloc(nconsts * sizeof(Py_ssize_t)); if (reverse_index_map == NULL) { + PyErr_NoMemory(); goto end; } for (Py_ssize_t i = 0; i < nconsts; i++) { From 2d432f21dba218c6442f29d1a28d24a8a7a7b1dc Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 9 Jun 2026 13:37:56 +0200 Subject: [PATCH 268/818] [3.15] gh-151130: Add more tests for PyWeakref_* C API (GH-151131) (GH-151140) (cherry picked from commit c3cd75afdf86f6a811663c71da22cc24c784a6f4) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> --- Lib/test/test_capi/test_weakref.py | 136 ++++++++++++++++++ ...-06-09-11-52-52.gh-issue-151130.1vslPH.rst | 1 + Modules/Setup.stdlib.in | 4 +- Modules/_testcapi/parts.h | 1 + Modules/_testcapi/weakref.c | 46 ++++++ Modules/_testcapimodule.c | 3 + Modules/_testlimitedcapi.c | 3 + Modules/_testlimitedcapi/parts.h | 1 + Modules/_testlimitedcapi/weakref.c | 78 ++++++++++ PCbuild/_testcapi.vcxproj | 1 + PCbuild/_testcapi.vcxproj.filters | 3 + PCbuild/_testlimitedcapi.vcxproj | 1 + PCbuild/_testlimitedcapi.vcxproj.filters | 1 + 13 files changed, 277 insertions(+), 2 deletions(-) create mode 100644 Lib/test/test_capi/test_weakref.py create mode 100644 Misc/NEWS.d/next/Tests/2026-06-09-11-52-52.gh-issue-151130.1vslPH.rst create mode 100644 Modules/_testcapi/weakref.c create mode 100644 Modules/_testlimitedcapi/weakref.c diff --git a/Lib/test/test_capi/test_weakref.py b/Lib/test/test_capi/test_weakref.py new file mode 100644 index 00000000000000..86ebe92da8d95d --- /dev/null +++ b/Lib/test/test_capi/test_weakref.py @@ -0,0 +1,136 @@ +import weakref +import unittest +from test.support import import_helper + +_testcapi = import_helper.import_module('_testcapi') +_testlimitedcapi = import_helper.import_module('_testlimitedcapi') +NULL = None + +class Object: + pass + +class Ref(weakref.ReferenceType): + pass + + +class CAPIWeakrefTest(unittest.TestCase): + def test_pyweakref_check(self): + # Test PyWeakref_Check() + check = _testlimitedcapi.pyweakref_check + obj = Object() + self.assertEqual(check(obj), 0) + self.assertEqual(check(weakref.ref(obj)), 1) + self.assertEqual(check(Ref(obj)), 1) + self.assertEqual(check(weakref.proxy(obj)), 1) + + # CRASHES check(NULL) + + def test_pyweakref_checkref(self): + # Test PyWeakref_CheckRef() + checkref = _testlimitedcapi.pyweakref_checkref + obj = Object() + self.assertEqual(checkref(obj), 0) + self.assertEqual(checkref(weakref.ref(obj)), 1) + self.assertEqual(checkref(Ref(obj)), 1) + self.assertEqual(checkref(weakref.proxy(obj)), 0) + + # CRASHES checkref(NULL) + + def test_pyweakref_checkrefexact(self): + # Test PyWeakref_CheckRefExact() + checkrefexact = _testlimitedcapi.pyweakref_checkrefexact + obj = Object() + self.assertEqual(checkrefexact(obj), 0) + self.assertEqual(checkrefexact(weakref.ref(obj)), 1) + self.assertEqual(checkrefexact(Ref(obj)), 0) + self.assertEqual(checkrefexact(weakref.proxy(obj)), 0) + + # CRASHES checkrefexact(NULL) + + def test_pyweakref_checkproxy(self): + # Test PyWeakref_CheckProxy() + checkproxy = _testlimitedcapi.pyweakref_checkproxy + obj = Object() + self.assertEqual(checkproxy(obj), 0) + self.assertEqual(checkproxy(weakref.ref(obj)), 0) + self.assertEqual(checkproxy(Ref(obj)), 0) + self.assertEqual(checkproxy(weakref.proxy(obj)), 1) + + # CRASHES checkproxy(NULL) + + def test_pyweakref_getref(self): + # Test PyWeakref_GetRef() + getref = _testcapi.pyweakref_getref + obj = Object() + wr = weakref.ref(obj) + wp = weakref.proxy(obj) + self.assertEqual(getref(wr), (1, obj)) + self.assertEqual(getref(wp), (1, obj)) + del obj + self.assertEqual(getref(wr), 0) + self.assertEqual(getref(wp), 0) + + self.assertRaises(TypeError, getref, 42) + self.assertRaises(SystemError, getref, NULL) + + def test_pyweakref_isdead(self): + # Test PyWeakref_IsDead() + isdead = _testcapi.pyweakref_isdead + obj = Object() + wr = weakref.ref(obj) + wp = weakref.proxy(obj) + self.assertEqual(isdead(wr), 0) + self.assertEqual(isdead(wp), 0) + del obj + self.assertEqual(isdead(wr), 1) + self.assertEqual(isdead(wp), 1) + + self.assertRaises(TypeError, isdead, 42) + self.assertRaises(SystemError, isdead, NULL) + + def test_pyweakref_newref(self): + # Test PyWeakref_NewRef() + newref = _testlimitedcapi.pyweakref_newref + obj = Object() + wr = newref(obj) + self.assertIs(type(wr), weakref.ReferenceType) + # PyWeakref_NewRef() handles None callback as NULL callback + wr = newref(obj, None) + self.assertIs(type(wr), weakref.ReferenceType) + log = [] + wr = newref(obj, log.append) + self.assertIs(type(wr), weakref.ReferenceType) + self.assertEqual(log, []) + del obj + self.assertEqual(log, [wr]) + + self.assertRaises(TypeError, newref, []) + # CRASHES newref(NULL) + + def test_pyweakref_newproxy(self): + # Test PyWeakref_NewProxy() + newproxy = _testlimitedcapi.pyweakref_newproxy + obj = Object() + wp = newproxy(obj) + self.assertIs(type(wp), weakref.ProxyType) + # PyWeakref_NewProxy() handles None callback as NULL callback + wp = newproxy(obj, None) + self.assertIs(type(wp), weakref.ProxyType) + log = [] + wp = newproxy(obj, log.append) + self.assertIs(type(wp), weakref.ProxyType) + self.assertEqual(log, []) + del obj + self.assertEqual(log, [wp]) + + def func(): + pass + wp = newproxy(func) + self.assertIs(type(wp), weakref.CallableProxyType) + + self.assertRaises(TypeError, newproxy, []) + # CRASHES newproxy(NULL) + + +if __name__ == "__main__": + unittest.main() diff --git a/Misc/NEWS.d/next/Tests/2026-06-09-11-52-52.gh-issue-151130.1vslPH.rst b/Misc/NEWS.d/next/Tests/2026-06-09-11-52-52.gh-issue-151130.1vslPH.rst new file mode 100644 index 00000000000000..0333e66446ce16 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2026-06-09-11-52-52.gh-issue-151130.1vslPH.rst @@ -0,0 +1 @@ +Add more tests for ``PyWeakref_*`` C API. diff --git a/Modules/Setup.stdlib.in b/Modules/Setup.stdlib.in index 5f8b0cf482472d..b8043d7e2c8c85 100644 --- a/Modules/Setup.stdlib.in +++ b/Modules/Setup.stdlib.in @@ -175,8 +175,8 @@ @MODULE__XXTESTFUZZ_TRUE@_xxtestfuzz _xxtestfuzz/_xxtestfuzz.c _xxtestfuzz/fuzzer.c @MODULE__TESTBUFFER_TRUE@_testbuffer _testbuffer.c @MODULE__TESTINTERNALCAPI_TRUE@_testinternalcapi _testinternalcapi.c _testinternalcapi/test_lock.c _testinternalcapi/pytime.c _testinternalcapi/set.c _testinternalcapi/test_critical_sections.c _testinternalcapi/complex.c _testinternalcapi/interpreter.c _testinternalcapi/tuple.c -@MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c _testcapi/heaptype.c _testcapi/abstract.c _testcapi/unicode.c _testcapi/dict.c _testcapi/set.c _testcapi/list.c _testcapi/tuple.c _testcapi/getargs.c _testcapi/datetime.c _testcapi/docstring.c _testcapi/mem.c _testcapi/watchers.c _testcapi/long.c _testcapi/float.c _testcapi/complex.c _testcapi/numbers.c _testcapi/structmember.c _testcapi/exceptions.c _testcapi/code.c _testcapi/buffer.c _testcapi/pyatomic.c _testcapi/run.c _testcapi/file.c _testcapi/codec.c _testcapi/immortal.c _testcapi/gc.c _testcapi/hash.c _testcapi/time.c _testcapi/bytes.c _testcapi/object.c _testcapi/modsupport.c _testcapi/monitoring.c _testcapi/config.c _testcapi/import.c _testcapi/frame.c _testcapi/type.c _testcapi/function.c _testcapi/module.c -@MODULE__TESTLIMITEDCAPI_TRUE@_testlimitedcapi _testlimitedcapi.c _testlimitedcapi/abstract.c _testlimitedcapi/bytearray.c _testlimitedcapi/bytes.c _testlimitedcapi/codec.c _testlimitedcapi/complex.c _testlimitedcapi/dict.c _testlimitedcapi/eval.c _testlimitedcapi/float.c _testlimitedcapi/heaptype_relative.c _testlimitedcapi/import.c _testlimitedcapi/list.c _testlimitedcapi/long.c _testlimitedcapi/object.c _testlimitedcapi/pyos.c _testlimitedcapi/set.c _testlimitedcapi/slots.c _testlimitedcapi/sys.c _testlimitedcapi/threadstate.c _testlimitedcapi/tuple.c _testlimitedcapi/unicode.c _testlimitedcapi/vectorcall_limited.c _testlimitedcapi/version.c _testlimitedcapi/file.c +@MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c _testcapi/heaptype.c _testcapi/abstract.c _testcapi/unicode.c _testcapi/dict.c _testcapi/set.c _testcapi/list.c _testcapi/tuple.c _testcapi/getargs.c _testcapi/datetime.c _testcapi/docstring.c _testcapi/mem.c _testcapi/watchers.c _testcapi/long.c _testcapi/float.c _testcapi/complex.c _testcapi/numbers.c _testcapi/structmember.c _testcapi/exceptions.c _testcapi/code.c _testcapi/buffer.c _testcapi/pyatomic.c _testcapi/run.c _testcapi/file.c _testcapi/codec.c _testcapi/immortal.c _testcapi/gc.c _testcapi/hash.c _testcapi/time.c _testcapi/bytes.c _testcapi/object.c _testcapi/modsupport.c _testcapi/monitoring.c _testcapi/config.c _testcapi/import.c _testcapi/frame.c _testcapi/type.c _testcapi/function.c _testcapi/module.c _testcapi/weakref.c +@MODULE__TESTLIMITEDCAPI_TRUE@_testlimitedcapi _testlimitedcapi.c _testlimitedcapi/abstract.c _testlimitedcapi/bytearray.c _testlimitedcapi/bytes.c _testlimitedcapi/codec.c _testlimitedcapi/complex.c _testlimitedcapi/dict.c _testlimitedcapi/eval.c _testlimitedcapi/float.c _testlimitedcapi/heaptype_relative.c _testlimitedcapi/import.c _testlimitedcapi/list.c _testlimitedcapi/long.c _testlimitedcapi/object.c _testlimitedcapi/pyos.c _testlimitedcapi/set.c _testlimitedcapi/slots.c _testlimitedcapi/sys.c _testlimitedcapi/threadstate.c _testlimitedcapi/tuple.c _testlimitedcapi/unicode.c _testlimitedcapi/vectorcall_limited.c _testlimitedcapi/version.c _testlimitedcapi/file.c _testlimitedcapi/weakref.c @MODULE__TESTCLINIC_TRUE@_testclinic _testclinic.c @MODULE__TESTCLINIC_LIMITED_TRUE@_testclinic_limited _testclinic_limited.c diff --git a/Modules/_testcapi/parts.h b/Modules/_testcapi/parts.h index a7feca5bd96070..98b5dd47accde3 100644 --- a/Modules/_testcapi/parts.h +++ b/Modules/_testcapi/parts.h @@ -67,5 +67,6 @@ int _PyTestCapi_Init_Frame(PyObject *mod); int _PyTestCapi_Init_Type(PyObject *mod); int _PyTestCapi_Init_Function(PyObject *mod); int _PyTestCapi_Init_Module(PyObject *mod); +int _PyTestCapi_Init_Weakref(PyObject *mod); #endif // Py_TESTCAPI_PARTS_H diff --git a/Modules/_testcapi/weakref.c b/Modules/_testcapi/weakref.c new file mode 100644 index 00000000000000..7c3ad8565991b7 --- /dev/null +++ b/Modules/_testcapi/weakref.c @@ -0,0 +1,46 @@ +#include "parts.h" +#include "util.h" + + +static PyObject * +pyweakref_getref(PyObject *module, PyObject *ref) +{ + NULLABLE(ref); + PyObject *obj = UNINITIALIZED_PTR; + int rc = PyWeakref_GetRef(ref, &obj); + if (rc == -1 && PyErr_Occurred()) { + assert(obj == NULL); + return NULL; + } + if (obj == NULL) { + return Py_BuildValue("i", rc); + } + else { + assert(obj != UNINITIALIZED_PTR); + return Py_BuildValue("iN", rc, obj); + } +} + +static PyObject * +pyweakref_isdead(PyObject *module, PyObject *obj) +{ + NULLABLE(obj); + int rc = PyWeakref_IsDead(obj); + if (rc == -1 && PyErr_Occurred()) { + return NULL; + } + return PyLong_FromLong(rc); +} + + +static PyMethodDef test_methods[] = { + {"pyweakref_getref", pyweakref_getref, METH_O}, + {"pyweakref_isdead", pyweakref_isdead, METH_O}, + {NULL}, +}; + +int +_PyTestCapi_Init_Weakref(PyObject *m) +{ + return PyModule_AddFunctions(m, test_methods); +} diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index be5ad3e9efa104..9c90d1fc36f398 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -3909,6 +3909,9 @@ _testcapi_exec(PyObject *m) if (_PyTestCapi_Init_Module(m) < 0) { return -1; } + if (_PyTestCapi_Init_Weakref(m) < 0) { + return -1; + } return 0; } diff --git a/Modules/_testlimitedcapi.c b/Modules/_testlimitedcapi.c index 5f2be0dd43954e..9314fccc6c915a 100644 --- a/Modules/_testlimitedcapi.c +++ b/Modules/_testlimitedcapi.c @@ -98,5 +98,8 @@ PyInit__testlimitedcapi(void) if (_PyTestLimitedCAPI_Init_File(mod) < 0) { return NULL; } + if (_PyTestLimitedCAPI_Init_Weakref(mod) < 0) { + return NULL; + } return mod; } diff --git a/Modules/_testlimitedcapi/parts.h b/Modules/_testlimitedcapi/parts.h index 1eea4f74d14416..c51d285e19ab0d 100644 --- a/Modules/_testlimitedcapi/parts.h +++ b/Modules/_testlimitedcapi/parts.h @@ -45,5 +45,6 @@ int _PyTestLimitedCAPI_Init_Unicode(PyObject *module); int _PyTestLimitedCAPI_Init_VectorcallLimited(PyObject *module); int _PyTestLimitedCAPI_Init_Version(PyObject *module); int _PyTestLimitedCAPI_Init_File(PyObject *module); +int _PyTestLimitedCAPI_Init_Weakref(PyObject *module); #endif // Py_TESTLIMITEDCAPI_PARTS_H diff --git a/Modules/_testlimitedcapi/weakref.c b/Modules/_testlimitedcapi/weakref.c new file mode 100644 index 00000000000000..e7f9d54d1a0d59 --- /dev/null +++ b/Modules/_testlimitedcapi/weakref.c @@ -0,0 +1,78 @@ +#include "pyconfig.h" // Py_GIL_DISABLED +#ifndef Py_GIL_DISABLED + // Need limited C API 3.5 for PyModule_AddFunctions() +# define Py_LIMITED_API 0x03050000 +#endif + +#include "parts.h" +#include "util.h" + + +static PyObject * +pyweakref_check(PyObject *module, PyObject *obj) +{ + NULLABLE(obj); + return PyLong_FromLong(PyWeakref_Check(obj)); +} + +static PyObject * +pyweakref_checkref(PyObject *module, PyObject *obj) +{ + NULLABLE(obj); + return PyLong_FromLong(PyWeakref_CheckRef(obj)); +} + +static PyObject * +pyweakref_checkrefexact(PyObject *module, PyObject *obj) +{ + NULLABLE(obj); + return PyLong_FromLong(PyWeakref_CheckRefExact(obj)); +} + +static PyObject * +pyweakref_checkproxy(PyObject *module, PyObject *obj) +{ + NULLABLE(obj); + return PyLong_FromLong(PyWeakref_CheckProxy(obj)); +} + +static PyObject * +pyweakref_newref(PyObject *module, PyObject *args) +{ + PyObject *obj; + PyObject *callback = NULL; + if (!PyArg_ParseTuple(args, "O|O", &obj, &callback)) { + return NULL; + } + NULLABLE(obj); + return PyWeakref_NewRef(obj, callback); +} + +static PyObject * +pyweakref_newproxy(PyObject *module, PyObject *args) +{ + PyObject *obj; + PyObject *callback = NULL; + if (!PyArg_ParseTuple(args, "O|O", &obj, &callback)) { + return NULL; + } + NULLABLE(obj); + return PyWeakref_NewProxy(obj, callback); +} + + +static PyMethodDef test_methods[] = { + {"pyweakref_check", pyweakref_check, METH_O}, + {"pyweakref_checkref", pyweakref_checkref, METH_O}, + {"pyweakref_checkrefexact", pyweakref_checkrefexact, METH_O}, + {"pyweakref_checkproxy", pyweakref_checkproxy, METH_O}, + {"pyweakref_newref", pyweakref_newref, METH_VARARGS}, + {"pyweakref_newproxy", pyweakref_newproxy, METH_VARARGS}, + {NULL}, +}; + +int +_PyTestLimitedCAPI_Init_Weakref(PyObject *m) +{ + return PyModule_AddFunctions(m, test_methods); +} diff --git a/PCbuild/_testcapi.vcxproj b/PCbuild/_testcapi.vcxproj index 62312acf248b91..64e50b67be4656 100644 --- a/PCbuild/_testcapi.vcxproj +++ b/PCbuild/_testcapi.vcxproj @@ -133,6 +133,7 @@ <ClCompile Include="..\Modules\_testcapi\frame.c" /> <ClCompile Include="..\Modules\_testcapi\type.c" /> <ClCompile Include="..\Modules\_testcapi\function.c" /> + <ClCompile Include="..\Modules\_testcapi\weakref.c" /> </ItemGroup> <ItemGroup> <ResourceCompile Include="..\PC\python_nt.rc" /> diff --git a/PCbuild/_testcapi.vcxproj.filters b/PCbuild/_testcapi.vcxproj.filters index b0e75ce433ab14..a3b62e1df663e0 100644 --- a/PCbuild/_testcapi.vcxproj.filters +++ b/PCbuild/_testcapi.vcxproj.filters @@ -132,6 +132,9 @@ <ClCompile Include="..\Modules\_testcapi\function.c"> <Filter>Source Files</Filter> </ClCompile> + <ClCompile Include="..\Modules\_testcapi\weakref.c"> + <Filter>Source Files</Filter> + </ClCompile> </ItemGroup> <ItemGroup> <ResourceCompile Include="..\PC\python_nt.rc"> diff --git a/PCbuild/_testlimitedcapi.vcxproj b/PCbuild/_testlimitedcapi.vcxproj index 34841ff9780a01..69558d204dbb8e 100644 --- a/PCbuild/_testlimitedcapi.vcxproj +++ b/PCbuild/_testlimitedcapi.vcxproj @@ -117,6 +117,7 @@ <ClCompile Include="..\Modules\_testlimitedcapi\vectorcall_limited.c" /> <ClCompile Include="..\Modules\_testlimitedcapi\version.c" /> <ClCompile Include="..\Modules\_testlimitedcapi\file.c" /> + <ClCompile Include="..\Modules\_testlimitedcapi\weakref.c" /> </ItemGroup> <ItemGroup> <ResourceCompile Include="..\PC\python_nt.rc" /> diff --git a/PCbuild/_testlimitedcapi.vcxproj.filters b/PCbuild/_testlimitedcapi.vcxproj.filters index a29973786c9485..2bcc3f6ff176bd 100644 --- a/PCbuild/_testlimitedcapi.vcxproj.filters +++ b/PCbuild/_testlimitedcapi.vcxproj.filters @@ -33,6 +33,7 @@ <ClCompile Include="..\Modules\_testlimitedcapi\vectorcall_limited.c" /> <ClCompile Include="..\Modules\_testlimitedcapi\version.c" /> <ClCompile Include="..\Modules\_testlimitedcapi\file.c" /> + <ClCompile Include="..\Modules\_testlimitedcapi\weakref.c" /> <ClCompile Include="..\Modules\_testlimitedcapi.c" /> </ItemGroup> <ItemGroup> From 3199f3ba29c3db9ff84147a228310a0408481d93 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 9 Jun 2026 14:14:47 +0200 Subject: [PATCH 269/818] [3.15] gh-151039: Fix a crash when `_datetime` types outlive `_datetime` module (GH-151044) (#151143) gh-151039: Fix a crash when `_datetime` types outlive `_datetime` module (GH-151044) (cherry picked from commit 9fdbade99e6bcc607d9f12416bfca5bbf94022b9) Co-authored-by: sobolevn <mail@sobolevn.me> --- Lib/test/datetimetester.py | 30 +++++++ ...-06-07-17-29-33.gh-issue-151039.AZ0qBn.rst | 1 + Modules/_datetimemodule.c | 81 +++++++++++++------ 3 files changed, 86 insertions(+), 26 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-06-07-17-29-33.gh-issue-151039.AZ0qBn.rst diff --git a/Lib/test/datetimetester.py b/Lib/test/datetimetester.py index 5d5b8e415f3cd2..d26e41982deb81 100644 --- a/Lib/test/datetimetester.py +++ b/Lib/test/datetimetester.py @@ -7509,6 +7509,36 @@ def func(): self.assertEqual(out, b"a" * 8) self.assertEqual(err, b"") + @support.cpython_only + @support.subTests(("setup", "call"), [ + ("obj = _datetime.timedelta", "obj(seconds=2)"), + ("obj = _datetime.timedelta(seconds=2)", "obj.total_seconds()"), + ("obj = _datetime.date(2026, 6, 7)", "obj.isocalendar()"), + ]) + def test_static_datetime_types_outlive_collected_module(self, setup, call): + # gh-151039: This code used to crash + script = f"""if True: + import sys, gc + import _datetime + + {setup} # static C type, survives the module + del sys.modules['_datetime'] + del _datetime + sys.modules['_datetime'] = None # block re-import + gc.collect() # module object is collected + + try: + {call} # used to be a segmentation fault + except ImportError: + pass + else: + raise AssertionError("ImportError not raised") + """ + rc, out, err = script_helper.assert_python_ok("-c", script) + self.assertEqual(rc, 0) + self.assertEqual(out, b'') + self.assertEqual(err, b'') + def load_tests(loader, standard_tests, pattern): standard_tests.addTest(ZoneInfoCompleteTest()) diff --git a/Misc/NEWS.d/next/Library/2026-06-07-17-29-33.gh-issue-151039.AZ0qBn.rst b/Misc/NEWS.d/next/Library/2026-06-07-17-29-33.gh-issue-151039.AZ0qBn.rst new file mode 100644 index 00000000000000..1e99567f555057 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-07-17-29-33.gh-issue-151039.AZ0qBn.rst @@ -0,0 +1 @@ +Fix a crash when static :mod:`datetime` types outlive the ``_datetime`` module. diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index 59af7afcfcc644..789e9a8b1488b9 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -126,8 +126,8 @@ get_module_state(PyObject *module) #define INTERP_KEY ((PyObject *)&_Py_ID(cached_datetime_module)) -static PyObject * -get_current_module(PyInterpreterState *interp) +static int +get_current_module(PyInterpreterState *interp, PyObject **p_mod) { PyObject *mod = NULL; @@ -139,20 +139,24 @@ get_current_module(PyInterpreterState *interp) if (PyDict_GetItemRef(dict, INTERP_KEY, &ref) < 0) { goto error; } - if (ref != NULL) { - if (ref != Py_None) { - (void)PyWeakref_GetRef(ref, &mod); - if (mod == Py_None) { - Py_CLEAR(mod); - } + if (ref != NULL && ref != Py_None) { + if (PyWeakref_GetRef(ref, &mod) < 0) { Py_DECREF(ref); + goto error; + } + if (mod == Py_None) { + Py_CLEAR(mod); } + Py_DECREF(ref); } - return mod; + assert(!PyErr_Occurred()); + *p_mod = mod; + return mod != NULL; error: assert(PyErr_Occurred()); - return NULL; + *p_mod = NULL; + return -1; } static PyModuleDef datetimemodule; @@ -161,22 +165,26 @@ static datetime_state * _get_current_state(PyObject **p_mod) { PyInterpreterState *interp = PyInterpreterState_Get(); - PyObject *mod = get_current_module(interp); + PyObject *mod; + if (get_current_module(interp, &mod) < 0) { + goto error; + } if (mod == NULL) { - assert(!PyErr_Occurred()); - if (PyErr_Occurred()) { - return NULL; - } /* The static types can outlive the module, * so we must re-import the module. */ mod = PyImport_ImportModule("_datetime"); if (mod == NULL) { - return NULL; + goto error; } } datetime_state *st = get_module_state(mod); *p_mod = mod; return st; + +error: + assert(PyErr_Occurred()); + *p_mod = NULL; + return NULL; } #define GET_CURRENT_STATE(MOD_VAR) \ @@ -2128,8 +2136,11 @@ delta_to_microseconds(PyDateTime_Delta *self) PyObject *x3 = NULL; PyObject *result = NULL; - PyObject *current_mod = NULL; + PyObject *current_mod; datetime_state *st = GET_CURRENT_STATE(current_mod); + if (st == NULL) { + return NULL; + } x1 = PyLong_FromLong(GET_TD_DAYS(self)); if (x1 == NULL) @@ -2207,8 +2218,11 @@ microseconds_to_delta_ex(PyObject *pyus, PyTypeObject *type) PyObject *num = NULL; PyObject *result = NULL; - PyObject *current_mod = NULL; + PyObject *current_mod; datetime_state *st = GET_CURRENT_STATE(current_mod); + if (st == NULL) { + return NULL; + } tuple = checked_divmod(pyus, CONST_US_PER_SECOND(st)); if (tuple == NULL) { @@ -2815,8 +2829,11 @@ delta_new_impl(PyTypeObject *type, PyObject *days, PyObject *seconds, { PyObject *self = NULL; - PyObject *current_mod = NULL; + PyObject *current_mod; datetime_state *st = GET_CURRENT_STATE(current_mod); + if (st == NULL) { + return NULL; + } PyObject *x = NULL; /* running sum of microseconds */ PyObject *y = NULL; /* temp sum of microseconds */ @@ -3014,8 +3031,12 @@ delta_total_seconds(PyObject *op, PyObject *Py_UNUSED(dummy)) if (total_microseconds == NULL) return NULL; - PyObject *current_mod = NULL; + PyObject *current_mod; datetime_state *st = GET_CURRENT_STATE(current_mod); + if (st == NULL) { + Py_DECREF(total_microseconds); + return NULL; + } total_seconds = PyNumber_TrueDivide(total_microseconds, CONST_US_PER_SECOND(st)); @@ -3867,8 +3888,11 @@ date_isocalendar(PyObject *self, PyObject *Py_UNUSED(dummy)) week = 0; } - PyObject *current_mod = NULL; + PyObject *current_mod; datetime_state *st = GET_CURRENT_STATE(current_mod); + if (st == NULL) { + return NULL; + } PyObject *v = iso_calendar_date_new_impl(ISOCALENDAR_DATE_TYPE(st), year, week + 1, day + 1); @@ -6800,8 +6824,11 @@ local_timezone(PyDateTime_DateTime *utc_time) PyObject *one_second; PyObject *seconds; - PyObject *current_mod = NULL; + PyObject *current_mod; datetime_state *st = GET_CURRENT_STATE(current_mod); + if (st == NULL) { + return NULL; + } delta = datetime_subtract((PyObject *)utc_time, CONST_EPOCH(st)); RELEASE_CURRENT_STATE(st, current_mod); @@ -7047,8 +7074,11 @@ datetime_timestamp(PyObject *op, PyObject *Py_UNUSED(dummy)) PyObject *result; if (HASTZINFO(self) && self->tzinfo != Py_None) { - PyObject *current_mod = NULL; + PyObject *current_mod; datetime_state *st = GET_CURRENT_STATE(current_mod); + if (st == NULL) { + return NULL; + } PyObject *delta; delta = datetime_subtract(op, CONST_EPOCH(st)); @@ -7581,9 +7611,8 @@ _datetime_exec(PyObject *module) datetime_state *st = get_module_state(module); PyInterpreterState *interp = PyInterpreterState_Get(); - PyObject *old_module = get_current_module(interp); - if (PyErr_Occurred()) { - assert(old_module == NULL); + PyObject *old_module; + if (get_current_module(interp, &old_module) < 0) { goto error; } /* We actually set the "current" module right before a successful return. */ From 19e4b8f559e849d77c0544f0d79af4fb358f1ab5 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 9 Jun 2026 15:06:30 +0200 Subject: [PATCH 270/818] [3.15] gh-109503: Fix document for shutil.move() on usage of os.rename() since it's inaccurate (GH-109507) (GH-150611) Nonatomic move might be used even if the files are on the same filesystem in some cases. (cherry picked from commit 6ecd197c03c43412fc400235949fd8297f142e89) Co-authored-by: Fang Li <fangli@users.noreply.github.com> --- Doc/library/shutil.rst | 12 ++++++++---- Lib/shutil.py | 12 ++++++++---- .../2023-09-16-23-42-27.gh-issue-109503.mZ-kdU.rst | 3 +++ 3 files changed, 19 insertions(+), 8 deletions(-) create mode 100644 Misc/NEWS.d/next/Documentation/2023-09-16-23-42-27.gh-issue-109503.mZ-kdU.rst diff --git a/Doc/library/shutil.rst b/Doc/library/shutil.rst index 6a734966d1e0a4..6febc7a187a15f 100644 --- a/Doc/library/shutil.rst +++ b/Doc/library/shutil.rst @@ -385,10 +385,14 @@ Directory and files operations If *dst* already exists but is not a directory, it may be overwritten depending on :func:`os.rename` semantics. - If the destination is on the current filesystem, then :func:`os.rename` is - used. Otherwise, *src* is copied to the destination using *copy_function* - and then removed. In case of symlinks, a new symlink pointing to the target - of *src* will be created as the destination and *src* will be removed. + :func:`os.rename` is preferably used internally when *src* and the destination are on + the same filesystem. In case :func:`os.rename` fails due to :exc:`OSError` + (e.g. the user has write permission to the destination file but not to its parent + directory), this method falls back to using *copy_function*, in which case + *src* is copied to the destination using *copy_function* and then removed. + + In case of symlinks, a new symlink pointing to the target of *src* will be + created in or as the destination, and *src* will be removed. If *copy_function* is given, it must be a callable that takes two arguments, *src* and the destination, and will be used to copy *src* to the destination diff --git a/Lib/shutil.py b/Lib/shutil.py index d3ac5dc5c50a73..2ac6a39ba37e9c 100644 --- a/Lib/shutil.py +++ b/Lib/shutil.py @@ -885,10 +885,14 @@ def move(src, dst, copy_function=copy2): If dst already exists but is not a directory, it may be overwritten depending on os.rename() semantics. - If the destination is on our current filesystem, then rename() is used. - Otherwise, src is copied to the destination and then removed. Symlinks are - recreated under the new name if os.rename() fails because of cross - filesystem renames. + os.rename() is preferably used if the source and destination are on the + same filesystem. In case os.rename() fails due to OSError (e.g. the user + has write permission to *dst* file but not to its parent directory), + this method falls back to using *copy_function* silently. + Symlinks are also recreated under the new name if os.rename() fails + because of cross filesystem renames. + + It's recommended to use os.rename() if atomic move is strictly required. The optional `copy_function` argument is a callable that will be used to copy the source or it will be delegated to `copytree`. diff --git a/Misc/NEWS.d/next/Documentation/2023-09-16-23-42-27.gh-issue-109503.mZ-kdU.rst b/Misc/NEWS.d/next/Documentation/2023-09-16-23-42-27.gh-issue-109503.mZ-kdU.rst new file mode 100644 index 00000000000000..c3c6c57569c2ea --- /dev/null +++ b/Misc/NEWS.d/next/Documentation/2023-09-16-23-42-27.gh-issue-109503.mZ-kdU.rst @@ -0,0 +1,3 @@ +Fix documentation for :func:`shutil.move` on usage of +:func:`os.rename` since nonatomic move might be used even if the files are +on the same filesystem. Patch by Fang Li From 22d32b6df0b2a098372c5dc661435189869ad382 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 9 Jun 2026 15:24:28 +0200 Subject: [PATCH 271/818] [3.15] Docs: Only add `profiling-sampling-visualization.{css,js}` to files when necessary (GH-151150) (cherry picked from commit 0a179e748bcf158bdcdd47f0e57a1983993f4610) Co-authored-by: Stan Ulbrych <stan@python.org> --- Doc/tools/extensions/profiling_trace.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Doc/tools/extensions/profiling_trace.py b/Doc/tools/extensions/profiling_trace.py index 7185ef351ddc7f..183c6de48714a4 100644 --- a/Doc/tools/extensions/profiling_trace.py +++ b/Doc/tools/extensions/profiling_trace.py @@ -154,10 +154,15 @@ def inject_trace(app, exception): ) +def add_assets(app, pagename, templatename, context, doctree): + if pagename == 'library/profiling.sampling': + app.add_js_file('profiling-sampling-visualization.js') + app.add_css_file('profiling-sampling-visualization.css') + + def setup(app): app.connect('build-finished', inject_trace) - app.add_js_file('profiling-sampling-visualization.js') - app.add_css_file('profiling-sampling-visualization.css') + app.connect('html-page-context', add_assets) return { 'version': '1.0', From 804be0a2236b7c207d84a440bbf2c12f0bced8f7 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 9 Jun 2026 17:45:23 +0200 Subject: [PATCH 272/818] [3.15] GH-54732: Tweak wording around empty lines in argument files (GH-150980) (#151165) GH-54732: Tweak wording around empty lines in argument files (GH-150980) (cherry picked from commit 528550e0e753d64714f65a02d567bdc1d63ae3f1) Co-authored-by: Savannah Ostrowski <savannah@python.org> --- Doc/library/argparse.rst | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst index db5fae2006678a..622f844a4a0b82 100644 --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -442,9 +442,8 @@ is considered equivalent to the expression ``['-f', 'foo', '-f', 'bar']``. .. note:: - Empty lines are treated as empty strings (``''``), which are allowed as values but - not as arguments. Empty lines that are read as arguments will result in an - "unrecognized arguments" error. + Each line is treated as a single argument, so an empty line is read as an + empty string (``''``). :class:`ArgumentParser` uses :term:`filesystem encoding and error handler` to read the file containing arguments. @@ -2232,6 +2231,9 @@ Customizing file parsing def convert_arg_line_to_args(self, arg_line): return arg_line.split() + Note that with this override an argument can no longer contain spaces, since + each space-separated word becomes a separate argument. + Exiting methods ^^^^^^^^^^^^^^^ From fda4f22d607f7c689a39755f3da673aaf26414e3 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 9 Jun 2026 17:46:39 +0200 Subject: [PATCH 273/818] [3.15] GH-61082: Clarify nargs='*' positional default behavior (GH-150989) (#151168) GH-61082: Clarify nargs='*' positional default behavior (GH-150989) (cherry picked from commit bc37a227b2f481d0f260f9beae5229e8d432a0cc) Co-authored-by: Savannah Ostrowski <savannah@python.org> --- Doc/library/argparse.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst index 622f844a4a0b82..4c588d447a9a7c 100644 --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -1051,6 +1051,10 @@ is used when no command-line argument was present:: >>> parser.parse_args([]) Namespace(foo=42) +Because ``nargs='*'`` gathers any supplied values into a list, an absent +positional argument yields an empty list (``[]``). Only a non-``None`` +*default* overrides this (so ``default=None`` still gives ``[]``). + For required_ arguments, the ``default`` value is ignored. For example, this applies to positional arguments with nargs_ values other than ``?`` or ``*``, or optional arguments marked as ``required=True``. From ca0cb46648ccdb530fb355c29df6c12b2ae22ec9 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 9 Jun 2026 18:41:26 +0200 Subject: [PATCH 274/818] [3.15] gh-150285: Fix too long docstrings in the concurrent package (GH-151076) (GH-151173) (cherry picked from commit 0fa06f4d7fb3494a62ba2631362ce8b98a7eec25) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> --- Lib/concurrent/futures/_base.py | 112 +++++++++++++------------ Lib/concurrent/futures/interpreter.py | 4 +- Lib/concurrent/futures/process.py | 49 ++++++----- Lib/concurrent/interpreters/_queues.py | 3 +- 4 files changed, 89 insertions(+), 79 deletions(-) diff --git a/Lib/concurrent/futures/_base.py b/Lib/concurrent/futures/_base.py index f506ce68aea5b2..4e71331f9a0a59 100644 --- a/Lib/concurrent/futures/_base.py +++ b/Lib/concurrent/futures/_base.py @@ -194,15 +194,15 @@ def as_completed(fs, timeout=None): """An iterator over the given futures that yields each as it completes. Args: - fs: The sequence of Futures (possibly created by different Executors) to - iterate over. - timeout: The maximum number of seconds to wait. If None, then there - is no limit on the wait time. + fs: The sequence of Futures (possibly created by different + Executors) to iterate over. + timeout: The maximum number of seconds to wait. If None, then + there is no limit on the wait time. Returns: - An iterator that yields the given Futures as they complete (finished or - cancelled). If any given Futures are duplicated, they will be returned - once. + An iterator that yields the given Futures as they complete + (finished or cancelled). If any given Futures are duplicated, + they will be returned once. Raises: TimeoutError: If the entire result iterator could not be generated @@ -258,19 +258,20 @@ def wait(fs, timeout=None, return_when=ALL_COMPLETED): """Wait for the futures in the given sequence to complete. Args: - fs: The sequence of Futures (possibly created by different Executors) to - wait upon. - timeout: The maximum number of seconds to wait. If None, then there - is no limit on the wait time. - return_when: Indicates when this function should return. The options - are: + fs: The sequence of Futures (possibly created by different + Executors) to wait upon. + timeout: The maximum number of seconds to wait. If None, then + there is no limit on the wait time. + return_when: Indicates when this function should return. + The options are: FIRST_COMPLETED - Return when any future finishes or is cancelled. FIRST_EXCEPTION - Return when any future finishes by raising an - exception. If no future raises an exception + exception. If no future raises an exception then it is equivalent to ALL_COMPLETED. - ALL_COMPLETED - Return when all futures finish or are cancelled. + ALL_COMPLETED - Return when all futures finish or are + cancelled. Returns: A named 2-tuple of sets. The first set, named 'done', contains the @@ -404,11 +405,12 @@ def add_done_callback(self, fn): Args: fn: A callable that will be called with this future as its only - argument when the future completes or is cancelled. The callable - will always be called by a thread in the same process in which - it was added. If the future has already completed or been - cancelled then the callable will be called immediately. These - callables are called in the order that they were added. + argument when the future completes or is cancelled. The + callable will always be called by a thread in the same + process in which it was added. If the future has already + completed or been cancelled then the callable will be + called immediately. These callables are called in the + order that they were added. """ with self._condition: if self._state not in [CANCELLED, CANCELLED_AND_NOTIFIED, FINISHED]: @@ -423,17 +425,19 @@ def result(self, timeout=None): """Return the result of the call that the future represents. Args: - timeout: The number of seconds to wait for the result if the future - isn't done. If None, then there is no limit on the wait time. + timeout: The number of seconds to wait for the result if the + future isn't done. If None, then there is no limit on the + wait time. Returns: The result of the call that the future represents. Raises: CancelledError: If the future was cancelled. - TimeoutError: If the future didn't finish executing before the given - timeout. - Exception: If the call raised then that exception will be raised. + TimeoutError: If the future didn't finish executing before the + given timeout. + Exception: If the call raised then that exception will be + raised. """ try: with self._condition: @@ -459,17 +463,17 @@ def exception(self, timeout=None): Args: timeout: The number of seconds to wait for the exception if the - future isn't done. If None, then there is no limit on the wait - time. + future isn't done. If None, then there is no limit on the + wait time. Returns: - The exception raised by the call that the future represents or None - if the call completed without raising. + The exception raised by the call that the future represents or + None if the call completed without raising. Raises: CancelledError: If the future was cancelled. - TimeoutError: If the future didn't finish executing before the given - timeout. + TimeoutError: If the future didn't finish executing before the + given timeout. """ with self._condition: @@ -494,22 +498,23 @@ def set_running_or_notify_cancel(self): Should only be used by Executor implementations and unit tests. If the future has been cancelled (cancel() was called and returned - True) then any threads waiting on the future completing (though calls - to as_completed() or wait()) are notified and False is returned. + True) then any threads waiting on the future completing (though + calls to as_completed() or wait()) are notified and False is + returned. If the future was not cancelled then it is put in the running state (future calls to running() will return True) and True is returned. This method should be called by Executor implementations before - executing the work associated with this future. If this method returns - False then the work should not be executed. + executing the work associated with this future. If this method + returns False then the work should not be executed. Returns: False if the Future was cancelled, True otherwise. Raises: - RuntimeError: if this method was already called or if set_result() - or set_exception() was called. + RuntimeError: if this method was already called or if + set_result() or set_exception() was called. """ with self._condition: if self._state == CANCELLED: @@ -593,8 +598,9 @@ class Executor(object): def submit(self, fn, /, *args, **kwargs): """Submits a callable to be executed with the given arguments. - Schedules the callable to be executed as fn(*args, **kwargs) and returns - a Future instance representing the execution of the callable. + Schedules the callable to be executed as fn(*args, **kwargs) and + returns a Future instance representing the execution of the + callable. Returns: A Future representing the given call. @@ -607,25 +613,25 @@ def map(self, fn, *iterables, timeout=None, chunksize=1, buffersize=None): Args: fn: A callable that will take as many arguments as there are passed iterables. - timeout: The maximum number of seconds to wait. If None, then there - is no limit on the wait time. - chunksize: The size of the chunks the iterable will be broken into - before being passed to a child process. This argument is only - used by ProcessPoolExecutor; it is ignored by + timeout: The maximum number of seconds to wait. If None, then + there is no limit on the wait time. + chunksize: The size of the chunks the iterable will be broken + into before being passed to a child process. This argument + is only used by ProcessPoolExecutor; it is ignored by ThreadPoolExecutor. buffersize: The number of submitted tasks whose results have not - yet been yielded. If the buffer is full, iteration over the + yet been yielded. If the buffer is full, iteration over the iterables pauses until a result is yielded from the buffer. - If None, all input elements are eagerly collected, and a task is - submitted for each. + If None, all input elements are eagerly collected, and + a task is submitted for each. Returns: - An iterator equivalent to: map(func, *iterables) but the calls may - be evaluated out-of-order. + An iterator equivalent to: map(func, *iterables) but the calls + may be evaluated out-of-order. Raises: - TimeoutError: If the entire result iterator could not be generated - before the given timeout. + TimeoutError: If the entire result iterator could not be + generated before the given timeout. Exception: If fn(*args) raises for any values. """ if buffersize is not None and not isinstance(buffersize, int): @@ -679,8 +685,8 @@ def shutdown(self, wait=True, *, cancel_futures=False): Args: wait: If True then shutdown will not return until all running - futures have finished executing and the resources used by the - executor have been reclaimed. + futures have finished executing and the resources used by + the executor have been reclaimed. cancel_futures: If True then shutdown will cancel all pending futures. Futures that are completed or running will not be cancelled. diff --git a/Lib/concurrent/futures/interpreter.py b/Lib/concurrent/futures/interpreter.py index 85c1da2c722894..fd3d45144b49a7 100644 --- a/Lib/concurrent/futures/interpreter.py +++ b/Lib/concurrent/futures/interpreter.py @@ -110,8 +110,8 @@ def __init__(self, max_workers=None, thread_name_prefix='', """Initializes a new InterpreterPoolExecutor instance. Args: - max_workers: The maximum number of interpreters that can be used to - execute the given calls. + max_workers: The maximum number of interpreters that can be used + to execute the given calls. thread_name_prefix: An optional name prefix to give our threads. initializer: A callable or script used to initialize each worker interpreter. diff --git a/Lib/concurrent/futures/process.py b/Lib/concurrent/futures/process.py index a42afa68efcb14..ed24cc25043413 100644 --- a/Lib/concurrent/futures/process.py +++ b/Lib/concurrent/futures/process.py @@ -656,19 +656,21 @@ def __init__(self, max_workers=None, mp_context=None, Args: max_workers: The maximum number of processes that can be used to - execute the given calls. If None or not given then as many - worker processes will be created as the machine has processors. - mp_context: A multiprocessing context to launch the workers created - using the multiprocessing.get_context('start method') API. This - object should provide SimpleQueue, Queue and Process. + execute the given calls. If None or not given then as many + worker processes will be created as the machine has + processors. + mp_context: A multiprocessing context to launch the workers + created using the multiprocessing.get_context('start method') + API. This object should provide SimpleQueue, Queue and + Process. initializer: A callable used to initialize worker processes. initargs: A tuple of arguments to pass to the initializer. - max_tasks_per_child: The maximum number of tasks a worker process - can complete before it will exit and be replaced with a fresh - worker process. The default of None means worker process will - live as long as the executor. Requires a non-'fork' mp_context - start method. When given, we default to using 'spawn' if no - mp_context is supplied. + max_tasks_per_child: The maximum number of tasks a worker + process can complete before it will exit and be replaced + with a fresh worker process. The default of None means + worker process will live as long as the executor. Requires + a non-'fork' mp_context start method. When given, we + default to using 'spawn' if no mp_context is supplied. """ _check_system_limits() @@ -838,24 +840,25 @@ def map(self, fn, *iterables, timeout=None, chunksize=1, buffersize=None): Args: fn: A callable that will take as many arguments as there are passed iterables. - timeout: The maximum number of seconds to wait. If None, then there - is no limit on the wait time. - chunksize: If greater than one, the iterables will be chopped into - chunks of size chunksize and submitted to the process pool. - If set to one, the items in the list will be sent one at a time. + timeout: The maximum number of seconds to wait. If None, then + there is no limit on the wait time. + chunksize: If greater than one, the iterables will be chopped + into chunks of size chunksize and submitted to the process + pool. If set to one, the items in the list will be sent + one at a time. buffersize: The number of submitted tasks whose results have not - yet been yielded. If the buffer is full, iteration over the + yet been yielded. If the buffer is full, iteration over the iterables pauses until a result is yielded from the buffer. - If None, all input elements are eagerly collected, and a task is - submitted for each. + If None, all input elements are eagerly collected, and + a task is submitted for each. Returns: - An iterator equivalent to: map(func, *iterables) but the calls may - be evaluated out-of-order. + An iterator equivalent to: map(func, *iterables) but the calls + may be evaluated out-of-order. Raises: - TimeoutError: If the entire result iterator could not be generated - before the given timeout. + TimeoutError: If the entire result iterator could not be + generated before the given timeout. Exception: If fn(*args) raises for any values. """ if chunksize < 1: diff --git a/Lib/concurrent/interpreters/_queues.py b/Lib/concurrent/interpreters/_queues.py index ee159d7de63827..5f3ee0934de59d 100644 --- a/Lib/concurrent/interpreters/_queues.py +++ b/Lib/concurrent/interpreters/_queues.py @@ -185,7 +185,8 @@ def put(self, obj, block=True, timeout=None, *, underlying data is actually shared. Furthermore, some types can be sent through a queue more efficiently than others. This group includes various immutable types like int, str, bytes, and - tuple (if the items are likewise efficiently shareable). See interpreters.is_shareable(). + tuple (if the items are likewise efficiently shareable). + See interpreters.is_shareable(). "unbounditems" controls the behavior of Queue.get() for the given object if the current interpreter (calling put()) is later From 2aba3d99acfeed753784311c7ad4d50233346a98 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 9 Jun 2026 18:41:54 +0200 Subject: [PATCH 275/818] [3.15] gh-150285: Fix too long docstrings in the asyncio package (GH-151074) (GH-151172) (cherry picked from commit ed2b04248aa1f608099e03437aa280d1be6e80c3) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> --- Lib/asyncio/base_events.py | 32 +++++++++---------- Lib/asyncio/events.py | 21 +++++++------ Lib/asyncio/graph.py | 14 ++++----- Lib/asyncio/locks.py | 18 +++++------ Lib/asyncio/queues.py | 36 +++++++++++---------- Lib/asyncio/runners.py | 3 +- Lib/asyncio/selector_events.py | 31 +++++++++--------- Lib/asyncio/streams.py | 14 ++++----- Lib/asyncio/taskgroups.py | 16 +++++----- Lib/asyncio/tasks.py | 57 ++++++++++++++++++---------------- Lib/asyncio/threads.py | 3 +- Lib/asyncio/timeouts.py | 3 +- Lib/asyncio/unix_events.py | 3 +- 13 files changed, 133 insertions(+), 118 deletions(-) diff --git a/Lib/asyncio/base_events.py b/Lib/asyncio/base_events.py index b651f40dc4a1ec..1761bccf5ca344 100644 --- a/Lib/asyncio/base_events.py +++ b/Lib/asyncio/base_events.py @@ -487,10 +487,10 @@ def set_task_factory(self, factory): If factory is None the default task factory will be set. If factory is a callable, it should have a signature matching - '(loop, coro, **kwargs)', where 'loop' will be a reference to the active - event loop, 'coro' will be a coroutine object, and **kwargs will be - arbitrary keyword arguments that should be passed on to Task. - The callable must return a Task. + '(loop, coro, **kwargs)', where 'loop' will be a reference to the + active event loop, 'coro' will be a coroutine object, and **kwargs + will be arbitrary keyword arguments that should be passed on to + Task. The callable must return a Task. """ if factory is not None and not callable(factory): raise TypeError('task factory must be a callable or None') @@ -726,8 +726,8 @@ def run_until_complete(self, future): def stop(self): """Stop running the event loop. - Every callback already scheduled will still run. This simply informs - run_forever to stop looping after a complete iteration. + Every callback already scheduled will still run. This simply + informs run_forever to stop looping after a complete iteration. """ self._stopping = True @@ -1075,12 +1075,12 @@ async def create_connection( Create a streaming transport connection to a given internet host and port: socket family AF_INET or socket.AF_INET6 depending on host (or - family if specified), socket type SOCK_STREAM. protocol_factory must be - a callable returning a protocol instance. + family if specified), socket type SOCK_STREAM. protocol_factory must + be a callable returning a protocol instance. - This method is a coroutine which will try to establish the connection - in the background. When successful, the coroutine returns a - (transport, protocol) pair. + This method is a coroutine which will try to establish the + connection in the background. When successful, the coroutine + returns a (transport, protocol) pair. """ if server_hostname is not None and not ssl: raise ValueError('server_hostname is only meaningful with ssl') @@ -1549,11 +1549,11 @@ async def create_server( The host parameter can be a string, in that case the TCP server is bound to host and port. - The host parameter can also be a sequence of strings and in that case - the TCP server is bound to all hosts of the sequence. If a host - appears multiple times (possibly indirectly e.g. when hostnames - resolve to the same IP address), the server is only bound once to that - host. + The host parameter can also be a sequence of strings and in that + case the TCP server is bound to all hosts of the sequence. If + a host appears multiple times (possibly indirectly e.g. when + hostnames resolve to the same IP address), the server is only bound + once to that host. Return a Server object which can be used to stop the service. diff --git a/Lib/asyncio/events.py b/Lib/asyncio/events.py index a7fb55982abe9c..42d8408a38dfd1 100644 --- a/Lib/asyncio/events.py +++ b/Lib/asyncio/events.py @@ -374,8 +374,8 @@ async def create_server( If host is an empty string or None all interfaces are assumed and a list of multiple sockets will be returned (most likely - one for IPv4 and another one for IPv6). The host parameter can also be - a sequence (e.g. list) of hosts to bind to. + one for IPv4 and another one for IPv6). The host parameter can also + be a sequence (e.g. list) of hosts to bind to. family can be set to either AF_INET or AF_INET6 to force the socket to use IPv4 or IPv6. If not set it will be determined @@ -415,8 +415,9 @@ async def create_server( start_serving set to True (default) causes the created server to start accepting connections immediately. When set to False, - the user should await Server.start_serving() or Server.serve_forever() - to make the server to start accepting connections. + the user should await Server.start_serving() or + Server.serve_forever() to make the server to start accepting + connections. """ raise NotImplementedError @@ -479,8 +480,9 @@ async def create_unix_server( start_serving set to True (default) causes the created server to start accepting connections immediately. When set to False, - the user should await Server.start_serving() or Server.serve_forever() - to make the server to start accepting connections. + the user should await Server.start_serving() or + Server.serve_forever() to make the server to start accepting + connections. """ raise NotImplementedError @@ -511,8 +513,8 @@ async def create_datagram_endpoint(self, protocol_factory, protocol_factory must be a callable returning a protocol instance. - socket family AF_INET, socket.AF_INET6 or socket.AF_UNIX depending on - host (or family if specified), socket type SOCK_DGRAM. + socket family AF_INET, socket.AF_INET6 or socket.AF_UNIX depending + on host (or family if specified), socket type SOCK_DGRAM. reuse_address tells the kernel to reuse a local socket in TIME_WAIT state, without waiting for its natural timeout to @@ -552,7 +554,8 @@ async def connect_read_pipe(self, protocol_factory, pipe): async def connect_write_pipe(self, protocol_factory, pipe): """Register write pipe in event loop. - protocol_factory should instantiate object with BaseProtocol interface. + protocol_factory should instantiate object with BaseProtocol + interface. Pipe is file-like object already switched to nonblocking. Return pair (transport, protocol), where transport support WriteTransport interface.""" diff --git a/Lib/asyncio/graph.py b/Lib/asyncio/graph.py index b5bfeb1630a159..35f7fa62140bd4 100644 --- a/Lib/asyncio/graph.py +++ b/Lib/asyncio/graph.py @@ -112,13 +112,13 @@ def capture_call_graph( optional keyword-only 'depth' argument can be used to skip the specified number of frames from top of the stack. - If the optional keyword-only 'limit' argument is provided, each call stack - in the resulting graph is truncated to include at most ``abs(limit)`` - entries. If 'limit' is positive, the entries left are the closest to - the invocation point. If 'limit' is negative, the topmost entries are - left. If 'limit' is omitted or None, all entries are present. - If 'limit' is 0, the call stack is not captured at all, only - "awaited by" information is present. + If the optional keyword-only 'limit' argument is provided, each call + stack in the resulting graph is truncated to include at most + ``abs(limit)`` entries. If 'limit' is positive, the entries left are + the closest to the invocation point. If 'limit' is negative, the + topmost entries are left. If 'limit' is omitted or None, all entries + are present. If 'limit' is 0, the call stack is not captured at all, + only "awaited by" information is present. """ loop = events._get_running_loop() diff --git a/Lib/asyncio/locks.py b/Lib/asyncio/locks.py index fa3a94764b507a..1592d30ed45832 100644 --- a/Lib/asyncio/locks.py +++ b/Lib/asyncio/locks.py @@ -158,10 +158,10 @@ def _wake_up_first(self): class Event(mixins._LoopBoundMixin): """Asynchronous equivalent to threading.Event. - Class implementing event objects. An event manages a flag that can be set - to true with the set() method and reset to false with the clear() method. - The wait() method blocks until the flag is true. The flag is initially - false. + Class implementing event objects. An event manages a flag that can be + set to true with the set() method and reset to false with the clear() + method. The wait() method blocks until the flag is true. The flag is + initially false. """ def __init__(self): @@ -353,9 +353,9 @@ class Semaphore(_ContextManagerMixin, mixins._LoopBoundMixin): """A Semaphore implementation. A semaphore manages an internal counter which is decremented by each - acquire() call and incremented by each release() call. The counter - can never go below zero; when acquire() finds that it is zero, it blocks, - waiting until some other thread calls release(). + acquire() call and incremented by each release() call. The counter + can never go below zero; when acquire() finds that it is zero, it + blocks, waiting until some other thread calls release(). Semaphores also support the context management protocol. @@ -511,8 +511,8 @@ async def __aexit__(self, *args): async def wait(self): """Wait for the barrier. - When the specified number of tasks have started waiting, they are all - simultaneously awoken. + When the specified number of tasks have started waiting, they are + all simultaneously awoken. Returns an unique and individual index number from 0 to 'parties-1'. """ async with self._cond: diff --git a/Lib/asyncio/queues.py b/Lib/asyncio/queues.py index 756216fac80932..30004f2bc9bacd 100644 --- a/Lib/asyncio/queues.py +++ b/Lib/asyncio/queues.py @@ -33,9 +33,9 @@ class QueueShutDown(Exception): class Queue(mixins._LoopBoundMixin): """A queue, useful for coordinating producer and consumer coroutines. - If maxsize is less than or equal to zero, the queue size is infinite. If it - is an integer greater than 0, then "await put()" will block when the - queue reaches maxsize, until an item is removed by get(). + If maxsize is less than or equal to zero, the queue size is infinite. + If it is an integer greater than 0, then "await put()" will block when + the queue reaches maxsize, until an item is removed by get(). Unlike queue.Queue, you can reliably know this Queue's size with qsize(), since your single-threaded asyncio application won't be @@ -174,8 +174,8 @@ async def get(self): If queue is empty, wait until an item is available. - Raises QueueShutDown if the queue has been shut down and is empty, or - if the queue has been shut down immediately. + Raises QueueShutDown if the queue has been shut down and is empty, + or if the queue has been shut down immediately. """ while self.empty(): if self._is_shutdown and self.empty(): @@ -203,10 +203,11 @@ async def get(self): def get_nowait(self): """Remove and return an item from the queue. - Return an item if one is immediately available, else raise QueueEmpty. + Return an item if one is immediately available, else raise + QueueEmpty. - Raises QueueShutDown if the queue has been shut down and is empty, or - if the queue has been shut down immediately. + Raises QueueShutDown if the queue has been shut down and is empty, + or if the queue has been shut down immediately. """ if self.empty(): if self._is_shutdown: @@ -223,12 +224,12 @@ def task_done(self): a subsequent call to task_done() tells the queue that the processing on the task is complete. - If a join() is currently blocking, it will resume when all items have - been processed (meaning that a task_done() call was received for every - item that had been put() into the queue). + If a join() is currently blocking, it will resume when all items + have been processed (meaning that a task_done() call was received + for every item that had been put() into the queue). - Raises ValueError if called more times than there were items placed in - the queue. + Raises ValueError if called more times than there were items placed + in the queue. """ if self._unfinished_tasks <= 0: raise ValueError('task_done() called too many times') @@ -239,10 +240,11 @@ def task_done(self): async def join(self): """Block until all items in the queue have been gotten and processed. - The count of unfinished tasks goes up whenever an item is added to the - queue. The count goes down whenever a consumer calls task_done() to - indicate that the item was retrieved and all work on it is complete. - When the count of unfinished tasks drops to zero, join() unblocks. + The count of unfinished tasks goes up whenever an item is added to + the queue. The count goes down whenever a consumer calls + task_done() to indicate that the item was retrieved and all work on + it is complete. When the count of unfinished tasks drops to zero, + join() unblocks. """ if self._unfinished_tasks > 0: await self._finished.wait() diff --git a/Lib/asyncio/runners.py b/Lib/asyncio/runners.py index ba37e003a655c0..774a317564df22 100644 --- a/Lib/asyncio/runners.py +++ b/Lib/asyncio/runners.py @@ -35,7 +35,8 @@ class Runner: with asyncio.Runner(debug=True) as runner: runner.run(main()) - The run() method can be called multiple times within the runner's context. + The run() method can be called multiple times within the runner's + context. This can be useful for interactive console (e.g. IPython), unittest runners, console tools, -- everywhere when async code diff --git a/Lib/asyncio/selector_events.py b/Lib/asyncio/selector_events.py index 961dbfb4b96303..7e2c0b99e87e49 100644 --- a/Lib/asyncio/selector_events.py +++ b/Lib/asyncio/selector_events.py @@ -533,11 +533,12 @@ def _sock_recvfrom_into(self, fut, sock, buf, bufsize): async def sock_sendall(self, sock, data): """Send data to the socket. - The socket must be connected to a remote socket. This method continues - to send data from data until either all data has been sent or an - error occurs. None is returned on success. On error, an exception is - raised, and there is no way to determine how much data, if any, was - successfully processed by the receiving end of the connection. + The socket must be connected to a remote socket. This method + continues to send data from data until either all data has been + sent or an error occurs. None is returned on success. On error, + an exception is raised, and there is no way to determine how much + data, if any, was successfully processed by the receiving end of + the connection. """ base_events._check_ssl_socket(sock) if self._debug and sock.gettimeout() != 0: @@ -586,11 +587,12 @@ def _sock_sendall(self, fut, sock, view, pos): async def sock_sendto(self, sock, data, address): """Send data to the socket. - The socket must be connected to a remote socket. This method continues - to send data from data until either all data has been sent or an - error occurs. None is returned on success. On error, an exception is - raised, and there is no way to determine how much data, if any, was - successfully processed by the receiving end of the connection. + The socket must be connected to a remote socket. This method + continues to send data from data until either all data has been + sent or an error occurs. None is returned on success. On error, + an exception is raised, and there is no way to determine how much + data, if any, was successfully processed by the receiving end of + the connection. """ base_events._check_ssl_socket(sock) if self._debug and sock.gettimeout() != 0: @@ -701,10 +703,11 @@ def _sock_connect_cb(self, fut, sock, address): async def sock_accept(self, sock): """Accept a connection. - The socket must be bound to an address and listening for connections. - The return value is a pair (conn, address) where conn is a new socket - object usable to send and receive data on the connection, and address - is the address bound to the socket on the other end of the connection. + The socket must be bound to an address and listening for + connections. The return value is a pair (conn, address) where + conn is a new socket object usable to send and receive data on the + connection, and address is the address bound to the socket on the + other end of the connection. """ base_events._check_ssl_socket(sock) if self._debug and sock.gettimeout() != 0: diff --git a/Lib/asyncio/streams.py b/Lib/asyncio/streams.py index d2db1a930c2ad2..a28c11e928f806 100644 --- a/Lib/asyncio/streams.py +++ b/Lib/asyncio/streams.py @@ -539,17 +539,17 @@ async def _wait_for_data(self, func_name): self._waiter = None async def readline(self): - """Read chunk of data from the stream until newline (b'\n') is found. + r"""Read chunk of data from the stream until newline (b'\n') is found. - On success, return chunk that ends with newline. If only partial + On success, return chunk that ends with newline. If only partial line can be read due to EOF, return incomplete line without - terminating newline. When EOF was reached while no bytes read, empty - bytes object is returned. + terminating newline. When EOF was reached while no bytes read, + empty bytes object is returned. - If limit is reached, ValueError will be raised. In that case, if + If limit is reached, ValueError will be raised. In that case, if newline was found, complete line including newline will be removed - from internal buffer. Else, internal buffer will be cleared. Limit is - compared against part of the line without newline. + from internal buffer. Else, internal buffer will be cleared. + Limit is compared against part of the line without newline. If stream was paused, this function will automatically resume it if needed. diff --git a/Lib/asyncio/taskgroups.py b/Lib/asyncio/taskgroups.py index 45dfebc65904fc..e1ec025791a52e 100644 --- a/Lib/asyncio/taskgroups.py +++ b/Lib/asyncio/taskgroups.py @@ -289,14 +289,14 @@ def cancel(self): """Cancel the task group `cancel()` will be called on any tasks in the group that aren't yet - done, as well as the parent (body) of the group. This will cause the - task group context manager to exit *without* `asyncio.CancelledError` - being raised. - - If `cancel()` is called before entering the task group, the group will be - cancelled upon entry. This is useful for patterns where one piece of - code passes an unused TaskGroup instance to another in order to have - the ability to cancel anything run within the group. + done, as well as the parent (body) of the group. This will cause + the task group context manager to exit *without* + `asyncio.CancelledError` being raised. + + If `cancel()` is called before entering the task group, the group + will be cancelled upon entry. This is useful for patterns where + one piece of code passes an unused TaskGroup instance to another in + order to have the ability to cancel anything run within the group. `cancel()` is idempotent and may be called after the task group has already exited. diff --git a/Lib/asyncio/tasks.py b/Lib/asyncio/tasks.py index fbd5c39a7c56ac..14d3c1ceb58cac 100644 --- a/Lib/asyncio/tasks.py +++ b/Lib/asyncio/tasks.py @@ -624,10 +624,11 @@ def as_completed(fs, *, timeout=None): Run the supplied awaitables concurrently. The returned object can be iterated to obtain the results of the awaitables as they finish. - The object returned can be iterated as an asynchronous iterator or a plain - iterator. When asynchronous iteration is used, the originally-supplied - awaitables are yielded if they are tasks or futures. This makes it easy to - correlate previously-scheduled tasks with their results: + The object returned can be iterated as an asynchronous iterator or + a plain iterator. When asynchronous iteration is used, the + originally-supplied awaitables are yielded if they are tasks or + futures. This makes it easy to correlate previously-scheduled tasks + with their results: ipv4_connect = create_task(open_connection("127.0.0.1", 80)) ipv6_connect = create_task(open_connection("::1", 80)) @@ -643,26 +644,27 @@ def as_completed(fs, *, timeout=None): else: print("IPv4 connection established.") - During asynchronous iteration, implicitly-created tasks will be yielded for - supplied awaitables that aren't tasks or futures. + During asynchronous iteration, implicitly-created tasks will be + yielded for supplied awaitables that aren't tasks or futures. - When used as a plain iterator, each iteration yields a new coroutine that - returns the result or raises the exception of the next completed awaitable. - This pattern is compatible with Python versions older than 3.13: + When used as a plain iterator, each iteration yields a new coroutine + that returns the result or raises the exception of the next completed + awaitable. This pattern is compatible with Python versions older than + 3.13: ipv4_connect = create_task(open_connection("127.0.0.1", 80)) ipv6_connect = create_task(open_connection("::1", 80)) tasks = [ipv4_connect, ipv6_connect] for next_connect in as_completed(tasks): - # next_connect is not one of the original task objects. It must be - # awaited to obtain the result value or raise the exception of the - # awaitable that finishes next. + # next_connect is not one of the original task objects. It must + # be awaited to obtain the result value or raise the exception + # of the awaitable that finishes next. reader, writer = await next_connect - A TimeoutError is raised if the timeout occurs before all awaitables are - done. This is raised by the async for loop during asynchronous iteration or - by the coroutines yielded during plain iteration. + A TimeoutError is raised if the timeout occurs before all awaitables + are done. This is raised by the async for loop during asynchronous + iteration or by the coroutines yielded during plain iteration. """ if inspect.isawaitable(fs): raise TypeError( @@ -1030,21 +1032,22 @@ def callback(): def create_eager_task_factory(custom_task_constructor): """Create a function suitable for use as a task factory on an event-loop. - Example usage: + Example usage: - loop.set_task_factory( - asyncio.create_eager_task_factory(my_task_constructor)) + loop.set_task_factory( + asyncio.create_eager_task_factory(my_task_constructor)) - Now, tasks created will be started immediately (rather than being first - scheduled to an event loop). The constructor argument can be any callable - that returns a Task-compatible object and has a signature compatible - with `Task.__init__`; it must have the `eager_start` keyword argument. + Now, tasks created will be started immediately (rather than being first + scheduled to an event loop). The constructor argument can be any + callable that returns a Task-compatible object and has a signature + compatible with `Task.__init__`; it must have the `eager_start` + keyword argument. - Most applications will use `Task` for `custom_task_constructor` and in - this case there's no need to call `create_eager_task_factory()` - directly. Instead the global `eager_task_factory` instance can be - used. E.g. `loop.set_task_factory(asyncio.eager_task_factory)`. - """ + Most applications will use `Task` for `custom_task_constructor` and in + this case there's no need to call `create_eager_task_factory()` + directly. Instead the global `eager_task_factory` instance can be + used. E.g. `loop.set_task_factory(asyncio.eager_task_factory)`. + """ def factory(loop, coro, *, eager_start=True, **kwargs): return custom_task_constructor( diff --git a/Lib/asyncio/threads.py b/Lib/asyncio/threads.py index db048a8231de16..5001351b0976ec 100644 --- a/Lib/asyncio/threads.py +++ b/Lib/asyncio/threads.py @@ -17,7 +17,8 @@ async def to_thread(func, /, *args, **kwargs): allowing context variables from the main thread to be accessed in the separate thread. - Return a coroutine that can be awaited to get the eventual result of *func*. + Return a coroutine that can be awaited to get the eventual result of + *func*. """ loop = events.get_running_loop() ctx = contextvars.copy_context() diff --git a/Lib/asyncio/timeouts.py b/Lib/asyncio/timeouts.py index 09342dc7c1310b..65ddc285abd971 100644 --- a/Lib/asyncio/timeouts.py +++ b/Lib/asyncio/timeouts.py @@ -25,7 +25,8 @@ class _State(enum.Enum): class Timeout: """Asynchronous context manager for cancelling overdue coroutines. - Use `timeout()` or `timeout_at()` rather than instantiating this class directly. + Use `timeout()` or `timeout_at()` rather than instantiating this class + directly. """ def __init__(self, when: float | None) -> None: diff --git a/Lib/asyncio/unix_events.py b/Lib/asyncio/unix_events.py index ab57efd48fce65..f9d52617ed9f78 100644 --- a/Lib/asyncio/unix_events.py +++ b/Lib/asyncio/unix_events.py @@ -54,7 +54,8 @@ def waitstatus_to_exitcode(status): class _UnixSelectorEventLoop(selector_events.BaseSelectorEventLoop): """Unix event loop. - Adds signal handling and UNIX Domain Socket support to SelectorEventLoop. + Adds signal handling and UNIX Domain Socket support to + SelectorEventLoop. """ def __init__(self, selector=None): From 489d6af9af5318c949e7311f343288ae2beda960 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 9 Jun 2026 19:10:18 +0200 Subject: [PATCH 276/818] [3.15] gh-151126: Add missing `PyErr_NoMemory` in `_winapi` module (GH-151154) (#151180) gh-151126: Add missing `PyErr_NoMemory` in `_winapi` module (GH-151154) (cherry picked from commit 8d94fa7b8696db6a7942f8a4b930289e69e9b174) Co-authored-by: sobolevn <mail@sobolevn.me> --- .../2026-06-09-10-28-30.gh-issue-151126.DKa6Sl.rst | 8 ++++++-- Modules/_winapi.c | 5 ++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-09-10-28-30.gh-issue-151126.DKa6Sl.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-09-10-28-30.gh-issue-151126.DKa6Sl.rst index 3f699a50d7a42b..81e87e539865ce 100644 --- a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-09-10-28-30.gh-issue-151126.DKa6Sl.rst +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-09-10-28-30.gh-issue-151126.DKa6Sl.rst @@ -1,3 +1,7 @@ Fix a crash, when there's no memory left on a device, -which happened in code compilation. -Now it raises a proper :exc:`MemoryError`. +which happened in: + +- code compilation +- :func:`!_winapi.CreateProcess` + +Now these places raise proper :exc:`MemoryError` errors. diff --git a/Modules/_winapi.c b/Modules/_winapi.c index ffa407b2f21f73..74644a57eb9d47 100644 --- a/Modules/_winapi.c +++ b/Modules/_winapi.c @@ -1187,8 +1187,10 @@ gethandlelist(PyObject *mapping, const char *name, Py_ssize_t *size) } ret = PyMem_Malloc(*size); - if (ret == NULL) + if (ret == NULL) { + PyErr_NoMemory(); goto cleanup; + } for (i = 0; i < PySequence_Fast_GET_SIZE(value_fast); i++) { ret[i] = PYNUM_TO_HANDLE(PySequence_Fast_GET_ITEM(value_fast, i)); @@ -1271,6 +1273,7 @@ getattributelist(PyObject *obj, const char *name, AttributeList *attribute_list) attribute_list->attribute_list = PyMem_Malloc(attribute_list_size); if (attribute_list->attribute_list == NULL) { ret = -1; + PyErr_NoMemory(); goto cleanup; } From ba8d0e37e77ed7a53e573f453d434a621d276ce9 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 9 Jun 2026 19:15:41 +0200 Subject: [PATCH 277/818] [3.15] GH-59633: Clarify dest collisions in argparse docs (GH-150987) (#151188) GH-59633: Clarify dest collisions in argparse docs (GH-150987) (cherry picked from commit 82cb7d4bf62041b75a08628baa1f9fe761fd6a79) Co-authored-by: Savannah Ostrowski <savannah@python.org> --- Doc/library/argparse.rst | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst index 4c588d447a9a7c..e4a5f4d109b499 100644 --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -1372,6 +1372,11 @@ behavior:: >>> parser.parse_args('--foo XXX'.split()) Namespace(bar='XXX') +Multiple arguments may share the same ``dest``. By default, the value from the +last such argument given on the command line wins. Use ``action='append'`` to +collect values from all of them into a list instead. For conflicting *option +strings* rather than ``dest`` names, see conflict_handler_. + .. versionchanged:: 3.15 Single-dash long option now takes precedence over short options. @@ -1780,6 +1785,11 @@ Subcommands present, and when the ``b`` command is specified, only the ``foo`` and ``baz`` attributes are present. + If a subparser defines an argument with the same ``dest`` as the parent + parser, the two share a single namespace attribute, so the parent's value + won't be retained. Users should give them distinct ``dest`` values to + keep both. + Similarly, when a help message is requested from a subparser, only the help for that particular parser will be printed. The help message will not include parent parser or sibling parser messages. (A help message for each From 427790ffbd02e1761d280a9d14611cfc3480f278 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 9 Jun 2026 19:33:23 +0200 Subject: [PATCH 278/818] [3.15] gh-151159: Update macOS installer to use OpenSSL 3.5.7. (GH-151171) (#151192) (cherry picked from commit 720fb82603a3c93b5941144feac1f25eacf74c03) Co-authored-by: Ivy Xu <fakeshadow1337@gmail.com> --- Mac/BuildScript/build-installer.py | 6 +++--- .../Security/2026-06-09-23-38-08.gh-issue-151159.ds-9f8.rst | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Security/2026-06-09-23-38-08.gh-issue-151159.ds-9f8.rst diff --git a/Mac/BuildScript/build-installer.py b/Mac/BuildScript/build-installer.py index e0e7076d681887..0c34f27b1923ea 100755 --- a/Mac/BuildScript/build-installer.py +++ b/Mac/BuildScript/build-installer.py @@ -246,9 +246,9 @@ def library_recipes(): result.extend([ dict( - name="OpenSSL 3.5.6", - url="https://github.com/openssl/openssl/releases/download/openssl-3.5.6/openssl-3.5.6.tar.gz", - checksum="deae7c80cba99c4b4f940ecadb3c3338b13cb77418409238e57d7f31f2a3b736", + name="OpenSSL 3.5.7", + url="https://github.com/openssl/openssl/releases/download/openssl-3.5.7/openssl-3.5.7.tar.gz", + checksum="a8c0d28a529ca480f9f36cf5792e2cd21984552a3c8e4aa11a24aa31aeac98e8", buildrecipe=build_universal_openssl, configure=None, install=None, diff --git a/Misc/NEWS.d/next/Security/2026-06-09-23-38-08.gh-issue-151159.ds-9f8.rst b/Misc/NEWS.d/next/Security/2026-06-09-23-38-08.gh-issue-151159.ds-9f8.rst new file mode 100644 index 00000000000000..d9251a93b40b2c --- /dev/null +++ b/Misc/NEWS.d/next/Security/2026-06-09-23-38-08.gh-issue-151159.ds-9f8.rst @@ -0,0 +1 @@ +Update macOS installer to use OpenSSL 3.5.7. From f1ca289fbfcda127c1d34047df79cd80467ae3ff Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 9 Jun 2026 19:44:44 +0200 Subject: [PATCH 279/818] [3.15] gh-151159: Update Windows builds to use OpenSSL 3.5.7 (GH-151189) (cherry picked from commit 6688b0c71536ac99ed629fbd5ea4b226245ffac6) Co-authored-by: Zachary Ware <zach@python.org> --- .../2026-06-09-11-40-48.gh-issue-151159.JKVfme.rst | 1 + Misc/externals.spdx.json | 8 ++++---- PCbuild/get_externals.bat | 4 ++-- PCbuild/python.props | 4 ++-- 4 files changed, 9 insertions(+), 8 deletions(-) create mode 100644 Misc/NEWS.d/next/Windows/2026-06-09-11-40-48.gh-issue-151159.JKVfme.rst diff --git a/Misc/NEWS.d/next/Windows/2026-06-09-11-40-48.gh-issue-151159.JKVfme.rst b/Misc/NEWS.d/next/Windows/2026-06-09-11-40-48.gh-issue-151159.JKVfme.rst new file mode 100644 index 00000000000000..ad1be115db5ce8 --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2026-06-09-11-40-48.gh-issue-151159.JKVfme.rst @@ -0,0 +1 @@ +Updated bundled version of OpenSSL to 3.5.7. diff --git a/Misc/externals.spdx.json b/Misc/externals.spdx.json index 080330c1cb75a5..dd49036a536079 100644 --- a/Misc/externals.spdx.json +++ b/Misc/externals.spdx.json @@ -70,21 +70,21 @@ "checksums": [ { "algorithm": "SHA256", - "checksumValue": "cf01946f3a61ba45a08c1e35b223d41d23963e3df5ac98cbad6c8fa5a81070ca" + "checksumValue": "ca94e7c6c223d9caf77bb51aac5949186379608ea2a0cad3aa8bdf31856912e9" } ], - "downloadLocation": "https://github.com/python/cpython-source-deps/archive/refs/tags/openssl-3.5.6.tar.gz", + "downloadLocation": "https://github.com/python/cpython-source-deps/archive/refs/tags/openssl-3.5.7.tar.gz", "externalRefs": [ { "referenceCategory": "SECURITY", - "referenceLocator": "cpe:2.3:a:openssl:openssl:3.5.6:*:*:*:*:*:*:*", + "referenceLocator": "cpe:2.3:a:openssl:openssl:3.5.7:*:*:*:*:*:*:*", "referenceType": "cpe23Type" } ], "licenseConcluded": "NOASSERTION", "name": "openssl", "primaryPackagePurpose": "SOURCE", - "versionInfo": "3.5.6" + "versionInfo": "3.5.7" }, { "SPDXID": "SPDXRef-PACKAGE-sqlite", diff --git a/PCbuild/get_externals.bat b/PCbuild/get_externals.bat index f6ba3d0fef3a60..f23a38ff6757d0 100644 --- a/PCbuild/get_externals.bat +++ b/PCbuild/get_externals.bat @@ -54,7 +54,7 @@ echo.Fetching external libraries... set libraries= set libraries=%libraries% bzip2-1.0.8 if NOT "%IncludeLibffiSrc%"=="false" set libraries=%libraries% libffi-3.4.4 -if NOT "%IncludeSSLSrc%"=="false" set libraries=%libraries% openssl-3.5.6 +if NOT "%IncludeSSLSrc%"=="false" set libraries=%libraries% openssl-3.5.7 set libraries=%libraries% mpdecimal-4.0.0 set libraries=%libraries% sqlite-3.53.1.0 if NOT "%IncludeTkinterSrc%"=="false" set libraries=%libraries% tcl-9.0.3.0 @@ -79,7 +79,7 @@ echo.Fetching external binaries... set binaries= if NOT "%IncludeLibffi%"=="false" set binaries=%binaries% libffi-3.4.4 -if NOT "%IncludeSSL%"=="false" set binaries=%binaries% openssl-bin-3.5.6 +if NOT "%IncludeSSL%"=="false" set binaries=%binaries% openssl-bin-3.5.7 if NOT "%IncludeTkinter%"=="false" set binaries=%binaries% tcltk-9.0.3.0 if NOT "%IncludeSSLSrc%"=="false" set binaries=%binaries% nasm-2.11.06 if NOT "%IncludeLLVM%"=="false" set binaries=%binaries% llvm-21.1.4.0 diff --git a/PCbuild/python.props b/PCbuild/python.props index edcda8fd8fc55d..86b88bf9ea75b4 100644 --- a/PCbuild/python.props +++ b/PCbuild/python.props @@ -105,8 +105,8 @@ <libffiOutDir Condition="$(libffiOutDir) == ''">$(libffiDir)$(ArchName)\</libffiOutDir> <libffiIncludeDir Condition="$(libffiIncludeDir) == ''">$(libffiOutDir)include</libffiIncludeDir> <mpdecimalDir Condition="$(mpdecimalDir) == ''">$(ExternalsDir)\mpdecimal-4.0.0\</mpdecimalDir> - <opensslDir Condition="$(opensslDir) == ''">$(ExternalsDir)openssl-3.5.6\</opensslDir> - <opensslOutDir Condition="$(opensslOutDir) == ''">$(ExternalsDir)openssl-bin-3.5.6\$(ArchName)\</opensslOutDir> + <opensslDir Condition="$(opensslDir) == ''">$(ExternalsDir)openssl-3.5.7\</opensslDir> + <opensslOutDir Condition="$(opensslOutDir) == ''">$(ExternalsDir)openssl-bin-3.5.7\$(ArchName)\</opensslOutDir> <opensslIncludeDir Condition="$(opensslIncludeDir) == ''">$(opensslOutDir)include</opensslIncludeDir> <nasmDir Condition="$(nasmDir) == ''">$(ExternalsDir)\nasm-2.11.06\</nasmDir> <zlibDir Condition="$(zlibDir) == ''">$(ExternalsDir)\zlib-1.3.1\</zlibDir> From c3d0205bbce0f6e08fc71a711fe3bd2deea1f5f2 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 9 Jun 2026 19:54:25 +0200 Subject: [PATCH 280/818] [3.15] gh-151159: Bump OpenSSL versions for iOS and Android (GH-151197) (cherry picked from commit 627dd14346b4c4c13d9203430c32556467b7fbd3) Co-authored-by: Zachary Ware <zach@python.org> --- .../Security/2026-06-09-10-23-57.gh-issue-151159.91GpWQ.rst | 1 + Platforms/Android/__main__.py | 2 +- Platforms/Apple/__main__.py | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Security/2026-06-09-10-23-57.gh-issue-151159.91GpWQ.rst diff --git a/Misc/NEWS.d/next/Security/2026-06-09-10-23-57.gh-issue-151159.91GpWQ.rst b/Misc/NEWS.d/next/Security/2026-06-09-10-23-57.gh-issue-151159.91GpWQ.rst new file mode 100644 index 00000000000000..735164c1a65ec3 --- /dev/null +++ b/Misc/NEWS.d/next/Security/2026-06-09-10-23-57.gh-issue-151159.91GpWQ.rst @@ -0,0 +1 @@ +Update Android and iOS installers to use OpenSSL 3.5.7. diff --git a/Platforms/Android/__main__.py b/Platforms/Android/__main__.py index 5c41aaca6ebf0b..f738a198e1a412 100755 --- a/Platforms/Android/__main__.py +++ b/Platforms/Android/__main__.py @@ -219,7 +219,7 @@ def unpack_deps(host, prefix_dir, cache_dir): for name_ver in [ "bzip2-1.0.8-3", "libffi-3.4.4-3", - "openssl-3.5.6-0", + "openssl-3.5.7-0", "sqlite-3.53.1-0", "xz-5.4.6-1", "zstd-1.5.7-2" diff --git a/Platforms/Apple/__main__.py b/Platforms/Apple/__main__.py index d94198a309f926..9f2d2afb0aa0f6 100644 --- a/Platforms/Apple/__main__.py +++ b/Platforms/Apple/__main__.py @@ -319,7 +319,7 @@ def unpack_deps( for name_ver in [ "BZip2-1.0.8-2", "libFFI-3.4.7-2", - "OpenSSL-3.5.6-1", + "OpenSSL-3.5.7-1", "XZ-5.6.4-2", "mpdecimal-4.0.0-2", "zstd-1.5.7-1", From dcb049f550cedf35c3c87c8e58fa8c68b422f791 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 9 Jun 2026 19:57:09 +0200 Subject: [PATCH 281/818] [3.15] gh-151159: Update CI to use latest SSL library versions (GH-151199) (cherry picked from commit 7053bbd7fd4967b8782bf0c8f6ad00248f0b0c5b) Co-authored-by: Zachary Ware <zach@python.org> --- .github/workflows/build.yml | 17 ++++++++--------- .github/workflows/reusable-ubuntu.yml | 2 +- Tools/ssl/multissltests.py | 14 +++++++------- 3 files changed, 16 insertions(+), 17 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 12bf160178e3c7..e08891ea88b540 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -325,14 +325,13 @@ jobs: # unsupported as it most resembles other 1.1.1-work-a-like ssl APIs # supported by important vendors such as AWS-LC. - { name: openssl, version: 1.1.1w } - - { name: openssl, version: 3.0.20 } - - { name: openssl, version: 3.3.7 } - - { name: openssl, version: 3.4.5 } - - { name: openssl, version: 3.5.6 } - - { name: openssl, version: 3.6.2 } - - { name: openssl, version: 4.0.0 } + - { name: openssl, version: 3.0.21 } + - { name: openssl, version: 3.4.6 } + - { name: openssl, version: 3.5.7 } + - { name: openssl, version: 3.6.3 } + - { name: openssl, version: 4.0.1 } ## AWS-LC - - { name: aws-lc, version: 1.72.1 } + - { name: aws-lc, version: 5.0.0 } env: SSLLIB_VER: ${{ matrix.ssllib.version }} MULTISSL_DIR: ${{ github.workspace }}/multissl @@ -446,7 +445,7 @@ jobs: needs: build-context if: needs.build-context.outputs.run-ubuntu == 'true' env: - OPENSSL_VER: 3.5.6 + OPENSSL_VER: 3.5.7 PYTHONSTRICTEXTENSIONBUILD: 1 steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 @@ -554,7 +553,7 @@ jobs: matrix: os: [ubuntu-24.04] env: - OPENSSL_VER: 3.5.6 + OPENSSL_VER: 3.5.7 PYTHONSTRICTEXTENSIONBUILD: 1 ASAN_OPTIONS: detect_leaks=0:allocator_may_return_null=1:handle_segv=0 steps: diff --git a/.github/workflows/reusable-ubuntu.yml b/.github/workflows/reusable-ubuntu.yml index a7e307848af670..f4321cefa1b598 100644 --- a/.github/workflows/reusable-ubuntu.yml +++ b/.github/workflows/reusable-ubuntu.yml @@ -35,7 +35,7 @@ jobs: runs-on: ${{ inputs.os }} timeout-minutes: 60 env: - OPENSSL_VER: 3.5.6 + OPENSSL_VER: 3.5.7 PYTHONSTRICTEXTENSIONBUILD: 1 TERM: linux steps: diff --git a/Tools/ssl/multissltests.py b/Tools/ssl/multissltests.py index ad3e4b6596ed7a..1a213187b897d1 100755 --- a/Tools/ssl/multissltests.py +++ b/Tools/ssl/multissltests.py @@ -46,15 +46,15 @@ "1.1.1w", "3.1.8", "3.2.6", + "3.3.7", ] OPENSSL_RECENT_VERSIONS = [ - "3.0.20", - "3.3.7", - "3.4.5", - "3.5.6", - "3.6.2", - "4.0.0", + "3.0.21", + "3.4.6", + "3.5.7", + "3.6.3", + "4.0.1", # See make_ssl_data.py for notes on adding a new version. ] @@ -65,7 +65,7 @@ ] AWSLC_RECENT_VERSIONS = [ - "1.68.0", + "5.0.0", ] # store files in ../multissl From e25cc9e93ce7755dba7467ec7d9566b9140e648a Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 9 Jun 2026 20:56:57 +0200 Subject: [PATCH 282/818] [3.15] gh-151163: Update Android, macOS installer, and Windows builds to SQLite 3.53.2 (GH-151204) (cherry picked from commit ab8ebe9034a85c441d1bb4208fa2d667fd38cc4d) Co-authored-by: Zachary Ware <zach@python.org> --- Mac/BuildScript/build-installer.py | 6 +++--- .../Build/2026-06-09-11-54-13.gh-issue-151163.vFAtjv.rst | 1 + .../2026-06-09-11-55-41.gh-issue-151163.oizZYV.rst | 1 + .../macOS/2026-06-09-11-52-35.gh-issue-151163.RlPXHq.rst | 1 + Misc/externals.spdx.json | 8 ++++---- PCbuild/get_externals.bat | 2 +- PCbuild/python.props | 2 +- PCbuild/readme.txt | 2 +- Platforms/Android/__main__.py | 2 +- 9 files changed, 14 insertions(+), 11 deletions(-) create mode 100644 Misc/NEWS.d/next/Build/2026-06-09-11-54-13.gh-issue-151163.vFAtjv.rst create mode 100644 Misc/NEWS.d/next/Windows/2026-06-09-11-55-41.gh-issue-151163.oizZYV.rst create mode 100644 Misc/NEWS.d/next/macOS/2026-06-09-11-52-35.gh-issue-151163.RlPXHq.rst diff --git a/Mac/BuildScript/build-installer.py b/Mac/BuildScript/build-installer.py index 0c34f27b1923ea..9c060f3ea15632 100755 --- a/Mac/BuildScript/build-installer.py +++ b/Mac/BuildScript/build-installer.py @@ -359,9 +359,9 @@ def library_recipes(): ), ), dict( - name="SQLite 3.53.1", - url="https://www.sqlite.org/2026/sqlite-autoconf-3530100.tar.gz", - checksum="83e6b2020a034e9a7ad4a72feea59e1ad52f162e09cbd26735a3ffb98359fc4f", + name="SQLite 3.53.2", + url="https://www.sqlite.org/2026/sqlite-autoconf-3530200.tar.gz", + checksum="588ad51949419a56ebe81fe56193d510c559eb94c9a57748387860b5d3069316", extra_cflags=('-Os ' '-DSQLITE_ENABLE_FTS5 ' '-DSQLITE_ENABLE_FTS4 ' diff --git a/Misc/NEWS.d/next/Build/2026-06-09-11-54-13.gh-issue-151163.vFAtjv.rst b/Misc/NEWS.d/next/Build/2026-06-09-11-54-13.gh-issue-151163.vFAtjv.rst new file mode 100644 index 00000000000000..e4f3a044c81c6f --- /dev/null +++ b/Misc/NEWS.d/next/Build/2026-06-09-11-54-13.gh-issue-151163.vFAtjv.rst @@ -0,0 +1 @@ +Updated Android build to include SQLite version 3.53.2. diff --git a/Misc/NEWS.d/next/Windows/2026-06-09-11-55-41.gh-issue-151163.oizZYV.rst b/Misc/NEWS.d/next/Windows/2026-06-09-11-55-41.gh-issue-151163.oizZYV.rst new file mode 100644 index 00000000000000..580a87400862c5 --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2026-06-09-11-55-41.gh-issue-151163.oizZYV.rst @@ -0,0 +1 @@ +Updated Windows builds to include SQLite version 3.53.2. diff --git a/Misc/NEWS.d/next/macOS/2026-06-09-11-52-35.gh-issue-151163.RlPXHq.rst b/Misc/NEWS.d/next/macOS/2026-06-09-11-52-35.gh-issue-151163.RlPXHq.rst new file mode 100644 index 00000000000000..7e9bf6f4587974 --- /dev/null +++ b/Misc/NEWS.d/next/macOS/2026-06-09-11-52-35.gh-issue-151163.RlPXHq.rst @@ -0,0 +1 @@ +Updated macOS installer to include SQLite version 3.53.2. diff --git a/Misc/externals.spdx.json b/Misc/externals.spdx.json index dd49036a536079..523d20259adaaa 100644 --- a/Misc/externals.spdx.json +++ b/Misc/externals.spdx.json @@ -91,21 +91,21 @@ "checksums": [ { "algorithm": "SHA256", - "checksumValue": "15e8fc7dc059f7b156e53629540951c2691acd71e027f6f8f66dacab5c66c884" + "checksumValue": "53f8711811090cc4d9ffc624c360f81e7b409763b145ab2e948998f1a0d6a612" } ], - "downloadLocation": "https://github.com/python/cpython-source-deps/archive/refs/tags/sqlite-3.53.1.0.tar.gz", + "downloadLocation": "https://github.com/python/cpython-source-deps/archive/refs/tags/sqlite-3.53.2.0.tar.gz", "externalRefs": [ { "referenceCategory": "SECURITY", - "referenceLocator": "cpe:2.3:a:sqlite:sqlite:3.53.1.0:*:*:*:*:*:*:*", + "referenceLocator": "cpe:2.3:a:sqlite:sqlite:3.53.2.0:*:*:*:*:*:*:*", "referenceType": "cpe23Type" } ], "licenseConcluded": "NOASSERTION", "name": "sqlite", "primaryPackagePurpose": "SOURCE", - "versionInfo": "3.53.1.0" + "versionInfo": "3.53.2.0" }, { "SPDXID": "SPDXRef-PACKAGE-tcl", diff --git a/PCbuild/get_externals.bat b/PCbuild/get_externals.bat index f23a38ff6757d0..47399fe65d1e54 100644 --- a/PCbuild/get_externals.bat +++ b/PCbuild/get_externals.bat @@ -56,7 +56,7 @@ set libraries=%libraries% bzip2-1.0.8 if NOT "%IncludeLibffiSrc%"=="false" set libraries=%libraries% libffi-3.4.4 if NOT "%IncludeSSLSrc%"=="false" set libraries=%libraries% openssl-3.5.7 set libraries=%libraries% mpdecimal-4.0.0 -set libraries=%libraries% sqlite-3.53.1.0 +set libraries=%libraries% sqlite-3.53.2.0 if NOT "%IncludeTkinterSrc%"=="false" set libraries=%libraries% tcl-9.0.3.0 if NOT "%IncludeTkinterSrc%"=="false" set libraries=%libraries% tk-9.0.3.1 set libraries=%libraries% xz-5.8.1.1 diff --git a/PCbuild/python.props b/PCbuild/python.props index 86b88bf9ea75b4..8d931bba28a389 100644 --- a/PCbuild/python.props +++ b/PCbuild/python.props @@ -98,7 +98,7 @@ <Import Project="$(ExternalProps)" Condition="$(ExternalProps) != '' and Exists('$(ExternalProps)')" /> <PropertyGroup> - <sqlite3Dir Condition="$(sqlite3Dir) == ''">$(ExternalsDir)sqlite-3.53.1.0\</sqlite3Dir> + <sqlite3Dir Condition="$(sqlite3Dir) == ''">$(ExternalsDir)sqlite-3.53.2.0\</sqlite3Dir> <bz2Dir Condition="$(bz2Dir) == ''">$(ExternalsDir)bzip2-1.0.8\</bz2Dir> <lzmaDir Condition="$(lzmaDir) == ''">$(ExternalsDir)xz-5.8.1.1\</lzmaDir> <libffiDir Condition="$(libffiDir) == ''">$(ExternalsDir)libffi-3.4.4\</libffiDir> diff --git a/PCbuild/readme.txt b/PCbuild/readme.txt index ea8adf21c279a6..7c5eab2eb75a1d 100644 --- a/PCbuild/readme.txt +++ b/PCbuild/readme.txt @@ -242,7 +242,7 @@ _ssl again when building. _sqlite3 - Wraps SQLite 3.53.1, which is itself built by sqlite3.vcxproj + Wraps SQLite 3.53.2, which is itself built by sqlite3.vcxproj Homepage: https://www.sqlite.org/ diff --git a/Platforms/Android/__main__.py b/Platforms/Android/__main__.py index f738a198e1a412..063e1f31603144 100755 --- a/Platforms/Android/__main__.py +++ b/Platforms/Android/__main__.py @@ -220,7 +220,7 @@ def unpack_deps(host, prefix_dir, cache_dir): "bzip2-1.0.8-3", "libffi-3.4.4-3", "openssl-3.5.7-0", - "sqlite-3.53.1-0", + "sqlite-3.53.2-0", "xz-5.4.6-1", "zstd-1.5.7-2" ]: From 50765f43f72b62778ed896e34faef8b10fc07058 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 9 Jun 2026 22:16:42 +0200 Subject: [PATCH 283/818] [3.15] gh-151112: Fix double free in `assemble_init` when out of memory (GH-151142) (#151205) gh-151112: Fix double free in `assemble_init` when out of memory (GH-151142) (cherry picked from commit 580499177ca91477b53b4a40afcec7d3370265b0) Co-authored-by: Stan Ulbrych <stan@python.org> --- .../2026-06-09-12-24-35.gh-issue-151112.4RKCkD.rst | 1 + Python/assemble.c | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-09-12-24-35.gh-issue-151112.4RKCkD.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-09-12-24-35.gh-issue-151112.4RKCkD.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-09-12-24-35.gh-issue-151112.4RKCkD.rst new file mode 100644 index 00000000000000..93ee5c8cf1914b --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-09-12-24-35.gh-issue-151112.4RKCkD.rst @@ -0,0 +1 @@ +Fix a crash in the compiler that could occur when running out of memory. diff --git a/Python/assemble.c b/Python/assemble.c index 3df959c3634195..8bcb4c7bf3a9aa 100644 --- a/Python/assemble.c +++ b/Python/assemble.c @@ -80,9 +80,9 @@ assemble_init(struct assembler *a, int firstlineno) } return SUCCESS; error: - Py_XDECREF(a->a_bytecode); - Py_XDECREF(a->a_linetable); - Py_XDECREF(a->a_except_table); + Py_CLEAR(a->a_bytecode); + Py_CLEAR(a->a_linetable); + Py_CLEAR(a->a_except_table); return ERROR; } From 73e5d444ac4f0801074c3a27271070774ff88b62 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 10 Jun 2026 01:33:04 +0200 Subject: [PATCH 284/818] [3.15] gh-150700: Fix class-scope inline comprehensions when nested scopes reference `__class__` and friends (GH-150735) (#151211) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gh-150700: Fix class-scope inline comprehensions when nested scopes reference `__class__` and friends (GH-150735) * Fix class-scope inline comprehensions when nested scopes reference `__class__` and friends In `inline_comprehension()`, when `__class__` / `__classdict__` / `__conditional_annotations__` appears as `FREE` in a comprehension's symbol table because a nested scope captured it (e.g. nested lambdas), this name is still discarded from `comp_free` unconditionally. This prevents `drop_class_free()` from seeing it, so the appropriate `ste_needs_(...)` flag is never set on the enclosing class. That leads to `codegen_make_closure()` throwing `SystemError` when it couldn't find `__class__` / `__classdict__` / `__conditional_annotations__` in the class's cellvars. From now on we just discard from `comp_free` when no child scope (e.g. a lambda) still needs the name as `FREE`. When a child scope does need it, keep it in `comp_free` so `drop_class_free()` can set the appropriate flag and the class creates the implicit cell. * Fix tests * Fix typo * Fix formatting * Add test checking validity of `__class__` returned * Prefer 'used' to 'deferred' (cherry picked from commit ce916dc50644bb1de940f5fb580bd9907cceb959) Co-authored-by: Bartosz Sławecki <bartosz@ilikepython.com> --- Lib/test/test_listcomps.py | 31 +++++++++++++++++++ ...-06-01-19-00-00.gh-issue-150700.W8CzVR.rst | 3 ++ Python/symtable.c | 13 +++++--- 3 files changed, 43 insertions(+), 4 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-01-19-00-00.gh-issue-150700.W8CzVR.rst diff --git a/Lib/test/test_listcomps.py b/Lib/test/test_listcomps.py index cee528722b85aa..cf3796d9480801 100644 --- a/Lib/test/test_listcomps.py +++ b/Lib/test/test_listcomps.py @@ -171,6 +171,17 @@ def test_references___class__(self): """ self._check_in_scopes(code, raises=NameError) + def test_references___class___nested(self): + code = """ + res = [(lambda: __class__)() for _ in [1]] + """ + self._check_in_scopes(code, raises=NameError) + + def test_references___class___nested_used(self): + class _C: + res = [lambda: __class__ for _ in [1]] + self.assertIs(_C.res[0](), _C) + def test_references___class___defined(self): code = """ __class__ = 2 @@ -180,18 +191,38 @@ def test_references___class___defined(self): code, outputs={"res": [2]}, scopes=["module", "function"]) self._check_in_scopes(code, raises=NameError, scopes=["class"]) + def test_references___class___defined_nested(self): + code = """ + __class__ = 2 + res = [(lambda: __class__)() for x in [1]] + """ + self._check_in_scopes( + code, outputs={"res": [2]}, scopes=["module", "function"]) + self._check_in_scopes(code, raises=NameError, scopes=["class"]) + def test_references___classdict__(self): code = """ class i: [__classdict__ for x in y] """ self._check_in_scopes(code, raises=NameError) + def test_references___classdict___nested(self): + class _C: + res = [(lambda: __classdict__)() for _ in [1]] + self.assertIn("res", _C.res[0]) + def test_references___conditional_annotations__(self): code = """ class i: [__conditional_annotations__ for x in y] """ self._check_in_scopes(code, raises=NameError) + def test_references___conditional_annotations___nested(self): + code = """ + class i: [lambda: __conditional_annotations__ for x in y] + """ + self._check_in_scopes(code, raises=NameError) + def test_references___class___enclosing(self): code = """ __class__ = 2 diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-01-19-00-00.gh-issue-150700.W8CzVR.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-01-19-00-00.gh-issue-150700.W8CzVR.rst new file mode 100644 index 00000000000000..e7734034ff5c81 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-01-19-00-00.gh-issue-150700.W8CzVR.rst @@ -0,0 +1,3 @@ +Fix a :exc:`SystemError` when compiling a class-scope comprehension containing +a ``lambda`` that references ``__class__``, ``__classdict__``, or +``__conditional_annotations__``. Patch by Bartosz Sławecki. diff --git a/Python/symtable.c b/Python/symtable.c index 9a2e278caaf9e2..bd2b5145efdd48 100644 --- a/Python/symtable.c +++ b/Python/symtable.c @@ -834,17 +834,22 @@ inline_comprehension(PySTEntryObject *ste, PySTEntryObject *comp, return 0; } // __class__, __classdict__ and __conditional_annotations__ are - // never allowed to be free through a class scope (see - // drop_class_free) + // not allowed to be free through a class scope (see + // drop_class_free) unless children scopes need it if (scope == FREE && ste->ste_type == ClassBlock && (_PyUnicode_EqualToASCIIString(k, "__class__") || _PyUnicode_EqualToASCIIString(k, "__classdict__") || _PyUnicode_EqualToASCIIString(k, "__conditional_annotations__"))) { scope = GLOBAL_IMPLICIT; - if (PySet_Discard(comp_free, k) < 0) { + int child_needs_free = is_free_in_any_child(comp, k); + if (child_needs_free < 0) { return 0; } - + if (!child_needs_free) { + if (PySet_Discard(comp_free, k) < 0) { + return 0; + } + } if (_PyUnicode_EqualToASCIIString(k, "__class__")) { remove_dunder_class = 1; } From 0318867acf72e3acf78f480db73a69982573263a Mon Sep 17 00:00:00 2001 From: Cody Maloney <cmaloney@users.noreply.github.com> Date: Wed, 10 Jun 2026 02:13:46 -0700 Subject: [PATCH 285/818] [3.15] gh-143008: Fix race re-initializing TextIOWrapper (#151203) __init__() changes multiple variables and may be called more than once from multiple threads. --- .../Library/2026-06-04-18-22-56.gh-issue-143008.z5tw-J.rst | 1 + Modules/_io/clinic/textio.c.h | 4 +++- Modules/_io/textio.c | 3 ++- 3 files changed, 6 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-06-04-18-22-56.gh-issue-143008.z5tw-J.rst diff --git a/Misc/NEWS.d/next/Library/2026-06-04-18-22-56.gh-issue-143008.z5tw-J.rst b/Misc/NEWS.d/next/Library/2026-06-04-18-22-56.gh-issue-143008.z5tw-J.rst new file mode 100644 index 00000000000000..e99bc39c45f9b8 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-04-18-22-56.gh-issue-143008.z5tw-J.rst @@ -0,0 +1 @@ +Fix race conditions when re-initializing a :class:`io.TextIOWrapper` object. diff --git a/Modules/_io/clinic/textio.c.h b/Modules/_io/clinic/textio.c.h index 9407076b850cee..8d59bda5f74b38 100644 --- a/Modules/_io/clinic/textio.c.h +++ b/Modules/_io/clinic/textio.c.h @@ -666,7 +666,9 @@ _io_TextIOWrapper___init__(PyObject *self, PyObject *args, PyObject *kwargs) goto exit; } skip_optional_pos: + Py_BEGIN_CRITICAL_SECTION(self); return_value = _io_TextIOWrapper___init___impl((textio *)self, buffer, encoding, errors, newline, line_buffering, write_through); + Py_END_CRITICAL_SECTION(); exit: return return_value; @@ -1329,4 +1331,4 @@ _io_TextIOWrapper__CHUNK_SIZE_set(PyObject *self, PyObject *value, void *Py_UNUS return return_value; } -/*[clinic end generated code: output=f900b42090c9781c input=a9049054013a1b77]*/ +/*[clinic end generated code: output=8c571c9dba87d2b1 input=a9049054013a1b77]*/ diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c index e80b75066c59a6..1547c04cdf06af 100644 --- a/Modules/_io/textio.c +++ b/Modules/_io/textio.c @@ -1061,6 +1061,7 @@ io_check_errors(PyObject *errors) /*[clinic input] +@critical_section _io.TextIOWrapper.__init__ buffer: object encoding: str(accept={str, NoneType}) = None @@ -1104,7 +1105,7 @@ _io_TextIOWrapper___init___impl(textio *self, PyObject *buffer, const char *encoding, PyObject *errors, const char *newline, int line_buffering, int write_through) -/*[clinic end generated code: output=72267c0c01032ed2 input=e6cfaaaf6059d4f5]*/ +/*[clinic end generated code: output=72267c0c01032ed2 input=0f077220214c40a4]*/ { PyObject *raw, *codec_info = NULL; PyObject *res; From 0b6adeb20f5d7c8b81673d14e0a4db41fd2fca2d Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka <storchaka@gmail.com> Date: Wed, 10 Jun 2026 13:41:19 +0300 Subject: [PATCH 286/818] [3.15] gh-80384: Fix docs for PyWeakref_NewRef() and PyWeakref_NewProxy() (GH-151146) The type of the callback argument is not checked. --- Doc/c-api/weakref.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Doc/c-api/weakref.rst b/Doc/c-api/weakref.rst index db6ae0a9d4ea3d..d0c8d4a847a7c8 100644 --- a/Doc/c-api/weakref.rst +++ b/Doc/c-api/weakref.rst @@ -42,8 +42,8 @@ as much as it can. callable object that receives notification when *ob* is garbage collected; it should accept a single parameter, which will be the weak reference object itself. *callback* may also be ``None`` or ``NULL``. If *ob* is not a - weakly referenceable object, or if *callback* is not callable, ``None``, or - ``NULL``, this will return ``NULL`` and raise :exc:`TypeError`. + weakly referenceable object, this will raise :exc:`TypeError` and return + ``NULL``. .. seealso:: :c:func:`PyType_SUPPORTS_WEAKREFS` for checking if *ob* is weakly @@ -58,8 +58,8 @@ as much as it can. be a callable object that receives notification when *ob* is garbage collected; it should accept a single parameter, which will be the weak reference object itself. *callback* may also be ``None`` or ``NULL``. If *ob* - is not a weakly referenceable object, or if *callback* is not callable, - ``None``, or ``NULL``, this will return ``NULL`` and raise :exc:`TypeError`. + weakly referenceable object, this will raise :exc:`TypeError` and return + ``NULL``. .. seealso:: :c:func:`PyType_SUPPORTS_WEAKREFS` for checking if *ob* is weakly From 153607ef892908d67a196e90a901af87adfb779d Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 10 Jun 2026 13:35:01 +0200 Subject: [PATCH 287/818] [3.15] gh-98894: Fix DTrace test_check_probes for shared builds (GH-151122) (#151235) gh-98894: Fix DTrace test_check_probes for shared builds (GH-151122) When building with --enable-shared, the SystemTap/DTrace notes live in libpython. Add detection logic to be used by readelf. Force the C locale on readelf output. (cherry picked from commit 3a08e9373977788e7691ec0a973fbe1abe170c91) Co-authored-by: stratakis <cstratak@redhat.com> --- Lib/test/test_dtrace.py | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_dtrace.py b/Lib/test/test_dtrace.py index 61320a472f3e02..6286b6d21b572e 100644 --- a/Lib/test/test_dtrace.py +++ b/Lib/test/test_dtrace.py @@ -378,11 +378,14 @@ def setUpClass(cls): def get_readelf_version(): try: cmd = ["readelf", "--version"] + # Force the C locale to disable localization. + env = dict(os.environ, LC_ALL="C") proc = subprocess.Popen( cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True, + env=env, ) with proc: version, stderr = proc.communicate() @@ -405,12 +408,36 @@ def get_readelf_version(): return int(match.group(1)), int(match.group(2)) def get_readelf_output(self): - command = ["readelf", "-n", sys.executable] + binary = sys.executable + if sysconfig.get_config_var("Py_ENABLE_SHARED"): + lib_dir = sysconfig.get_config_var("LIBDIR") + if not lib_dir or sysconfig.is_python_build(): + lib_dir = os.path.abspath(os.path.dirname(sys.executable)) + + lib_names = [] + for name in ( + sysconfig.get_config_var("INSTSONAME"), + sysconfig.get_config_var("LDLIBRARY"), + ): + if name and name not in lib_names: + lib_names.append(name) + + if lib_dir: + for name in lib_names: + libpython_path = os.path.join(lib_dir, name) + if os.path.exists(libpython_path): + binary = libpython_path + break + + command = ["readelf", "-n", binary] + # Force the C locale to disable localization. + env = dict(os.environ, LC_ALL="C") stdout, _ = subprocess.Popen( command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True, + env=env, ).communicate() return stdout From 7201b9d18f2f94906bb9d75f59ad9d4696d7a68f Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 10 Jun 2026 14:56:54 +0200 Subject: [PATCH 288/818] [3.15] gh-150988: Fix refleak in `OSError` when attrs are set before `super().__init__()` (GH-150990) (#151240) gh-150988: Fix refleak in `OSError` when attrs are set before `super().__init__()` (GH-150990) (cherry picked from commit f2a0f82282d6307f7fd2d4ccf52a8fd95ac3922f) Co-authored-by: Lukas Geiger <lukas.geiger94@gmail.com> Co-authored-by: Victor Stinner <vstinner@python.org> --- Lib/test/test_exceptions.py | 14 ++++++++++++++ .../2026-06-05-22-52-41.gh-issue-150988.fDKfMJ.rst | 2 ++ Objects/exceptions.c | 10 +++++----- 3 files changed, 21 insertions(+), 5 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-05-22-52-41.gh-issue-150988.fDKfMJ.rst diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py index 3f5fcb29b442de..df7a04273b9b41 100644 --- a/Lib/test/test_exceptions.py +++ b/Lib/test/test_exceptions.py @@ -1714,6 +1714,20 @@ def inner(): gc_collect() # For PyPy or other GCs. self.assertEqual(wr(), None) + def test_oserror_reinit_leak(self): + # gh-150988: Check for memory leak when re-initializing OSError. + # Previously, setting OSError attributes in a subclass + # before calling super().__init__() leaked memory. + class LeakingOSError(OSError): + def __init__(self, code, message, filename, filename2): + self.strerror = message + self.filename = filename + self.filename2 = filename2 + super().__init__(code, message, filename, None, filename2) + + exc = LeakingOSError(1, "some message", "filename.py", "filename2.py") + exc.__init__(2, "another message", "filename3.py", "filename4.py") + def test_errno_ENOTDIR(self): # Issue #12802: "not a directory" errors are ENOTDIR even on Windows with self.assertRaises(OSError) as cm: diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-05-22-52-41.gh-issue-150988.fDKfMJ.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-05-22-52-41.gh-issue-150988.fDKfMJ.rst new file mode 100644 index 00000000000000..6fb70a1ce2685c --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-05-22-52-41.gh-issue-150988.fDKfMJ.rst @@ -0,0 +1,2 @@ +Fix a reference leak in :exc:`OSError` when attributes are set before +``super().__init__()``. diff --git a/Objects/exceptions.c b/Objects/exceptions.c index 10d100384be7aa..7b97d9e99431c3 100644 --- a/Objects/exceptions.c +++ b/Objects/exceptions.c @@ -2140,10 +2140,10 @@ oserror_init(PyOSErrorObject *self, PyObject **p_args, return -1; } else { - self->filename = Py_NewRef(filename); + Py_XSETREF(self->filename, Py_NewRef(filename)); if (filename2 && filename2 != Py_None) { - self->filename2 = Py_NewRef(filename2); + Py_XSETREF(self->filename2, Py_NewRef(filename2)); } if (nargs >= 2 && nargs <= 5) { @@ -2158,10 +2158,10 @@ oserror_init(PyOSErrorObject *self, PyObject **p_args, } } } - self->myerrno = Py_XNewRef(myerrno); - self->strerror = Py_XNewRef(strerror); + Py_XSETREF(self->myerrno, Py_XNewRef(myerrno)); + Py_XSETREF(self->strerror, Py_XNewRef(strerror)); #ifdef MS_WINDOWS - self->winerror = Py_XNewRef(winerror); + Py_XSETREF(self->winerror, Py_XNewRef(winerror)); #endif /* Steals the reference to args */ From de5da36c6622a47b9347386e9c5ad2a7e16ab43b Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 10 Jun 2026 15:09:28 +0200 Subject: [PATCH 289/818] [3.15] gh-89554: Document socket.SocketType as a class (GH-150683) (#151244) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gh-89554: Document socket.SocketType as a class (GH-150683) socket.SocketType is a class (re-exported from _socket as an alias of _socket.socket, the base class of socket.socket), but was documented with the ".. data::" directive, so ":class:" cross-references to it cannot resolve against a py:class target. Switch the entry to ".. class::", correct the misleading description (SocketType is the base class of the socket type, not "type(socket(...))" which is socket.socket; addresses gh-88427), move it into the Socket Objects section, and document the socket object methods and attributes nested under the socket class, dropping the redundant "socket." prefix. (cherry picked from commit a621e8ad811e7d51d69b0969a2bd07888a02db1e) Co-authored-by: Bernát Gábor <gaborjbernat@gmail.com> --- Doc/library/socket.rst | 1050 ++++++++++++++++++++-------------------- 1 file changed, 527 insertions(+), 523 deletions(-) diff --git a/Doc/library/socket.rst b/Doc/library/socket.rst index 96bc9e7a0d61e3..836aa91bb0885b 100644 --- a/Doc/library/socket.rst +++ b/Doc/library/socket.rst @@ -842,65 +842,8 @@ Creating sockets The following functions all create :ref:`socket objects <socket-objects>`. -.. class:: socket(family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None) - - Create a new socket using the given address family, socket type and protocol - number. The address family should be :const:`AF_INET` (the default), - :const:`AF_INET6`, :const:`AF_UNIX`, :const:`AF_CAN`, :const:`AF_PACKET`, - or :const:`AF_RDS`. The socket type should be :const:`SOCK_STREAM` (the - default), :const:`SOCK_DGRAM`, :const:`SOCK_RAW` or perhaps one of the other - ``SOCK_`` constants. The protocol number is usually zero and may be omitted - or in the case where the address family is :const:`AF_CAN` the protocol - should be one of :const:`CAN_RAW`, :const:`CAN_BCM`, :const:`CAN_ISOTP` or - :const:`CAN_J1939`. - - If *fileno* is specified, the values for *family*, *type*, and *proto* are - auto-detected from the specified file descriptor. Auto-detection can be - overruled by calling the function with explicit *family*, *type*, or *proto* - arguments. This only affects how Python represents e.g. the return value - of :meth:`socket.getpeername` but not the actual OS resource. Unlike - :func:`socket.fromfd`, *fileno* will return the same socket and not a - duplicate. This may help close a detached socket using - :meth:`socket.close`. - - The newly created socket is :ref:`non-inheritable <fd_inheritance>`. - - .. audit-event:: socket.__new__ self,family,type,protocol socket.socket - - .. versionchanged:: 3.3 - The AF_CAN family was added. - The AF_RDS family was added. - - .. versionchanged:: 3.4 - The CAN_BCM protocol was added. - - .. versionchanged:: 3.4 - The returned socket is now non-inheritable. - - .. versionchanged:: 3.7 - The CAN_ISOTP protocol was added. - - .. versionchanged:: 3.7 - When :const:`SOCK_NONBLOCK` or :const:`SOCK_CLOEXEC` - bit flags are applied to *type* they are cleared, and - :attr:`socket.type` will not reflect them. They are still passed - to the underlying system ``socket()`` call. Therefore, - - :: - - sock = socket.socket( - socket.AF_INET, - socket.SOCK_STREAM | socket.SOCK_NONBLOCK) - - will still create a non-blocking socket on OSes that support - ``SOCK_NONBLOCK``, but ``sock.type`` will be set to - ``socket.SOCK_STREAM``. - - .. versionchanged:: 3.9 - The CAN_J1939 protocol was added. - - .. versionchanged:: 3.10 - The IPPROTO_MPTCP protocol was added. +The :class:`socket <socket.socket>` class constructor creates a new socket +directly; see :ref:`socket-objects` for its parameters and full description. .. function:: socketpair([family[, type[, proto]]]) @@ -1025,12 +968,6 @@ The following functions all create :ref:`socket objects <socket-objects>`. .. versionadded:: 3.3 -.. data:: SocketType - - This is a Python type object that represents the socket object type. It is the - same as ``type(socket(...))``. - - Other functions ''''''''''''''' @@ -1538,642 +1475,709 @@ The :mod:`!socket` module also offers various network-related services: Socket Objects -------------- -Socket objects have the following methods. Except for -:meth:`~socket.makefile`, these correspond to Unix system calls applicable -to sockets. +.. class:: socket(family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None) -.. versionchanged:: 3.2 - Support for the :term:`context manager` protocol was added. Exiting the - context manager is equivalent to calling :meth:`~socket.close`. + Create a new socket using the given address family, socket type and protocol + number. The address family should be :const:`AF_INET` (the default), + :const:`AF_INET6`, :const:`AF_UNIX`, :const:`AF_CAN`, :const:`AF_PACKET`, + or :const:`AF_RDS`. The socket type should be :const:`SOCK_STREAM` (the + default), :const:`SOCK_DGRAM`, :const:`SOCK_RAW` or perhaps one of the other + ``SOCK_`` constants. The protocol number is usually zero and may be omitted + or in the case where the address family is :const:`AF_CAN` the protocol + should be one of :const:`CAN_RAW`, :const:`CAN_BCM`, :const:`CAN_ISOTP` or + :const:`CAN_J1939`. + If *fileno* is specified, the values for *family*, *type*, and *proto* are + auto-detected from the specified file descriptor. Auto-detection can be + overruled by calling the function with explicit *family*, *type*, or *proto* + arguments. This only affects how Python represents e.g. the return value + of :meth:`socket.getpeername` but not the actual OS resource. Unlike + :func:`socket.fromfd`, *fileno* will return the same socket and not a + duplicate. This may help close a detached socket using + :meth:`socket.close`. -.. method:: socket.accept() + The newly created socket is :ref:`non-inheritable <fd_inheritance>`. - Accept a connection. The socket must be bound to an address and listening for - connections. The return value is a pair ``(conn, address)`` where *conn* is a - *new* socket object usable to send and receive data on the connection, and - *address* is the address bound to the socket on the other end of the connection. + .. audit-event:: socket.__new__ self,family,type,protocol socket.socket - The newly created socket is :ref:`non-inheritable <fd_inheritance>`. + .. versionchanged:: 3.3 + The AF_CAN family was added. + The AF_RDS family was added. .. versionchanged:: 3.4 - The socket is now non-inheritable. + The CAN_BCM protocol was added. - .. versionchanged:: 3.5 - If the system call is interrupted and the signal handler does not raise - an exception, the method now retries the system call instead of raising - an :exc:`InterruptedError` exception (see :pep:`475` for the rationale). + .. versionchanged:: 3.4 + The returned socket is now non-inheritable. + .. versionchanged:: 3.7 + The CAN_ISOTP protocol was added. -.. method:: socket.bind(address) + .. versionchanged:: 3.7 + When :const:`SOCK_NONBLOCK` or :const:`SOCK_CLOEXEC` + bit flags are applied to *type* they are cleared, and + :attr:`socket.type` will not reflect them. They are still passed + to the underlying system ``socket()`` call. Therefore, - Bind the socket to *address*. The socket must not already be bound. The format - of *address* depends on the address family --- see :ref:`socket-addresses`. + :: - .. audit-event:: socket.bind self,address socket.socket.bind + sock = socket.socket( + socket.AF_INET, + socket.SOCK_STREAM | socket.SOCK_NONBLOCK) - .. availability:: not WASI. + will still create a non-blocking socket on OSes that support + ``SOCK_NONBLOCK``, but ``sock.type`` will be set to + ``socket.SOCK_STREAM``. + .. versionchanged:: 3.9 + The CAN_J1939 protocol was added. -.. method:: socket.close() + .. versionchanged:: 3.10 + The IPPROTO_MPTCP protocol was added. - Mark the socket closed. The underlying system resource (e.g. a file - descriptor) is also closed when all file objects from :meth:`makefile` - are closed. Once that happens, all future operations on the socket - object will fail. The remote end will receive no more data (after - queued data is flushed). + Socket objects have the following methods. Except for + :meth:`~socket.makefile`, these correspond to Unix system calls applicable + to sockets. - Sockets are automatically closed when they are garbage-collected, but - it is recommended to :meth:`close` them explicitly, or to use a - :keyword:`with` statement around them. + .. versionchanged:: 3.2 + Support for the :term:`context manager` protocol was added. Exiting the + context manager is equivalent to calling :meth:`~socket.close`. - .. versionchanged:: 3.6 - :exc:`OSError` is now raised if an error occurs when the underlying - :c:func:`close` call is made. - .. note:: + .. method:: accept() - :meth:`close` releases the resource associated with a connection but - does not necessarily close the connection immediately. If you want - to close the connection in a timely fashion, call :meth:`shutdown` - before :meth:`close`. + Accept a connection. The socket must be bound to an address and listening for + connections. The return value is a pair ``(conn, address)`` where *conn* is a + *new* socket object usable to send and receive data on the connection, and + *address* is the address bound to the socket on the other end of the connection. + The newly created socket is :ref:`non-inheritable <fd_inheritance>`. -.. method:: socket.connect(address) + .. versionchanged:: 3.4 + The socket is now non-inheritable. - Connect to a remote socket at *address*. The format of *address* depends on the - address family --- see :ref:`socket-addresses`. + .. versionchanged:: 3.5 + If the system call is interrupted and the signal handler does not raise + an exception, the method now retries the system call instead of raising + an :exc:`InterruptedError` exception (see :pep:`475` for the rationale). - If the connection is interrupted by a signal, the method waits until the - connection completes, or raises a :exc:`TimeoutError` on timeout, if the - signal handler doesn't raise an exception and the socket is blocking or has - a timeout. For non-blocking sockets, the method raises an - :exc:`InterruptedError` exception if the connection is interrupted by a - signal (or the exception raised by the signal handler). - .. audit-event:: socket.connect self,address socket.socket.connect + .. method:: bind(address) - .. versionchanged:: 3.5 - The method now waits until the connection completes instead of raising an + Bind the socket to *address*. The socket must not already be bound. The format + of *address* depends on the address family --- see :ref:`socket-addresses`. + + .. audit-event:: socket.bind self,address socket.socket.bind + + .. availability:: not WASI. + + + .. method:: close() + + Mark the socket closed. The underlying system resource (e.g. a file + descriptor) is also closed when all file objects from :meth:`makefile` + are closed. Once that happens, all future operations on the socket + object will fail. The remote end will receive no more data (after + queued data is flushed). + + Sockets are automatically closed when they are garbage-collected, but + it is recommended to :meth:`close` them explicitly, or to use a + :keyword:`with` statement around them. + + .. versionchanged:: 3.6 + :exc:`OSError` is now raised if an error occurs when the underlying + :c:func:`!close` call is made. + + .. note:: + + :meth:`close` releases the resource associated with a connection but + does not necessarily close the connection immediately. If you want + to close the connection in a timely fashion, call :meth:`shutdown` + before :meth:`close`. + + + .. method:: connect(address) + + Connect to a remote socket at *address*. The format of *address* depends on the + address family --- see :ref:`socket-addresses`. + + If the connection is interrupted by a signal, the method waits until the + connection completes, or raises a :exc:`TimeoutError` on timeout, if the + signal handler doesn't raise an exception and the socket is blocking or has + a timeout. For non-blocking sockets, the method raises an :exc:`InterruptedError` exception if the connection is interrupted by a - signal, the signal handler doesn't raise an exception and the socket is - blocking or has a timeout (see the :pep:`475` for the rationale). + signal (or the exception raised by the signal handler). - .. availability:: not WASI. + .. audit-event:: socket.connect self,address socket.socket.connect + .. versionchanged:: 3.5 + The method now waits until the connection completes instead of raising an + :exc:`InterruptedError` exception if the connection is interrupted by a + signal, the signal handler doesn't raise an exception and the socket is + blocking or has a timeout (see the :pep:`475` for the rationale). -.. method:: socket.connect_ex(address) + .. availability:: not WASI. - Like ``connect(address)``, but return an error indicator instead of raising an - exception for errors returned by the C-level :c:func:`connect` call (other - problems, such as "host not found," can still raise exceptions). The error - indicator is ``0`` if the operation succeeded, otherwise the value of the - :c:data:`errno` variable. This is useful to support, for example, asynchronous - connects. - .. audit-event:: socket.connect self,address socket.socket.connect_ex + .. method:: connect_ex(address) - .. availability:: not WASI. + Like ``connect(address)``, but return an error indicator instead of raising an + exception for errors returned by the C-level :c:func:`!connect` call (other + problems, such as "host not found," can still raise exceptions). The error + indicator is ``0`` if the operation succeeded, otherwise the value of the + :c:data:`errno` variable. This is useful to support, for example, asynchronous + connects. -.. method:: socket.detach() + .. audit-event:: socket.connect self,address socket.socket.connect_ex - Put the socket object into closed state without actually closing the - underlying file descriptor. The file descriptor is returned, and can - be reused for other purposes. + .. availability:: not WASI. - .. versionadded:: 3.2 + .. method:: detach() + Put the socket object into closed state without actually closing the + underlying file descriptor. The file descriptor is returned, and can + be reused for other purposes. -.. method:: socket.dup() + .. versionadded:: 3.2 - Duplicate the socket. - The newly created socket is :ref:`non-inheritable <fd_inheritance>`. + .. method:: dup() - .. versionchanged:: 3.4 - The socket is now non-inheritable. + Duplicate the socket. - .. availability:: not WASI. + The newly created socket is :ref:`non-inheritable <fd_inheritance>`. + .. versionchanged:: 3.4 + The socket is now non-inheritable. -.. method:: socket.fileno() + .. availability:: not WASI. - Return the socket's file descriptor (a small integer), or -1 on failure. This - is useful with :func:`select.select`. - Under Windows the small integer returned by this method cannot be used where a - file descriptor can be used (such as :func:`os.fdopen`). Unix does not have - this limitation. + .. method:: fileno() -.. method:: socket.get_inheritable() + Return the socket's file descriptor (a small integer), or -1 on failure. This + is useful with :func:`select.select`. - Get the :ref:`inheritable flag <fd_inheritance>` of the socket's file - descriptor or socket's handle: ``True`` if the socket can be inherited in - child processes, ``False`` if it cannot. + Under Windows the small integer returned by this method cannot be used where a + file descriptor can be used (such as :func:`os.fdopen`). Unix does not have + this limitation. - .. versionadded:: 3.4 + .. method:: get_inheritable() + Get the :ref:`inheritable flag <fd_inheritance>` of the socket's file + descriptor or socket's handle: ``True`` if the socket can be inherited in + child processes, ``False`` if it cannot. -.. method:: socket.getpeername() + .. versionadded:: 3.4 - Return the remote address to which the socket is connected. This is useful to - find out the port number of a remote IPv4/v6 socket, for instance. The format - of the address returned depends on the address family --- see :ref:`socket-addresses`. - On some systems this function is not supported. + .. method:: getpeername() -.. method:: socket.getsockname() + Return the remote address to which the socket is connected. This is useful to + find out the port number of a remote IPv4/v6 socket, for instance. The format + of the address returned depends on the address family --- see :ref:`socket-addresses`. + On some systems this function is not supported. - Return the socket's own address. This is useful to find out the port number of - an IPv4/v6 socket, for instance. The format of the address returned depends on - the address family --- see :ref:`socket-addresses`. + .. method:: getsockname() -.. method:: socket.getsockopt(level, optname[, buflen]) + Return the socket's own address. This is useful to find out the port number of + an IPv4/v6 socket, for instance. The format of the address returned depends on + the address family --- see :ref:`socket-addresses`. - Return the value of the given socket option (see the Unix man page - :manpage:`getsockopt(2)`). The needed symbolic constants (:ref:`SO_\* etc. <socket-unix-constants>`) - are defined in this module. If *buflen* is absent, an integer option is assumed - and its integer value is returned by the function. If *buflen* is present, it - specifies the maximum length of the buffer used to receive the option in, and - this buffer is returned as a bytes object. It is up to the caller to decode the - contents of the buffer (see the optional built-in module :mod:`struct` for a way - to decode C structures encoded as byte strings). - .. availability:: not WASI. + .. method:: getsockopt(level, optname[, buflen]) + Return the value of the given socket option (see the Unix man page + :manpage:`getsockopt(2)`). The needed symbolic constants (:ref:`SO_\* etc. <socket-unix-constants>`) + are defined in this module. If *buflen* is absent, an integer option is assumed + and its integer value is returned by the function. If *buflen* is present, it + specifies the maximum length of the buffer used to receive the option in, and + this buffer is returned as a bytes object. It is up to the caller to decode the + contents of the buffer (see the optional built-in module :mod:`struct` for a way + to decode C structures encoded as byte strings). -.. method:: socket.getblocking() + .. availability:: not WASI. - Return ``True`` if socket is in blocking mode, ``False`` if in - non-blocking. - This is equivalent to checking ``socket.gettimeout() != 0``. + .. method:: getblocking() - .. versionadded:: 3.7 + Return ``True`` if socket is in blocking mode, ``False`` if in + non-blocking. + This is equivalent to checking ``socket.gettimeout() != 0``. -.. method:: socket.gettimeout() + .. versionadded:: 3.7 - Return the timeout in seconds (float) associated with socket operations, - or ``None`` if no timeout is set. This reflects the last call to - :meth:`setblocking` or :meth:`settimeout`. + .. method:: gettimeout() -.. method:: socket.ioctl(control, option) + Return the timeout in seconds (float) associated with socket operations, + or ``None`` if no timeout is set. This reflects the last call to + :meth:`setblocking` or :meth:`settimeout`. - The :meth:`ioctl` method is a limited interface to the WSAIoctl system - interface. Please refer to the `Win32 documentation - <https://msdn.microsoft.com/en-us/library/ms741621%28VS.85%29.aspx>`_ for more - information. - On other platforms, the generic :func:`fcntl.fcntl` and :func:`fcntl.ioctl` - functions may be used; they accept a socket object as their first argument. + .. method:: ioctl(control, option) - Currently only the following control codes are supported: - ``SIO_RCVALL``, ``SIO_KEEPALIVE_VALS``, and ``SIO_LOOPBACK_FAST_PATH``. + The :meth:`ioctl` method is a limited interface to the WSAIoctl system + interface. Please refer to the `Win32 documentation + <https://msdn.microsoft.com/en-us/library/ms741621%28VS.85%29.aspx>`_ for more + information. - .. availability:: Windows + On other platforms, the generic :func:`fcntl.fcntl` and :func:`fcntl.ioctl` + functions may be used; they accept a socket object as their first argument. - .. versionchanged:: 3.6 - ``SIO_LOOPBACK_FAST_PATH`` was added. + Currently only the following control codes are supported: + ``SIO_RCVALL``, ``SIO_KEEPALIVE_VALS``, and ``SIO_LOOPBACK_FAST_PATH``. + .. availability:: Windows -.. method:: socket.listen([backlog]) + .. versionchanged:: 3.6 + ``SIO_LOOPBACK_FAST_PATH`` was added. - Enable a server to accept connections. If *backlog* is specified, it must - be at least 0 (if it is lower, it is set to 0); it specifies the number of - unaccepted connections that the system will allow before refusing new - connections. If not specified, a default reasonable value is chosen. - .. availability:: not WASI. + .. method:: listen([backlog]) - .. versionchanged:: 3.5 - The *backlog* parameter is now optional. + Enable a server to accept connections. If *backlog* is specified, it must + be at least 0 (if it is lower, it is set to 0); it specifies the number of + unaccepted connections that the system will allow before refusing new + connections. If not specified, a default reasonable value is chosen. + .. availability:: not WASI. -.. method:: socket.makefile(mode='r', buffering=None, *, encoding=None, \ - errors=None, newline=None) + .. versionchanged:: 3.5 + The *backlog* parameter is now optional. - .. index:: single: I/O control; buffering - Return a :term:`file object` associated with the socket. The exact returned - type depends on the arguments given to :meth:`makefile`. These arguments are - interpreted the same way as by the built-in :func:`open` function, except - the only supported *mode* values are ``'r'`` (default), ``'w'``, ``'b'``, or - a combination of those. + .. method:: makefile(mode='r', buffering=None, *, encoding=None, \ + errors=None, newline=None) - The socket must be in blocking mode; it can have a timeout, but the file - object's internal buffer may end up in an inconsistent state if a timeout - occurs. + .. index:: single: I/O control; buffering - Closing the file object returned by :meth:`makefile` won't close the - original socket unless all other file objects have been closed and - :meth:`socket.close` has been called on the socket object. + Return a :term:`file object` associated with the socket. The exact returned + type depends on the arguments given to :meth:`makefile`. These arguments are + interpreted the same way as by the built-in :func:`open` function, except + the only supported *mode* values are ``'r'`` (default), ``'w'``, ``'b'``, or + a combination of those. - .. note:: + The socket must be in blocking mode; it can have a timeout, but the file + object's internal buffer may end up in an inconsistent state if a timeout + occurs. - On Windows, the file-like object created by :meth:`makefile` cannot be - used where a file object with a file descriptor is expected, such as the - stream arguments of :meth:`subprocess.Popen`. + Closing the file object returned by :meth:`makefile` won't close the + original socket unless all other file objects have been closed and + :meth:`socket.close` has been called on the socket object. + .. note:: -.. method:: socket.recv(bufsize[, flags]) + On Windows, the file-like object created by :meth:`makefile` cannot be + used where a file object with a file descriptor is expected, such as the + stream arguments of :meth:`subprocess.Popen`. - Receive data from the socket. The return value is a bytes object representing the - data received. The maximum amount of data to be received at once is specified - by *bufsize*. A returned empty bytes object indicates that the client has disconnected. - See the Unix manual page :manpage:`recv(2)` for the meaning of the optional argument - *flags*; it defaults to zero. - .. versionchanged:: 3.5 - If the system call is interrupted and the signal handler does not raise - an exception, the method now retries the system call instead of raising - an :exc:`InterruptedError` exception (see :pep:`475` for the rationale). + .. method:: recv(bufsize[, flags]) + Receive data from the socket. The return value is a bytes object representing the + data received. The maximum amount of data to be received at once is specified + by *bufsize*. A returned empty bytes object indicates that the client has disconnected. + See the Unix manual page :manpage:`recv(2)` for the meaning of the optional argument + *flags*; it defaults to zero. -.. method:: socket.recvfrom(bufsize[, flags]) + .. versionchanged:: 3.5 + If the system call is interrupted and the signal handler does not raise + an exception, the method now retries the system call instead of raising + an :exc:`InterruptedError` exception (see :pep:`475` for the rationale). - Receive data from the socket. The return value is a pair ``(bytes, address)`` - where *bytes* is a bytes object representing the data received and *address* is the - address of the socket sending the data. See the Unix manual page - :manpage:`recv(2)` for the meaning of the optional argument *flags*; it defaults - to zero. The format of *address* depends on the address family --- see - :ref:`socket-addresses`. - .. versionchanged:: 3.5 - If the system call is interrupted and the signal handler does not raise - an exception, the method now retries the system call instead of raising - an :exc:`InterruptedError` exception (see :pep:`475` for the rationale). + .. method:: recvfrom(bufsize[, flags]) - .. versionchanged:: 3.7 - For multicast IPv6 address, first item of *address* does not contain - ``%scope_id`` part anymore. In order to get full IPv6 address use - :func:`getnameinfo`. - -.. method:: socket.recvmsg(bufsize[, ancbufsize[, flags]]) - - Receive normal data (up to *bufsize* bytes) and ancillary data from - the socket. The *ancbufsize* argument sets the size in bytes of - the internal buffer used to receive the ancillary data; it defaults - to 0, meaning that no ancillary data will be received. Appropriate - buffer sizes for ancillary data can be calculated using - :func:`CMSG_SPACE` or :func:`CMSG_LEN`, and items which do not fit - into the buffer might be truncated or discarded. The *flags* - argument defaults to 0 and has the same meaning as for - :meth:`recv`. - - The return value is a 4-tuple: ``(data, ancdata, msg_flags, - address)``. The *data* item is a :class:`bytes` object holding the - non-ancillary data received. The *ancdata* item is a list of zero - or more tuples ``(cmsg_level, cmsg_type, cmsg_data)`` representing - the ancillary data (control messages) received: *cmsg_level* and - *cmsg_type* are integers specifying the protocol level and - protocol-specific type respectively, and *cmsg_data* is a - :class:`bytes` object holding the associated data. The *msg_flags* - item is the bitwise OR of various flags indicating conditions on - the received message; see your system documentation for details. - If the receiving socket is unconnected, *address* is the address of - the sending socket, if available; otherwise, its value is - unspecified. - - On some systems, :meth:`sendmsg` and :meth:`recvmsg` can be used to - pass file descriptors between processes over an :const:`AF_UNIX` - socket. When this facility is used (it is often restricted to - :const:`SOCK_STREAM` sockets), :meth:`recvmsg` will return, in its - ancillary data, items of the form ``(socket.SOL_SOCKET, - socket.SCM_RIGHTS, fds)``, where *fds* is a :class:`bytes` object - representing the new file descriptors as a binary array of the - native C :c:expr:`int` type. If :meth:`recvmsg` raises an - exception after the system call returns, it will first attempt to - close any file descriptors received via this mechanism. - - Some systems do not indicate the truncated length of ancillary data - items which have been only partially received. If an item appears - to extend beyond the end of the buffer, :meth:`recvmsg` will issue - a :exc:`RuntimeWarning`, and will return the part of it which is - inside the buffer provided it has not been truncated before the - start of its associated data. - - On systems which support the :const:`SCM_RIGHTS` mechanism, the - following function will receive up to *maxfds* file descriptors, - returning the message data and a list containing the descriptors - (while ignoring unexpected conditions such as unrelated control - messages being received). See also :meth:`sendmsg`. :: - - import socket, array - - def recv_fds(sock, msglen, maxfds): - fds = array.array("i") # Array of ints - msg, ancdata, flags, addr = sock.recvmsg(msglen, socket.CMSG_LEN(maxfds * fds.itemsize)) - for cmsg_level, cmsg_type, cmsg_data in ancdata: - if cmsg_level == socket.SOL_SOCKET and cmsg_type == socket.SCM_RIGHTS: - # Append data, ignoring any truncated integers at the end. - fds.frombytes(cmsg_data[:len(cmsg_data) - (len(cmsg_data) % fds.itemsize)]) - return msg, list(fds) - - .. availability:: Unix. + Receive data from the socket. The return value is a pair ``(bytes, address)`` + where *bytes* is a bytes object representing the data received and *address* is the + address of the socket sending the data. See the Unix manual page + :manpage:`recv(2)` for the meaning of the optional argument *flags*; it defaults + to zero. The format of *address* depends on the address family --- see + :ref:`socket-addresses`. - Most Unix platforms. + .. versionchanged:: 3.5 + If the system call is interrupted and the signal handler does not raise + an exception, the method now retries the system call instead of raising + an :exc:`InterruptedError` exception (see :pep:`475` for the rationale). - .. versionadded:: 3.3 + .. versionchanged:: 3.7 + For multicast IPv6 address, first item of *address* does not contain + ``%scope_id`` part anymore. In order to get full IPv6 address use + :func:`getnameinfo`. - .. versionchanged:: 3.5 - If the system call is interrupted and the signal handler does not raise - an exception, the method now retries the system call instead of raising - an :exc:`InterruptedError` exception (see :pep:`475` for the rationale). - - -.. method:: socket.recvmsg_into(buffers[, ancbufsize[, flags]]) - - Receive normal data and ancillary data from the socket, behaving as - :meth:`recvmsg` would, but scatter the non-ancillary data into a - series of buffers instead of returning a new bytes object. The - *buffers* argument must be an iterable of objects that export - writable buffers (e.g. :class:`bytearray` objects); these will be - filled with successive chunks of the non-ancillary data until it - has all been written or there are no more buffers. The operating - system may set a limit (:func:`~os.sysconf` value ``SC_IOV_MAX``) - on the number of buffers that can be used. The *ancbufsize* and - *flags* arguments have the same meaning as for :meth:`recvmsg`. - - The return value is a 4-tuple: ``(nbytes, ancdata, msg_flags, - address)``, where *nbytes* is the total number of bytes of - non-ancillary data written into the buffers, and *ancdata*, - *msg_flags* and *address* are the same as for :meth:`recvmsg`. - - Example:: - - >>> import socket - >>> s1, s2 = socket.socketpair() - >>> b1 = bytearray(b'----') - >>> b2 = bytearray(b'0123456789') - >>> b3 = bytearray(b'--------------') - >>> s1.send(b'Mary had a little lamb') - 22 - >>> s2.recvmsg_into([b1, memoryview(b2)[2:9], b3]) - (22, [], 0, None) - >>> [b1, b2, b3] - [bytearray(b'Mary'), bytearray(b'01 had a 9'), bytearray(b'little lamb---')] - - .. availability:: Unix. + .. method:: recvmsg(bufsize[, ancbufsize[, flags]]) + + Receive normal data (up to *bufsize* bytes) and ancillary data from + the socket. The *ancbufsize* argument sets the size in bytes of + the internal buffer used to receive the ancillary data; it defaults + to 0, meaning that no ancillary data will be received. Appropriate + buffer sizes for ancillary data can be calculated using + :func:`CMSG_SPACE` or :func:`CMSG_LEN`, and items which do not fit + into the buffer might be truncated or discarded. The *flags* + argument defaults to 0 and has the same meaning as for + :meth:`recv`. + + The return value is a 4-tuple: ``(data, ancdata, msg_flags, + address)``. The *data* item is a :class:`bytes` object holding the + non-ancillary data received. The *ancdata* item is a list of zero + or more tuples ``(cmsg_level, cmsg_type, cmsg_data)`` representing + the ancillary data (control messages) received: *cmsg_level* and + *cmsg_type* are integers specifying the protocol level and + protocol-specific type respectively, and *cmsg_data* is a + :class:`bytes` object holding the associated data. The *msg_flags* + item is the bitwise OR of various flags indicating conditions on + the received message; see your system documentation for details. + If the receiving socket is unconnected, *address* is the address of + the sending socket, if available; otherwise, its value is + unspecified. + + On some systems, :meth:`sendmsg` and :meth:`recvmsg` can be used to + pass file descriptors between processes over an :const:`AF_UNIX` + socket. When this facility is used (it is often restricted to + :const:`SOCK_STREAM` sockets), :meth:`recvmsg` will return, in its + ancillary data, items of the form ``(socket.SOL_SOCKET, + socket.SCM_RIGHTS, fds)``, where *fds* is a :class:`bytes` object + representing the new file descriptors as a binary array of the + native C :c:expr:`int` type. If :meth:`recvmsg` raises an + exception after the system call returns, it will first attempt to + close any file descriptors received via this mechanism. + + Some systems do not indicate the truncated length of ancillary data + items which have been only partially received. If an item appears + to extend beyond the end of the buffer, :meth:`recvmsg` will issue + a :exc:`RuntimeWarning`, and will return the part of it which is + inside the buffer provided it has not been truncated before the + start of its associated data. + + On systems which support the :const:`!SCM_RIGHTS` mechanism, the + following function will receive up to *maxfds* file descriptors, + returning the message data and a list containing the descriptors + (while ignoring unexpected conditions such as unrelated control + messages being received). See also :meth:`sendmsg`. :: + + import socket, array + + def recv_fds(sock, msglen, maxfds): + fds = array.array("i") # Array of ints + msg, ancdata, flags, addr = sock.recvmsg(msglen, socket.CMSG_LEN(maxfds * fds.itemsize)) + for cmsg_level, cmsg_type, cmsg_data in ancdata: + if cmsg_level == socket.SOL_SOCKET and cmsg_type == socket.SCM_RIGHTS: + # Append data, ignoring any truncated integers at the end. + fds.frombytes(cmsg_data[:len(cmsg_data) - (len(cmsg_data) % fds.itemsize)]) + return msg, list(fds) + + .. availability:: Unix. + + Most Unix platforms. + + .. versionadded:: 3.3 + + .. versionchanged:: 3.5 + If the system call is interrupted and the signal handler does not raise + an exception, the method now retries the system call instead of raising + an :exc:`InterruptedError` exception (see :pep:`475` for the rationale). + + + .. method:: recvmsg_into(buffers[, ancbufsize[, flags]]) + + Receive normal data and ancillary data from the socket, behaving as + :meth:`recvmsg` would, but scatter the non-ancillary data into a + series of buffers instead of returning a new bytes object. The + *buffers* argument must be an iterable of objects that export + writable buffers (e.g. :class:`bytearray` objects); these will be + filled with successive chunks of the non-ancillary data until it + has all been written or there are no more buffers. The operating + system may set a limit (:func:`~os.sysconf` value ``SC_IOV_MAX``) + on the number of buffers that can be used. The *ancbufsize* and + *flags* arguments have the same meaning as for :meth:`recvmsg`. + + The return value is a 4-tuple: ``(nbytes, ancdata, msg_flags, + address)``, where *nbytes* is the total number of bytes of + non-ancillary data written into the buffers, and *ancdata*, + *msg_flags* and *address* are the same as for :meth:`recvmsg`. + + Example:: + + >>> import socket + >>> s1, s2 = socket.socketpair() + >>> b1 = bytearray(b'----') + >>> b2 = bytearray(b'0123456789') + >>> b3 = bytearray(b'--------------') + >>> s1.send(b'Mary had a little lamb') + 22 + >>> s2.recvmsg_into([b1, memoryview(b2)[2:9], b3]) + (22, [], 0, None) + >>> [b1, b2, b3] + [bytearray(b'Mary'), bytearray(b'01 had a 9'), bytearray(b'little lamb---')] + + .. availability:: Unix. + + Most Unix platforms. + + .. versionadded:: 3.3 + + + .. method:: recvfrom_into(buffer[, nbytes[, flags]]) + + Receive data from the socket, writing it into *buffer* instead of creating a + new bytestring. The return value is a pair ``(nbytes, address)`` where *nbytes* is + the number of bytes received and *address* is the address of the socket sending + the data. See the Unix manual page :manpage:`recv(2)` for the meaning of the + optional argument *flags*; it defaults to zero. The format of *address* + depends on the address family --- see :ref:`socket-addresses`. + + + .. method:: recv_into(buffer[, nbytes[, flags]]) + + Receive up to *nbytes* bytes from the socket, storing the data into a buffer + rather than creating a new bytestring. If *nbytes* is not specified (or 0), + receive up to the size available in the given buffer. Returns the number of + bytes received. See the Unix manual page :manpage:`recv(2)` for the meaning + of the optional argument *flags*; it defaults to zero. - Most Unix platforms. - .. versionadded:: 3.3 + .. method:: send(bytes[, flags]) + Send data to the socket. The socket must be connected to a remote socket. The + optional *flags* argument has the same meaning as for :meth:`recv`. + Returns the number of bytes sent. Applications are responsible for checking that + all data has been sent; if only some of the data was transmitted, the + application needs to attempt delivery of the remaining data. For further + information on this topic, consult the :ref:`socket-howto`. -.. method:: socket.recvfrom_into(buffer[, nbytes[, flags]]) + .. versionchanged:: 3.5 + If the system call is interrupted and the signal handler does not raise + an exception, the method now retries the system call instead of raising + an :exc:`InterruptedError` exception (see :pep:`475` for the rationale). - Receive data from the socket, writing it into *buffer* instead of creating a - new bytestring. The return value is a pair ``(nbytes, address)`` where *nbytes* is - the number of bytes received and *address* is the address of the socket sending - the data. See the Unix manual page :manpage:`recv(2)` for the meaning of the - optional argument *flags*; it defaults to zero. The format of *address* - depends on the address family --- see :ref:`socket-addresses`. + .. method:: sendall(bytes[, flags]) -.. method:: socket.recv_into(buffer[, nbytes[, flags]]) + Send data to the socket. The socket must be connected to a remote socket. The + optional *flags* argument has the same meaning as for :meth:`recv`. + Unlike :meth:`send`, this method continues to send data from *bytes* until + either all data has been sent or an error occurs. ``None`` is returned on + success. On error, an exception is raised, and there is no way to determine how + much data, if any, was successfully sent. - Receive up to *nbytes* bytes from the socket, storing the data into a buffer - rather than creating a new bytestring. If *nbytes* is not specified (or 0), - receive up to the size available in the given buffer. Returns the number of - bytes received. See the Unix manual page :manpage:`recv(2)` for the meaning - of the optional argument *flags*; it defaults to zero. + .. versionchanged:: 3.5 + The socket timeout is no longer reset each time data is sent successfully. + The socket timeout is now the maximum total duration to send all data. + .. versionchanged:: 3.5 + If the system call is interrupted and the signal handler does not raise + an exception, the method now retries the system call instead of raising + an :exc:`InterruptedError` exception (see :pep:`475` for the rationale). -.. method:: socket.send(bytes[, flags]) - Send data to the socket. The socket must be connected to a remote socket. The - optional *flags* argument has the same meaning as for :meth:`recv`. - Returns the number of bytes sent. Applications are responsible for checking that - all data has been sent; if only some of the data was transmitted, the - application needs to attempt delivery of the remaining data. For further - information on this topic, consult the :ref:`socket-howto`. + .. method:: sendto(bytes, address) + sendto(bytes, flags, address) - .. versionchanged:: 3.5 - If the system call is interrupted and the signal handler does not raise - an exception, the method now retries the system call instead of raising - an :exc:`InterruptedError` exception (see :pep:`475` for the rationale). + Send data to the socket. The socket should not be connected to a remote socket, + since the destination socket is specified by *address*. The optional *flags* + argument has the same meaning as for :meth:`recv`. Return the number of + bytes sent. The format of *address* depends on the address family --- see + :ref:`socket-addresses`. + .. audit-event:: socket.sendto self,address socket.socket.sendto -.. method:: socket.sendall(bytes[, flags]) + .. versionchanged:: 3.5 + If the system call is interrupted and the signal handler does not raise + an exception, the method now retries the system call instead of raising + an :exc:`InterruptedError` exception (see :pep:`475` for the rationale). - Send data to the socket. The socket must be connected to a remote socket. The - optional *flags* argument has the same meaning as for :meth:`recv`. - Unlike :meth:`send`, this method continues to send data from *bytes* until - either all data has been sent or an error occurs. ``None`` is returned on - success. On error, an exception is raised, and there is no way to determine how - much data, if any, was successfully sent. - .. versionchanged:: 3.5 - The socket timeout is no longer reset each time data is sent successfully. - The socket timeout is now the maximum total duration to send all data. + .. method:: sendmsg(buffers[, ancdata[, flags[, address]]]) - .. versionchanged:: 3.5 - If the system call is interrupted and the signal handler does not raise - an exception, the method now retries the system call instead of raising - an :exc:`InterruptedError` exception (see :pep:`475` for the rationale). + Send normal and ancillary data to the socket, gathering the + non-ancillary data from a series of buffers and concatenating it + into a single message. The *buffers* argument specifies the + non-ancillary data as an iterable of + :term:`bytes-like objects <bytes-like object>` + (e.g. :class:`bytes` objects); the operating system may set a limit + (:func:`~os.sysconf` value ``SC_IOV_MAX``) on the number of buffers + that can be used. The *ancdata* argument specifies the ancillary + data (control messages) as an iterable of zero or more tuples + ``(cmsg_level, cmsg_type, cmsg_data)``, where *cmsg_level* and + *cmsg_type* are integers specifying the protocol level and + protocol-specific type respectively, and *cmsg_data* is a + bytes-like object holding the associated data. Note that + some systems (in particular, systems without :func:`CMSG_SPACE`) + might support sending only one control message per call. The + *flags* argument defaults to 0 and has the same meaning as for + :meth:`send`. If *address* is supplied and not ``None``, it sets a + destination address for the message. The return value is the + number of bytes of non-ancillary data sent. + The following function sends the list of file descriptors *fds* + over an :const:`AF_UNIX` socket, on systems which support the + :const:`!SCM_RIGHTS` mechanism. See also :meth:`recvmsg`. :: -.. method:: socket.sendto(bytes, address) - socket.sendto(bytes, flags, address) + import socket, array - Send data to the socket. The socket should not be connected to a remote socket, - since the destination socket is specified by *address*. The optional *flags* - argument has the same meaning as for :meth:`recv`. Return the number of - bytes sent. The format of *address* depends on the address family --- see - :ref:`socket-addresses`. + def send_fds(sock, msg, fds): + return sock.sendmsg([msg], [(socket.SOL_SOCKET, socket.SCM_RIGHTS, array.array("i", fds))]) - .. audit-event:: socket.sendto self,address socket.socket.sendto + .. availability:: Unix, not WASI. - .. versionchanged:: 3.5 - If the system call is interrupted and the signal handler does not raise - an exception, the method now retries the system call instead of raising - an :exc:`InterruptedError` exception (see :pep:`475` for the rationale). - - -.. method:: socket.sendmsg(buffers[, ancdata[, flags[, address]]]) - - Send normal and ancillary data to the socket, gathering the - non-ancillary data from a series of buffers and concatenating it - into a single message. The *buffers* argument specifies the - non-ancillary data as an iterable of - :term:`bytes-like objects <bytes-like object>` - (e.g. :class:`bytes` objects); the operating system may set a limit - (:func:`~os.sysconf` value ``SC_IOV_MAX``) on the number of buffers - that can be used. The *ancdata* argument specifies the ancillary - data (control messages) as an iterable of zero or more tuples - ``(cmsg_level, cmsg_type, cmsg_data)``, where *cmsg_level* and - *cmsg_type* are integers specifying the protocol level and - protocol-specific type respectively, and *cmsg_data* is a - bytes-like object holding the associated data. Note that - some systems (in particular, systems without :func:`CMSG_SPACE`) - might support sending only one control message per call. The - *flags* argument defaults to 0 and has the same meaning as for - :meth:`send`. If *address* is supplied and not ``None``, it sets a - destination address for the message. The return value is the - number of bytes of non-ancillary data sent. - - The following function sends the list of file descriptors *fds* - over an :const:`AF_UNIX` socket, on systems which support the - :const:`SCM_RIGHTS` mechanism. See also :meth:`recvmsg`. :: - - import socket, array - - def send_fds(sock, msg, fds): - return sock.sendmsg([msg], [(socket.SOL_SOCKET, socket.SCM_RIGHTS, array.array("i", fds))]) + Most Unix platforms. - .. availability:: Unix, not WASI. + .. audit-event:: socket.sendmsg self,address socket.socket.sendmsg - Most Unix platforms. + .. versionadded:: 3.3 - .. audit-event:: socket.sendmsg self,address socket.socket.sendmsg + .. versionchanged:: 3.5 + If the system call is interrupted and the signal handler does not raise + an exception, the method now retries the system call instead of raising + an :exc:`InterruptedError` exception (see :pep:`475` for the rationale). - .. versionadded:: 3.3 + .. method:: sendmsg_afalg([msg], *, op[, iv[, assoclen[, flags]]]) - .. versionchanged:: 3.5 - If the system call is interrupted and the signal handler does not raise - an exception, the method now retries the system call instead of raising - an :exc:`InterruptedError` exception (see :pep:`475` for the rationale). + Specialized version of :meth:`~socket.sendmsg` for :const:`AF_ALG` socket. + Set mode, IV, AEAD associated data length and flags for :const:`AF_ALG` socket. -.. method:: socket.sendmsg_afalg([msg], *, op[, iv[, assoclen[, flags]]]) + .. availability:: Linux >= 2.6.38. - Specialized version of :meth:`~socket.sendmsg` for :const:`AF_ALG` socket. - Set mode, IV, AEAD associated data length and flags for :const:`AF_ALG` socket. + .. versionadded:: 3.6 - .. availability:: Linux >= 2.6.38. + .. method:: sendfile(file, offset=0, count=None) - .. versionadded:: 3.6 + Send a file until EOF is reached by using high-performance + :mod:`os.sendfile` and return the total number of bytes which were sent. + *file* must be a regular file object opened in binary mode. If + :mod:`os.sendfile` is not available (e.g. Windows) or *file* is not a + regular file :meth:`send` will be used instead. *offset* tells from where to + start reading the file. If specified, *count* is the total number of bytes + to transmit as opposed to sending the file until EOF is reached. File + position is updated on return or also in case of error in which case + :meth:`file.tell() <io.IOBase.tell>` can be used to figure out the number of + bytes which were sent. The socket must be of :const:`SOCK_STREAM` type. + Non-blocking sockets are not supported. -.. method:: socket.sendfile(file, offset=0, count=None) + .. versionadded:: 3.5 - Send a file until EOF is reached by using high-performance - :mod:`os.sendfile` and return the total number of bytes which were sent. - *file* must be a regular file object opened in binary mode. If - :mod:`os.sendfile` is not available (e.g. Windows) or *file* is not a - regular file :meth:`send` will be used instead. *offset* tells from where to - start reading the file. If specified, *count* is the total number of bytes - to transmit as opposed to sending the file until EOF is reached. File - position is updated on return or also in case of error in which case - :meth:`file.tell() <io.IOBase.tell>` can be used to figure out the number of - bytes which were sent. The socket must be of :const:`SOCK_STREAM` type. - Non-blocking sockets are not supported. + .. method:: set_inheritable(inheritable) - .. versionadded:: 3.5 + Set the :ref:`inheritable flag <fd_inheritance>` of the socket's file + descriptor or socket's handle. -.. method:: socket.set_inheritable(inheritable) + .. versionadded:: 3.4 - Set the :ref:`inheritable flag <fd_inheritance>` of the socket's file - descriptor or socket's handle. - .. versionadded:: 3.4 + .. method:: setblocking(flag) + Set blocking or non-blocking mode of the socket: if *flag* is false, the + socket is set to non-blocking, else to blocking mode. -.. method:: socket.setblocking(flag) + This method is a shorthand for certain :meth:`~socket.settimeout` calls: - Set blocking or non-blocking mode of the socket: if *flag* is false, the - socket is set to non-blocking, else to blocking mode. + * ``sock.setblocking(True)`` is equivalent to ``sock.settimeout(None)`` - This method is a shorthand for certain :meth:`~socket.settimeout` calls: + * ``sock.setblocking(False)`` is equivalent to ``sock.settimeout(0.0)`` - * ``sock.setblocking(True)`` is equivalent to ``sock.settimeout(None)`` + .. versionchanged:: 3.7 + The method no longer applies :const:`SOCK_NONBLOCK` flag on + :attr:`socket.type`. - * ``sock.setblocking(False)`` is equivalent to ``sock.settimeout(0.0)`` - .. versionchanged:: 3.7 - The method no longer applies :const:`SOCK_NONBLOCK` flag on - :attr:`socket.type`. + .. method:: settimeout(value) + Set a timeout on blocking socket operations. The *value* argument can be a + nonnegative real number expressing seconds, or ``None``. + If a non-zero value is given, subsequent socket operations will raise a + :exc:`timeout` exception if the timeout period *value* has elapsed before + the operation has completed. If zero is given, the socket is put in + non-blocking mode. If ``None`` is given, the socket is put in blocking mode. -.. method:: socket.settimeout(value) + For further information, please consult the :ref:`notes on socket timeouts <socket-timeouts>`. - Set a timeout on blocking socket operations. The *value* argument can be a - nonnegative real number expressing seconds, or ``None``. - If a non-zero value is given, subsequent socket operations will raise a - :exc:`timeout` exception if the timeout period *value* has elapsed before - the operation has completed. If zero is given, the socket is put in - non-blocking mode. If ``None`` is given, the socket is put in blocking mode. + .. versionchanged:: 3.7 + The method no longer toggles :const:`SOCK_NONBLOCK` flag on + :attr:`socket.type`. - For further information, please consult the :ref:`notes on socket timeouts <socket-timeouts>`. + .. versionchanged:: 3.15 + Accepts any real number, not only integer or float. - .. versionchanged:: 3.7 - The method no longer toggles :const:`SOCK_NONBLOCK` flag on - :attr:`socket.type`. - .. versionchanged:: 3.15 - Accepts any real number, not only integer or float. + .. method:: setsockopt(level, optname, value: int | Buffer) + setsockopt(level, optname, None, optlen: int) + .. index:: pair: module; struct -.. method:: socket.setsockopt(level, optname, value: int | Buffer) - socket.setsockopt(level, optname, None, optlen: int) + Set the value of the given socket option (see the Unix manual page + :manpage:`setsockopt(2)`). The needed symbolic constants are defined in this + module (:ref:`!SO_\* etc. <socket-unix-constants>`). The value can be an integer, + ``None`` or a :term:`bytes-like object` representing a buffer. In the latter + case it is up to the caller to ensure that the bytestring contains the + proper bits (see the optional built-in module :mod:`struct` for a way to + encode C structures as bytestrings). When *value* is set to ``None``, + *optlen* argument is required. It's equivalent to calling :c:func:`!setsockopt` C + function with ``optval=NULL`` and ``optlen=optlen``. - .. index:: pair: module; struct + .. versionchanged:: 3.5 + Writable :term:`bytes-like object` is now accepted. - Set the value of the given socket option (see the Unix manual page - :manpage:`setsockopt(2)`). The needed symbolic constants are defined in this - module (:ref:`!SO_\* etc. <socket-unix-constants>`). The value can be an integer, - ``None`` or a :term:`bytes-like object` representing a buffer. In the latter - case it is up to the caller to ensure that the bytestring contains the - proper bits (see the optional built-in module :mod:`struct` for a way to - encode C structures as bytestrings). When *value* is set to ``None``, - *optlen* argument is required. It's equivalent to calling :c:func:`setsockopt` C - function with ``optval=NULL`` and ``optlen=optlen``. + .. versionchanged:: 3.6 + setsockopt(level, optname, None, optlen: int) form added. - .. versionchanged:: 3.5 - Writable :term:`bytes-like object` is now accepted. + .. availability:: not WASI. - .. versionchanged:: 3.6 - setsockopt(level, optname, None, optlen: int) form added. - .. availability:: not WASI. + .. method:: shutdown(how) + Shut down one or both halves of the connection. If *how* is :const:`SHUT_RD`, + further receives are disallowed. If *how* is :const:`SHUT_WR`, further sends + are disallowed. If *how* is :const:`SHUT_RDWR`, further sends and receives are + disallowed. -.. method:: socket.shutdown(how) + .. availability:: not WASI. - Shut down one or both halves of the connection. If *how* is :const:`SHUT_RD`, - further receives are disallowed. If *how* is :const:`SHUT_WR`, further sends - are disallowed. If *how* is :const:`SHUT_RDWR`, further sends and receives are - disallowed. - .. availability:: not WASI. + .. method:: share(process_id) + Duplicate a socket and prepare it for sharing with a target process. The + target process must be provided with *process_id*. The resulting bytes object + can then be passed to the target process using some form of interprocess + communication and the socket can be recreated there using :func:`fromshare`. + Once this method has been called, it is safe to close the socket since + the operating system has already duplicated it for the target process. -.. method:: socket.share(process_id) + .. availability:: Windows. - Duplicate a socket and prepare it for sharing with a target process. The - target process must be provided with *process_id*. The resulting bytes object - can then be passed to the target process using some form of interprocess - communication and the socket can be recreated there using :func:`fromshare`. - Once this method has been called, it is safe to close the socket since - the operating system has already duplicated it for the target process. + .. versionadded:: 3.3 - .. availability:: Windows. - .. versionadded:: 3.3 + Note that there are no methods :meth:`!read` or :meth:`!write`; use + :meth:`~socket.recv` and :meth:`~socket.send` without *flags* argument instead. + Socket objects also have these (read-only) attributes that correspond to the + values given to the :class:`~socket.socket` constructor. -Note that there are no methods :meth:`read` or :meth:`write`; use -:meth:`~socket.recv` and :meth:`~socket.send` without *flags* argument instead. -Socket objects also have these (read-only) attributes that correspond to the -values given to the :class:`~socket.socket` constructor. + .. attribute:: family + The socket family. -.. attribute:: socket.family - The socket family. + .. attribute:: type + The socket type. -.. attribute:: socket.type - The socket type. + .. attribute:: proto + The socket protocol. -.. attribute:: socket.proto - The socket protocol. +.. class:: SocketType + The base class of the :class:`~socket.socket` type, re-exported from + :mod:`!_socket`. An instance check such as + ``isinstance(socket(...), SocketType)`` is true, but ``SocketType`` is not + the same as ``type(socket(...))``, which is :class:`~socket.socket` itself. .. _socket-timeouts: From 9761ef9bb8d9e607ad14782a2f64f52d8246ac74 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 10 Jun 2026 15:21:48 +0200 Subject: [PATCH 290/818] [3.15] Docs: Fix typos in the "Memory Management" section (GH-151243) (GH-151247) Docs: Fix typos in the "Memory Management" section (GH-151243) (cherry picked from commit 8c0e2515bb0059b75e264cc5baeb27bb17337c83) Co-authored-by: Manoj K M <manojkm24dev@gmail.com> --- Doc/c-api/memory.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Doc/c-api/memory.rst b/Doc/c-api/memory.rst index 9f84e4bc6dfd91..73310670ac371c 100644 --- a/Doc/c-api/memory.rst +++ b/Doc/c-api/memory.rst @@ -77,7 +77,7 @@ memory footprint as a whole. Consequently, under certain circumstances, the Python memory manager may or may not trigger appropriate actions, like garbage collection, memory compaction or other preventive procedures. Note that by using the C library allocator as shown in the previous example, the allocated memory -for the I/O buffer escapes completely the Python memory manager. +for the I/O buffer completely escapes the Python memory manager. .. seealso:: @@ -157,7 +157,7 @@ zero bytes. .. c:function:: void* PyMem_RawCalloc(size_t nelem, size_t elsize) - Allocates *nelem* elements each whose size in bytes is *elsize* and returns + Allocates *nelem* elements each of size *elsize* bytes and returns a pointer of type :c:expr:`void*` to the allocated memory, or ``NULL`` if the request fails. The memory is initialized to zeros. @@ -235,7 +235,7 @@ In the GIL-enabled build (default build) the .. c:function:: void* PyMem_Calloc(size_t nelem, size_t elsize) - Allocates *nelem* elements each whose size in bytes is *elsize* and returns + Allocates *nelem* elements each of size *elsize* bytes and returns a pointer of type :c:expr:`void*` to the allocated memory, or ``NULL`` if the request fails. The memory is initialized to zeros. @@ -368,7 +368,7 @@ The :ref:`default object allocator <default-memory-allocators>` uses the .. c:function:: void* PyObject_Calloc(size_t nelem, size_t elsize) - Allocates *nelem* elements each whose size in bytes is *elsize* and returns + Allocates *nelem* elements each of size *elsize* bytes and returns a pointer of type :c:expr:`void*` to the allocated memory, or ``NULL`` if the request fails. The memory is initialized to zeros. From 7a76730125144a36ceba94067fa25e2afa302f5f Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 10 Jun 2026 15:36:58 +0200 Subject: [PATCH 291/818] [3.15] Add yet one assertion in test_set_text_charset_cp949 (GH-151224) (GH-151237) Add yet one assertion in test_set_text_charset_cp949 (GH-151224) Check bytes(m), not only str(m). (cherry picked from commit 3ca93ab198497da9451101019b67c52e7873377d) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> --- Lib/test/test_email/test_contentmanager.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_email/test_contentmanager.py b/Lib/test/test_email/test_contentmanager.py index bc0e5d35618159..0b1b6e89f8c992 100644 --- a/Lib/test/test_email/test_contentmanager.py +++ b/Lib/test/test_email/test_contentmanager.py @@ -352,7 +352,14 @@ def test_set_text_charset_cp949(self): x9Gxub7uCoFBCg== """)) - self.assertEqual(m.get_payload(decode=True).decode('ks_c_5601-1987'), content) + self.assertEqual(bytes(m), textwrap.dedent("""\ + Content-Type: text/plain; charset="ks_c_5601-1987" + Content-Transfer-Encoding: 8bit + + \ud55c\uad6d\uc5b4 + \uac02 + """).encode('ks_c_5601-1987')) + self.assertEqual(m.get_payload(decode=True), content.encode('ks_c_5601-1987')) self.assertEqual(m.get_content(), content) def test_set_text_plain_long_line_heuristics(self): From 637746d6fc9de2c07cf532ffe84ba270398ca8d5 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 10 Jun 2026 16:11:26 +0200 Subject: [PATCH 292/818] [3.15] add asyncio guide for Free-Threaded Python (GH-150456) (#151257) add asyncio guide for Free-Threaded Python (GH-150456) (cherry picked from commit e2bd50d2e1cfe474f3b1f88a3d2b7e26cfda1295) Co-authored-by: Kumar Aditya <kumaraditya@python.org> --- Doc/library/asyncio-threading.rst | 154 ++++++++++++++++++++++++++++++ Doc/library/asyncio.rst | 1 + 2 files changed, 155 insertions(+) create mode 100644 Doc/library/asyncio-threading.rst diff --git a/Doc/library/asyncio-threading.rst b/Doc/library/asyncio-threading.rst new file mode 100644 index 00000000000000..526901a2e7eb20 --- /dev/null +++ b/Doc/library/asyncio-threading.rst @@ -0,0 +1,154 @@ +.. currentmodule:: asyncio + +.. _asyncio-threading: + +asyncio and free-threaded Python +================================ + +asyncio uses an event loop as a scheduler to enable highly efficient +concurrency by switching between tasks to allow non-blocking I/O +operations. This results in better performance for I/O-bound use +cases. It also allows off-loading CPU-bound work to a thread or +process pool, but that is still limited by the :term:`global +interpreter lock` in CPython. + +However, in :ref:`free-threaded Python <freethreading-python-howto>`, +the GIL is disabled and Python can run true multi-threaded code. This +means that asyncio can now take advantage of multiple CPU cores without +the limitations imposed by the GIL. + +Since Python 3.14, asyncio has first-class support for free-threaded +Python, and the implementation of asyncio is safe to use in a +multi-threaded environment. + +A single event loop on one core can handle many connections +concurrently, but the Python code that runs to handle each one still +executes serially. Once requests involve a non-trivial amount of +per-request computation, that handling becomes the bottleneck, and a +single core can no longer keep up. Combining asyncio with threads is +most useful here: by running an event loop per thread, the handling of +different requests can run in parallel across multiple CPU cores. It is +also useful when you need to run blocking or CPU-bound code from an +asyncio application. + + +.. seealso:: + + `Scaling asyncio on Free-Threaded Python + <https://labs.quansight.org/blog/scaling-asyncio-on-free-threaded-python>`__, + a blog post by Kumar Aditya which explains the internal changes + that make asyncio safe and efficient under free-threaded Python, + together with benchmarks of the resulting improvements. + + +Thread safety considerations +---------------------------- + +While asyncio is designed to be thread-safe in a free-threaded Python +environment, there are still some considerations to keep in mind when +using asyncio with threads: + +1. **Event loop**: Each thread should have its own event loop which + should not be shared across threads. This ensures that the event loop + can manage its own tasks and callbacks without interference from + other threads. + +2. **Task management**: Tasks and futures created in one thread should + not be awaited or manipulated from another thread. + +3. **Thread-safe APIs**: When interacting with asyncio from multiple + threads, it's important to use thread-safe APIs provided by asyncio, + such as :func:`asyncio.run_coroutine_threadsafe` for submitting + coroutines to an event loop from another thread. If you need to + call a callback from a different thread, you can use + :meth:`loop.call_soon_threadsafe` to schedule it safely. + +4. **Synchronization**: The synchronization primitives provided by + asyncio (like :class:`asyncio.Lock` and :class:`asyncio.Event`) + are not designed to be used across threads. If you need to + synchronize between threads, you should use the synchronization + primitives from the :mod:`threading` module instead. + + +Using asyncio with threads +-------------------------- + +asyncio supports running one event loop per thread, which allows you to +take advantage of multiple CPU cores in a free-threaded Python +environment. Each thread can run its own event loop, and tasks can be +scheduled on those loops independently. + +Here's an example of how to use asyncio with threads:: + + import asyncio + import threading + + async def worker(name: str) -> None: + print(f"Worker {name} starting") + await asyncio.sleep(1) + print(f"Worker {name} done") + + def run_loop(name: str) -> None: + asyncio.run(worker(name)) + + threads = [ + threading.Thread(target=run_loop, args=(f"T{i}",)) + for i in range(4) + ] + for t in threads: + t.start() + for t in threads: + t.join() + +In this example, each thread creates its own event loop with +:func:`asyncio.run` and runs a coroutine on it. The threads execute +concurrently, and in a free-threaded build they can run on separate +CPU cores in parallel. + + +Producer/consumer across threads +-------------------------------- + +When a regular (non-asyncio) thread needs to hand work to an asyncio +event loop running in another thread, use a thread-safe primitive such +as :class:`queue.Queue` rather than :class:`asyncio.Queue`, which is +only safe within a single event loop.:: + + import asyncio + import queue + import threading + + def producer(q: queue.Queue[int]) -> None: + for i in range(5): + print(f"Producing {i}") + q.put(i) + q.shutdown() + + async def consumer(q: queue.Queue[int]) -> None: + while True: + try: + item = q.get_nowait() + except queue.Empty: + await asyncio.sleep(0.1) + continue + except queue.ShutDown: + break + print(f"Consumed {item}") + await asyncio.sleep(item) + + q: queue.Queue[int] = queue.Queue() + consumer_thread = threading.Thread( + target=lambda: asyncio.run(consumer(q)) + ) + consumer_thread.start() + producer(q) + consumer_thread.join() + +The producer runs on the main thread while the consumer runs inside an +event loop on its own thread, yet they communicate safely through +``queue.Queue``. When the queue is empty the consumer sleeps briefly +and tries again. When the producer is done it calls +:meth:`~queue.Queue.shutdown`, which causes subsequent +:meth:`~queue.Queue.get_nowait` calls to raise :exc:`queue.ShutDown` +so the consumer can exit cleanly. + diff --git a/Doc/library/asyncio.rst b/Doc/library/asyncio.rst index 0f72e31dee5f1d..90a465f3e1d3af 100644 --- a/Doc/library/asyncio.rst +++ b/Doc/library/asyncio.rst @@ -128,6 +128,7 @@ for full functionality and the latest features. asyncio-api-index.rst asyncio-llapi-index.rst asyncio-dev.rst + asyncio-threading.rst .. note:: The source code for asyncio can be found in :source:`Lib/asyncio/`. From 9261f8b5888e37f9072f046816a1b00ce8dbc4ea Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 10 Jun 2026 16:25:33 +0200 Subject: [PATCH 293/818] [3.15] gh-143988: Fix re-entrant mutation crashes in socket sendmsg/recvmsg_into (GH-143987) (#151246) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gh-143988: Fix re-entrant mutation crashes in socket sendmsg/recvmsg_into (GH-143987) Fix crashes in socket.sendmsg() and socket.recvmsg_into() that could occur if buffer sequences are mutated re-entrantly during argument parsing via __buffer__ protocol callbacks. The bug occurs because: 1. PySequence_Fast() returns the original list object when the input is already a list (not a copy). 2. During iteration, PyObject_GetBuffer() triggers __buffer__ callbacks which may clear the list. 3. Subsequent iterations access invalid memory (heap OOB read). The fix replaces PySequence_Fast() with PySequence_Tuple() which always creates a new tuple, ensuring the sequence cannot be mutated during iteration. (cherry picked from commit 896f7fdc7d0ba6d4ace06935b9d67c4da0f9ecbe) Co-authored-by: tonghuaroot (童话) <tonghuaroot@gmail.com> Co-authored-by: tonghuaroot <23011166+tonghuaroot@users.noreply.github.com> --- Lib/test/test_socket.py | 56 +++++++++++++++++++ ...-01-18-06-42-47.gh-issue-143988.MtLtCP.rst | 2 + Modules/socketmodule.c | 26 +++++---- 3 files changed, 72 insertions(+), 12 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-01-18-06-42-47.gh-issue-143988.MtLtCP.rst diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py index 47830d0e9645ef..e80a0868546218 100644 --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -7534,6 +7534,62 @@ def detach(): pass +class ReentrantMutationTests(unittest.TestCase): + """Regression tests for re-entrant mutation in sendmsg/recvmsg_into. + + These tests verify that mutating sequences during argument parsing + via __buffer__ protocol does not cause crashes. + + See: https://github.com/python/cpython/issues/143988 + """ + + @unittest.skipUnless(hasattr(socket.socket, "sendmsg"), + "sendmsg not supported") + def test_sendmsg_reentrant_data_mutation(self): + seq = [] + + class MutBuffer: + def __init__(self): + self.tripped = False + + def __buffer__(self, flags): + if not self.tripped: + self.tripped = True + seq.clear() + return memoryview(b'Hello') + + seq = [MutBuffer(), b'World', b'Test'] + + left, right = socket.socketpair() + with left, right: + left.sendmsg(seq) + self.assertEqual(right.recv(1024), b'HelloWorldTest') + + @unittest.skipUnless(hasattr(socket.socket, "recvmsg_into"), + "recvmsg_into not supported") + def test_recvmsg_into_reentrant_buffer_mutation(self): + seq = [] + buf1 = bytearray(100) + + class MutBuffer: + def __init__(self): + self.tripped = False + + def __buffer__(self, flags): + if not self.tripped: + self.tripped = True + seq.clear() + return memoryview(buf1) + + seq = [MutBuffer(), bytearray(100), bytearray(100)] + + left, right = socket.socketpair() + with left, right: + left.send(b'Hello World!') + right.recvmsg_into(seq) + self.assertEqual(buf1, b'Hello World!'.ljust(100, b'\x00')) + + def setUpModule(): thread_info = threading_helper.threading_setup() unittest.addModuleCleanup(threading_helper.threading_cleanup, *thread_info) diff --git a/Misc/NEWS.d/next/Library/2026-01-18-06-42-47.gh-issue-143988.MtLtCP.rst b/Misc/NEWS.d/next/Library/2026-01-18-06-42-47.gh-issue-143988.MtLtCP.rst new file mode 100644 index 00000000000000..fcc0cb54934b90 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-01-18-06-42-47.gh-issue-143988.MtLtCP.rst @@ -0,0 +1,2 @@ +Fixed crashes in :meth:`socket.socket.sendmsg` and :meth:`socket.socket.recvmsg_into` +that could occur if buffer sequences are concurrently mutated. diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c index cf7aadfe95a721..c69a9cc0498272 100644 --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -4518,17 +4518,19 @@ sock_recvmsg_into(PyObject *self, PyObject *args) struct iovec *iovs = NULL; Py_ssize_t i, nitems, nbufs = 0; Py_buffer *bufs = NULL; - PyObject *buffers_arg, *fast, *retval = NULL; + PyObject *buffers_arg, *buffers_tuple, *retval = NULL; if (!PyArg_ParseTuple(args, "O|ni:recvmsg_into", &buffers_arg, &ancbufsize, &flags)) return NULL; - if ((fast = PySequence_Fast(buffers_arg, - "recvmsg_into() argument 1 must be an " - "iterable")) == NULL) + buffers_tuple = PySequence_Tuple(buffers_arg); + if (buffers_tuple == NULL) { + PyErr_SetString(PyExc_TypeError, + "recvmsg_into() argument 1 must be an iterable"); return NULL; - nitems = PySequence_Fast_GET_SIZE(fast); + } + nitems = PyTuple_GET_SIZE(buffers_tuple); if (nitems > INT_MAX) { PyErr_SetString(PyExc_OSError, "recvmsg_into() argument 1 is too long"); goto finally; @@ -4542,7 +4544,7 @@ sock_recvmsg_into(PyObject *self, PyObject *args) goto finally; } for (; nbufs < nitems; nbufs++) { - if (!PyArg_Parse(PySequence_Fast_GET_ITEM(fast, nbufs), + if (!PyArg_Parse(PyTuple_GET_ITEM(buffers_tuple, nbufs), "w*;recvmsg_into() argument 1 must be an iterable " "of single-segment read-write buffers", &bufs[nbufs])) @@ -4558,7 +4560,7 @@ sock_recvmsg_into(PyObject *self, PyObject *args) PyBuffer_Release(&bufs[i]); PyMem_Free(bufs); PyMem_Free(iovs); - Py_DECREF(fast); + Py_DECREF(buffers_tuple); return retval; } @@ -4853,14 +4855,14 @@ sock_sendmsg_iovec(PySocketSockObject *s, PyObject *data_arg, /* Fill in an iovec for each message part, and save the Py_buffer structs to release afterwards. */ - data_fast = PySequence_Fast(data_arg, - "sendmsg() argument 1 must be an " - "iterable"); + data_fast = PySequence_Tuple(data_arg); if (data_fast == NULL) { + PyErr_SetString(PyExc_TypeError, + "sendmsg() argument 1 must be an iterable"); goto finally; } - ndataparts = PySequence_Fast_GET_SIZE(data_fast); + ndataparts = PyTuple_GET_SIZE(data_fast); if (ndataparts > INT_MAX) { PyErr_SetString(PyExc_OSError, "sendmsg() argument 1 is too long"); goto finally; @@ -4882,7 +4884,7 @@ sock_sendmsg_iovec(PySocketSockObject *s, PyObject *data_arg, } } for (; ndatabufs < ndataparts; ndatabufs++) { - if (PyObject_GetBuffer(PySequence_Fast_GET_ITEM(data_fast, ndatabufs), + if (PyObject_GetBuffer(PyTuple_GET_ITEM(data_fast, ndatabufs), &databufs[ndatabufs], PyBUF_SIMPLE) < 0) goto finally; iovs[ndatabufs].iov_base = databufs[ndatabufs].buf; From 68d23722401c805290151819a317d41a2f926f4b Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 10 Jun 2026 18:04:48 +0200 Subject: [PATCH 294/818] [3.15] gh-141984: Reword the Generator expressions section (GH-150518) (GH-151261) (cherry picked from commit 7bbb9607a2e7d1f8a7de11ce02f0a2402d6e7262) Co-authored-by: Petr Viktorin <encukou@gmail.com> Co-authored-by: Blaise Pabon <blaise@gmail.com> Co-authored-by: Stan Ulbrych <stan@python.org> --- Doc/reference/expressions.rst | 113 ++++++++++++++++++++++++++-------- 1 file changed, 87 insertions(+), 26 deletions(-) diff --git a/Doc/reference/expressions.rst b/Doc/reference/expressions.rst index 12c1446e071240..9f55e9ad7eb5c1 100644 --- a/Doc/reference/expressions.rst +++ b/Doc/reference/expressions.rst @@ -956,39 +956,100 @@ Generator expressions pair: object; generator single: () (parentheses); generator expression -A generator expression is a compact generator notation in parentheses: +The syntax for :dfn:`generator expressions` is the same as for +list :ref:`comprehensions <comprehensions>`, except that they are enclosed in +parentheses instead of brackets. +For example:: -.. productionlist:: python-grammar - generator_expression: "(" `comprehension` ")" + >>> iterator = (x ** 2 for x in range(10)) + >>> iterator + <generator object <genexpr> at ...> + +At runtime, a generator expression evaluates to a :term:`generator iterator` +which yields the same values as the corresponding list comprehension:: + + >>> list(iterator) + [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] + +Thus, the example above is roughly equivalent to defining and calling +the following generator function:: -A generator expression yields a new generator object. Its syntax is the same as -for comprehensions, except that it is enclosed in parentheses instead of -brackets or curly braces. - -Variables used in the generator expression are evaluated lazily when the -:meth:`~generator.__next__` method is called for the generator object (in the same -fashion as normal generators). However, the iterable expression in the -leftmost :keyword:`!for` clause is immediately evaluated, and the -:term:`iterator` is immediately created for that iterable, so that an error -produced while creating the iterator will be emitted at the point where the generator expression -is defined, rather than at the point where the first value is retrieved. -Subsequent :keyword:`!for` clauses and any filter condition in the leftmost -:keyword:`!for` clause cannot be evaluated in the enclosing scope as they may -depend on the values obtained from the leftmost iterable. For example: -``(x*y for x in range(10) for y in range(x, x+10))``. - -The parentheses can be omitted on calls with only one argument. See section -:ref:`calls` for details. + def make_generator_of_squares(iterator): + for x in iterator: + yield x ** 2 + + make_generator_of_squares(iter(range(10))) + +The enclosing parentheses can be omitted in calls when the generator +expression is the only positional argument and there are no keyword +arguments. +See the :ref:`Calls section <calls>` for details. +For example:: + + # The parentheses after `sum` are part of the call syntax: + >>> sum(x ** 2 for x in range(10)) + 285 + + # The generator needs its own parentheses if it's not the only argument: + >>> sum((x ** 2 for x in range(10)), start=1000) + 1285 + +The iterable expression in the leftmost :keyword:`!for` clause is +evaluated immediately, so that an error raised by this expression will be +emitted at the point where the generator expression is defined, +rather than at the point where the first value is retrieved:: + + >>> (x ** 2 for x in nonexistent_iterable) + Traceback (most recent call last): + ... + NameError: name 'nonexistent_iterable' is not defined + +After the expression is evaluated, an iterator is created +from the result, as if :py:func:`iter` was called on it. +Any error raised when creating the iterator is also emitted immediately:: + + >>> (x ** 2 for x in None) + Traceback (most recent call last): + ... + TypeError: 'NoneType' object is not iterable + +All other expressions are evaluated lazily, in the same fashion as normal +generators (that is, when the iterator is asked to yield a value):: + + >>> iterator = (nonexistent_value for x in range(10)) + >>> iterator + <generator object <genexpr> at ...> + >>> list(iterator) + Traceback (most recent call last): + ... + NameError: name 'nonexistent_value' is not defined + +:: + + >>> iterator = (x * y for x in range(10) for y in nonexistent_iterable) + >>> iterator + <generator object <genexpr> at ...> + >>> list(iterator) + Traceback (most recent call last): + ... + NameError: name 'nonexistent_iterable' is not defined To avoid interfering with the expected operation of the generator expression -itself, ``yield`` and ``yield from`` expressions are prohibited in the -implicitly defined generator. +itself, ``yield`` and ``yield from`` expressions are prohibited inside +the implicitly nested scope. If a generator expression contains either :keyword:`!async for` clauses or :keyword:`await` expressions it is called an -:dfn:`asynchronous generator expression`. An asynchronous generator -expression returns a new asynchronous generator object, -which is an asynchronous iterator (see :ref:`async-iterators`). +:dfn:`asynchronous generator expression`. +An asynchronous generator expression returns a new asynchronous generator +object, which is an asynchronous iterator (see :ref:`async-iterators`). + +The formal grammar for generator expressions is: + +.. grammar-snippet:: + :group: python-grammar + + generator_expression: "(" `comprehension` ")" .. versionadded:: 3.6 Asynchronous generator expressions were introduced. From 54ee910bcd107ed5645ab5f88a0491266bb725c8 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 10 Jun 2026 18:26:38 +0200 Subject: [PATCH 295/818] [3.15] gh-151126: Fix missing memory errors in `_interpchannelsmodule.c` (GH-151239) (#151265) gh-151126: Fix missing memory errors in `_interpchannelsmodule.c` (GH-151239) (cherry picked from commit 9fd1a125bc0ebdc26eae684da6e48ef24ee23b34) Co-authored-by: sobolevn <mail@sobolevn.me> --- .../2026-06-09-10-28-30.gh-issue-151126.DKa6Sl.rst | 6 ++---- Modules/_interpchannelsmodule.c | 6 +++++- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-09-10-28-30.gh-issue-151126.DKa6Sl.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-09-10-28-30.gh-issue-151126.DKa6Sl.rst index 81e87e539865ce..67e2ce4044431f 100644 --- a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-09-10-28-30.gh-issue-151126.DKa6Sl.rst +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-09-10-28-30.gh-issue-151126.DKa6Sl.rst @@ -1,7 +1,5 @@ Fix a crash, when there's no memory left on a device, -which happened in: - -- code compilation -- :func:`!_winapi.CreateProcess` +which happened in: code compilation, :mod:`!_interpchannels` module, +:func:`!_winapi.CreateProcess` function. Now these places raise proper :exc:`MemoryError` errors. diff --git a/Modules/_interpchannelsmodule.c b/Modules/_interpchannelsmodule.c index c6d107d243dda0..3614890757d69d 100644 --- a/Modules/_interpchannelsmodule.c +++ b/Modules/_interpchannelsmodule.c @@ -921,7 +921,8 @@ static _channelends * _channelends_new(void) { _channelends *ends = GLOBAL_MALLOC(_channelends); - if (ends== NULL) { + if (ends == NULL) { + PyErr_NoMemory(); return NULL; } ends->numsendopen = 0; @@ -1115,6 +1116,7 @@ _channel_new(PyThread_type_lock mutex, struct _channeldefaults defaults) assert(check_unbound(defaults.unboundop)); _channel_state *chan = GLOBAL_MALLOC(_channel_state); if (chan == NULL) { + PyErr_NoMemory(); return NULL; } chan->mutex = mutex; @@ -1313,6 +1315,7 @@ _channelref_new(int64_t cid, _channel_state *chan) { _channelref *ref = GLOBAL_MALLOC(_channelref); if (ref == NULL) { + PyErr_NoMemory(); return NULL; } ref->cid = cid; @@ -1698,6 +1701,7 @@ _channel_set_closing(_channelref *ref, PyThread_type_lock mutex) { } chan->closing = GLOBAL_MALLOC(struct _channel_closing); if (chan->closing == NULL) { + PyErr_NoMemory(); goto done; } chan->closing->ref = ref; From 5c830373134ad29a6a637e0a6671df45c19b70a0 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 10 Jun 2026 18:48:10 +0200 Subject: [PATCH 296/818] [3.15] gh-109940: Respect VIRTUAL_ENV_DISABLE_PROMPT in activate.bat (GH-151215) (GH-151225) Co-authored-by: Harjoth Khara <harjoth.khara@gmail.com> --- Lib/test/test_venv.py | 45 +++++++++++++++++++ Lib/venv/scripts/nt/activate.bat | 4 +- ...-06-10-00-00-02.gh-issue-109940.Cx1099.rst | 2 + 3 files changed, 49 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-06-10-00-00-02.gh-issue-109940.Cx1099.rst diff --git a/Lib/test/test_venv.py b/Lib/test/test_venv.py index 9d2960664abfad..4b7860e757d79f 100644 --- a/Lib/test/test_venv.py +++ b/Lib/test/test_venv.py @@ -592,6 +592,51 @@ def test_unicode_in_batch_file(self): ) self.assertEqual(out.strip(), '0') + @unittest.skipUnless(os.name == 'nt', 'only relevant on Windows') + def test_activate_bat_respects_disable_prompt(self): + rmtree(self.env_dir) + env_dir = os.path.join(os.path.realpath(self.env_dir), 'venv') + builder = venv.EnvBuilder(clear=True) + builder.create(env_dir) + activate = os.path.join(env_dir, self.bindir, 'activate.bat') + test_batch = os.path.join(self.env_dir, 'test_disable_prompt.bat') + with open(test_batch, "w") as f: + f.write('@echo off\n' + 'set "PROMPT=base$G"\n' + 'set "VIRTUAL_ENV_DISABLE_PROMPT=1"\n' + f'call "{activate}"\n' + 'echo ACTIVE_PROMPT:%PROMPT%\n' + 'echo VIRTUAL_ENV:%VIRTUAL_ENV%\n' + 'set "PROMPT=changed$G"\n' + 'call deactivate\n' + 'echo FINAL_PROMPT:%PROMPT%\n') + out, err = check_output([test_batch]) + lines = out.splitlines() + self.assertEqual(lines[0], b'ACTIVE_PROMPT:base$G') + self.assertEndsWith(lines[1], os.fsencode(env_dir)) + self.assertEqual(lines[2], b'FINAL_PROMPT:changed$G') + + @unittest.skipUnless(os.name == 'nt', 'only relevant on Windows') + def test_activate_bat_prefixes_prompt_by_default(self): + rmtree(self.env_dir) + env_dir = os.path.join(os.path.realpath(self.env_dir), 'venv') + builder = venv.EnvBuilder(clear=True) + builder.create(env_dir) + activate = os.path.join(env_dir, self.bindir, 'activate.bat') + test_batch = os.path.join(self.env_dir, 'test_enable_prompt.bat') + with open(test_batch, "w") as f: + f.write('@echo off\n' + 'set "PROMPT=base) $G"\n' + 'set "VIRTUAL_ENV_DISABLE_PROMPT="\n' + f'call "{activate}"\n' + 'echo ACTIVE_PROMPT:%PROMPT%\n' + 'call deactivate\n' + 'echo FINAL_PROMPT:%PROMPT%\n') + out, err = check_output([test_batch]) + lines = out.splitlines() + self.assertEqual(lines[0], b'ACTIVE_PROMPT:(venv) base) $G') + self.assertEqual(lines[1], b'FINAL_PROMPT:base) $G') + @unittest.skipUnless(os.name == 'nt' and can_symlink(), 'symlinks on Windows') def test_failed_symlink(self): diff --git a/Lib/venv/scripts/nt/activate.bat b/Lib/venv/scripts/nt/activate.bat index 06f4753d73b7ae..4a3e791abb86bd 100644 --- a/Lib/venv/scripts/nt/activate.bat +++ b/Lib/venv/scripts/nt/activate.bat @@ -13,8 +13,8 @@ @if defined _OLD_VIRTUAL_PROMPT @set PROMPT=%_OLD_VIRTUAL_PROMPT% @if defined _OLD_VIRTUAL_PYTHONHOME @set PYTHONHOME=%_OLD_VIRTUAL_PYTHONHOME% -@set "_OLD_VIRTUAL_PROMPT=%PROMPT%" -@set "PROMPT=(__VENV_PROMPT__) %PROMPT%" +@if not defined VIRTUAL_ENV_DISABLE_PROMPT @set "_OLD_VIRTUAL_PROMPT=%PROMPT%" +@if not defined VIRTUAL_ENV_DISABLE_PROMPT @set "PROMPT=(__VENV_PROMPT__) %PROMPT%" @if defined PYTHONHOME @set _OLD_VIRTUAL_PYTHONHOME=%PYTHONHOME% @set PYTHONHOME= diff --git a/Misc/NEWS.d/next/Library/2026-06-10-00-00-02.gh-issue-109940.Cx1099.rst b/Misc/NEWS.d/next/Library/2026-06-10-00-00-02.gh-issue-109940.Cx1099.rst new file mode 100644 index 00000000000000..130dc780b61286 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-10-00-00-02.gh-issue-109940.Cx1099.rst @@ -0,0 +1,2 @@ +Fix Windows :mod:`venv` activation in ``cmd.exe`` to respect +``VIRTUAL_ENV_DISABLE_PROMPT``. From 040cee94aa356a128ceca4967f16e570fbed3c14 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 10 Jun 2026 19:37:52 +0200 Subject: [PATCH 297/818] [3.15] GHA: Display output when a sanitizer test fails (GH-151268) (#151272) GHA: Display output when a sanitizer test fails (GH-151268) Modify GitHub Action "Reusable Sanitizer" to display output when a test fails: pass -W option. (cherry picked from commit 3a8bebd86f36be05442fa2f3adcc83c2a4b00ef2) Co-authored-by: Victor Stinner <vstinner@python.org> --- .github/workflows/reusable-san.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/reusable-san.yml b/.github/workflows/reusable-san.yml index 33f6f0ef455fe0..d1e9cb9636698b 100644 --- a/.github/workflows/reusable-san.yml +++ b/.github/workflows/reusable-san.yml @@ -89,12 +89,12 @@ jobs: ./python -m test ${{ inputs.sanitizer == 'TSan' && '--tsan' || '' }} ${{ inputs.sanitizer == 'UBSan' && '-x test_capi -x test_faulthandler' || '' }} - -j4 + -j4 -W - name: Parallel tests if: >- inputs.sanitizer == 'TSan' && fromJSON(inputs.free-threading) - run: ./python -m test --tsan-parallel --parallel-threads=4 -j4 + run: ./python -m test --tsan-parallel --parallel-threads=4 -j4 -W - name: Display logs if: always() run: find "${GITHUB_WORKSPACE}" -name 'san_log.*' | xargs head -n 1000 From 10f616cf3939f87605081d05c1913ba630046c54 Mon Sep 17 00:00:00 2001 From: Victor Stinner <vstinner@python.org> Date: Wed, 10 Jun 2026 22:03:27 +0200 Subject: [PATCH 298/818] [3.15] gh-151253: Dump the Python path configuration on _PyCodec_InitRegistry() failure (#151250) (#151269) gh-151253: Dump the Python path configuration on _PyCodec_InitRegistry() failure (#151250) If "import encodings" fails at Python startup, dump the Python path configuration to help users debugging their configuration. The encodings module is the first module imported during Python startup. (cherry picked from commit 7b6e98911e1485be13817f2aedbbfadb1c4ea876) --- Lib/test/test_cmd_line.py | 11 +++++++++++ .../2026-06-10-15-42-46.gh-issue-151253.7MMQ8P.rst | 3 +++ Python/codecs.c | 3 +++ 3 files changed, 17 insertions(+) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-10-15-42-46.gh-issue-151253.7MMQ8P.rst diff --git a/Lib/test/test_cmd_line.py b/Lib/test/test_cmd_line.py index 3b556ec31445df..a8645af26b25d8 100644 --- a/Lib/test/test_cmd_line.py +++ b/Lib/test/test_cmd_line.py @@ -1314,6 +1314,17 @@ def test_presite(self): proc = assert_python_ok("-X", f"presite={entrypoint}", "-c", "pass") self.assertEqual(proc.out.rstrip(), b"presite func") + def test_dump_path_config(self): + # gh-151253: At the first import (import encodings) during Python + # startup, if the import fails, dump the Python path configuration. + nonexistent = '/nonexistent-python-path' + # Use -X frozen_modules=off to disable frozen encodings module + # on release build. + cmd = ["-X", "frozen_modules=off", "-c", "pass"] + proc = assert_python_failure(*cmd, PYTHONHOME=nonexistent) + self.assertIn(b'Python path configuration:', proc.err) + self.assertIn(f"PYTHONHOME = '{nonexistent}'".encode(), proc.err) + @unittest.skipIf(interpreter_requires_environment(), 'Cannot run -I tests when PYTHON env vars are required.') diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-10-15-42-46.gh-issue-151253.7MMQ8P.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-10-15-42-46.gh-issue-151253.7MMQ8P.rst new file mode 100644 index 00000000000000..56d2f3b2633bb0 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-10-15-42-46.gh-issue-151253.7MMQ8P.rst @@ -0,0 +1,3 @@ +If ``import encodings`` (first import) fails at Python startup, dump the +Python path configuration to help users debugging their configuration. Patch +by Victor Stinner. diff --git a/Python/codecs.c b/Python/codecs.c index 0bde56c0ac662e..2cf8460d2087cf 100644 --- a/Python/codecs.c +++ b/Python/codecs.c @@ -10,6 +10,7 @@ Copyright (c) Corporation for National Research Initiatives. #include "Python.h" #include "pycore_call.h" // _PyObject_CallNoArgs() +#include "pycore_initconfig.h" // _Py_DumpPathConfig() #include "pycore_interp.h" // PyInterpreterState.codec_search_path #include "pycore_pyerrors.h" // _PyErr_FormatNote() #include "pycore_pystate.h" // _PyInterpreterState_GET() @@ -1685,6 +1686,8 @@ _PyCodec_InitRegistry(PyInterpreterState *interp) // search functions, so this is done after everything else is initialized. PyObject *mod = PyImport_ImportModule("encodings"); if (mod == NULL) { + PyThreadState *tstate = _PyThreadState_GET(); + _Py_DumpPathConfig(tstate); return PyStatus_Error("Failed to import encodings module"); } Py_DECREF(mod); From e8d914fd4964a0aa67f7ff2ab4920bb665201dfc Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 10 Jun 2026 22:07:07 +0200 Subject: [PATCH 299/818] [3.15] gh-151278: Fix test_faulthandler on UBSan (GH-151279) (#151281) gh-151278: Fix test_faulthandler on UBSan (GH-151279) * Py_FatalError() no longer calls _PyFaulthandler_Fini() if it doesn't hold the GIL. * Skip test_faulthandler tests raising signals if run with UBSan. * Enable test_faulthandler in GitHub Action "Reusable Sanitizer". (cherry picked from commit e60c42dc3f5a8dd9b10bc9a8a028ef2765469650) Co-authored-by: Victor Stinner <vstinner@python.org> --- .github/workflows/reusable-san.yml | 4 ++-- Lib/test/test_faulthandler.py | 13 +++++++++---- Python/pylifecycle.c | 4 +++- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/.github/workflows/reusable-san.yml b/.github/workflows/reusable-san.yml index d1e9cb9636698b..6127c7e1c05369 100644 --- a/.github/workflows/reusable-san.yml +++ b/.github/workflows/reusable-san.yml @@ -82,13 +82,13 @@ jobs: run: make -j4 - name: Display build info run: make pythoninfo - # test_{capi,faulthandler} are skipped under UBSan because + # test_capi is skipped under UBSan because # they raise signals that UBSan with halt_on_error=1 intercepts. - name: Tests run: >- ./python -m test ${{ inputs.sanitizer == 'TSan' && '--tsan' || '' }} - ${{ inputs.sanitizer == 'UBSan' && '-x test_capi -x test_faulthandler' || '' }} + ${{ inputs.sanitizer == 'UBSan' && '-x test_capi' || '' }} -j4 -W - name: Parallel tests if: >- diff --git a/Lib/test/test_faulthandler.py b/Lib/test/test_faulthandler.py index 11df59f2346f31..5a493a4fd95680 100644 --- a/Lib/test/test_faulthandler.py +++ b/Lib/test/test_faulthandler.py @@ -33,6 +33,11 @@ CURRENT_THREAD_HEADER = fr'{CURRENT_THREAD_ID} \(most recent call first\):' +def skip_if_sanitizer_signal(signame): + return support.skip_if_sanitizer(f"TSAN/UBSan itercepts {signame}", + thread=True, ub=True) + + def expected_traceback(lineno1, lineno2, header, min_count=1): regex = header regex += ' File "<string>", line %s in func\n' % lineno1 @@ -224,7 +229,7 @@ def test_fatal_error_c_thread(self): func='faulthandler_fatal_error_thread', py_fatal_error=True) - @support.skip_if_sanitizer("TSAN itercepts SIGABRT", thread=True) + @skip_if_sanitizer_signal("SIGABRT") def test_sigabrt(self): self.check_fatal_error(""" import faulthandler @@ -236,7 +241,7 @@ def test_sigabrt(self): @unittest.skipIf(sys.platform == 'win32', "SIGFPE cannot be caught on Windows") - @support.skip_if_sanitizer("TSAN itercepts SIGFPE", thread=True) + @skip_if_sanitizer_signal("SIGFPE") def test_sigfpe(self): self.check_fatal_error(""" import faulthandler @@ -248,7 +253,7 @@ def test_sigfpe(self): @unittest.skipIf(_testcapi is None, 'need _testcapi') @unittest.skipUnless(hasattr(signal, 'SIGBUS'), 'need signal.SIGBUS') - @support.skip_if_sanitizer("TSAN itercepts SIGBUS", thread=True) + @skip_if_sanitizer_signal("SIGBUS") @skip_segfault_on_android def test_sigbus(self): self.check_fatal_error(""" @@ -263,7 +268,7 @@ def test_sigbus(self): @unittest.skipIf(_testcapi is None, 'need _testcapi') @unittest.skipUnless(hasattr(signal, 'SIGILL'), 'need signal.SIGILL') - @support.skip_if_sanitizer("TSAN itercepts SIGILL", thread=True) + @skip_if_sanitizer_signal("SIGILL") @skip_segfault_on_android def test_sigill(self): self.check_fatal_error(""" diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 0bdc7ddd92dc82..311332434d69a4 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -3724,7 +3724,9 @@ fatal_error(int fd, int header, const char *prefix, const char *msg, This function already did its best to display a traceback. Disable faulthandler to prevent writing a second traceback on abort(). */ - _PyFaulthandler_Fini(); + if (has_tstate_and_gil) { + _PyFaulthandler_Fini(); + } /* Check if the current Python thread hold the GIL */ if (has_tstate_and_gil) { From f3316ca675fada57bdf862d7e3aebfd6bb5ac02c Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 11 Jun 2026 08:38:03 +0200 Subject: [PATCH 300/818] [3.15] gh-136880: Add warning about PYTHONPATH (GH-151098) (GH-151299) (cherry picked from commit 84630e2cb90ef334e41eb9bccd860b3b0a7ff51b) --- Doc/tutorial/venv.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Doc/tutorial/venv.rst b/Doc/tutorial/venv.rst index f362e1943b666f..6b6b8a768e3f58 100644 --- a/Doc/tutorial/venv.rst +++ b/Doc/tutorial/venv.rst @@ -88,6 +88,11 @@ For example: '~/envs/tutorial-env/lib/python3.5/site-packages'] >>> +Note that the activated virtual environment does not alter the ``PYTHONPATH`` variable in any way. +This may lead to unexpected results if the path includes references to code which is incompatible with +the Python version the virtual environment is using. The best practice is to ``unset PYTHONPATH`` +in bash or the equivalent for the shell you are using. + To deactivate a virtual environment, type:: deactivate From 9d0999133e546b36d51469c2738215281571bb9e Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 11 Jun 2026 10:30:24 +0200 Subject: [PATCH 301/818] [3.15] gh-151295: Fix use-after-free in bytes.join()/bytearray.join() via re-entrant __buffer__ (GH-151296) (GH-151304) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (cherry picked from commit 84a322aa1555df745a2c115df03bfb7a4ed8c594) Co-authored-by: tonghuaroot (童话) <tonghuaroot@gmail.com> --- Lib/test/test_bytes.py | 26 +++++++++++++++++++ ...-06-11-00-00-00.gh-issue-151295.NQYUzW.rst | 4 +++ Objects/stringlib/join.h | 5 ++++ 3 files changed, 35 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2026-06-11-00-00-00.gh-issue-151295.NQYUzW.rst diff --git a/Lib/test/test_bytes.py b/Lib/test/test_bytes.py index e0e8dd4eccfb1b..e211c3d15a4ed2 100644 --- a/Lib/test/test_bytes.py +++ b/Lib/test/test_bytes.py @@ -645,6 +645,32 @@ def test_join(self): with self.assertRaises(TypeError): dot_join([memoryview(b"ab"), "cd", b"ef"]) + def test_join_concurrent_buffer_mutation(self): + # __buffer__() can release the GIL, letting another thread concurrently + # mutate the joined sequence (simulated here by mutating in __buffer__). + # See: https://github.com/python/cpython/issues/151295 + def make_seq(mutate): + # Item is only referenced from the list slot, so mutate() frees it. + class Item: + def __buffer__(self, flags): + mutate(seq) + return memoryview(b'x') + seq = [b'a', Item(), b'c'] + return seq + + for sep in (self.type2test(b''), self.type2test(b'::')): + with self.subTest(sep=sep): + # Changing the list length is reported as a RuntimeError. + seq = make_seq(lambda seq: seq.clear()) + self.assertRaises(RuntimeError, sep.join, seq) + + # The list length is unchanged, so the size-change recheck + # cannot fire: only keeping the item alive avoids the crash. + def replace(seq): + seq[1] = b'z' + seq = make_seq(replace) + self.assertEqual(sep.join(seq), sep.join([b'a', b'x', b'c'])) + def test_count(self): b = self.type2test(b'mississippi') i = 105 diff --git a/Misc/NEWS.d/next/Library/2026-06-11-00-00-00.gh-issue-151295.NQYUzW.rst b/Misc/NEWS.d/next/Library/2026-06-11-00-00-00.gh-issue-151295.NQYUzW.rst new file mode 100644 index 00000000000000..e9012f023ff7f7 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-11-00-00-00.gh-issue-151295.NQYUzW.rst @@ -0,0 +1,4 @@ +Fixed a crash (use-after-free) in :meth:`bytes.join` and +:meth:`bytearray.join` that could occur if an item's +:meth:`~object.__buffer__` concurrently mutates the sequence being joined. +The mutation is now reported as a :exc:`RuntimeError` instead. diff --git a/Objects/stringlib/join.h b/Objects/stringlib/join.h index de6bd83ffe4c8b..deebfeadc0f4fd 100644 --- a/Objects/stringlib/join.h +++ b/Objects/stringlib/join.h @@ -68,13 +68,18 @@ STRINGLIB(bytes_join)(PyObject *sep, PyObject *iterable) buffers[i].len = PyBytes_GET_SIZE(item); } else { + /* item is only borrowed; its __buffer__() may run Python that + drops the sequence's last reference to it. */ + Py_INCREF(item); if (PyObject_GetBuffer(item, &buffers[i], PyBUF_SIMPLE) != 0) { + Py_DECREF(item); PyErr_Format(PyExc_TypeError, "sequence item %zd: expected a bytes-like object, " "%.80s found", i, Py_TYPE(item)->tp_name); goto error; } + Py_DECREF(item); /* If the backing objects are mutable, then dropping the GIL * opens up race conditions where another thread tries to modify * the object which we hold a buffer on it. Such code has data From a8ddc9a77ac3aff3a149a3c182d285db361961c4 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 11 Jun 2026 10:55:01 +0200 Subject: [PATCH 302/818] [3.15] Drop historical `:author:`s from HOWTOs (GH-151091) (#151310) (cherry picked from commit 9620f69cd4cd0b3691bc9feb279ddf45f71a9e7d) Co-authored-by: Stan Ulbrych <stan@python.org> --- Doc/howto/annotations.rst | 2 -- Doc/howto/argparse.rst | 2 -- Doc/howto/curses.rst | 3 --- Doc/howto/descriptor.rst | 3 --- Doc/howto/functional.rst | 12 +++++------- Doc/howto/instrumentation.rst | 3 --- Doc/howto/ipaddress.rst | 3 --- Doc/howto/logging-cookbook.rst | 2 -- Doc/howto/logging.rst | 2 -- Doc/howto/perf_profiling.rst | 2 -- Doc/howto/pyporting.rst | 2 -- Doc/howto/regex.rst | 2 -- Doc/howto/sockets.rst | 3 --- Doc/howto/sorting.rst | 3 --- Doc/howto/unicode.rst | 2 -- Doc/howto/urllib2.rst | 3 --- 16 files changed, 5 insertions(+), 44 deletions(-) diff --git a/Doc/howto/annotations.rst b/Doc/howto/annotations.rst index d7deb6c6bc1768..bd784235016dc6 100644 --- a/Doc/howto/annotations.rst +++ b/Doc/howto/annotations.rst @@ -4,8 +4,6 @@ Annotations Best Practices ************************** -:author: Larry Hastings - .. topic:: Abstract This document is designed to encapsulate the best practices diff --git a/Doc/howto/argparse.rst b/Doc/howto/argparse.rst index 902c50de00803c..0cb8c5cc3ebd36 100644 --- a/Doc/howto/argparse.rst +++ b/Doc/howto/argparse.rst @@ -4,8 +4,6 @@ Argparse Tutorial ***************** -:author: Tshepang Mbambo - .. currentmodule:: argparse This tutorial is intended to be a gentle introduction to :mod:`argparse`, the diff --git a/Doc/howto/curses.rst b/Doc/howto/curses.rst index 816639552d7cd6..e5f85e0110321c 100644 --- a/Doc/howto/curses.rst +++ b/Doc/howto/curses.rst @@ -6,9 +6,6 @@ .. currentmodule:: curses -:Author: A.M. Kuchling, Eric S. Raymond -:Release: 2.04 - .. topic:: Abstract diff --git a/Doc/howto/descriptor.rst b/Doc/howto/descriptor.rst index a7a68281860cb5..ec83c6f93e0d54 100644 --- a/Doc/howto/descriptor.rst +++ b/Doc/howto/descriptor.rst @@ -4,9 +4,6 @@ Descriptor Guide ================ -:Author: Raymond Hettinger -:Contact: <python at rcn dot com> - .. Contents:: diff --git a/Doc/howto/functional.rst b/Doc/howto/functional.rst index ebc7a100d91a64..a61fdaee27f6b1 100644 --- a/Doc/howto/functional.rst +++ b/Doc/howto/functional.rst @@ -4,9 +4,6 @@ Functional Programming HOWTO ******************************** -:Author: \A. M. Kuchling -:Release: 0.32 - In this document, we'll take a tour of Python's features suitable for implementing programs in a functional style. After an introduction to the concepts of functional programming, we'll look at language features such as @@ -1185,7 +1182,8 @@ about whether this lambda-free style is better. Revision History and Acknowledgements ===================================== -The author would like to thank the following people for offering suggestions, +This HOWTO was originally written by A. M. Kuchling. The author would like to +thank the following people for offering suggestions, corrections and assistance with various drafts of this article: Ian Bicking, Nick Coghlan, Nick Efford, Raymond Hettinger, Jim Jewett, Mike Krell, Leandro Lameiro, Jussi Salmela, Collin Winter, Blake Winton. @@ -1239,9 +1237,9 @@ Text Processing". Mertz also wrote a 3-part series of articles on functional programming for IBM's DeveloperWorks site; see -`part 1 <https://developer.ibm.com/articles/l-prog/>`__, -`part 2 <https://developer.ibm.com/tutorials/l-prog2/>`__, and -`part 3 <https://developer.ibm.com/tutorials/l-prog3/>`__, +`part 1 <https://web.archive.org/web/20211006103639/https://developer.ibm.com/articles/l-prog/>`__, +`part 2 <https://web.archive.org/web/20211205224606/https://developer.ibm.com/tutorials/l-prog2/>`__, and +`part 3 <https://web.archive.org/web/20211127083846/https://developer.ibm.com/tutorials/l-prog3/>`__. Python documentation diff --git a/Doc/howto/instrumentation.rst b/Doc/howto/instrumentation.rst index 06c1ae40da5e67..8f0b0c41ea4861 100644 --- a/Doc/howto/instrumentation.rst +++ b/Doc/howto/instrumentation.rst @@ -6,9 +6,6 @@ Instrumenting CPython with DTrace and SystemTap =============================================== -:author: David Malcolm -:author: Łukasz Langa - DTrace and SystemTap are monitoring tools, each providing a way to inspect what the processes on a computer system are doing. They both use domain-specific languages allowing a user to write scripts which: diff --git a/Doc/howto/ipaddress.rst b/Doc/howto/ipaddress.rst index e852db98156fac..646c4c4d9e7ab1 100644 --- a/Doc/howto/ipaddress.rst +++ b/Doc/howto/ipaddress.rst @@ -8,9 +8,6 @@ An introduction to the ipaddress module *************************************** -:author: Peter Moody -:author: Nick Coghlan - .. topic:: Overview This document aims to provide a gentle introduction to the diff --git a/Doc/howto/logging-cookbook.rst b/Doc/howto/logging-cookbook.rst index 0ee4c0086dd98c..87025814aafb9a 100644 --- a/Doc/howto/logging-cookbook.rst +++ b/Doc/howto/logging-cookbook.rst @@ -4,8 +4,6 @@ Logging Cookbook ================ -:Author: Vinay Sajip <vinay_sajip at red-dove dot com> - This page contains a number of recipes related to logging, which have been found useful in the past. For links to tutorial and reference information, please see :ref:`cookbook-ref-links`. diff --git a/Doc/howto/logging.rst b/Doc/howto/logging.rst index 454e2f4930e724..c8ce0df9e937f8 100644 --- a/Doc/howto/logging.rst +++ b/Doc/howto/logging.rst @@ -4,8 +4,6 @@ Logging HOWTO ============= -:Author: Vinay Sajip <vinay_sajip at red-dove dot com> - .. _logging-basic-tutorial: .. currentmodule:: logging diff --git a/Doc/howto/perf_profiling.rst b/Doc/howto/perf_profiling.rst index 657cb287ad3d60..5565f99b244f11 100644 --- a/Doc/howto/perf_profiling.rst +++ b/Doc/howto/perf_profiling.rst @@ -6,8 +6,6 @@ Python support for the ``perf map`` compatible profilers ======================================================== -:author: Pablo Galindo - `The Linux perf profiler <https://perf.wiki.kernel.org>`_ and `samply <https://github.com/mstange/samply>`_ are powerful tools that allow you to profile and obtain information about the performance of your application. diff --git a/Doc/howto/pyporting.rst b/Doc/howto/pyporting.rst index 9f73c811cfcbc0..f19f6006dbac9e 100644 --- a/Doc/howto/pyporting.rst +++ b/Doc/howto/pyporting.rst @@ -6,8 +6,6 @@ How to port Python 2 Code to Python 3 ************************************* -:author: Brett Cannon - Python 2 reached its official end-of-life at the start of 2020. This means that no new bug reports, fixes, or changes will be made to Python 2 - it's no longer supported: see :pep:`373` and diff --git a/Doc/howto/regex.rst b/Doc/howto/regex.rst index 6fc087c3f1c367..ecdb35136a99f3 100644 --- a/Doc/howto/regex.rst +++ b/Doc/howto/regex.rst @@ -4,8 +4,6 @@ Regular expression HOWTO **************************** -:Author: A.M. Kuchling <amk@amk.ca> - .. TODO: Document lookbehind assertions Better way of displaying a RE, a string, and what it matches diff --git a/Doc/howto/sockets.rst b/Doc/howto/sockets.rst index cbc49d15a0771b..b17ab3f4391dad 100644 --- a/Doc/howto/sockets.rst +++ b/Doc/howto/sockets.rst @@ -4,9 +4,6 @@ Socket Programming HOWTO **************************** -:Author: Gordon McMillan - - .. topic:: Abstract Sockets are used nearly everywhere, but are one of the most severely diff --git a/Doc/howto/sorting.rst b/Doc/howto/sorting.rst index 70c34cde8a0659..ed9ce306225f4d 100644 --- a/Doc/howto/sorting.rst +++ b/Doc/howto/sorting.rst @@ -3,9 +3,6 @@ Sorting Techniques ****************** -:Author: Andrew Dalke and Raymond Hettinger - - Python lists have a built-in :meth:`list.sort` method that modifies the list in-place. There is also a :func:`sorted` built-in function that builds a new sorted list from an iterable. diff --git a/Doc/howto/unicode.rst b/Doc/howto/unicode.rst index 243cc27bac7025..cbd53d5b619f5a 100644 --- a/Doc/howto/unicode.rst +++ b/Doc/howto/unicode.rst @@ -4,8 +4,6 @@ Unicode HOWTO ***************** -:Release: 1.12 - This HOWTO discusses Python's support for the Unicode specification for representing textual data, and explains various problems that people commonly encounter when trying to work with Unicode. diff --git a/Doc/howto/urllib2.rst b/Doc/howto/urllib2.rst index 4e77d2cb407f72..e4f218f088ba89 100644 --- a/Doc/howto/urllib2.rst +++ b/Doc/howto/urllib2.rst @@ -4,9 +4,6 @@ HOWTO Fetch Internet Resources Using The urllib Package *********************************************************** -:Author: `Michael Foord <https://agileabstractions.com/>`_ - - Introduction ============ From e3b94d8fa459502e411ec1d0366d17bdb7523c1c Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 11 Jun 2026 11:46:04 +0200 Subject: [PATCH 303/818] [3.15] gh-151112: Move an `assert` that may fail in `cfg_builder_check` (GH-151153) (#151313) (cherry picked from commit 2d3381035df24fbf512d897daa19a1040f7af3fd) Co-authored-by: Stan Ulbrych <stan@python.org> --- Python/flowgraph.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Python/flowgraph.c b/Python/flowgraph.c index b63906818e2d6c..d9b8b2a3af402b 100644 --- a/Python/flowgraph.c +++ b/Python/flowgraph.c @@ -403,7 +403,6 @@ cfg_builder_maybe_start_new_block(cfg_builder *g) static bool cfg_builder_check(cfg_builder *g) { - assert(g->g_entryblock->b_iused > 0); for (basicblock *block = g->g_block_list; block != NULL; block = block->b_list) { assert(!_PyMem_IsPtrFreed(block)); if (block->b_instr != NULL) { @@ -3756,6 +3755,7 @@ _PyCfg_OptimizeCodeUnit(cfg_builder *g, PyObject *consts, PyObject *const_cache, int nlocals, int nparams, int firstlineno) { assert(cfg_builder_check(g)); + assert(g->g_entryblock->b_iused > 0); /** Preprocessing **/ /* Map labels to targets and mark exception handlers */ RETURN_IF_ERROR(translate_jump_labels_to_targets(g->g_entryblock)); From 491768da4c7ffcc38809724d4d9c4a67e7131b9d Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 11 Jun 2026 12:10:55 +0200 Subject: [PATCH 304/818] [3.15] gh-151177: Fix race condition in `_testembed` (GH-151293) (GH-151312) gh-151177: Fix race condition in `_testembed` (GH-151293) (cherry picked from commit f9ffca39351b77197e4dc2775a0d1e4ad64bf0e5) Co-authored-by: Peter Bierma <zintensitydev@gmail.com> --- Programs/_testembed.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Programs/_testembed.c b/Programs/_testembed.c index 278984ddb17c1a..fa223c24b2e79a 100644 --- a/Programs/_testembed.c +++ b/Programs/_testembed.c @@ -2710,8 +2710,8 @@ do_tstate_ensure(void *arg) PyThreadState_Release(tokens[2]); PyThreadState_Release(tokens[1]); PyThreadState_Release(tokens[0]); - PyInterpreterGuard_Close(guard); _Py_atomic_store_int(&data->done, 1); + PyInterpreterGuard_Close(guard); } static int From dc5ebe3da4defe5d3cda0ca0c781ea20942e8d0f Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 11 Jun 2026 13:21:26 +0200 Subject: [PATCH 305/818] [3.15] gh-123619: Fix PyUnstable_Object_EnableDeferredRefcount() (GH-151260) (#151326) gh-123619: Fix PyUnstable_Object_EnableDeferredRefcount() (GH-151260) Return 0 if the object is not tracked by the GC. (cherry picked from commit 72e7eddce6c7137cef06b6eba15641597919e3d4) Co-authored-by: Victor Stinner <vstinner@python.org> --- Lib/test/test_capi/test_object.py | 6 ++++++ .../C_API/2026-06-10-16-43-37.gh-issue-123619.dV82r6.rst | 3 +++ Objects/object.c | 7 +++++++ 3 files changed, 16 insertions(+) create mode 100644 Misc/NEWS.d/next/C_API/2026-06-10-16-43-37.gh-issue-123619.dV82r6.rst diff --git a/Lib/test/test_capi/test_object.py b/Lib/test/test_capi/test_object.py index e5c50902a0118d..433afac875aa7b 100644 --- a/Lib/test/test_capi/test_object.py +++ b/Lib/test/test_capi/test_object.py @@ -178,11 +178,17 @@ class EnableDeferredRefcountingTest(unittest.TestCase): @support.requires_resource("cpu") def test_enable_deferred_refcount(self): from threading import Thread + import gc self.assertEqual(_testcapi.pyobject_enable_deferred_refcount("not tracked"), 0) foo = [] self.assertEqual(_testcapi.pyobject_enable_deferred_refcount(foo), int(support.Py_GIL_DISABLED)) + # The object must be tracked by the GC + not_gc_tracked = tuple([1, 2]) + self.assertFalse(gc.is_tracked(not_gc_tracked)) + self.assertEqual(_testcapi.pyobject_enable_deferred_refcount(not_gc_tracked), 0) + # Make sure reference counting works on foo now self.assertEqual(foo, []) if support.Py_GIL_DISABLED: diff --git a/Misc/NEWS.d/next/C_API/2026-06-10-16-43-37.gh-issue-123619.dV82r6.rst b/Misc/NEWS.d/next/C_API/2026-06-10-16-43-37.gh-issue-123619.dV82r6.rst new file mode 100644 index 00000000000000..4d4c94563330c0 --- /dev/null +++ b/Misc/NEWS.d/next/C_API/2026-06-10-16-43-37.gh-issue-123619.dV82r6.rst @@ -0,0 +1,3 @@ +:c:func:`PyUnstable_Object_EnableDeferredRefcount` now returns ``0`` if the +object is not tracked by the garbage collector: if :func:`gc.is_tracked` is +false. Patch by Victor Stinner. diff --git a/Objects/object.c b/Objects/object.c index e0e26bb50d3653..bd23c2e2388194 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -2821,6 +2821,13 @@ PyUnstable_Object_EnableDeferredRefcount(PyObject *op) return 0; } + if (!PyObject_GC_IsTracked(op)) { + // When deferred refcount is enabled, the object will only be + // deallocated by the tracing garbage collector. So it must be tracked + // by the garbage collector. + return 0; + } + uint8_t bits = _Py_atomic_load_uint8(&op->ob_gc_bits); if ((bits & _PyGC_BITS_DEFERRED) != 0) { From f3532d62ed143e0e8e1037fed7679159277b369c Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 11 Jun 2026 16:58:13 +0200 Subject: [PATCH 306/818] [3.15] gh-151238: Check for `_get_resized_exprs` failure in `_PyPegen_{joined,template}_str` (GH-151259) (#151344) (cherry picked from commit 4b44b1e1fd654f3a3fefb02ae7fb26456fe33dc3) Co-authored-by: Stan Ulbrych <stan@python.org> --- Lib/test/test_fstring.py | 11 +++++++++++ .../2026-06-10-15-19-58.gh-issue-151238.C9Wu4x.rst | 2 ++ Parser/action_helpers.c | 6 ++++++ 3 files changed, 19 insertions(+) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-10-15-19-58.gh-issue-151238.C9Wu4x.rst diff --git a/Lib/test/test_fstring.py b/Lib/test/test_fstring.py index 05d0cbd2445c4c..5cc02c30ec2ba3 100644 --- a/Lib/test/test_fstring.py +++ b/Lib/test/test_fstring.py @@ -593,6 +593,17 @@ def test_compile_time_concat_errors(self): r"""b'' f''""", ]) + def test_concat_decode_failure_does_not_crash(self): + script = r''' +import builtins +builtins.__import__ = builtins # Breaks warning machinery so _get_resized_exprs returns NULL +try: + compile('"x"f"\]"b""', '<test>', 'exec') +except Exception: + pass +''' + assert_python_ok('-c', script) + def test_literal(self): self.assertEqual(f'', '') self.assertEqual(f'a', 'a') diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-10-15-19-58.gh-issue-151238.C9Wu4x.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-10-15-19-58.gh-issue-151238.C9Wu4x.rst new file mode 100644 index 00000000000000..fe7519fb487895 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-10-15-19-58.gh-issue-151238.C9Wu4x.rst @@ -0,0 +1,2 @@ +Fix a crash when compiling a concatenated f-string or t-string if an error +occurs when processing one of it's parts. diff --git a/Parser/action_helpers.c b/Parser/action_helpers.c index 5e52bb83871904..c74eb34deb7c35 100644 --- a/Parser/action_helpers.c +++ b/Parser/action_helpers.c @@ -1416,6 +1416,9 @@ expr_ty _PyPegen_template_str(Parser *p, Token *a, asdl_expr_seq *raw_expressions, Token *b) { asdl_expr_seq *resized_exprs = _get_resized_exprs(p, a, raw_expressions, b, TSTRING); + if (resized_exprs == NULL) { + return NULL; + } return _PyAST_TemplateStr(resized_exprs, a->lineno, a->col_offset, b->end_lineno, b->end_col_offset, p->arena); @@ -1425,6 +1428,9 @@ expr_ty _PyPegen_joined_str(Parser *p, Token* a, asdl_expr_seq* raw_expressions, Token*b) { asdl_expr_seq *resized_exprs = _get_resized_exprs(p, a, raw_expressions, b, FSTRING); + if (resized_exprs == NULL) { + return NULL; + } return _PyAST_JoinedStr(resized_exprs, a->lineno, a->col_offset, b->end_lineno, b->end_col_offset, p->arena); From dc7ca40343e13c92afa2fff8bfe5a85914a20474 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 11 Jun 2026 17:01:11 +0200 Subject: [PATCH 307/818] [3.15] gh-150285: Suppress showing the __getstate__() comment in the help for dataclasses (GH-151328) (GH-151331) (cherry picked from commit 0066fd73a20950dc790d219f4e3cfb07e816df47) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> --- Lib/dataclasses.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Lib/dataclasses.py b/Lib/dataclasses.py index dbfabded2e47aa..863e4101f98bd6 100644 --- a/Lib/dataclasses.py +++ b/Lib/dataclasses.py @@ -1250,6 +1250,7 @@ def _process_class(cls, init, repr, eq, order, unsafe_hash, frozen, # classes with slots. These could be slightly more performant if we generated # the code instead of iterating over fields. But that can be a project for # another day, if performance becomes an issue. + def _dataclass_getstate(self): return [getattr(self, f.name) for f in fields(self)] From 0d4d4cd746578a0dd26333c82e520f586f029e5e Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 11 Jun 2026 17:15:10 +0200 Subject: [PATCH 308/818] [3.15] gh-150397: Fix pyexpat bigmem test (GH-151329) (#151348) gh-150397: Fix pyexpat bigmem test (GH-151329) Add missing parameter (size). (cherry picked from commit 0bbde07a0bbad3c79073fd133d6df70837e4cfee) Co-authored-by: Victor Stinner <vstinner@python.org> --- Lib/test/test_pyexpat.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_pyexpat.py b/Lib/test/test_pyexpat.py index 10dca684accee3..5a42bbb5f087f4 100644 --- a/Lib/test/test_pyexpat.py +++ b/Lib/test/test_pyexpat.py @@ -827,7 +827,7 @@ def test_change_size_2(self): @support.requires_resource('cpu') @support.requires_resource('walltime') @support.bigmemtest(size=2**31, memuse=4, dry_run=False) - def test_large_character_data_does_not_crash(self): + def test_large_character_data_does_not_crash(self, size): # See https://github.com/python/cpython/issues/148441 parser = expat.ParserCreate() parser.buffer_text = True From cedb4d65f1878e49ed9b40568d6e609b6bb4de4b Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 11 Jun 2026 17:21:26 +0200 Subject: [PATCH 309/818] [3.15] gh-139588: Fix nondeterministic `make latex` doc build under parallel make (GH-151343) (#151352) (cherry picked from commit b9bffc09a6e47959cb5c306040fd0bfd77ae2786) Co-authored-by: Maciej Olko <maciej.olko@affirm.com> --- Doc/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/Makefile b/Doc/Makefile index 60970d50833f14..d77ece1e681bcf 100644 --- a/Doc/Makefile +++ b/Doc/Makefile @@ -88,9 +88,9 @@ htmlhelp: build "build/htmlhelp/pydoc.hhp project file." .PHONY: latex -latex: _ensure-sphinxcontrib-svg2pdfconverter latex: BUILDER = latex -latex: build +latex: _ensure-sphinxcontrib-svg2pdfconverter + $(MAKE) build BUILDER=$(BUILDER) @echo "Build finished; the LaTeX files are in build/latex." @echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \ "run these through (pdf)latex." From 42e81e35a067320c71297d91846690210ab6858e Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 11 Jun 2026 17:22:31 +0200 Subject: [PATCH 310/818] [3.15] gh-151112: Fix crash in `compiler_mod()` when entering the current compilation unit fails (GH-151234) (#151350) (cherry picked from commit 937d89c4d9b7c5fda6730a1127db118d881d13cb) Co-authored-by: Stan Ulbrych <stan@python.org> --- Python/compile.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Python/compile.c b/Python/compile.c index eb9fc827bea40a..e223ef42a42e22 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -893,12 +893,15 @@ compiler_mod(compiler *c, mod_ty mod) { PyCodeObject *co = NULL; int addNone = mod->kind != Expression_kind; + assert(c->u == NULL); if (compiler_codegen(c, mod) < 0) { goto finally; } co = _PyCompile_OptimizeAndAssemble(c, addNone); finally: - _PyCompile_ExitScope(c); + if (c->u != NULL) { + _PyCompile_ExitScope(c); + } return co; } From fdf0132e35ebddd1ca3f366c2359fe3dd297e070 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 11 Jun 2026 17:42:23 +0200 Subject: [PATCH 311/818] [3.15] gh-101100: Fix Sphinx nitpick in `unittest.mock.rst` (GH-151302) (#151355) (cherry picked from commit b18168cb32d545ed976b760983478cbd5dde5bdf) Co-authored-by: Cody Maloney <cmaloney@users.noreply.github.com> --- Doc/library/unittest.mock.rst | 2 +- Doc/tools/.nitignore | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/Doc/library/unittest.mock.rst b/Doc/library/unittest.mock.rst index 2ff1015af7a86e..6ba1b87ea942a9 100644 --- a/Doc/library/unittest.mock.rst +++ b/Doc/library/unittest.mock.rst @@ -2223,7 +2223,7 @@ return something else:: >>> mock == 3 True -The return value of :meth:`MagicMock.__iter__` can be any iterable object and isn't +The return value of :meth:`!__iter__` can be any iterable object and isn't required to be an iterator: >>> mock = MagicMock() diff --git a/Doc/tools/.nitignore b/Doc/tools/.nitignore index 31173134dd5019..aa08f7acb99197 100644 --- a/Doc/tools/.nitignore +++ b/Doc/tools/.nitignore @@ -29,7 +29,6 @@ Doc/library/test.rst Doc/library/tkinter.rst Doc/library/tkinter.scrolledtext.rst Doc/library/tkinter.ttk.rst -Doc/library/unittest.mock.rst Doc/library/urllib.parse.rst Doc/library/urllib.request.rst Doc/library/wsgiref.rst From 85404a02ba9e52776c4a16a1b2dc473c47972dac Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 11 Jun 2026 18:34:26 +0200 Subject: [PATCH 312/818] [3.15] gh-151228: fix data race on clearing embedded dict values (GH-151330) (#151359) gh-151228: fix data race on clearing embedded dict values (GH-151330) (cherry picked from commit 6112d70abee2455bfa44a76a49a5a80472e21134) Co-authored-by: Kumar Aditya <kumaraditya@python.org> --- Lib/test/test_free_threading/test_dict.py | 18 ++++++++++++++++++ Objects/dictobject.c | 2 +- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_free_threading/test_dict.py b/Lib/test/test_free_threading/test_dict.py index dfe0634211d4b0..ad23290a92ab34 100644 --- a/Lib/test/test_free_threading/test_dict.py +++ b/Lib/test/test_free_threading/test_dict.py @@ -296,6 +296,24 @@ def reader(): threading_helper.run_concurrently([clearer, reader, reader]) + def test_racing_embedded_values_clear_and_lookup(self): + class C: + pass + + obj = C() + def writer(): + for _ in range(1000): + obj.x = 1 + obj.y = 2 + obj.z = 3 + obj.__dict__.clear() + + def reader(): + for _ in range(1000): + obj.__dict__.get('x') + + threading_helper.run_concurrently([writer, reader, reader]) + def test_racing_dict_update_and_method_lookup(self): # gh-144295: test race between dict modifications and method lookups. # Uses BytesIO because the race requires a type without Py_TPFLAGS_INLINE_VALUES diff --git a/Objects/dictobject.c b/Objects/dictobject.c index e279c8765dd464..25dc81f726f59c 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -3039,7 +3039,7 @@ clear_embedded_values(PyDictValues *values, Py_ssize_t nentries) assert(nentries <= SHARED_KEYS_MAX_SIZE); for (Py_ssize_t i = 0; i < nentries; i++) { refs[i] = values->values[i]; - values->values[i] = NULL; + FT_ATOMIC_STORE_PTR_RELEASE(values->values[i], NULL); } values->size = 0; for (Py_ssize_t i = 0; i < nentries; i++) { From b53743fb7898be82d86cc34ff4b1c5a635e99c72 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 11 Jun 2026 18:55:19 +0200 Subject: [PATCH 313/818] [3.15] gh-151126: Fix missing memory error in `os._path_splitroot` (GH-151339) (#151360) gh-151126: Fix missing memory error in `os._path_splitroot` (GH-151339) (cherry picked from commit 10595b1cb7ac04ba9a3ef3f7da4fa31c9966300d) Co-authored-by: sobolevn <mail@sobolevn.me> --- .../next/Library/2026-06-11-16-25-38.gh-issue-151126.bh_Usy.rst | 2 ++ Modules/posixmodule.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2026-06-11-16-25-38.gh-issue-151126.bh_Usy.rst diff --git a/Misc/NEWS.d/next/Library/2026-06-11-16-25-38.gh-issue-151126.bh_Usy.rst b/Misc/NEWS.d/next/Library/2026-06-11-16-25-38.gh-issue-151126.bh_Usy.rst new file mode 100644 index 00000000000000..25149057aa7d09 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-11-16-25-38.gh-issue-151126.bh_Usy.rst @@ -0,0 +1,2 @@ +Fix a crash when :exc:`MemoryError` in :func:`!os._path_splitroot` +was not set properly. diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 4b6b5196173169..b58b2af3c5f887 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -5699,7 +5699,7 @@ os__path_splitroot_impl(PyObject *module, path_t *path) buffer = (wchar_t*)PyMem_Malloc(sizeof(wchar_t) * (wcslen(path->wide) + 1)); if (!buffer) { - return NULL; + return PyErr_NoMemory(); } wcscpy(buffer, path->wide); for (wchar_t *p = wcschr(buffer, L'/'); p; p = wcschr(p, L'/')) { From f3fd7b85298679f118feddf41b1dae04cc43ff1a Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 11 Jun 2026 19:22:52 +0200 Subject: [PATCH 314/818] [3.15] gh-150285: Fix too long docstrings in GenericAlias and __class_getitem__ (GH-151354) (GH-151367) (cherry picked from commit 65047f2e2fb80e4ad36df56a343d75963a20c110) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> --- Objects/genericaliasobject.c | 3 ++- Objects/tupleobject.c | 6 ++++-- Objects/typevarobject.c | 5 +++-- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/Objects/genericaliasobject.c b/Objects/genericaliasobject.c index 9c797e8dd6fd2c..c2083e6fcb77f4 100644 --- a/Objects/genericaliasobject.c +++ b/Objects/genericaliasobject.c @@ -572,7 +572,8 @@ PyDoc_STRVAR(genericalias__doc__, "--\n\n" "Represent a PEP 585 generic type\n" "\n" -"E.g. for t = list[int], t.__origin__ is list and t.__args__ is (int,)."); +"For example, for t = list[int], t.__origin__ is list and t.__args__\n" +"is (int,)."); static PyObject * ga_getitem(PyObject *self, PyObject *item) diff --git a/Objects/tupleobject.c b/Objects/tupleobject.c index 5aa5188905305a..780a692f982533 100644 --- a/Objects/tupleobject.c +++ b/Objects/tupleobject.c @@ -957,8 +957,10 @@ tuple___getnewargs___impl(PyTupleObject *self) PyDoc_STRVAR(tuple_class_getitem_doc, "Tuples are generic over the types of their contents.\n\n\ -For example, use ``tuple[int, str]`` for a pair whose first element is an int and second element is a string.\n\n\ -Tuples also support the form ``tuple[T, ...]`` to indicate an arbitrary length tuple of elements of type T."); +For example, use ``tuple[int, str]`` for a pair whose first element\n\ +is an int and second element is a string.\n\n\ +Tuples also support the form ``tuple[T, ...]`` to indicate\n\ +an arbitrary length tuple of elements of type T."); static PyMethodDef tuple_methods[] = { TUPLE___GETNEWARGS___METHODDEF diff --git a/Objects/typevarobject.c b/Objects/typevarobject.c index 8ad590cc6e6093..78750a955d2a49 100644 --- a/Objects/typevarobject.c +++ b/Objects/typevarobject.c @@ -2311,8 +2311,9 @@ PyDoc_STRVAR(generic_class_getitem_doc, "Parameterizes a generic class.\n\ \n\ At least, parameterizing a generic class is the *main* thing this\n\ -method does. For example, for some generic class `Foo`, this is called\n\ -when we do `Foo[int]` - there, with `cls=Foo` and `params=int`.\n\ +method does. For example, for some generic class `Foo`, this is\n\ +called when we do `Foo[int]` - there, with `cls=Foo` and\n\ +`params=int`.\n\ \n\ However, note that this method is also called when defining generic\n\ classes in the first place with `class Foo[T]: ...`.\n\ From f3632b47ce7abe48d66116149293c0c57a8be942 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 11 Jun 2026 19:45:30 +0200 Subject: [PATCH 315/818] [3.15] gh-138991: Update dataclass documentation for new eq behavior in Python 3.13 (GH-139007) (#151372) gh-138991: Update dataclass documentation for new eq behavior in Python 3.13 (GH-139007) And add tests. (cherry picked from commit 402668b2b1a63a2b3cfd7a2ede07f6786f9beb8e) Co-authored-by: Aniket <148300120+Aniketsy@users.noreply.github.com> Co-authored-by: Victor Stinner <vstinner@python.org> --- Doc/library/dataclasses.rst | 23 ++++++++++--- Lib/test/test_dataclasses/__init__.py | 49 +++++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 5 deletions(-) diff --git a/Doc/library/dataclasses.rst b/Doc/library/dataclasses.rst index a09c28ad979158..a77213af778ae6 100644 --- a/Doc/library/dataclasses.rst +++ b/Doc/library/dataclasses.rst @@ -100,12 +100,25 @@ Module contents ignored. - *eq*: If true (the default), an :meth:`~object.__eq__` method will be - generated. This method compares the class as if it were a tuple - of its fields, in order. Both instances in the comparison must - be of the identical type. + generated. - If the class already defines :meth:`!__eq__`, this parameter is - ignored. + This method compares the class by comparing each field in order. Both + instances in the comparison must be of the identical type. + + If the class already defines :meth:`!__eq__`, this parameter is ignored. + + .. versionchanged:: 3.13 + The generated ``__eq__`` method now compares each field individually + (for example, ``self.a == other.a and self.b == other.b``), rather than + comparing tuples of fields as in previous versions. + + This change makes the comparison faster but it may alter results in cases + where attributes compare equal by identity but not by value (such as + ``float('nan')``). + + In Python 3.12 and earlier, the comparison was performed by creating + tuples of the fields and comparing them (for example, + ``(self.a, self.b) == (other.a, other.b)``). - *order*: If true (the default is ``False``), :meth:`~object.__lt__`, :meth:`~object.__le__`, :meth:`~object.__gt__`, and :meth:`~object.__ge__` methods will be diff --git a/Lib/test/test_dataclasses/__init__.py b/Lib/test/test_dataclasses/__init__.py index dcd6a3ef9abfab..cede6671da1475 100644 --- a/Lib/test/test_dataclasses/__init__.py +++ b/Lib/test/test_dataclasses/__init__.py @@ -2792,6 +2792,55 @@ def __eq__(self, other): self.assertEqual(C(1), 5) self.assertNotEqual(C(1), 1) + def test_eq_field_by_field(self): + @dataclasses.dataclass + class Point: + x: int + y: int + + p1 = Point(1, 2) + p2 = Point(1, 2) + p3 = Point(2, 1) + self.assertEqual(p1, p2) + self.assertNotEqual(p1, p3) + + def test_eq_type_check(self): + @dataclasses.dataclass + class A: + x: int + + @dataclasses.dataclass + class B: + x: int + + a = A(1) + b = B(1) + self.assertNotEqual(a, b) + + def test_eq_custom_field(self): + class AlwaysEqual(int): + def __eq__(self, other): + return True + + @dataclasses.dataclass + class Foo: + x: AlwaysEqual + y: int + + f1 = Foo(AlwaysEqual(1), 2) + f2 = Foo(AlwaysEqual(2), 2) + self.assertEqual(f1, f2) + + def test_eq_nan_field(self): + @dataclasses.dataclass + class D: + x: float + + nan = float('nan') + d1 = D(nan) + d2 = D(nan) + self.assertNotEqual(d1, d2) + class TestOrdering(unittest.TestCase): def test_functools_total_ordering(self): From e87e732fda179e17421ae17cfc90456118f95d3b Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 11 Jun 2026 22:25:05 +0200 Subject: [PATCH 316/818] [3.15] gh-151337: Avoid possible memory leak in `_tkinter.c` on Windows. (GH-151340) (GH-151379) (cherry picked from commit 71805db4294de9495954571c82a835d94ba67594) Co-authored-by: Ivy Xu <fakeshadow1337@gmail.com> --- ...2026-06-11-21-43-24.gh-issue-151337.JSVV18.rst | 1 + Modules/_tkinter.c | 15 ++++++++++----- 2 files changed, 11 insertions(+), 5 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-06-11-21-43-24.gh-issue-151337.JSVV18.rst diff --git a/Misc/NEWS.d/next/Library/2026-06-11-21-43-24.gh-issue-151337.JSVV18.rst b/Misc/NEWS.d/next/Library/2026-06-11-21-43-24.gh-issue-151337.JSVV18.rst new file mode 100644 index 00000000000000..0344eee9471d29 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-11-21-43-24.gh-issue-151337.JSVV18.rst @@ -0,0 +1 @@ +Avoid possible memory leak in ``tkinter.c`` on Windows. diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c index 58fdabecf16ada..6eca98a3c8033f 100644 --- a/Modules/_tkinter.c +++ b/Modules/_tkinter.c @@ -128,18 +128,20 @@ _get_tcl_lib_path(void) } /* Check expected location for an installed Python first */ - tcl_library_path = PyUnicode_FromString("\\tcl\\tcl" TCL_VERSION); - if (tcl_library_path == NULL) { + PyObject* tmp_tcl_library_path = PyUnicode_FromString("\\tcl\\tcl" TCL_VERSION); + if (tmp_tcl_library_path == NULL) { Py_DECREF(prefix); return NULL; } - tcl_library_path = PyUnicode_Concat(prefix, tcl_library_path); + tcl_library_path = PyUnicode_Concat(prefix, tmp_tcl_library_path); + Py_DECREF(tmp_tcl_library_path); Py_DECREF(prefix); if (tcl_library_path == NULL) { return NULL; } stat_return_value = _Py_stat(tcl_library_path, &stat_buf); if (stat_return_value == -2) { + Py_DECREF(tcl_library_path); return NULL; } if (stat_return_value == -1) { @@ -154,16 +156,17 @@ _get_tcl_lib_path(void) } stat_return_value = _Py_stat(tcl_library_path, &stat_buf); if (stat_return_value == -2) { + Py_DECREF(tcl_library_path); return NULL; } if (stat_return_value == -1) { /* tcltkDir for a repository build doesn't exist either, reset errno and leave Tcl to its own devices */ errno = 0; - tcl_library_path = NULL; + Py_CLEAR(tcl_library_path); } #else - tcl_library_path = NULL; + Py_CLEAR(tcl_library_path); #endif } already_checked = 1; @@ -707,11 +710,13 @@ Tkapp_New(const char *screenName, const char *className, if (!ret && GetLastError() == ERROR_ENVVAR_NOT_FOUND) { str_path = _get_tcl_lib_path(); if (str_path == NULL && PyErr_Occurred()) { + Py_DECREF(v); return NULL; } if (str_path != NULL) { utf8_path = PyUnicode_AsUTF8String(str_path); if (utf8_path == NULL) { + Py_DECREF(v); return NULL; } Tcl_SetVar(v->interp, From a12a0e9529b4847f1cde0a4b1d777251b7efdb40 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 12 Jun 2026 00:39:37 +0200 Subject: [PATCH 317/818] [3.15] gh-151065: Copy fix for memory leak from mimalloc upstream (GH-151066) (GH-151383) Applies https://github.com/microsoft/mimalloc/commit/d7a72c4912943e8aaf135e465ca5ea229ea96646 to our copy of mimalloc. (cherry picked from commit 80f9467434cecbc4e97b853b3876de13e75aec38) Co-authored-by: Peter Bierma <zintensitydev@gmail.com> --- .../2026-06-08-05-31-22.gh-issue-151065._o_31F.rst | 1 + Objects/mimalloc/init.c | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-08-05-31-22.gh-issue-151065._o_31F.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-08-05-31-22.gh-issue-151065._o_31F.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-08-05-31-22.gh-issue-151065._o_31F.rst new file mode 100644 index 00000000000000..e46c96ef784cc9 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-08-05-31-22.gh-issue-151065._o_31F.rst @@ -0,0 +1 @@ +Fix memory leak when using the :ref:`mimalloc memory allocator <mimalloc>`. diff --git a/Objects/mimalloc/init.c b/Objects/mimalloc/init.c index 81b241063ff40f..7711c827a58b1c 100644 --- a/Objects/mimalloc/init.c +++ b/Objects/mimalloc/init.c @@ -183,9 +183,9 @@ mi_heap_t* _mi_heap_main_get(void) { // note: in x64 in release build `sizeof(mi_thread_data_t)` is under 4KiB (= OS page size). typedef struct mi_thread_data_s { - mi_heap_t heap; // must come first due to cast in `_mi_heap_done` + mi_heap_t heap; // must come first due to cast in `_mi_heap_done` mi_tld_t tld; - mi_memid_t memid; + mi_memid_t memid; // must come last due to zero'ing } mi_thread_data_t; @@ -231,7 +231,7 @@ static mi_thread_data_t* mi_thread_data_zalloc(void) { } if (td != NULL && !is_zero) { - _mi_memzero_aligned(td, sizeof(*td)); + _mi_memzero_aligned(td, offsetof(mi_thread_data_t,memid)); } return td; } From a2e551610f6248cfd130172e1cf9f5ee811758b9 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 12 Jun 2026 03:47:01 +0200 Subject: [PATCH 318/818] [3.15] gh-151297: Fix undefined behavior in `_PyObject_MiRealloc` (GH-151358) (GH-151388) The standard says that a call to `memcpy` must pass a valid source and destination pointer even if the size is 0, so we must avoid calling `memcpy` when our source pointer is NULL. If we don't, an optimizing compiler can decide that the pointer must be non-NULL based on the presence of UB, and optimize out checks for null pointers. Specifically, note that the standard says: Where an argument declared as size_t n specifies the length of the array for a function, n can have the value zero on a call to that function. Unless explicitly stated otherwise in the description of a particular function in this subclause, pointer arguments on such a call shall still have valid values, as described in 7.1.4. And section 7.1.4 says: If an argument to a function has an invalid value (such as a value outside the domain of the function, or a pointer outside the address space of the program, or a null pointer, or a pointer to non-modifiable storage when the corresponding parameter is not const-qualified) or a type (after default argument promotion) not expected by a function with a variable number of arguments, the behavior is undefined. The specification for `memcpy` doesn't state that it's allowed to be called with null pointers, and Linux's `/usr/include/string.h` declares `memcpy` as `__nonnull ((1, 2))`. (cherry picked from commit c37599200f688538efa34a49f262a9a4a899a953) Co-authored-by: Matt Wozniski <mwozniski@bloomberg.net> --- ...-06-11-16-03-23.gh-issue-151297.NGPkUM.rst | 1 + Modules/_testcapi/mem.c | 47 +++++++++++++++++++ Objects/obmalloc.c | 5 +- 3 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-11-16-03-23.gh-issue-151297.NGPkUM.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-11-16-03-23.gh-issue-151297.NGPkUM.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-11-16-03-23.gh-issue-151297.NGPkUM.rst new file mode 100644 index 00000000000000..288d726e0f1004 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-11-16-03-23.gh-issue-151297.NGPkUM.rst @@ -0,0 +1 @@ +Fix an invalid pointer dereference that could occur when calling :c:func:`PyObject_Realloc` with a NULL pointer in :term:`free-threaded builds <free-threaded build>` or with :envvar:`PYTHONMALLOC` set to ``mimalloc``. diff --git a/Modules/_testcapi/mem.c b/Modules/_testcapi/mem.c index b4896f984510bd..6aaf0c7d4e942d 100644 --- a/Modules/_testcapi/mem.c +++ b/Modules/_testcapi/mem.c @@ -323,6 +323,53 @@ test_setallocators(PyMemAllocatorDomain domain) goto fail; } + /* realloc(NULL, size) should behave like malloc(size) */ + size_t size3 = 100; + void *ptr3; + switch(domain) { + case PYMEM_DOMAIN_RAW: + ptr3 = PyMem_RawRealloc(NULL, size3); + break; + case PYMEM_DOMAIN_MEM: + ptr3 = PyMem_Realloc(NULL, size3); + break; + case PYMEM_DOMAIN_OBJ: + ptr3 = PyObject_Realloc(NULL, size3); + break; + default: + ptr3 = NULL; + break; + } + + CHECK_CTX("realloc(NULL, size)"); + if (ptr3 == NULL) { + error_msg = "realloc(NULL, size) failed"; + goto fail; + } + if (hook.realloc_ptr != NULL || hook.realloc_new_size != size3) { + error_msg = "realloc(NULL, size) invalid parameters"; + goto fail; + } + + hook.free_ptr = NULL; + switch(domain) { + case PYMEM_DOMAIN_RAW: + PyMem_RawFree(ptr3); + break; + case PYMEM_DOMAIN_MEM: + PyMem_Free(ptr3); + break; + case PYMEM_DOMAIN_OBJ: + PyObject_Free(ptr3); + break; + } + + CHECK_CTX("realloc(NULL, size) free"); + if (hook.free_ptr != ptr3) { + error_msg = "unexpected pointer passed to free"; + goto fail; + } + res = Py_NewRef(Py_None); goto finally; diff --git a/Objects/obmalloc.c b/Objects/obmalloc.c index 1809bd30451327..0947d47c8a5558 100644 --- a/Objects/obmalloc.c +++ b/Objects/obmalloc.c @@ -363,7 +363,10 @@ _PyObject_MiRealloc(void *ctx, void *ptr, size_t nbytes) _mi_memcpy((char*)newp + offset, (char*)ptr + offset, copy_size - offset); } else { - _mi_memcpy(newp, ptr, copy_size); + // memcpy(dst, NULL, 0) is undefined behavior. See gh-151297. + if mi_likely(ptr) { + _mi_memcpy(newp, ptr, copy_size); + } } mi_free(ptr); return newp; From 3603bd318b93d1ee1c40f39b6f2db08190a9e34a Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 12 Jun 2026 13:31:51 +0200 Subject: [PATCH 319/818] [3.15] gh-151126: Fix crash on unset memory error in `ctypes.get_errno` (GH-151382) (#151398) gh-151126: Fix crash on unset memory error in `ctypes.get_errno` (GH-151382) (cherry picked from commit 6b217ea90b9cd694fded6308bc796e324bbacd19) Co-authored-by: sobolevn <mail@sobolevn.me> --- .../Library/2026-06-12-00-04-34.gh-issue-151126.aHaBYq.rst | 2 ++ Modules/_ctypes/callproc.c | 5 +++-- 2 files changed, 5 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-06-12-00-04-34.gh-issue-151126.aHaBYq.rst diff --git a/Misc/NEWS.d/next/Library/2026-06-12-00-04-34.gh-issue-151126.aHaBYq.rst b/Misc/NEWS.d/next/Library/2026-06-12-00-04-34.gh-issue-151126.aHaBYq.rst new file mode 100644 index 00000000000000..20ef69d5de5ac5 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-12-00-04-34.gh-issue-151126.aHaBYq.rst @@ -0,0 +1,2 @@ +Fix crash on unset :exc:`MemoryError` on allocation failure in +:func:`ctypes.get_errno`. diff --git a/Modules/_ctypes/callproc.c b/Modules/_ctypes/callproc.c index e453cfeec9cc8c..ccc57e347b07ac 100644 --- a/Modules/_ctypes/callproc.c +++ b/Modules/_ctypes/callproc.c @@ -168,8 +168,9 @@ _ctypes_get_errobj(ctypes_state *st, int **pspace) } else { void *space = PyMem_Calloc(2, sizeof(int)); - if (space == NULL) - return NULL; + if (space == NULL) { + return PyErr_NoMemory(); + } errobj = PyCapsule_New(space, CTYPES_CAPSULE_NAME_PYMEM, pymem_destructor); if (errobj == NULL) { PyMem_Free(space); From 5caef8590a06487be5cabdfc890fdc0cd3421751 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 12 Jun 2026 15:10:41 +0200 Subject: [PATCH 320/818] [3.15] gh-151284: Fix test_capi on UBSan (GH-151286) (#151323) gh-151284: Fix test_capi on UBSan (GH-151286) Comment two checks relying on undefined behavior in test_fromwidechar() of test_capi. Enable test_capi in GitHub Action "Reusable Sanitizer". (cherry picked from commit d87d77287392b78d36a06660228f6a5ca88888d7) Co-authored-by: Victor Stinner <vstinner@python.org> --- .github/workflows/reusable-san.yml | 3 --- Lib/test/test_capi/test_unicode.py | 6 ++++-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/.github/workflows/reusable-san.yml b/.github/workflows/reusable-san.yml index 6127c7e1c05369..2ceb1000e8a5a9 100644 --- a/.github/workflows/reusable-san.yml +++ b/.github/workflows/reusable-san.yml @@ -82,13 +82,10 @@ jobs: run: make -j4 - name: Display build info run: make pythoninfo - # test_capi is skipped under UBSan because - # they raise signals that UBSan with halt_on_error=1 intercepts. - name: Tests run: >- ./python -m test ${{ inputs.sanitizer == 'TSan' && '--tsan' || '' }} - ${{ inputs.sanitizer == 'UBSan' && '-x test_capi' || '' }} -j4 -W - name: Parallel tests if: >- diff --git a/Lib/test/test_capi/test_unicode.py b/Lib/test/test_capi/test_unicode.py index 5dee25756fe289..0dcd8a25ad0128 100644 --- a/Lib/test/test_capi/test_unicode.py +++ b/Lib/test/test_capi/test_unicode.py @@ -842,9 +842,7 @@ def test_fromwidechar(self): if SIZEOF_WCHAR_T == 2: self.assertEqual(fromwidechar('a\U0001f600'.encode(encoding), 2), 'a\ud83d') - self.assertRaises(MemoryError, fromwidechar, b'', PY_SSIZE_T_MAX) self.assertRaises(SystemError, fromwidechar, b'\0'*SIZEOF_WCHAR_T, -2) - self.assertRaises(SystemError, fromwidechar, b'\0'*SIZEOF_WCHAR_T, PY_SSIZE_T_MIN) self.assertEqual(fromwidechar(NULL, 0), '') self.assertRaises(SystemError, fromwidechar, NULL, 1) self.assertRaises(SystemError, fromwidechar, NULL, PY_SSIZE_T_MAX) @@ -852,6 +850,10 @@ def test_fromwidechar(self): self.assertRaises(SystemError, fromwidechar, NULL, -2) self.assertRaises(SystemError, fromwidechar, NULL, PY_SSIZE_T_MIN) + # The following tests are skipped since they rely on undefined behavior + #self.assertRaises(MemoryError, fromwidechar, b'', PY_SSIZE_T_MAX) + #self.assertRaises(SystemError, fromwidechar, b'\0'*SIZEOF_WCHAR_T, PY_SSIZE_T_MIN) + @support.cpython_only @unittest.skipIf(_testlimitedcapi is None, 'need _testlimitedcapi module') def test_aswidechar(self): From bdb53b555310dcb1a875d2a89bfbe7e398755c03 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 12 Jun 2026 17:01:30 +0200 Subject: [PATCH 321/818] [3.15] Docs: avoid repetitions of class references in functions.rst (GH-150891) (#151405) Co-authored-by: Maciej Olko <maciej.olko@affirm.com> --- Doc/library/functions.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst index def2a211d1b3b4..f38440569d5169 100644 --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -485,7 +485,7 @@ are always available. They are listed here in alphabetical order. :noindex: Create a new dictionary. The :class:`dict` object is the dictionary class. - See :class:`dict` and :ref:`typesmapping` for documentation about this class. + See also :ref:`typesmapping` for documentation about this class. For other containers see the built-in :class:`frozendict`, :class:`list`, :class:`set`, and :class:`tuple` classes, as well as the :mod:`collections` module. @@ -873,7 +873,7 @@ are always available. They are listed here in alphabetical order. :noindex: Create a new frozen dictionary. The :class:`frozendict` object is a built-in class. - See :class:`frozendict` and :ref:`typesmapping` for documentation about this class. + See also :ref:`typesmapping` for documentation about this class. For other containers see the built-in :class:`dict`, :class:`list`, :class:`set`, and :class:`tuple` classes, as well as the :mod:`collections` module. @@ -886,7 +886,7 @@ are always available. They are listed here in alphabetical order. :noindex: Return a new :class:`frozenset` object, optionally with elements taken from - *iterable*. ``frozenset`` is a built-in class. See :class:`frozenset` and + *iterable*. :class:`frozenset` is a built-in class. See also :ref:`types-set` for documentation about this class. For other containers see the built-in :class:`set`, :class:`list`, @@ -1814,7 +1814,7 @@ are always available. They are listed here in alphabetical order. :noindex: Return a new :class:`set` object, optionally with elements taken from - *iterable*. ``set`` is a built-in class. See :class:`set` and + *iterable*. :class:`set` is a built-in class. See also :ref:`types-set` for documentation about this class. For other containers see the built-in :class:`frozenset`, :class:`list`, From 04973e705b936fbda6a0d3691957c07ca1880cba Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 12 Jun 2026 18:11:06 +0200 Subject: [PATCH 322/818] [3.15] Fix typos in the `curses.ascii` module documentation (GH-129300) (#151413) (cherry picked from commit f4f102027a9b0edc72a048f17b696aa92d2e6893) Co-authored-by: Rafael Fontenelle <rffontenelle@users.noreply.github.com> Co-authored-by: Stan Ulbrych <stan@python.org> --- Doc/library/curses.ascii.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/curses.ascii.rst b/Doc/library/curses.ascii.rst index 9ae82c14465538..8f8e3ddda8ef52 100644 --- a/Doc/library/curses.ascii.rst +++ b/Doc/library/curses.ascii.rst @@ -130,7 +130,7 @@ C library: .. function:: isgraph(c) - Checks for ASCII any printable character except space. + Checks for any ASCII printable character except space. .. function:: islower(c) @@ -145,7 +145,7 @@ C library: .. function:: ispunct(c) - Checks for any printable ASCII character which is not a space or an alphanumeric + Checks for any ASCII printable character which is not a space or an alphanumeric character. From 8b291463e3ec5620bf1896a9b7c31994c1393675 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 13 Jun 2026 10:55:30 +0200 Subject: [PATCH 323/818] [3.15] Docs: Fix method directive signatures in `enum` docs (GH-151429) (#151434) (cherry picked from commit 5b385197625e669473859c63bee6f14c983d2be6) Co-authored-by: Jonathan Dung <jonathandung@yahoo.com> --- Doc/library/enum.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Doc/library/enum.rst b/Doc/library/enum.rst index be7f59b0fce2a5..d2ebbe468e82dc 100644 --- a/Doc/library/enum.rst +++ b/Doc/library/enum.rst @@ -629,7 +629,7 @@ Data types >>> white in purple False - .. method:: __iter__(self): + .. method:: __iter__(self) Returns all contained non-alias members:: @@ -640,7 +640,7 @@ Data types .. versionadded:: 3.11 - .. method:: __len__(self): + .. method:: __len__(self) Returns number of members in flag:: @@ -651,7 +651,7 @@ Data types .. versionadded:: 3.11 - .. method:: __bool__(self): + .. method:: __bool__(self) Returns *True* if any members in flag, *False* otherwise:: @@ -688,7 +688,7 @@ Data types >>> purple ^ Color.GREEN <Color.RED|GREEN|BLUE: 7> - .. method:: __invert__(self): + .. method:: __invert__(self) Returns all the flags in *type(self)* that are not in *self*:: From 5d7cf16f3f7fa711dcf254fc67b649be3fba1ec5 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 13 Jun 2026 11:06:55 +0200 Subject: [PATCH 324/818] [3.15] gh-101267: ProcessPoolExecutor no longer shares 1 BrokenProcessPool exception among all failed futures (GH-101268) (#151430) gh-101267: ProcessPoolExecutor no longer shares 1 BrokenProcessPool exception among all failed futures (GH-101268) (cherry picked from commit 3c00ebc2bbd902495b163def850bc931420209fc) Co-authored-by: Daniel Shields <daniel.shields@twosigma.com> Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com> Co-authored-by: Gregory P. Smith <greg@krypto.org> --- Lib/concurrent/futures/process.py | 16 ++++++----- .../test_process_pool.py | 27 +++++++++++++++++++ Misc/ACKS | 1 + ...-01-23-21-23-50.gh-issue-101267._f-cFH.rst | 7 +++++ 4 files changed, 44 insertions(+), 7 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-01-23-21-23-50.gh-issue-101267._f-cFH.rst diff --git a/Lib/concurrent/futures/process.py b/Lib/concurrent/futures/process.py index ed24cc25043413..10d4ac89d72571 100644 --- a/Lib/concurrent/futures/process.py +++ b/Lib/concurrent/futures/process.py @@ -469,11 +469,9 @@ def _terminate_broken(self, cause): executor._shutdown_thread = True executor = None - # All pending tasks are to be marked failed with the following - # BrokenProcessPool error - bpe = BrokenProcessPool("A process in the process pool was " - "terminated abruptly while the future was " - "running or pending.") + # All pending tasks are to be marked failed with a + # BrokenProcessPool error, as separate instances to avoid sharing + # a traceback (gh-101267). cause_str = None if cause is not None: cause_str = ''.join(cause) @@ -489,11 +487,15 @@ def _terminate_broken(self, cause): f"with exit code {p.exitcode}") if errors: cause_str = "\n".join(errors) - if cause_str: - bpe.__cause__ = _RemoteTraceback(f"\n'''\n{cause_str}'''") + cause_tb = f"\n'''\n{cause_str}'''" if cause_str else None # Mark pending tasks as failed. for work_id, work_item in self.pending_work_items.items(): + bpe = BrokenProcessPool("A process in the process pool was " + "terminated abruptly while the future was " + "running or pending.") + if cause_tb is not None: + bpe.__cause__ = _RemoteTraceback(cause_tb) try: work_item.future.set_exception(bpe) except _base.InvalidStateError: diff --git a/Lib/test/test_concurrent_futures/test_process_pool.py b/Lib/test/test_concurrent_futures/test_process_pool.py index 731419a48bd128..56cc38984a2cb3 100644 --- a/Lib/test/test_concurrent_futures/test_process_pool.py +++ b/Lib/test/test_concurrent_futures/test_process_pool.py @@ -3,6 +3,7 @@ import sys import threading import time +import traceback import unittest import unittest.mock from concurrent import futures @@ -62,6 +63,32 @@ def test_killed_child(self): # Submitting other jobs fails as well. self.assertRaises(BrokenProcessPool, self.executor.submit, pow, 2, 8) + @warnings_helper.ignore_fork_in_thread_deprecation_warnings() + def test_broken_process_pool_traceback(self): + # When a child process is abruptly terminated, the whole pool gets + # "broken", and a BrokenProcessPool exception should be created + # for each future instead of sharing one exception among all futures. + event = self.create_event() + futures = [self.executor.submit(event.wait) for _ in range(3)] + p = next(iter(self.executor._processes.values())) + p.terminate() + for fut in futures: + # Don't use assertRaises(): it clears the traceback off exc. + try: + fut.result() + except BrokenProcessPool as exc: + tb = exc.__traceback__ + else: + self.fail("BrokenProcessPool not raised") + count = sum( + 1 + for frame_summary in traceback.extract_tb(tb) + if frame_summary.filename == __file__ + ) + # This code file should appear exactly once in the traceback. + # A shared exception would accumulate a frame per result() call. + self.assertEqual(count, 1) + @warnings_helper.ignore_fork_in_thread_deprecation_warnings() def test_map_chunksize(self): def bad_map(): diff --git a/Misc/ACKS b/Misc/ACKS index 14f0db7549534b..38817b1698c09a 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1762,6 +1762,7 @@ Charlie Shepherd Bruce Sherwood Gregory Shevchenko Hai Shi +Daniel Shields Alexander Shigin Pete Shinners Michael Shiplett diff --git a/Misc/NEWS.d/next/Library/2023-01-23-21-23-50.gh-issue-101267._f-cFH.rst b/Misc/NEWS.d/next/Library/2023-01-23-21-23-50.gh-issue-101267._f-cFH.rst new file mode 100644 index 00000000000000..901a3fb60ab5b9 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-01-23-21-23-50.gh-issue-101267._f-cFH.rst @@ -0,0 +1,7 @@ +When a worker process terminates unexpectedly, +:class:`concurrent.futures.ProcessPoolExecutor` now sets a separate +:exc:`~concurrent.futures.process.BrokenProcessPool` exception on each pending +future instead of sharing a single instance among them all. Sharing one +exception produced malformed tracebacks: each +:meth:`Future.result() <concurrent.futures.Future.result>` call re-raised the +same object, appending another copy of the traceback to it. From 5156e8fb0d846cfba2791ce4c134d1034d609b50 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 13 Jun 2026 15:00:54 +0200 Subject: [PATCH 325/818] [3.15] gh-77328: Update `base64` module RFC references to RFC 4648 (GH-151275) (#151438) (cherry picked from commit e9339876883f96af2e406a92a05be647b7fbe5d5) Co-authored-by: Stan Ulbrych <stan@python.org> --- Lib/base64.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Lib/base64.py b/Lib/base64.py index 4a0e9d446edb0b..fa562f74a81034 100644 --- a/Lib/base64.py +++ b/Lib/base64.py @@ -1,4 +1,4 @@ -"""Base16, Base32, Base64 (RFC 3548), Base85 and Ascii85 data encodings""" +"""Base16, Base32, Base64 (RFC 4648), Base85 and Ascii85 data encodings""" # Modified 04-Oct-1995 by Jack Jansen to use binascii module # Modified 30-Dec-2003 by Barry Warsaw to add full RFC 3548 support @@ -219,7 +219,7 @@ def urlsafe_b64decode(s, *, padded=False): characters present in the input. ''' _B32_DECODE_MAP01_DOCSTRING = ''' -RFC 3548 allows for optional mapping of the digit 0 (zero) to the +RFC 4648 allows for optional mapping of the digit 0 (zero) to the letter O (oh), and for optional mapping of the digit 1 (one) to either the letter I (eye) or letter L (el). The optional argument map01 when not None, specifies which letter the digit 1 should be @@ -266,7 +266,7 @@ def b32hexdecode(s, casefold=False, *, padded=True, ignorechars=b'', extra_args='') -# RFC 3548, Base 16 Alphabet specifies uppercase, but hexlify() returns +# RFC 4648, Base 16 Alphabet specifies uppercase, but hexlify() returns # lowercase. The RFC also recommends against accepting input case # insensitively. def b16encode(s, *, wrapcol=0): From 56ad6505e193ab98bf661daf770dea161d83965d Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 13 Jun 2026 20:39:44 +0200 Subject: [PATCH 326/818] [3.15] gh-151443: Fix documented default of `unittest.mock.mock_open`'s `read_data` parameter (GH-151444) (#151450) (cherry picked from commit 9ad6ba0324a71ae5b51ded6e59b1ea3b653814a5) Co-authored-by: Shardul Deshpande <iamsharduld@users.noreply.github.com> --- Doc/library/unittest.mock.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/unittest.mock.rst b/Doc/library/unittest.mock.rst index 6ba1b87ea942a9..5e28a8ada595ef 100644 --- a/Doc/library/unittest.mock.rst +++ b/Doc/library/unittest.mock.rst @@ -2539,7 +2539,7 @@ Alternatively you can just use ``vars(my_mock)`` (instance members) and mock_open ~~~~~~~~~ -.. function:: mock_open(mock=None, read_data=None) +.. function:: mock_open(mock=None, read_data='') A helper function to create a mock to replace the use of :func:`open`. It works for :func:`open` called directly or used as a context manager. From 5dd32176a1802da2d849060a87ad1907d4fc0b38 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 13 Jun 2026 23:32:48 +0200 Subject: [PATCH 327/818] [3.15] gh-151403: Fix use-after-free when an argv item's __fspath__ mutates args (GH-151404) (#151445) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gh-151403: Fix use-after-free when an argv item's __fspath__ mutates args (GH-151404) --------- (cherry picked from commit 6679ac07d881f6e0ce30b7cc28b5671eafa20d9d) Co-authored-by: tonghuaroot (童话) <tonghuaroot@gmail.com> Co-authored-by: tonghuaroot <23011166+tonghuaroot@users.noreply.github.com> --- .../2026-06-12-22-46-31.gh-issue-151403.DalZWh.rst | 3 +++ Modules/_posixsubprocess.c | 8 +++++++- 2 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2026-06-12-22-46-31.gh-issue-151403.DalZWh.rst diff --git a/Misc/NEWS.d/next/Library/2026-06-12-22-46-31.gh-issue-151403.DalZWh.rst b/Misc/NEWS.d/next/Library/2026-06-12-22-46-31.gh-issue-151403.DalZWh.rst new file mode 100644 index 00000000000000..ca779ed684e761 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-12-22-46-31.gh-issue-151403.DalZWh.rst @@ -0,0 +1,3 @@ +Fixed a crash in :class:`subprocess.Popen` (and ``_posixsubprocess.fork_exec``) +when an ``argv`` item's :meth:`~os.PathLike.__fspath__` concurrently mutates the +``args`` sequence being converted. diff --git a/Modules/_posixsubprocess.c b/Modules/_posixsubprocess.c index bcee5633987797..f42c990700b422 100644 --- a/Modules/_posixsubprocess.c +++ b/Modules/_posixsubprocess.c @@ -1090,8 +1090,14 @@ subprocess_fork_exec_impl(PyObject *module, PyObject *process_args, goto cleanup; } borrowed_arg = PySequence_Fast_GET_ITEM(fast_args, arg_num); - if (PyUnicode_FSConverter(borrowed_arg, &converted_arg) == 0) + /* borrowed_arg is only borrowed; its __fspath__() may run Python + that drops fast_args' last reference to it. */ + Py_INCREF(borrowed_arg); + if (PyUnicode_FSConverter(borrowed_arg, &converted_arg) == 0) { + Py_DECREF(borrowed_arg); goto cleanup; + } + Py_DECREF(borrowed_arg); PyTuple_SET_ITEM(converted_args, arg_num, converted_arg); } From 75289a92dfb460acde427b9f399881a108427b6c Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 14 Jun 2026 01:40:19 +0200 Subject: [PATCH 328/818] [3.15] gh-151424: Fix impossible stack traces in `RemoteUnwinder(..., cache_frames=True)` by copying chunks on cache miss (GH-151426) (#151459) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gh-151424: Fix impossible stack traces in `RemoteUnwinder(..., cache_frames=True)` by copying chunks on cache miss (GH-151426) (cherry picked from commit 6ce088e20a13ac25320d94c5775bb1a4edc75ba4) Co-authored-by: Maurycy Pawłowski-Wieroński <maurycy@maurycy.com> --- .../2026-06-13-04-11-00.gh-issue-151426.f2V67e.rst | 4 ++++ Modules/_remote_debugging/frames.c | 8 ++++++++ 2 files changed, 12 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2026-06-13-04-11-00.gh-issue-151426.f2V67e.rst diff --git a/Misc/NEWS.d/next/Library/2026-06-13-04-11-00.gh-issue-151426.f2V67e.rst b/Misc/NEWS.d/next/Library/2026-06-13-04-11-00.gh-issue-151426.f2V67e.rst new file mode 100644 index 00000000000000..428302e5f847f3 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-13-04-11-00.gh-issue-151426.f2V67e.rst @@ -0,0 +1,4 @@ +Fix impossible stack traces (callers and callees cross called, orphans and +incorrect lines) in the Tachyon profiler when caching frames, by snapshotting +the stack chunks before walking the frame chain on a cache miss. Patch by +Maurycy Pawłowski-Wieroński. diff --git a/Modules/_remote_debugging/frames.c b/Modules/_remote_debugging/frames.c index d73cd080dc477f..e7d2a276439026 100644 --- a/Modules/_remote_debugging/frames.c +++ b/Modules/_remote_debugging/frames.c @@ -580,6 +580,14 @@ collect_frames_with_cache( return full_hit < 0 ? -1 : 0; } + assert(ctx->chunks != NULL); + + if (ctx->chunks->count == 0) { + if (copy_stack_chunks(unwinder, ctx->thread_state_addr, ctx->chunks) < 0) { + PyErr_Clear(); + } + } + Py_ssize_t frames_before = PyList_GET_SIZE(ctx->frame_info); if (process_frame_chain(unwinder, ctx) < 0) { From 03873bb5f0ca3a7f426c1d30a273238f3ca75b7a Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 14 Jun 2026 14:47:39 +0200 Subject: [PATCH 329/818] [3.15] gh-139837: Document attributes of objects recorded by warnings.catch_warnings (GH-139893) (GH-151472) (cherry picked from commit 47b7dc788c9bcf3d5ea69a2ea0aed3d5883647a8) Co-authored-by: Aniket <148300120+Aniketsy@users.noreply.github.com> Co-authored-by: Victor Stinner <vstinner@python.org> --- Doc/library/warnings.rst | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/Doc/library/warnings.rst b/Doc/library/warnings.rst index b25384dbfce54b..9063bea96ccb0a 100644 --- a/Doc/library/warnings.rst +++ b/Doc/library/warnings.rst @@ -626,9 +626,28 @@ Available Context Managers If the *record* argument is :const:`False` (the default) the context manager returns :class:`None` on entry. If *record* is :const:`True`, a list is returned that is progressively populated with objects as seen by a custom - :func:`showwarning` function (which also suppresses output to ``sys.stdout``). - Each object in the list has attributes with the same names as the arguments to - :func:`showwarning`. + :func:`showwarning` function (which also suppresses output to ``sys.stderr``). + Each object in the list is guaranteed to have the following attributes: + + - ``message``: the warning message (an instance of :exc:`Warning`) + - ``category``: the warning category (a subclass of :exc:`Warning`) + - ``filename``: the file name where the warning occurred (:class:`str`) + - ``lineno``: the line number in the file (:class:`int`) + - ``file``: the file object used for output (if any), or ``None`` + - ``line``: the line of source code (if available), or ``None`` + - ``source``: the original object that generated the warning (if + available), or ``None`` + - ``module``: the module name where the warning occurred + (:class:`str`), or ``None`` + + .. versionchanged:: 3.6 + The ``source`` attribute was added. + + .. versionchanged:: 3.15 + The ``module`` attribute was added. + + The type of these objects is not specified and may change; only the + presence of these attributes is guaranteed. The *module* argument takes a module that will be used instead of the module returned when you import :mod:`!warnings` whose filter will be From 89e178d78cb297755ddb58b55e42e74ed31aa810 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 14 Jun 2026 14:58:37 +0200 Subject: [PATCH 330/818] [3.15] gh-151461: Fix encoding-related exception handling in file tokenizer (GH-151462) (GH-151470) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (cherry picked from commit f1a5f68e3761e010ccd4dda1342500c5ae40bbc4) Co-authored-by: Bartosz Sławecki <bartosz@ilikepython.com> --- Lib/test/test_source_encoding.py | 17 ++++++- ...-06-14-05-05-15.gh-issue-151461.5q0s88.rst | 3 ++ Parser/pegen.c | 5 +- Parser/pegen.h | 1 - Parser/pegen_errors.c | 47 ----------------- Parser/tokenizer/helpers.c | 51 ++++++++++++++++++- Parser/tokenizer/helpers.h | 1 + 7 files changed, 72 insertions(+), 53 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-14-05-05-15.gh-issue-151461.5q0s88.rst diff --git a/Lib/test/test_source_encoding.py b/Lib/test/test_source_encoding.py index 8ac64b3105708f..53fffe7cfb56d0 100644 --- a/Lib/test/test_source_encoding.py +++ b/Lib/test/test_source_encoding.py @@ -387,8 +387,7 @@ def test_utf8_non_utf8_third_line_error(self): b'#third\xa4\n' b'raise RuntimeError\n') self.check_script_error(src, - br"'utf-8' codec can't decode byte|" - br"encoding problem: utf8") + br"'utf-8' codec can't decode byte") def test_crlf(self): src = (b'print(ascii("""\r\n"""))\n') @@ -540,6 +539,20 @@ def check_script_error(self, src, expected, lineno=...): line = line.removeprefix('\ufeff') self.assertIn(line.encode(), err) + def test_coding_spec_unknown_encoding(self): + src = (b'# coding: c1252\n' + b'print("Hi!")\n') + self.check_script_error(src, br"unknown encoding: c1252") + + def test_coding_spec_decode_error(self): + src = (b'# coding: shift-jis\n' + b'print("\xc4\x85")\n') + self.check_script_error(src, br"'shift_jis' codec can't decode byte") + + def test_coding_spec_non_text_encoding(self): + src = (b'# coding: hex_codec\n' + b'print("eggs")\n') + self.check_script_error(src, br"'hex_codec' is not a text encoding") if __name__ == "__main__": diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-14-05-05-15.gh-issue-151461.5q0s88.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-14-05-05-15.gh-issue-151461.5q0s88.rst new file mode 100644 index 00000000000000..d76a9bc95278bc --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-14-05-05-15.gh-issue-151461.5q0s88.rst @@ -0,0 +1,3 @@ +Fix direct execution of files with invalid source encodings to report the +underlying codec lookup or decoding error instead of the generic +``SyntaxError: encoding problem`` message. Patch by Bartosz Sławecki. diff --git a/Parser/pegen.c b/Parser/pegen.c index 569f5afb312008..bb222b50fc095f 100644 --- a/Parser/pegen.c +++ b/Parser/pegen.c @@ -9,6 +9,7 @@ #include "lexer/lexer.h" #include "tokenizer/tokenizer.h" +#include "tokenizer/helpers.h" #include "pegen.h" // Internal parser functions @@ -993,7 +994,7 @@ _PyPegen_run_parser_from_file_pointer(FILE *fp, int start_rule, PyObject *filena struct tok_state *tok = _PyTokenizer_FromFile(fp, enc, ps1, ps2); if (tok == NULL) { if (PyErr_Occurred()) { - _PyPegen_raise_tokenizer_init_error(filename_ob); + _PyTokenizer_raise_init_error(filename_ob); return NULL; } return NULL; @@ -1051,7 +1052,7 @@ _PyPegen_run_parser_from_string(const char *str, int start_rule, PyObject *filen } if (tok == NULL) { if (PyErr_Occurred()) { - _PyPegen_raise_tokenizer_init_error(filename_ob); + _PyTokenizer_raise_init_error(filename_ob); } return NULL; } diff --git a/Parser/pegen.h b/Parser/pegen.h index 85c9ada765d9bd..5c461e82a7f0fa 100644 --- a/Parser/pegen.h +++ b/Parser/pegen.h @@ -174,7 +174,6 @@ typedef enum { } TARGETS_TYPE; int _Pypegen_raise_decode_error(Parser *p); -void _PyPegen_raise_tokenizer_init_error(PyObject *filename); int _Pypegen_tokenizer_error(Parser *p); void *_PyPegen_raise_error(Parser *p, PyObject *errtype, int use_mark, const char *errmsg, ...); void *_PyPegen_raise_error_known_location(Parser *p, PyObject *errtype, diff --git a/Parser/pegen_errors.c b/Parser/pegen_errors.c index 312699415efd9a..b13e1c079220a9 100644 --- a/Parser/pegen_errors.c +++ b/Parser/pegen_errors.c @@ -10,53 +10,6 @@ // TOKENIZER ERRORS -void -_PyPegen_raise_tokenizer_init_error(PyObject *filename) -{ - if (!(PyErr_ExceptionMatches(PyExc_LookupError) - || PyErr_ExceptionMatches(PyExc_SyntaxError) - || PyErr_ExceptionMatches(PyExc_ValueError) - || PyErr_ExceptionMatches(PyExc_UnicodeDecodeError))) { - return; - } - PyObject *errstr = NULL; - PyObject *tuple = NULL; - PyObject *type; - PyObject *value; - PyObject *tback; - PyErr_Fetch(&type, &value, &tback); - if (PyErr_GivenExceptionMatches(value, PyExc_SyntaxError)) { - if (PyObject_SetAttr(value, &_Py_ID(filename), filename)) { - goto error; - } - PyErr_Restore(type, value, tback); - return; - } - errstr = PyObject_Str(value); - if (!errstr) { - goto error; - } - - PyObject *tmp = Py_BuildValue("(OiiO)", filename, 0, -1, Py_None); - if (!tmp) { - goto error; - } - - tuple = _PyTuple_FromPair(errstr, tmp); - Py_DECREF(tmp); - if (!tuple) { - goto error; - } - PyErr_SetObject(PyExc_SyntaxError, tuple); - -error: - Py_XDECREF(type); - Py_XDECREF(value); - Py_XDECREF(tback); - Py_XDECREF(errstr); - Py_XDECREF(tuple); -} - static inline void raise_unclosed_parentheses_error(Parser *p) { int error_lineno = p->tok->parenlinenostack[p->tok->level-1]; diff --git a/Parser/tokenizer/helpers.c b/Parser/tokenizer/helpers.c index c69e66d0ab9b7a..62b0971d418c39 100644 --- a/Parser/tokenizer/helpers.c +++ b/Parser/tokenizer/helpers.c @@ -1,6 +1,8 @@ #include "Python.h" #include "errcode.h" +#include "pycore_runtime.h" // _Py_ID() #include "pycore_token.h" +#include "pycore_tuple.h" // _PyTuple_FromPair #include "../lexer/state.h" @@ -149,6 +151,53 @@ _PyTokenizer_warn_invalid_escape_sequence(struct tok_state *tok, int first_inval return 0; } +void +_PyTokenizer_raise_init_error(PyObject *filename) +{ + if (!(PyErr_ExceptionMatches(PyExc_LookupError) + || PyErr_ExceptionMatches(PyExc_SyntaxError) + || PyErr_ExceptionMatches(PyExc_ValueError) + || PyErr_ExceptionMatches(PyExc_UnicodeDecodeError))) { + return; + } + PyObject *errstr = NULL; + PyObject *tuple = NULL; + PyObject *type; + PyObject *value; + PyObject *tback; + PyErr_Fetch(&type, &value, &tback); + if (PyErr_GivenExceptionMatches(value, PyExc_SyntaxError)) { + if (PyObject_SetAttr(value, &_Py_ID(filename), filename)) { + goto error; + } + PyErr_Restore(type, value, tback); + return; + } + errstr = PyObject_Str(value); + if (!errstr) { + goto error; + } + + PyObject *tmp = Py_BuildValue("(OiiO)", filename, 0, -1, Py_None); + if (!tmp) { + goto error; + } + + tuple = _PyTuple_FromPair(errstr, tmp); + Py_DECREF(tmp); + if (!tuple) { + goto error; + } + PyErr_SetObject(PyExc_SyntaxError, tuple); + +error: + Py_XDECREF(type); + Py_XDECREF(value); + Py_XDECREF(tback); + Py_XDECREF(errstr); + Py_XDECREF(tuple); +} + int _PyTokenizer_parser_warn(struct tok_state *tok, PyObject *category, const char *format, ...) { @@ -418,8 +467,8 @@ _PyTokenizer_check_coding_spec(const char* line, Py_ssize_t size, struct tok_sta if (tok->encoding == NULL) { assert(tok->decoding_readline == NULL); if (strcmp(cs, "utf-8") != 0 && !set_readline(tok, cs)) { + _PyTokenizer_raise_init_error(tok->filename); _PyTokenizer_error_ret(tok); - PyErr_Format(PyExc_SyntaxError, "encoding problem: %s", cs); PyMem_Free(cs); return 0; } diff --git a/Parser/tokenizer/helpers.h b/Parser/tokenizer/helpers.h index 98f6445d5a3b40..34303999a60aff 100644 --- a/Parser/tokenizer/helpers.h +++ b/Parser/tokenizer/helpers.h @@ -15,6 +15,7 @@ int _PyTokenizer_indenterror(struct tok_state *tok); int _PyTokenizer_warn_invalid_escape_sequence(struct tok_state *tok, int first_invalid_escape_char); int _PyTokenizer_parser_warn(struct tok_state *tok, PyObject *category, const char *format, ...); char *_PyTokenizer_error_ret(struct tok_state *tok); +void _PyTokenizer_raise_init_error(PyObject *filename); char *_PyTokenizer_new_string(const char *s, Py_ssize_t len, struct tok_state *tok); char *_PyTokenizer_translate_newlines(const char *s, int exec_input, int preserve_crlf, struct tok_state *tok); From 114a7a86a9aff0de538ae5485093fe052f7d8b24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartosz=20S=C5=82awecki?= <bartosz@ilikepython.com> Date: Sun, 14 Jun 2026 18:38:07 +0200 Subject: [PATCH 331/818] [3.15] gh-151390: Colorize `match +` and `match -` in the REPL (GH-151391) (#151476) (cherry picked from commit a7007322c2a70b01e7c2a9e6b3f8f222d241c7d7) --- Lib/_pyrepl/utils.py | 2 +- Lib/test/test_pyrepl/test_utils.py | 16 ++++++++++++++++ ...6-06-12-07-20-08.gh-issue-151390.CmYN9EeJ.rst | 1 + 3 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2026-06-12-07-20-08.gh-issue-151390.CmYN9EeJ.rst diff --git a/Lib/_pyrepl/utils.py b/Lib/_pyrepl/utils.py index b50426c31ead53..4d1f936b4224ad 100644 --- a/Lib/_pyrepl/utils.py +++ b/Lib/_pyrepl/utils.py @@ -259,7 +259,7 @@ def is_soft_keyword_used(*tokens: TI | None) -> bool: None | TI(T.NEWLINE) | TI(T.INDENT) | TI(string=":"), TI(string="match"), TI(T.NUMBER | T.STRING | T.FSTRING_START | T.TSTRING_START) - | TI(T.OP, string="(" | "*" | "[" | "{" | "~" | "...") + | TI(T.OP, string="(" | "*" | "-" | "+" | "[" | "{" | "~" | "...") ): return True case ( diff --git a/Lib/test/test_pyrepl/test_utils.py b/Lib/test/test_pyrepl/test_utils.py index 3c55b6bdaeee9e..e8157f164b3063 100644 --- a/Lib/test/test_pyrepl/test_utils.py +++ b/Lib/test/test_pyrepl/test_utils.py @@ -125,6 +125,22 @@ def test_gen_colors_keyword_highlighting(self): ("import", "keyword"), ], ), + ( + "match +1", + [ + ("match", "soft_keyword"), + ("+", "op"), + ("1", "number"), + ], + ), + ( + "match -1", + [ + ("match", "soft_keyword"), + ("-", "op"), + ("1", "number"), + ], + ), ] for code, expected_highlights in cases: with self.subTest(code=code): diff --git a/Misc/NEWS.d/next/Library/2026-06-12-07-20-08.gh-issue-151390.CmYN9EeJ.rst b/Misc/NEWS.d/next/Library/2026-06-12-07-20-08.gh-issue-151390.CmYN9EeJ.rst new file mode 100644 index 00000000000000..ff8de30599c6ad --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-12-07-20-08.gh-issue-151390.CmYN9EeJ.rst @@ -0,0 +1 @@ +Colorize ``match`` in the :term:`REPL` when followed by a unary ``+`` or ``-`` operator. Patch by Bartosz Sławecki. From 1b457d3bbc528184f373bdcac47f0951052f90b7 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 14 Jun 2026 20:37:23 +0200 Subject: [PATCH 332/818] [3.15] Skip test_highly_nested_objects_decoding during the PGO profile task. (GH-151460) (#151468) Skip test_highly_nested_objects_decoding during the PGO profile task. (GH-151460) Since the recursion guard tracks real C-stack bounds (gh-91079), this test asserts that 500k nesting levels overflow the stack margin. On a 64 MiB stack (some Nix build envs use one that large), the optimized interpreter uses ~160 bytes/level (raises at ~420k levels) so the assertion holds with only ~16% margin; the PGO *instrumented* stage inlines less, its per-level scanner frames are smaller, and the 500k-deep decode completes -- "RecursionError not raised" fails the profile run and aborts `make profile-opt`. Upstream's skip_if_unlimited_stack_size (gh-143460) only covers RLIM_INFINITY, not large-finite stacks like ours. We could also keep playing whack a mole and raise the 500k to a much larger number... but there's little value in PGO training on this test anyways. (cherry picked from commit e91f68ab40e25dc964afb872eb75873c8b1838d6) Co-authored-by: Gregory P. Smith <68491+gpshead@users.noreply.github.com> --- Lib/test/test_json/test_recursion.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Lib/test/test_json/test_recursion.py b/Lib/test/test_json/test_recursion.py index ffd3404e6f77a0..d732fc80cf1cf3 100644 --- a/Lib/test/test_json/test_recursion.py +++ b/Lib/test/test_json/test_recursion.py @@ -68,6 +68,7 @@ def default(self, o): self.fail("didn't raise ValueError on default recursion") + @support.skip_if_pgo_task # fails during PGO training w/ some stack sizes @support.skip_if_unlimited_stack_size @support.skip_emscripten_stack_overflow() @support.skip_wasi_stack_overflow() From f7ab7c4462501fa42399cdd76ae3a10bde43d9a6 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 15 Jun 2026 11:01:30 +0200 Subject: [PATCH 333/818] [3.15] gh-149671: Restore compatibility with setuptools -nspkg.pth files in site module (GH-151319) (#151489) gh-149671: Restore compatibility with setuptools -nspkg.pth files in site module (GH-151319) Inject the "sitedir" variable in the frame which executes ".pth" code. (cherry picked from commit 18f3ffec43b98db34c6d378cfc012814a901bb41) Co-authored-by: Victor Stinner <vstinner@python.org> --- Lib/site.py | 5 +++++ Lib/test/test_site.py | 14 ++++++++++++++ .../2026-06-11-11-52-23.gh-issue-149671.6Rpr5r.rst | 3 +++ 3 files changed, 22 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2026-06-11-11-52-23.gh-issue-149671.6Rpr5r.rst diff --git a/Lib/site.py b/Lib/site.py index b7f5c7f0246bc1..d06549b8df800e 100644 --- a/Lib/site.py +++ b/Lib/site.py @@ -505,6 +505,11 @@ def _exec_imports(self): # batch. In that case, PEP 829 says the import lines are # suppressed in favor of the .start's entry points. for filename, imports in self._importexecs.items(): + # Inject 'sitedir' local variable in the current frame for + # compatibility with Python 3.14. Especially, "-nspkg.pth" files + # generated by setuptools use: sys._getframe(1).f_locals['sitedir']. + sitedir = os.path.dirname(filename) + # Given "/path/to/foo.pth", check whether "/path/to/foo.start" was # registered in this same batch. name, dot, pth = filename.rpartition(".") diff --git a/Lib/test/test_site.py b/Lib/test/test_site.py index 5fd65ad999210e..bcb51ed7d8476a 100644 --- a/Lib/test/test_site.py +++ b/Lib/test/test_site.py @@ -233,6 +233,20 @@ def test_addsitedir_hidden_file_attribute(self): self.assertNotIn(site.makepath(pth_file.good_dir_path)[0], sys.path) self.assertIn(pth_file.base_dir, sys.path) + def test_sitedir_variable(self): + # gh-149671: setuptools use of `-nspkg.pth` files in Python < 3.15. + code = '; '.join(( + # Code used by "-nspkg.pth" files generated by setuptools. + "import sys", + "sitedir = sys._getframe(1).f_locals['sitedir']", + "print(sitedir)", + )) + pth_dir, pth_fn = self.make_pth(code) + with support.captured_stdout() as stdout: + known_paths = site.addpackage(pth_dir, pth_fn, set()) + sitedir = stdout.getvalue().rstrip() + self.assertEqual(sitedir, pth_dir) + # This tests _getuserbase, hence the double underline # to distinguish from a test for getuserbase def test__getuserbase(self): diff --git a/Misc/NEWS.d/next/Library/2026-06-11-11-52-23.gh-issue-149671.6Rpr5r.rst b/Misc/NEWS.d/next/Library/2026-06-11-11-52-23.gh-issue-149671.6Rpr5r.rst new file mode 100644 index 00000000000000..5c08828e5fd77e --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-11-11-52-23.gh-issue-149671.6Rpr5r.rst @@ -0,0 +1,3 @@ +Restore compatibility with setuptools ``-nspkg.pth`` files in the :mod:`site` +module. Inject ``sitedir`` variable in the frame which executes pth code. +Patch by Victor Stinner. From cc91b26ce1a0991cf68fcc1678424a2b787eae50 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 15 Jun 2026 11:42:09 +0200 Subject: [PATCH 334/818] [3.15] Add `.toml` to `.editorconfig` (GH-151481) (#151491) Add `.toml` to `.editorconfig` (GH-151481) (cherry picked from commit 7a70afa199a9bdd5bf65b2b396b9fa76c8842ac2) Co-authored-by: sobolevn <mail@sobolevn.me> --- .editorconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.editorconfig b/.editorconfig index 25bc5935258bd1..ab1f7ce8425769 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,11 +1,11 @@ root = true -[*.{py,c,cpp,h,js,rst,md,yml,yaml,gram}] +[*.{py,c,cpp,h,js,rst,md,yml,yaml,toml,gram}] trim_trailing_whitespace = true insert_final_newline = true indent_style = space -[*.{py,c,cpp,h,gram}] +[*.{py,c,cpp,h,toml,gram}] indent_size = 4 [*.rst] From b5eea71702cb9ecff6b79c72b1f680ae88617316 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 15 Jun 2026 16:55:27 +0200 Subject: [PATCH 335/818] [3.15] gh-148853: Catch PermissionError in test in_systemd_nspawn_sync_suppressed() (GH-148854) (#151506) gh-148853: Catch PermissionError in test in_systemd_nspawn_sync_suppressed() (GH-148854) /run/ on my FreeBSD install is not readable causing failing test. (cherry picked from commit 35ce2e5f98c04cb8d1e442de5439d3151362e21b) Co-authored-by: Nick Begg <nick@stunttruck.net> Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com> --- Lib/test/support/__init__.py | 2 +- .../next/Tests/2026-04-24-01-38-56.gh-issue-148853._uM4_Q.rst | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Tests/2026-04-24-01-38-56.gh-issue-148853._uM4_Q.rst diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index f9601655dfe157..ebbce63852c4b8 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -3164,7 +3164,7 @@ def in_systemd_nspawn_sync_suppressed() -> bool: with open("/run/systemd/container", "rb") as fp: if fp.read().rstrip() != b"systemd-nspawn": return False - except FileNotFoundError: + except (FileNotFoundError, PermissionError): return False # If systemd-nspawn is used, O_SYNC flag will immediately diff --git a/Misc/NEWS.d/next/Tests/2026-04-24-01-38-56.gh-issue-148853._uM4_Q.rst b/Misc/NEWS.d/next/Tests/2026-04-24-01-38-56.gh-issue-148853._uM4_Q.rst new file mode 100644 index 00000000000000..9d3fbc2590dc7a --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2026-04-24-01-38-56.gh-issue-148853._uM4_Q.rst @@ -0,0 +1,2 @@ +Fix tests failing on FreeBSD in test.support's +in_systemd_nspawn_sync_suppressed() due to unreadable /run directory. From 255b3fff97ff31c95c3cfeb56d85c304642d864d Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 15 Jun 2026 19:22:52 +0200 Subject: [PATCH 336/818] [3.15] gh-151223: fix tsan data races in load global specializations (GH-151393) (#151513) gh-151223: fix tsan data races in load global specializations (GH-151393) (cherry picked from commit e9d5280f6c040f859907eb3c04ec308f4918db9f) Co-authored-by: Kumar Aditya <kumaraditya@python.org> --- Modules/_testinternalcapi/test_cases.c.h | 6 +++--- Python/bytecodes.c | 6 +++--- Python/executor_cases.c.h | 6 +++--- Python/generated_cases.c.h | 6 +++--- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Modules/_testinternalcapi/test_cases.c.h b/Modules/_testinternalcapi/test_cases.c.h index a2506524f0bb6d..aa4419b323e5b3 100644 --- a/Modules/_testinternalcapi/test_cases.c.h +++ b/Modules/_testinternalcapi/test_cases.c.h @@ -8841,7 +8841,7 @@ assert(keys->dk_kind == DICT_KEYS_UNICODE); assert(index < FT_ATOMIC_LOAD_SSIZE_RELAXED(keys->dk_nentries)); PyDictUnicodeEntry *ep = DK_UNICODE_ENTRIES(keys) + index; - PyObject *attr_o = FT_ATOMIC_LOAD_PTR_RELAXED(ep->me_value); + PyObject *attr_o = FT_ATOMIC_LOAD_PTR_CONSUME(ep->me_value); if (attr_o == NULL) { UPDATE_MISS_STATS(LOAD_ATTR); assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); @@ -9729,7 +9729,7 @@ } assert(keys->dk_kind == DICT_KEYS_UNICODE); PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(keys); - PyObject *res_o = FT_ATOMIC_LOAD_PTR_RELAXED(entries[index].me_value); + PyObject *res_o = FT_ATOMIC_LOAD_PTR_CONSUME(entries[index].me_value); if (res_o == NULL) { UPDATE_MISS_STATS(LOAD_GLOBAL); assert(_PyOpcode_Deopt[opcode] == (LOAD_GLOBAL)); @@ -9796,7 +9796,7 @@ assert(keys->dk_kind == DICT_KEYS_UNICODE); PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(keys); assert(index < DK_SIZE(keys)); - PyObject *res_o = FT_ATOMIC_LOAD_PTR_RELAXED(entries[index].me_value); + PyObject *res_o = FT_ATOMIC_LOAD_PTR_CONSUME(entries[index].me_value); if (res_o == NULL) { UPDATE_MISS_STATS(LOAD_GLOBAL); assert(_PyOpcode_Deopt[opcode] == (LOAD_GLOBAL)); diff --git a/Python/bytecodes.c b/Python/bytecodes.c index f7487c7136962f..c77823b78eadc1 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -2348,7 +2348,7 @@ dummy_func( assert(keys->dk_kind == DICT_KEYS_UNICODE); PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(keys); assert(index < DK_SIZE(keys)); - PyObject *res_o = FT_ATOMIC_LOAD_PTR_RELAXED(entries[index].me_value); + PyObject *res_o = FT_ATOMIC_LOAD_PTR_CONSUME(entries[index].me_value); DEOPT_IF(res_o == NULL); #if Py_GIL_DISABLED int increfed = _Py_TryIncrefCompareStackRef(&entries[index].me_value, res_o, &res); @@ -2367,7 +2367,7 @@ dummy_func( DEOPT_IF(FT_ATOMIC_LOAD_UINT32_RELAXED(keys->dk_version) != version); assert(keys->dk_kind == DICT_KEYS_UNICODE); PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(keys); - PyObject *res_o = FT_ATOMIC_LOAD_PTR_RELAXED(entries[index].me_value); + PyObject *res_o = FT_ATOMIC_LOAD_PTR_CONSUME(entries[index].me_value); DEOPT_IF(res_o == NULL); #if Py_GIL_DISABLED int increfed = _Py_TryIncrefCompareStackRef(&entries[index].me_value, res_o, &res); @@ -2957,7 +2957,7 @@ dummy_func( assert(keys->dk_kind == DICT_KEYS_UNICODE); assert(index < FT_ATOMIC_LOAD_SSIZE_RELAXED(keys->dk_nentries)); PyDictUnicodeEntry *ep = DK_UNICODE_ENTRIES(keys) + index; - PyObject *attr_o = FT_ATOMIC_LOAD_PTR_RELAXED(ep->me_value); + PyObject *attr_o = FT_ATOMIC_LOAD_PTR_CONSUME(ep->me_value); EXIT_IF(attr_o == NULL); #ifdef Py_GIL_DISABLED int increfed = _Py_TryIncrefCompareStackRef(&ep->me_value, attr_o, &attr); diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index efa61d7de74e88..882201bbc06c16 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -10300,7 +10300,7 @@ assert(keys->dk_kind == DICT_KEYS_UNICODE); PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(keys); assert(index < DK_SIZE(keys)); - PyObject *res_o = FT_ATOMIC_LOAD_PTR_RELAXED(entries[index].me_value); + PyObject *res_o = FT_ATOMIC_LOAD_PTR_CONSUME(entries[index].me_value); if (res_o == NULL) { UOP_STAT_INC(uopcode, miss); SET_CURRENT_CACHED_VALUES(0); @@ -10345,7 +10345,7 @@ } assert(keys->dk_kind == DICT_KEYS_UNICODE); PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(keys); - PyObject *res_o = FT_ATOMIC_LOAD_PTR_RELAXED(entries[index].me_value); + PyObject *res_o = FT_ATOMIC_LOAD_PTR_CONSUME(entries[index].me_value); if (res_o == NULL) { UOP_STAT_INC(uopcode, miss); SET_CURRENT_CACHED_VALUES(0); @@ -12151,7 +12151,7 @@ assert(keys->dk_kind == DICT_KEYS_UNICODE); assert(index < FT_ATOMIC_LOAD_SSIZE_RELAXED(keys->dk_nentries)); PyDictUnicodeEntry *ep = DK_UNICODE_ENTRIES(keys) + index; - PyObject *attr_o = FT_ATOMIC_LOAD_PTR_RELAXED(ep->me_value); + PyObject *attr_o = FT_ATOMIC_LOAD_PTR_CONSUME(ep->me_value); if (attr_o == NULL) { UOP_STAT_INC(uopcode, miss); _tos_cache0 = owner; diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 53e09a8f4523c7..5033b994c33512 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -8840,7 +8840,7 @@ assert(keys->dk_kind == DICT_KEYS_UNICODE); assert(index < FT_ATOMIC_LOAD_SSIZE_RELAXED(keys->dk_nentries)); PyDictUnicodeEntry *ep = DK_UNICODE_ENTRIES(keys) + index; - PyObject *attr_o = FT_ATOMIC_LOAD_PTR_RELAXED(ep->me_value); + PyObject *attr_o = FT_ATOMIC_LOAD_PTR_CONSUME(ep->me_value); if (attr_o == NULL) { UPDATE_MISS_STATS(LOAD_ATTR); assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); @@ -9727,7 +9727,7 @@ } assert(keys->dk_kind == DICT_KEYS_UNICODE); PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(keys); - PyObject *res_o = FT_ATOMIC_LOAD_PTR_RELAXED(entries[index].me_value); + PyObject *res_o = FT_ATOMIC_LOAD_PTR_CONSUME(entries[index].me_value); if (res_o == NULL) { UPDATE_MISS_STATS(LOAD_GLOBAL); assert(_PyOpcode_Deopt[opcode] == (LOAD_GLOBAL)); @@ -9794,7 +9794,7 @@ assert(keys->dk_kind == DICT_KEYS_UNICODE); PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(keys); assert(index < DK_SIZE(keys)); - PyObject *res_o = FT_ATOMIC_LOAD_PTR_RELAXED(entries[index].me_value); + PyObject *res_o = FT_ATOMIC_LOAD_PTR_CONSUME(entries[index].me_value); if (res_o == NULL) { UPDATE_MISS_STATS(LOAD_GLOBAL); assert(_PyOpcode_Deopt[opcode] == (LOAD_GLOBAL)); From e2c7fa7ff65dce05b857a3bbac275894dad967ad Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 16 Jun 2026 00:45:45 +0200 Subject: [PATCH 337/818] [3.15] gh-151422: Don't link libffi into _ctypes_test.so (GH-151423) (#151516) _ctypes_test doesn't use libffi directly, and linking it into the module causes emscripten tests to fail. (cherry picked from commit 8646385076ea4f6ef08682d8ef07a544d3b4ef30) Co-authored-by: Hood Chatham <roberthoodchatham@gmail.com> --- Lib/test/test_ctypes/test_as_parameter.py | 3 ++- Lib/test/test_ctypes/test_structures.py | 7 +++++++ configure | 4 ++-- configure.ac | 4 +++- 4 files changed, 14 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_ctypes/test_as_parameter.py b/Lib/test/test_ctypes/test_as_parameter.py index 2da1acfcf2989e..c9d728e9ae2f9c 100644 --- a/Lib/test/test_ctypes/test_as_parameter.py +++ b/Lib/test/test_ctypes/test_as_parameter.py @@ -5,7 +5,7 @@ c_short, c_int, c_long, c_longlong, c_byte, c_wchar, c_float, c_double, ArgumentError) -from test.support import import_helper, skip_if_sanitizer +from test.support import import_helper, skip_if_sanitizer, skip_emscripten_stack_overflow _ctypes_test = import_helper.import_module("_ctypes_test") @@ -193,6 +193,7 @@ class S8I(Structure): (9*2, 8*3, 7*4, 6*5, 5*6, 4*7, 3*8, 2*9)) @skip_if_sanitizer('requires deep stack', thread=True) + @skip_emscripten_stack_overflow() def test_recursive_as_param(self): class A: pass diff --git a/Lib/test/test_ctypes/test_structures.py b/Lib/test/test_ctypes/test_structures.py index 92d4851d739d47..65ccc12625f72b 100644 --- a/Lib/test/test_ctypes/test_structures.py +++ b/Lib/test/test_ctypes/test_structures.py @@ -299,9 +299,16 @@ class X(Structure): self.assertEqual(s.first, got.first) self.assertEqual(s.second, got.second) + @unittest.skipIf(support.is_wasm32, "wasm ABI is incompatible with test expectations") def _test_issue18060(self, Vector): # Regression tests for gh-62260 + # This test passes a struct of two doubles by value to atan2(), whose C + # signature is atan2(double, double), so it only works on platforms + # where the abi of a function that takes a struct with two doubles + # matches the abi of a function that takes two doubles. The wasm32 ABI + # does not satisfy this condition and the test breaks. + # The call to atan2() should succeed if the # class fields were correctly cloned in the # subclasses. Otherwise, it will segfault. diff --git a/configure b/configure index 7abc41648b3c45..3a1c40e49d580b 100755 --- a/configure +++ b/configure @@ -34966,8 +34966,8 @@ fi if test "x$py_cv_module__ctypes_test" = xyes then : - as_fn_append MODULE_BLOCK "MODULE__CTYPES_TEST_CFLAGS=$LIBFFI_CFLAGS$as_nl" - as_fn_append MODULE_BLOCK "MODULE__CTYPES_TEST_LDFLAGS=$LIBFFI_LIBS $LIBM$as_nl" + + as_fn_append MODULE_BLOCK "MODULE__CTYPES_TEST_LDFLAGS=$LIBM$as_nl" fi if test "$py_cv_module__ctypes_test" = yes; then diff --git a/configure.ac b/configure.ac index 47a6e59623b830..62d761130ac07f 100644 --- a/configure.ac +++ b/configure.ac @@ -8479,9 +8479,11 @@ PY_STDLIB_MOD([_testmultiphase], [test "$TEST_MODULES" = yes], [test "$ac_cv_fun PY_STDLIB_MOD([_testsinglephase], [test "$TEST_MODULES" = yes], [test "$ac_cv_func_dlopen" = yes]) PY_STDLIB_MOD([xxsubtype], [test "$TEST_MODULES" = yes]) PY_STDLIB_MOD([_xxtestfuzz], [test "$TEST_MODULES" = yes]) +dnl Check have_libffi so _ctypes_test is only built if _ctypes is built. +dnl _ctypes_test doesn't use libffi directly. PY_STDLIB_MOD([_ctypes_test], [test "$TEST_MODULES" = yes], [test "$have_libffi" = yes -a "$ac_cv_func_dlopen" = yes], - [$LIBFFI_CFLAGS], [$LIBFFI_LIBS $LIBM]) + [], [$LIBM]) dnl Limited API template modules. dnl Emscripten does not support shared libraries yet. From 1a8e7435a5ef2b581a2866cfff28ea8de7a1c5cc Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 16 Jun 2026 07:54:42 +0200 Subject: [PATCH 338/818] [3.15] gh-151522: Guard against None transport in slow-socket SSL test (GH-151523) (#151528) gh-151522: Guard against None transport in slow-socket SSL test (GH-151523) (cherry picked from commit 11f032f904c8019b332a3c367f335e05cde63628) Co-authored-by: Itamar Oren <itamarost@gmail.com> --- Lib/test/test_asyncio/test_ssl.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Lib/test/test_asyncio/test_ssl.py b/Lib/test/test_asyncio/test_ssl.py index ca15fc3bdd42dd..784c784d261dc6 100644 --- a/Lib/test/test_asyncio/test_ssl.py +++ b/Lib/test/test_asyncio/test_ssl.py @@ -1544,6 +1544,9 @@ async def client(addr): # This triggers bug gh-115514, also tested using mocks in # test.test_asyncio.test_selector_events.SelectorSocketTransportTests.test_write_buffer_after_close socket_transport = writer.transport._ssl_protocol._transport + # connection_lost may have already cleared _transport. + if socket_transport is None: + return class SocketWrapper: def __init__(self, sock) -> None: From 488a03bd2b6ee594dfa65fbb7c1e7c60c41389c4 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 16 Jun 2026 13:52:39 +0200 Subject: [PATCH 339/818] [3.15] gh-149716: Document PySlot_DATA for Py_mod_gil and Py_mod_multiple_interpreters (GH-150053) (#151322) Co-authored-by: Taeknology <20297177+Taeknology@users.noreply.github.com> --- Doc/c-api/module.rst | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/Doc/c-api/module.rst b/Doc/c-api/module.rst index 20fd66e35a0d4d..9f68abba66bc5d 100644 --- a/Doc/c-api/module.rst +++ b/Doc/c-api/module.rst @@ -247,6 +247,15 @@ Feature slots If ``Py_mod_multiple_interpreters`` is not specified, the import machinery defaults to ``Py_MOD_MULTIPLE_INTERPRETERS_SUPPORTED``. + For historical reasons, the values are declared as pointers (``void *``). + When using :c:type:`PySlot` arrays, use :c:macro:`PySlot_DATA` for + :c:macro:`!Py_mod_multiple_interpreters`: + + .. code-block:: c + + PySlot_DATA(Py_mod_multiple_interpreters, + Py_MOD_PER_INTERPRETER_GIL_SUPPORTED) + .. versionadded:: 3.12 .. c:macro:: Py_mod_gil @@ -272,6 +281,14 @@ Feature slots If ``Py_mod_gil`` is not specified, the import machinery defaults to ``Py_MOD_GIL_USED``. + For historical reasons, the values are declared as pointers (``void *``). + When using :c:type:`PySlot` arrays, use :c:macro:`PySlot_DATA` for + :c:macro:`!Py_mod_gil`: + + .. code-block:: c + + PySlot_DATA(Py_mod_gil, Py_MOD_GIL_NOT_USED) + .. versionadded:: 3.13 From ab61101f96477df9d09ceaabe3b9219f28b1ab59 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 16 Jun 2026 14:18:56 +0200 Subject: [PATCH 340/818] [3.15] gh-150771: Fix email serialization for shift_jis and euc-jp (GH-151120) (GH-151541) Encode the payload with output_charset instead of input_charset. (cherry picked from commit 0777a58d8012bbdd0d72654b56f9112686ae6ff0) Co-authored-by: dev <b.chouksey27@gmail.com> --- Lib/email/contentmanager.py | 3 +- Lib/test/test_email/test_contentmanager.py | 40 +++++++++++++++++++ ...-06-09-12-00-00.gh-issue-150771.K7mNx2.rst | 4 ++ 3 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2026-06-09-12-00-00.gh-issue-150771.K7mNx2.rst diff --git a/Lib/email/contentmanager.py b/Lib/email/contentmanager.py index faf2626bccce65..c0090af716575d 100644 --- a/Lib/email/contentmanager.py +++ b/Lib/email/contentmanager.py @@ -174,7 +174,8 @@ def set_text_content(msg, string, subtype="plain", charset='utf-8', cte=None, params=None, headers=None): _prepare_set(msg, 'text', subtype, headers) - charset = email.charset.Charset(charset).input_charset + cs = email.charset.Charset(charset) + charset = cs.output_charset cte, payload = _encode_text(string, charset, cte, msg.policy) msg.set_payload(payload) msg.set_param('charset', charset, replace=True) diff --git a/Lib/test/test_email/test_contentmanager.py b/Lib/test/test_email/test_contentmanager.py index 0b1b6e89f8c992..3115941f870319 100644 --- a/Lib/test/test_email/test_contentmanager.py +++ b/Lib/test/test_email/test_contentmanager.py @@ -362,6 +362,46 @@ def test_set_text_charset_cp949(self): self.assertEqual(m.get_payload(decode=True), content.encode('ks_c_5601-1987')) self.assertEqual(m.get_content(), content) + def test_set_text_charset_shift_jis(self): + m = self._make_message() + content = "\u65e5\u672c\u8a9e\n" + raw_data_manager.set_content(m, content, charset='shift_jis') + self.assertEqual(m['Content-Type'], 'text/plain; charset="iso-2022-jp"') + self.assertEqual(m.get_payload(decode=True), content.encode('iso-2022-jp')) + self.assertEqual(m.get_content(), content) + self.assertEqual(str(m), textwrap.dedent("""\ + Content-Type: text/plain; charset="iso-2022-jp" + Content-Transfer-Encoding: 7bit + + \x1b$BF|K\\8l\x1b(B + """)) + self.assertEqual(bytes(m), textwrap.dedent("""\ + Content-Type: text/plain; charset="iso-2022-jp" + Content-Transfer-Encoding: 7bit + + \u65e5\u672c\u8a9e + """).encode('iso-2022-jp')) + + def test_set_text_charset_euc_jp(self): + m = self._make_message() + content = "\u65e5\u672c\u8a9e\n" + raw_data_manager.set_content(m, content, charset='euc-jp') + self.assertEqual(m['Content-Type'], 'text/plain; charset="iso-2022-jp"') + self.assertEqual(m.get_payload(decode=True), content.encode('iso-2022-jp')) + self.assertEqual(m.get_content(), content) + self.assertEqual(str(m), textwrap.dedent("""\ + Content-Type: text/plain; charset="iso-2022-jp" + Content-Transfer-Encoding: 7bit + + \x1b$BF|K\\8l\x1b(B + """)) + self.assertEqual(bytes(m), textwrap.dedent("""\ + Content-Type: text/plain; charset="iso-2022-jp" + Content-Transfer-Encoding: 7bit + + \u65e5\u672c\u8a9e + """).encode('iso-2022-jp')) + def test_set_text_plain_long_line_heuristics(self): m = self._make_message() content = ("Simple but long message that is over 78 characters" diff --git a/Misc/NEWS.d/next/Library/2026-06-09-12-00-00.gh-issue-150771.K7mNx2.rst b/Misc/NEWS.d/next/Library/2026-06-09-12-00-00.gh-issue-150771.K7mNx2.rst new file mode 100644 index 00000000000000..6535e5c48bf036 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-09-12-00-00.gh-issue-150771.K7mNx2.rst @@ -0,0 +1,4 @@ +Fix :mod:`email` messages created with ``shift_jis`` or ``euc-jp`` charsets. +``set_content()`` now stores the payload using the output charset +(``iso-2022-jp``) so printing the message no longer raises +:exc:`UnicodeEncodeError`. From 19bf6a3fa1d1497f8b73f971df07109f2da000ca Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 16 Jun 2026 18:42:24 +0200 Subject: [PATCH 341/818] [3.15] gh-151519: Check effective gid in `_test_all_chown_common` group-0 guard (GH-151521) (#151549) gh-151519: Check effective gid in `_test_all_chown_common` group-0 guard (GH-151521) The guard that skips the "chown to gid 0 should fail" assertion used only `os.getgroups()` (supplementary groups). The kernel also accepts the effective/filesystem gid for chown, so when a process runs with egid 0 and a non-zero uid (common in containers and user namespaces), chown(-1, 0) succeeds and the assertion spuriously fails. Add an `os.getegid() != 0` check alongside the existing `0 not in os.getgroups()` guard. (cherry picked from commit 2ce260033b457a0ad2c9767a1d9902bef5a30b0e) Co-authored-by: Itamar Oren <itamarost@gmail.com> --- Lib/test/test_os/test_posix.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_os/test_posix.py b/Lib/test/test_os/test_posix.py index 0e8495a4eff2ed..a1ffd4fbe8cf2b 100644 --- a/Lib/test/test_os/test_posix.py +++ b/Lib/test/test_os/test_posix.py @@ -899,7 +899,9 @@ def check_stat(uid, gid): self.assertRaises(OSError, chown_func, first_param, 0, -1) check_stat(uid, gid) if hasattr(os, 'getgroups'): - if 0 not in os.getgroups(): + # Also check the effective gid, which the kernel + # accepts for chown even if not in getgroups(). + if 0 not in os.getgroups() and os.getegid() != 0: self.assertRaises(OSError, chown_func, first_param, -1, 0) check_stat(uid, gid) # test illegal types From ff6e973c3bbe419ff8aef16b05a1c77749c073c2 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 16 Jun 2026 18:48:56 +0200 Subject: [PATCH 342/818] [3.15] gh-151218: Replace sys.flags in PyConfig_Set() (GH-151402) (#151552) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gh-151218: Replace sys.flags in PyConfig_Set() (GH-151402) PyConfig_Set() and sys.set_int_max_str_digits() now replace sys.flags (create a new object), instead of modifying sys.flags in-place. Modifying sys.flags in-place can lead to data races when multiple threads are reading or writing sys.flags in parallel. Use _Py_atomic functions to get and set max_str_digits members. (cherry picked from commit b16d23fc9fe9cb72fa15c8a3036753e5437b5b8c) Co-authored-by: Victor Stinner <vstinner@python.org> Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com> --- Doc/c-api/init_config.rst | 4 ++ Lib/test/test_capi/test_config.py | 2 + Lib/test/test_free_threading/test_sys.py | 28 ++++++++ Lib/test/test_sys.py | 20 ++++++ ...-06-12-15-30-25.gh-issue-151218.5M_nv8.rst | 3 + Objects/longobject.c | 6 +- Python/initconfig.c | 3 +- Python/pylifecycle.c | 3 +- Python/sysmodule.c | 65 ++++++++++++++----- 9 files changed, 111 insertions(+), 23 deletions(-) create mode 100644 Lib/test/test_free_threading/test_sys.py create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-12-15-30-25.gh-issue-151218.5M_nv8.rst diff --git a/Doc/c-api/init_config.rst b/Doc/c-api/init_config.rst index 209e48767ccfd6..d6b9837987a399 100644 --- a/Doc/c-api/init_config.rst +++ b/Doc/c-api/init_config.rst @@ -623,6 +623,10 @@ Some options are read from the :mod:`sys` attributes. For example, the option .. versionadded:: 3.14 + .. versionchanged:: next + The function now replaces :data:`sys.flags` (create a new object), + instead of modifying :data:`sys.flags` in-place. + .. _pyconfig_api: diff --git a/Lib/test/test_capi/test_config.py b/Lib/test/test_capi/test_config.py index f10ad50d3bea7e..c750a6c2a477ab 100644 --- a/Lib/test/test_capi/test_config.py +++ b/Lib/test/test_capi/test_config.py @@ -356,9 +356,11 @@ def expect_bool_not(value): for value in new_values: expected, expect_flag = expect_func(value) + old_flags = sys.flags config_set(name, value) self.assertEqual(config_get(name), expected) self.assertEqual(getattr(sys.flags, sys_flag), expect_flag) + self.assertIsNot(sys.flags, old_flags) if name == "write_bytecode": self.assertEqual(getattr(sys, "dont_write_bytecode"), expect_flag) diff --git a/Lib/test/test_free_threading/test_sys.py b/Lib/test/test_free_threading/test_sys.py new file mode 100644 index 00000000000000..37b53bd723fd76 --- /dev/null +++ b/Lib/test/test_free_threading/test_sys.py @@ -0,0 +1,28 @@ +import sys +import unittest +from test.support import threading_helper + + +class SysModuleTest(unittest.TestCase): + def test_int_max_str_digits_thread(self): + # gh-151218: Check that it's safe to call get_int_max_str_digits() and + # set_int_max_str_digits() in parallel. Previously, this test triggered + # warnings in TSan on a free threaded build. + + old_limit = sys.get_int_max_str_digits() + self.addCleanup(sys.set_int_max_str_digits, old_limit) + + def worker(worker_id): + if not worker_id: + for i in range (20_000): + sys.get_int_max_str_digits() + else: + for i in range (20_000): + sys.set_int_max_str_digits(4300 + (i & 7)) + + workers = [lambda: worker(i) for i in range(5)] + threading_helper.run_concurrently(workers) + + +if __name__ == "__main__": + unittest.main() diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index 3002fa528eab17..8be7e50624054e 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -1359,6 +1359,26 @@ def test_pystats(self): def test_disable_gil_abi(self): self.assertEqual('t' in sys.abiflags, support.Py_GIL_DISABLED) + def test_int_max_str_digits(self): + old_limit = sys.get_int_max_str_digits() + self.assertIsInstance(old_limit, int) + self.assertGreaterEqual(old_limit, 0) + self.addCleanup(sys.set_int_max_str_digits, old_limit) + + sys.set_int_max_str_digits(0) + self.assertEqual(sys.get_int_max_str_digits(), 0) + + sys.set_int_max_str_digits(2_048) + self.assertEqual(sys.get_int_max_str_digits(), 2_048) + + with self.assertRaises(ValueError): + # the minimum is 640 digits + sys.set_int_max_str_digits(5) + with self.assertRaises(ValueError): + sys.set_int_max_str_digits(-2) + with self.assertRaises(TypeError): + sys.set_int_max_str_digits(2_048.0) + @test.support.cpython_only @test.support.force_not_colorized_test_class diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-12-15-30-25.gh-issue-151218.5M_nv8.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-12-15-30-25.gh-issue-151218.5M_nv8.rst new file mode 100644 index 00000000000000..46539efc373eb0 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-12-15-30-25.gh-issue-151218.5M_nv8.rst @@ -0,0 +1,3 @@ +:c:func:`PyConfig_Set` and :func:`sys.set_int_max_str_digits` now replace +:data:`sys.flags` (create a new object), instead of modifying :data:`sys.flags` +in-place. Patch by Victor Stinner. diff --git a/Objects/longobject.c b/Objects/longobject.c index 6e6011cb19aab5..7a38ae8ea5a36f 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -2125,7 +2125,7 @@ long_to_decimal_string_internal(PyObject *aa, if (size_a >= 10 * _PY_LONG_MAX_STR_DIGITS_THRESHOLD / (3 * PyLong_SHIFT) + 2) { PyInterpreterState *interp = _PyInterpreterState_GET(); - int max_str_digits = interp->long_state.max_str_digits; + int max_str_digits = _Py_atomic_load_int(&interp->long_state.max_str_digits); if ((max_str_digits > 0) && (max_str_digits / (3 * PyLong_SHIFT) <= (size_a - 11) / 10)) { PyErr_Format(PyExc_ValueError, _MAX_STR_DIGITS_ERROR_FMT_TO_STR, @@ -2206,7 +2206,7 @@ long_to_decimal_string_internal(PyObject *aa, } if (strlen > _PY_LONG_MAX_STR_DIGITS_THRESHOLD) { PyInterpreterState *interp = _PyInterpreterState_GET(); - int max_str_digits = interp->long_state.max_str_digits; + int max_str_digits = _Py_atomic_load_int(&interp->long_state.max_str_digits); Py_ssize_t strlen_nosign = strlen - negative; if ((max_str_digits > 0) && (strlen_nosign > max_str_digits)) { Py_DECREF(scratch); @@ -3021,7 +3021,7 @@ long_from_string_base(const char **str, int base, PyLongObject **res) * quadratic algorithm. */ if (digits > _PY_LONG_MAX_STR_DIGITS_THRESHOLD) { PyInterpreterState *interp = _PyInterpreterState_GET(); - int max_str_digits = interp->long_state.max_str_digits; + int max_str_digits = _Py_atomic_load_int(&interp->long_state.max_str_digits); if ((max_str_digits > 0) && (digits > max_str_digits)) { PyErr_Format(PyExc_ValueError, _MAX_STR_DIGITS_ERROR_FMT_TO_INT, max_str_digits, digits); diff --git a/Python/initconfig.c b/Python/initconfig.c index bebadcc76111b7..185b5b107d68db 100644 --- a/Python/initconfig.c +++ b/Python/initconfig.c @@ -4596,7 +4596,8 @@ config_get(const PyConfig *config, const PyConfigSpec *spec, if (strcmp(spec->name, "int_max_str_digits") == 0) { PyInterpreterState *interp = _PyInterpreterState_GET(); - return PyLong_FromLong(interp->long_state.max_str_digits); + int maxdigits = _Py_atomic_load_int(&interp->long_state.max_str_digits); + return PyLong_FromLong(maxdigits); } } diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 311332434d69a4..3933c321ed2e3d 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -428,7 +428,8 @@ interpreter_update_config(PyThreadState *tstate, int only_update_path_config) } } - tstate->interp->long_state.max_str_digits = config->int_max_str_digits; + _Py_atomic_store_int(&tstate->interp->long_state.max_str_digits, + config->int_max_str_digits); // Update the sys module for the new configuration if (_PySys_UpdateConfig(tstate) < 0) { diff --git a/Python/sysmodule.c b/Python/sysmodule.c index b79ebf56371ff2..aa9ff9e9a455de 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -1904,7 +1904,8 @@ sys_get_int_max_str_digits_impl(PyObject *module) /*[clinic end generated code: output=0042f5e8ae0e8631 input=77fb74e987ba7ecb]*/ { PyInterpreterState *interp = _PyInterpreterState_GET(); - return PyLong_FromLong(interp->long_state.max_str_digits); + int maxdigits = _Py_atomic_load_int(&interp->long_state.max_str_digits); + return PyLong_FromLong(maxdigits); } @@ -3528,14 +3529,39 @@ sys_set_flag(PyObject *flags, Py_ssize_t pos, PyObject *value) int _PySys_SetFlagObj(Py_ssize_t pos, PyObject *value) { - PyObject *flags = PySys_GetAttrString("flags"); - if (flags == NULL) { - return -1; + PyObject *new_flags = NULL; + PyObject *flags_str = &_Py_ID(flags); // immortal ref + + PyObject *old_flags = PySys_GetAttr(flags_str); + if (old_flags == NULL) { + goto error; } - sys_set_flag(flags, pos, value); - Py_DECREF(flags); - return 0; + new_flags = PyStructSequence_New(&FlagsType); + if (new_flags == NULL) { + goto error; + } + + for (Py_ssize_t i = 0; i < (Py_ssize_t)(Py_ARRAY_LENGTH(flags_fields) - 1); i++) { + if (i != pos) { + PyObject *old_value; + old_value = PyStructSequence_GET_ITEM(old_flags, i); // borrowed ref + sys_set_flag(new_flags, i, old_value); + } + else { + sys_set_flag(new_flags, pos, value); + } + } + + int res = _PySys_SetAttr(flags_str, new_flags); + Py_DECREF(old_flags); + Py_DECREF(new_flags); + return res; + +error: + Py_XDECREF(old_flags); + Py_XDECREF(new_flags); + return -1; } @@ -3559,8 +3585,6 @@ set_flags_from_config(PyInterpreterState *interp, PyObject *flags) const PyPreConfig *preconfig = &interp->runtime->preconfig; const PyConfig *config = _PyInterpreterState_GetConfig(interp); - // _PySys_UpdateConfig() modifies sys.flags in-place: - // Py_XDECREF() is needed in this case. Py_ssize_t pos = 0; #define SetFlagObj(expr) \ do { \ @@ -4071,7 +4095,7 @@ _PySys_InitCore(PyThreadState *tstate, PyObject *sysdict) /* implementation */ SET_SYS("implementation", make_impl_info(version_info)); - // sys.flags: updated in-place later by _PySys_UpdateConfig() + // sys.flags: updated later by _PySys_UpdateConfig() ENSURE_INFO_TYPE(FlagsType, flags_desc); SET_SYS("flags", make_flags(tstate->interp)); @@ -4191,16 +4215,21 @@ _PySys_UpdateConfig(PyThreadState *tstate) #undef COPY_LIST #undef COPY_WSTR - // sys.flags - PyObject *flags = PySys_GetAttrString("flags"); - if (flags == NULL) { + // replace sys.flags + PyObject *new_flags = PyStructSequence_New(&FlagsType); + if (new_flags == NULL) { return -1; } - if (set_flags_from_config(interp, flags) < 0) { - Py_DECREF(flags); + if (set_flags_from_config(interp, new_flags) < 0) { + Py_DECREF(new_flags); + return -1; + } + + res = _PySys_SetAttr(&_Py_ID(flags), new_flags); + Py_DECREF(new_flags); + if (res < 0) { return -1; } - Py_DECREF(flags); SET_SYS("dont_write_bytecode", PyBool_FromLong(!config->write_bytecode)); @@ -4713,7 +4742,7 @@ _PySys_SetIntMaxStrDigits(int maxdigits) // Set PyInterpreterState.long_state.max_str_digits // and PyInterpreterState.config.int_max_str_digits. PyInterpreterState *interp = _PyInterpreterState_GET(); - interp->long_state.max_str_digits = maxdigits; - interp->config.int_max_str_digits = maxdigits; + _Py_atomic_store_int(&interp->long_state.max_str_digits, maxdigits); + _Py_atomic_store_int(&interp->config.int_max_str_digits, maxdigits); return 0; } From a5c5edddbc3ca7192c057f65fb3a8ff4ea360f96 Mon Sep 17 00:00:00 2001 From: Victor Stinner <vstinner@python.org> Date: Wed, 17 Jun 2026 11:13:40 +0200 Subject: [PATCH 343/818] [3.15] gh-151546: Fix stack limits on musl (#151548) (#151583) gh-151546: Fix stack limits on musl (#151548) If the thread stack size is set by linker flags, pass the stack size to Python/ceval.c via the new _Py_LINKER_THREAD_STACK_SIZE variable to set Py_C_STACK_SIZE macro. (cherry picked from commit 9a61d1c0c8ebe21277c0a84abf6000049540464f) --- .../2026-06-16-17-23-37.gh-issue-151546.LhiaZz.rst | 3 +++ Python/ceval.c | 4 +++- configure | 4 ++++ configure.ac | 3 +++ pyconfig.h.in | 3 +++ 5 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-16-17-23-37.gh-issue-151546.LhiaZz.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-16-17-23-37.gh-issue-151546.LhiaZz.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-16-17-23-37.gh-issue-151546.LhiaZz.rst new file mode 100644 index 00000000000000..af1c23bd50355f --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-16-17-23-37.gh-issue-151546.LhiaZz.rst @@ -0,0 +1,3 @@ +Fix the stack limit check if Python is linked to musl (ex: Alpine Linux). +Use the stack size set by the linker to compute the stack limits. Patch by +Victor Stinner. diff --git a/Python/ceval.c b/Python/ceval.c index 5661200e74d0a5..3feb6ad0050d14 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -63,7 +63,9 @@ _Py_EnterRecursiveCallUnchecked(PyThreadState *tstate) } } -#if defined(__s390x__) +#if defined(_Py_LINKER_THREAD_STACK_SIZE) +# define Py_C_STACK_SIZE _Py_LINKER_THREAD_STACK_SIZE +#elif defined(__s390x__) # define Py_C_STACK_SIZE 320000 #elif defined(_WIN32) // Don't define Py_C_STACK_SIZE, ask the O/S diff --git a/configure b/configure index 3a1c40e49d580b..e60a71cff469bc 100755 --- a/configure +++ b/configure @@ -9918,6 +9918,10 @@ printf "%s\n" "$ac_cv_thread_stack_size" >&6; } if test "$ac_cv_thread_stack_size" != "default" -a "$ac_cv_thread_stack_size" != "unknown"; then LDFLAGS="$LDFLAGS -Wl,-z,stack-size=$ac_cv_thread_stack_size" + # Stack size used by Python/ceval.c to set Py_C_STACK_SIZE + +printf "%s\n" "#define _Py_LINKER_THREAD_STACK_SIZE $ac_cv_thread_stack_size" >>confdefs.h + fi fi diff --git a/configure.ac b/configure.ac index 62d761130ac07f..c6485093032439 100644 --- a/configure.ac +++ b/configure.ac @@ -2507,6 +2507,9 @@ EOF if test "$ac_cv_thread_stack_size" != "default" -a "$ac_cv_thread_stack_size" != "unknown"; then LDFLAGS="$LDFLAGS -Wl,-z,stack-size=$ac_cv_thread_stack_size" + # Stack size used by Python/ceval.c to set Py_C_STACK_SIZE + AC_DEFINE_UNQUOTED([_Py_LINKER_THREAD_STACK_SIZE], [$ac_cv_thread_stack_size], + [Thread stack size set by the linker (in bytes).]) fi fi diff --git a/pyconfig.h.in b/pyconfig.h.in index 7ef83fcd0b9e0b..f26c67644d5e5d 100644 --- a/pyconfig.h.in +++ b/pyconfig.h.in @@ -2067,6 +2067,9 @@ /* Define if you have the 'PR_SET_VMA_ANON_NAME' constant. */ #undef _Py_HAVE_PR_SET_VMA_ANON_NAME +/* Thread stack size set by the linker (in bytes). */ +#undef _Py_LINKER_THREAD_STACK_SIZE + /* Define to 1 if the machine stack grows down (default); 0 if it grows up. */ #undef _Py_STACK_GROWS_DOWN From d7e7d856096444ab1ba534bf71437b2a934d00bb Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 17 Jun 2026 11:28:34 +0200 Subject: [PATCH 344/818] [3.15] gh-151496: Use process groups in test_dtrace (GH-151512) (#151589) gh-151496: Use process groups in test_dtrace (GH-151512) Create a new process group to run bpftrace commands, so it's possible to kill also child processes on timeout. (cherry picked from commit a064b323f4350305e7486c7b1090cf12b19e7738) Co-authored-by: Victor Stinner <vstinner@python.org> --- Lib/test/test_dtrace.py | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/Lib/test/test_dtrace.py b/Lib/test/test_dtrace.py index 6286b6d21b572e..592f59d77f9221 100644 --- a/Lib/test/test_dtrace.py +++ b/Lib/test/test_dtrace.py @@ -1,6 +1,7 @@ import dis import os.path import re +import signal import subprocess import sys import sysconfig @@ -50,6 +51,24 @@ def normalize_trace_output(output): ) +USE_PROCESS_GROUP = (hasattr(os, "setsid") and hasattr(os, "killpg")) + +def create_process_group(*args, **kwargs): + if USE_PROCESS_GROUP: + kwargs['start_new_session'] = True + return subprocess.Popen(*args, **kwargs) + +def kill_process_group(proc): + if USE_PROCESS_GROUP: + try: + os.killpg(proc.pid, signal.SIGKILL) + except ProcessLookupError: + pass + else: + proc.kill() + proc.communicate() # Clean up + + class TraceBackend: EXTENSION = None COMMAND = None @@ -205,7 +224,7 @@ def run_case(self, name, optimize_python=None): program = self.PROGRAMS[name].format(python=sys.executable) try: - proc = subprocess.Popen( + proc = create_process_group( ["bpftrace", "-e", program, "-c", " ".join(subcommand)], stdout=subprocess.PIPE, stderr=subprocess.PIPE, @@ -213,7 +232,7 @@ def run_case(self, name, optimize_python=None): ) stdout, stderr = proc.communicate(timeout=60) except subprocess.TimeoutExpired: - proc.kill() + kill_process_group(proc) raise AssertionError("bpftrace timed out") except (FileNotFoundError, PermissionError) as e: raise unittest.SkipTest(f"bpftrace not available: {e}") @@ -243,7 +262,7 @@ def assert_usable(self): # Check if bpftrace is available and can attach to USDT probes program = f'usdt:{sys.executable}:python:function__entry {{ printf("probe: success\\n"); exit(); }}' try: - proc = subprocess.Popen( + proc = create_process_group( ["bpftrace", "-e", program, "-c", f"{sys.executable} -c pass"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, @@ -251,8 +270,7 @@ def assert_usable(self): ) stdout, stderr = proc.communicate(timeout=10) except subprocess.TimeoutExpired: - proc.kill() - proc.communicate() # Clean up + kill_process_group(proc) raise unittest.SkipTest("bpftrace timed out during usability check") except OSError as e: raise unittest.SkipTest(f"bpftrace not available: {e}") From 2a5ed2292337e313b4f292fd57a8ce4841740331 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 17 Jun 2026 13:28:42 +0200 Subject: [PATCH 345/818] [3.15] gh-151593: Use timeout on GitHub Action TSan jobs (GH-151594) (#151597) gh-151593: Use timeout on GitHub Action TSan jobs (GH-151594) Use a timeout of 15 minutes for --tsan command and a timeout of 10 minutes for --tsan-parallel command. Display also the slowest tests to help adjusting these timeouts later if needed. (cherry picked from commit 460dec26518df5aa262ded5a2ee4e94b8854b569) Co-authored-by: Victor Stinner <vstinner@python.org> --- .github/workflows/reusable-san.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/reusable-san.yml b/.github/workflows/reusable-san.yml index 2ceb1000e8a5a9..ef36447964cf41 100644 --- a/.github/workflows/reusable-san.yml +++ b/.github/workflows/reusable-san.yml @@ -86,12 +86,12 @@ jobs: run: >- ./python -m test ${{ inputs.sanitizer == 'TSan' && '--tsan' || '' }} - -j4 -W + -j4 -W --timeout=900 --slowest - name: Parallel tests if: >- inputs.sanitizer == 'TSan' && fromJSON(inputs.free-threading) - run: ./python -m test --tsan-parallel --parallel-threads=4 -j4 -W + run: ./python -m test --tsan-parallel --parallel-threads=4 -j4 -W --timeout=600 --slowest - name: Display logs if: always() run: find "${GITHUB_WORKSPACE}" -name 'san_log.*' | xargs head -n 1000 From 821e5d79fa238e7e5e8bc59c72d53edf52d3b168 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 17 Jun 2026 16:10:31 +0200 Subject: [PATCH 346/818] [3.15] gh-151584: Remove `PyUnstable_Module_SetGIL` call in `_remote_debugging` (GH-151585) (#151603) gh-151584: Remove `PyUnstable_Module_SetGIL` call in `_remote_debugging` (GH-151585) (cherry picked from commit a173a6d65ba0eb77776ca4f7f1cb277877a43f9b) Co-authored-by: sobolevn <mail@sobolevn.me> --- Modules/_remote_debugging/module.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/Modules/_remote_debugging/module.c b/Modules/_remote_debugging/module.c index 984213d1881752..36115f20d9d4cc 100644 --- a/Modules/_remote_debugging/module.c +++ b/Modules/_remote_debugging/module.c @@ -1624,9 +1624,6 @@ _remote_debugging_exec(PyObject *m) return -1; } -#ifdef Py_GIL_DISABLED - PyUnstable_Module_SetGIL(m, Py_MOD_GIL_NOT_USED); -#endif int rc = PyModule_AddIntConstant(m, "PROCESS_VM_READV_SUPPORTED", HAVE_PROCESS_VM_READV); if (rc < 0) { return -1; From 1e7fb93df765c41a58ce94ba3d2f71af8d22718e Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 17 Jun 2026 16:58:42 +0200 Subject: [PATCH 347/818] [3.15] gh-150966: Fix live profiling error tests (GH-151020) (#151604) gh-150966: Fix live profiling error tests (GH-151020) (cherry picked from commit 6b142ab9a0007d37c68c74f81e2c8638330003e2) Co-authored-by: Pablo Galindo Salgado <Pablogsal@gmail.com> --- .../test_live_collector_ui.py | 27 +++++++++++++++---- ...-06-06-16-22-00.gh-issue-150966.7N9x5Q.rst | 2 ++ 2 files changed, 24 insertions(+), 5 deletions(-) create mode 100644 Misc/NEWS.d/next/Tests/2026-06-06-16-22-00.gh-issue-150966.7N9x5Q.rst diff --git a/Lib/test/test_profiling/test_sampling_profiler/test_live_collector_ui.py b/Lib/test/test_profiling/test_sampling_profiler/test_live_collector_ui.py index 59373a8d00c03c..ae4ee969f34d8b 100644 --- a/Lib/test/test_profiling/test_sampling_profiler/test_live_collector_ui.py +++ b/Lib/test/test_profiling/test_sampling_profiler/test_live_collector_ui.py @@ -825,17 +825,34 @@ def test_get_all_lines_full_display(self): class TestLiveModeErrors(unittest.TestCase): """Tests running error commands in the live mode fails gracefully.""" + class QuitWhenFinishedDisplay(MockDisplay): + def __init__(self, collector): + super().__init__() + self.collector = collector + + def get_input(self): + ch = super().get_input() + if ch != -1: + return ch + # Sampling only stops once the target process has exited, at + # which point the collector is marked finished. Quit then so the + # run can surface the target's stderr. We must not rely on the + # target's pid still being signalable: once it exits it lingers + # as a zombie (it is reaped after sample_live returns), so a + # liveness check would never observe it gone and would hang. + if self.collector.finished: + return ord('q') + return -1 + def mock_curses_wrapper(self, func): func(mock.MagicMock()) def mock_init_curses_side_effect(self, n_times, mock_self, stdscr): - mock_self.display = MockDisplay() - # Allow the loop to run for a bit (approx 0.5s) before quitting - # This ensures we don't exit too early while the subprocess is - # still failing + mock_self.display = self.QuitWhenFinishedDisplay(mock_self) + # Feed non-input events so live mode keeps polling while the target + # process is still running; once it exits the display quits on its own. for _ in range(n_times): mock_self.display.simulate_input(-1) - mock_self.display.simulate_input(ord('q')) def test_run_failed_module_live(self): """Test that running a existing module that fails exits with clean error.""" diff --git a/Misc/NEWS.d/next/Tests/2026-06-06-16-22-00.gh-issue-150966.7N9x5Q.rst b/Misc/NEWS.d/next/Tests/2026-06-06-16-22-00.gh-issue-150966.7N9x5Q.rst new file mode 100644 index 00000000000000..3bbb471163d64e --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2026-06-06-16-22-00.gh-issue-150966.7N9x5Q.rst @@ -0,0 +1,2 @@ +Avoid prematurely terminating failing live sampling profiler test targets, +which made stderr assertions flaky on ASAN buildbots. From a86de0bc236fbb9452f98998fc8437e9fca35700 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 17 Jun 2026 17:42:35 +0200 Subject: [PATCH 348/818] [3.15] gh-151544: Fixes CVE-2026-12003 by removing the fallback to %VPATH%/Modules/Setup.local for discovering sources in getpath.py (GH-151545) (cherry picked from commit 9e863fab283eddca9c2a8f9d1ee30f4dc243e314) Co-authored-by: Steve Dower <steve.dower@python.org> --- Makefile.pre.in | 2 ++ ...2026-06-16-14-58-02.gh-issue-151544._bexVy.rst | 4 ++++ Modules/getpath.py | 15 ++++----------- 3 files changed, 10 insertions(+), 11 deletions(-) create mode 100644 Misc/NEWS.d/next/Security/2026-06-16-14-58-02.gh-issue-151544._bexVy.rst diff --git a/Makefile.pre.in b/Makefile.pre.in index 9c358bc6fbc681..e411160d3ba842 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -1709,6 +1709,8 @@ Programs/_bootstrap_python.o: Programs/_bootstrap_python.c $(BOOTSTRAP_HEADERS) _bootstrap_python: $(LIBRARY_OBJS_OMIT_FROZEN) Programs/_bootstrap_python.o Modules/getpath.o Modules/Setup.local $(LINKCC) $(PY_LDFLAGS_NOLTO) -o $@ $(LIBRARY_OBJS_OMIT_FROZEN) \ Programs/_bootstrap_python.o Modules/getpath.o $(LIBS) $(MODLIBS) $(SYSLIBS) + # Dummy pybuilddir.txt is needed for _bootstrap_python to be runnable + @echo "none" > ./pybuilddir.txt ############################################################################ diff --git a/Misc/NEWS.d/next/Security/2026-06-16-14-58-02.gh-issue-151544._bexVy.rst b/Misc/NEWS.d/next/Security/2026-06-16-14-58-02.gh-issue-151544._bexVy.rst new file mode 100644 index 00000000000000..418e3b4b967794 --- /dev/null +++ b/Misc/NEWS.d/next/Security/2026-06-16-14-58-02.gh-issue-151544._bexVy.rst @@ -0,0 +1,4 @@ +:file:`Modules/Setup.local` is no longer used as a landmark to discover +whether Python is running in a source tree, as it could potentially affect +actual installs. The :file:`pybuilddir.txt` file is now the sole indicator +of running in a source tree. diff --git a/Modules/getpath.py b/Modules/getpath.py index 4dceb5cdc8dfcf..6199567bd777aa 100644 --- a/Modules/getpath.py +++ b/Modules/getpath.py @@ -129,8 +129,7 @@ # checked by looking for the BUILDDIR_TXT file, which contains the # relative path to the platlib dir. The executable_dir value is # derived from joining the VPATH preprocessor variable to the -# directory containing pybuilddir.txt. If it is not found, the -# BUILD_LANDMARK file is found, which is part of the source tree. +# directory containing pybuilddir.txt. # prefix is then found by searching up for a file that should only # exist in the source tree, and the stdlib dir is set to prefix/Lib. @@ -177,7 +176,6 @@ if os_name == 'posix' or os_name == 'darwin': BUILDDIR_TXT = 'pybuilddir.txt' - BUILD_LANDMARK = 'Modules/Setup.local' DEFAULT_PROGRAM_NAME = f'python{VERSION_MAJOR}' STDLIB_SUBDIR = f'{platlibdir}/python{VERSION_MAJOR}.{VERSION_MINOR}{ABI_THREAD}' STDLIB_LANDMARKS = [f'{STDLIB_SUBDIR}/os.py', f'{STDLIB_SUBDIR}/os.pyc'] @@ -190,7 +188,6 @@ elif os_name == 'nt': BUILDDIR_TXT = 'pybuilddir.txt' - BUILD_LANDMARK = f'{VPATH}\\Modules\\Setup.local' DEFAULT_PROGRAM_NAME = f'python' STDLIB_SUBDIR = 'Lib' STDLIB_LANDMARKS = [f'{STDLIB_SUBDIR}\\os.py', f'{STDLIB_SUBDIR}\\os.pyc'] @@ -513,13 +510,9 @@ def search_up(prefix, *landmarks, test=isfile): platstdlib_dir = real_executable_dir build_prefix = joinpath(real_executable_dir, VPATH) except (FileNotFoundError, PermissionError): - if isfile(joinpath(real_executable_dir, BUILD_LANDMARK)): - build_prefix = joinpath(real_executable_dir, VPATH) - if os_name == 'nt': - # QUIRK: Windows builds need platstdlib_dir to be the executable - # dir. Normally the builddir marker handles this, but in this - # case we need to correct manually. - platstdlib_dir = real_executable_dir + # We used to check for an alternate landmark here, but now we require + # BUILDDIR_TXT to exist. (gh-151544; CVE-2026-12003) + pass if build_prefix: if os_name == 'nt': From 6d29a08d15caeeb3686ca88df1e01881d6ff686b Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 17 Jun 2026 17:47:27 +0200 Subject: [PATCH 349/818] [3.15] gh-120665: make unittest loaders avoid loading test cases that are abstract base classes (GH-120666) (#151601) gh-120665: make unittest loaders avoid loading test cases that are abstract base classes (GH-120666) (cherry picked from commit 5ad3c6dfbfe60a7f232e9604866c77ced24c4bfe) Co-authored-by: blhsing <blhsing@gmail.com> --- Lib/test/test_unittest/test_loader.py | 51 +++++++++++++++++++ Lib/unittest/loader.py | 11 +++- ...-06-18-04-08-37.gh-issue-120665.x7T1hV.rst | 1 + 3 files changed, 61 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2024-06-18-04-08-37.gh-issue-120665.x7T1hV.rst diff --git a/Lib/test/test_unittest/test_loader.py b/Lib/test/test_unittest/test_loader.py index cdff6d1a20c8df..f4e50a3dccb2bc 100644 --- a/Lib/test/test_unittest/test_loader.py +++ b/Lib/test/test_unittest/test_loader.py @@ -1,3 +1,4 @@ +import abc import functools import sys import types @@ -98,6 +99,22 @@ def test_loadTestsFromTestCase__from_FunctionTestCase(self): self.assertIsInstance(suite, loader.suiteClass) self.assertEqual(list(suite), []) + # "Do not load any tests from a TestCase-derived class that is an abstract + # base class." + def test_loadTestsFromTestCase__from_abc_TestCase(self): + class FooBase(unittest.TestCase, metaclass=abc.ABCMeta): + @abc.abstractmethod + def test(self): ... + class Foo(FooBase): + def test(self): pass + + empty_suite = unittest.TestSuite() + + loader = unittest.TestLoader() + suite = loader.loadTestsFromTestCase(Foo) + self.assertEqual(loader.loadTestsFromTestCase(FooBase), empty_suite) + self.assertEqual(list(suite), [Foo('test')]) + ################################################################ ### /Tests for TestLoader.loadTestsFromTestCase @@ -252,6 +269,24 @@ def load_tests(loader, tests, pattern): self.assertRaisesRegex(TypeError, "some failure", test.m) + # Check that loadTestsFromModule skips abstract base classes derived from + # TestCase, which can't be instantiated. + def test_loadTestsFromModule__skip_abc_TestCase(self): + m = types.ModuleType('m') + class MyTestCaseBase(unittest.TestCase, metaclass=abc.ABCMeta): + @abc.abstractmethod + def test(self): + ... + class MyTestCase(MyTestCaseBase): + def test(self): + pass + m.testcase_1 = MyTestCaseBase + m.testcase_2 = MyTestCase + loader = unittest.TestLoader() + suite = loader.loadTestsFromModule(m) + expected = [loader.suiteClass([MyTestCase('test')])] + self.assertEqual(list(suite), expected) + ################################################################ ### /Tests for TestLoader.loadTestsFromModule() @@ -1052,6 +1087,22 @@ def test_loadTestsFromNames__module_not_loaded(self): if module_name in sys.modules: del sys.modules[module_name] + # "The specifier should not refer to a test method in a TestCase-derived + # subclass that is an abstract base class" + def test_loadTestsFromNames__testmethod_in_abc_TestCase(self): + m = types.ModuleType('m') + class Foo(unittest.TestCase, metaclass=abc.ABCMeta): + @abc.abstractmethod + def test_1(self): ... + def test_2(self): pass + m.Foo = Foo + + loader = unittest.TestLoader() + for name in 'Foo.test_1', 'Foo.test_2': + with self.subTest(name=name), self.assertRaisesRegex(TypeError, + "Cannot instantiate abstract test case Foo"): + loader.loadTestsFromNames([name], m) + ################################################################ ### /Tests for TestLoader.loadTestsFromNames() diff --git a/Lib/unittest/loader.py b/Lib/unittest/loader.py index a52950dad224ee..697520246f0e3c 100644 --- a/Lib/unittest/loader.py +++ b/Lib/unittest/loader.py @@ -1,5 +1,6 @@ """Loading unittests.""" +import inspect import os import re import sys @@ -84,8 +85,10 @@ def loadTestsFromTestCase(self, testCaseClass): raise TypeError("Test cases should not be derived from " "TestSuite. Maybe you meant to derive from " "TestCase?") - if testCaseClass in (case.TestCase, case.FunctionTestCase): - # We don't load any tests from base types that should not be loaded. + if (testCaseClass in (case.TestCase, case.FunctionTestCase) or + inspect.isabstract(testCaseClass)): + # We don't load any tests from base types that should not be loaded, + # and abstract base classes that can't be instantiated testCaseNames = [] else: testCaseNames = self.getTestCaseNames(testCaseClass) @@ -103,6 +106,7 @@ def loadTestsFromModule(self, module, *, pattern=None): isinstance(obj, type) and issubclass(obj, case.TestCase) and obj not in (case.TestCase, case.FunctionTestCase) + and not inspect.isabstract(obj) ): tests.append(self.loadTestsFromTestCase(obj)) @@ -181,6 +185,9 @@ def loadTestsFromName(self, name, module=None): elif (isinstance(obj, types.FunctionType) and isinstance(parent, type) and issubclass(parent, case.TestCase)): + if inspect.isabstract(parent): + raise TypeError( + "Cannot instantiate abstract test case %s" % parent.__name__) name = parts[-1] inst = parent(name) # static methods follow a different path diff --git a/Misc/NEWS.d/next/Library/2024-06-18-04-08-37.gh-issue-120665.x7T1hV.rst b/Misc/NEWS.d/next/Library/2024-06-18-04-08-37.gh-issue-120665.x7T1hV.rst new file mode 100644 index 00000000000000..27e93988ed11ef --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-06-18-04-08-37.gh-issue-120665.x7T1hV.rst @@ -0,0 +1 @@ +Fixed an issue where ``unittest`` loaders would load and instantiate :class:`unittest.TestCase`-derived subclasses that are also abstract base classes, which can't be instantiated. From 8fe5897853b1f5d8b7a1dc9fc2b72c6244a74983 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 17 Jun 2026 20:40:33 +0200 Subject: [PATCH 350/818] [3.15] gh-151510: Fix __lazy_import__ without frame (GH-151511) (#151610) gh-151510: Fix __lazy_import__ without frame (GH-151511) (cherry picked from commit eff805b7a7a9678639bbcebe804864406cc4eab2) Co-authored-by: AN Long <aisk@users.noreply.github.com> --- Lib/test/test_lazy_import/__init__.py | 11 ++++++++++ ...-06-16-00-45-42.gh-issue-151510.HJ-kGn.rst | 2 ++ Modules/_testcapi/import.c | 22 +++++++++++++++++++ Python/bltinmodule.c | 6 +++++ 4 files changed, 41 insertions(+) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-16-00-45-42.gh-issue-151510.HJ-kGn.rst diff --git a/Lib/test/test_lazy_import/__init__.py b/Lib/test/test_lazy_import/__init__.py index c99c22491028d3..b531a4227bc9a8 100644 --- a/Lib/test/test_lazy_import/__init__.py +++ b/Lib/test/test_lazy_import/__init__.py @@ -1957,6 +1957,17 @@ def filter(*args): def test_set_bad_filter(self): self.assertRaises(ValueError, _testcapi.PyImport_SetLazyImportsFilter, 42) + def test_dunder_lazy_import_without_frame(self): + # gh-151510: __lazy_import__() called with no globals and no running + # Python frame must raise TypeError instead of crashing. + with self.assertRaisesRegex( + TypeError, + r"__lazy_import__\(\) missing globals when called without a frame", + ): + _testcapi.lazy_import_without_frame( + "test.test_lazy_import.data.basic2" + ) + if __name__ == '__main__': unittest.main() diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-16-00-45-42.gh-issue-151510.HJ-kGn.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-16-00-45-42.gh-issue-151510.HJ-kGn.rst new file mode 100644 index 00000000000000..cfa5ee8d3839c1 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-16-00-45-42.gh-issue-151510.HJ-kGn.rst @@ -0,0 +1,2 @@ +Fix a crash in :func:`!__lazy_import__` when called without an explicit +``globals`` argument and without a current Python frame. diff --git a/Modules/_testcapi/import.c b/Modules/_testcapi/import.c index 384a8f52da4b98..11d0e6acaebe1f 100644 --- a/Modules/_testcapi/import.c +++ b/Modules/_testcapi/import.c @@ -1,6 +1,27 @@ #include "parts.h" #include "util.h" +static PyObject * +pyimport_lazyimportwithoutframe(PyObject *self, PyObject *name) +{ + PyObject *lazy_import = PyImport_ImportModuleAttrString("builtins", + "__lazy_import__"); + if (lazy_import == NULL) { + return NULL; + } + + // Simulate being called with no running Python frame (e.g. from a freshly + // attached C thread), so that PyEval_GetGlobals() returns NULL. + PyThreadState *tstate = PyThreadState_Get(); + struct _PyInterpreterFrame *saved = tstate->current_frame; + tstate->current_frame = NULL; + PyObject *res = PyObject_CallOneArg(lazy_import, name); + tstate->current_frame = saved; + + Py_DECREF(lazy_import); + return res; +} + // Test PyImport_ImportModuleAttr() static PyObject * pyimport_importmoduleattr(PyObject *self, PyObject *args) @@ -95,6 +116,7 @@ static PyMethodDef test_methods[] = { {"PyImport_GetLazyImportsMode", pyimport_getlazyimportsmode, METH_NOARGS}, {"PyImport_SetLazyImportsFilter", pyimport_setlazyimportsfilter, METH_VARARGS}, {"PyImport_GetLazyImportsFilter", pyimport_getlazyimportsfilter, METH_NOARGS}, + {"lazy_import_without_frame", pyimport_lazyimportwithoutframe, METH_O}, {NULL}, }; diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c index d5129bf6a5a6bc..fa64255be00e75 100644 --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -313,6 +313,12 @@ builtin___lazy_import___impl(PyObject *module, PyObject *name, PyThreadState *tstate = PyThreadState_GET(); if (globals == NULL) { globals = PyEval_GetGlobals(); + if (globals == NULL) { + PyErr_SetString(PyExc_TypeError, + "__lazy_import__() missing globals " + "when called without a frame"); + return NULL; + } } if (locals == NULL) { locals = globals; From e9c7cc1f0b67a582cb44791d72ce0b858f937e0d Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 18 Jun 2026 10:17:15 +0200 Subject: [PATCH 351/818] [3.15] gh-149044: Improve Py_tp_base[s] docs & error message for non-type bases (GH-151252) (GH-151606) gh-149044: Improve Py_tp_base[s] docs & error message for non-type bases (GH-151252) The initial implementation of PEP 820 worsened the error message when non-types are given as base types in Py_tp_bases & Py_tp_base. Bring back the 'bases must be types' wording and add a 'got' note for easier debugging. Improve slot ID documentation, and soft-deprecate Py_tp_base (as per the PEP). (cherry picked from commit 16185e9fe2037d2171626f79c3d099bd7772b53e) Co-authored-by: Petr Viktorin <encukou@gmail.com> --- Doc/c-api/type.rst | 43 ++++++++++++++++--- Doc/c-api/typeobj.rst | 11 ++--- Doc/tools/removed-ids.txt | 4 ++ Doc/whatsnew/3.15.rst | 6 +++ Lib/test/test_capi/test_misc.py | 2 +- Lib/test/test_capi/test_slots.py | 35 +++++++++++++++ ...-06-10-15-22-44.gh-issue-149044.O7KEcs.rst | 3 ++ Modules/_testlimitedcapi/slots.c | 43 +++++++++++++++++++ Objects/typeobject.c | 18 ++++---- 9 files changed, 142 insertions(+), 23 deletions(-) create mode 100644 Misc/NEWS.d/next/C_API/2026-06-10-15-22-44.gh-issue-149044.O7KEcs.rst diff --git a/Doc/c-api/type.rst b/Doc/c-api/type.rst index 4771d0a7781bd6..48eb16bd90834b 100644 --- a/Doc/c-api/type.rst +++ b/Doc/c-api/type.rst @@ -563,10 +563,10 @@ but need extra remarks for use as slots: :c:member:`Slot ID <PySlot.sl_id>` for the name of the type, used to set :c:member:`PyTypeObject.tp_name`. - This slot (or :c:func:`PyType_Spec.name`) is required to create a type. + This slot (or :c:member:`PyType_Spec.name`) is required to create a type. This may not be used in :c:member:`PyType_Spec.slots`. - Use :c:func:`PyType_Spec.name` instead. + Use :c:member:`PyType_Spec.name` instead. .. impl-detail:: @@ -585,7 +585,7 @@ but need extra remarks for use as slots: The value must be positive. This may not be used in :c:member:`PyType_Spec.slots`. - Use :c:func:`PyType_Spec.basicsize` instead. + Use :c:member:`PyType_Spec.basicsize` instead. This slot may not be used with :c:func:`PyType_GetSlot`. Use :c:member:`PyTypeObject.tp_basicsize` instead if needed, but be aware @@ -616,7 +616,7 @@ but need extra remarks for use as slots: :c:macro:`!Py_tp_extra_basicsize` is an error. This may not be used in :c:member:`PyType_Spec.slots`. - Use negative :c:func:`PyType_Spec.basicsize` instead. + Use negative :c:member:`PyType_Spec.basicsize` instead. This slot may not be used with :c:func:`PyType_GetSlot`. @@ -648,7 +648,7 @@ but need extra remarks for use as slots: - With the :c:macro:`Py_TPFLAGS_ITEMS_AT_END` flag. This may not be used in :c:member:`PyType_Spec.slots`. - Use :c:func:`PyType_Spec.itemsize` instead. + Use :c:member:`PyType_Spec.itemsize` instead. This slot may not be used with :c:func:`PyType_GetSlot`. @@ -663,13 +663,44 @@ but need extra remarks for use as slots: :c:func:`PyType_FromSpecWithBases` sets it automatically. This may not be used in :c:member:`PyType_Spec.slots`. - Use negative :c:func:`PyType_Spec.basicsize` instead. + Use negative :c:member:`PyType_Spec.basicsize` instead. This slot may not be used with :c:func:`PyType_GetSlot`. Use :c:func:`PyType_GetFlags` instead. .. versionadded:: 3.15 +.. c:macro:: Py_tp_bases + + :c:member:`Slot ID <PySlot.sl_id>` for type flags, used to set + :c:member:`PyTypeObject.tp_bases`. + + The slot can be set to a tuple of type objects which the newly created + type should inherit from, like the "positional arguments" of + a Python :ref:`class definition <class>`. + + Alternately, the slot can be set to a single type object to specify + a single base. + The effect is the same as specifying a one-element tuple. + + .. versionchanged:: 3.15 + + Previously, :c:macro:`!Py_tp_bases` required a tuple of types. + +.. c:macro:: Py_tp_base + + Equivalent to :c:macro:`Py_tp_bases` (with ``s`` at the end). + If both are specified, :c:macro:`!Py_tp_bases` takes priority and + this slot is ignored. + + .. versionchanged:: 3.15 + + Previously, :c:macro:`!Py_tp_base` required a single type, not a tuple. + + .. soft-deprecated:: 3.15 + + When not targetting older Python versions, pefer :c:macro:`!Py_tp_bases`. + The following slots do not correspond to public fields in the underlying structures: diff --git a/Doc/c-api/typeobj.rst b/Doc/c-api/typeobj.rst index dcc9e243c2f314..16dcb880712d24 100644 --- a/Doc/c-api/typeobj.rst +++ b/Doc/c-api/typeobj.rst @@ -1936,12 +1936,12 @@ and :c:data:`PyType_Type` effectively act as defaults.) .. c:member:: PyTypeObject* PyTypeObject.tp_base - .. corresponding-type-slot:: Py_tp_base - An optional pointer to a base type from which type properties are inherited. At this level, only single inheritance is supported; multiple inheritance require dynamically creating a type object by calling the metatype. + For the corresponding slot ID, see :c:macro:`Py_tp_base`. + .. note:: .. from Modules/xxmodule.c @@ -2253,17 +2253,12 @@ and :c:data:`PyType_Type` effectively act as defaults.) .. c:member:: PyObject* PyTypeObject.tp_bases - .. corresponding-type-slot:: Py_tp_bases - Tuple of base types. This field should be set to ``NULL`` and treated as read-only. Python will fill it in when the type is :c:func:`initialized <PyType_Ready>`. - For dynamically created classes, the :c:data:`Py_tp_bases` - :c:type:`slot <PyType_Slot>` can be used instead of the *bases* argument - of :c:func:`PyType_FromSpecWithBases`. - The argument form is preferred. + For the corresponding slot ID, see :c:macro:`Py_tp_bases`. .. warning:: diff --git a/Doc/tools/removed-ids.txt b/Doc/tools/removed-ids.txt index 474376f4bd7bae..ffffda3506c066 100644 --- a/Doc/tools/removed-ids.txt +++ b/Doc/tools/removed-ids.txt @@ -21,3 +21,7 @@ reference/expressions.html: grammar-token-python-grammar-enclosure reference/expressions.html: grammar-token-python-grammar-list_display reference/expressions.html: grammar-token-python-grammar-parenth_form reference/expressions.html: grammar-token-python-grammar-set_display + +# Moved to a different page +c-api/typeobj.html: c.Py_tp_base +c-api/typeobj.html: c.Py_tp_bases diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst index 36a18f15a3deb2..88b238c709dd0e 100644 --- a/Doc/whatsnew/3.15.rst +++ b/Doc/whatsnew/3.15.rst @@ -2474,6 +2474,12 @@ New features * :c:func:`PyModule_FromDefAndSpec2` * :c:func:`PyModule_ExecDef` + + The slots :c:macro:`Py_tp_bases` and :c:macro:`Py_tp_base` are now + equivalent: they can be set either to a single type or a tuple of types. + The :c:macro:`Py_tp_bases` slot is preferred; the other is ignored if both + are specified. + (Contributed by Petr Viktorin in :gh:`149044`.) * Add :c:func:`PyUnstable_ThreadState_SetStackProtection` and diff --git a/Lib/test/test_capi/test_misc.py b/Lib/test/test_capi/test_misc.py index 3debc6369e89fb..6d84f0b8c305df 100644 --- a/Lib/test/test_capi/test_misc.py +++ b/Lib/test/test_capi/test_misc.py @@ -924,7 +924,7 @@ def test_tp_bases_slot(self): def test_tp_bases_slot_none(self): self.assertRaisesRegex( TypeError, - "metaclass conflict", + "bases must be types", _testcapi.create_heapctype_with_none_bases_slot ) diff --git a/Lib/test/test_capi/test_slots.py b/Lib/test/test_capi/test_slots.py index c78b118712b11d..b8b6d00b5f84d5 100644 --- a/Lib/test/test_capi/test_slots.py +++ b/Lib/test/test_capi/test_slots.py @@ -312,3 +312,38 @@ def test_repeat_error(self): _testlimitedcapi.module_from_slots("repeat_exec", FakeSpec()) with self.assertRaisesRegex(SystemError, "multiple"): _testlimitedcapi.module_from_slots("repeat_gil", FakeSpec()) + + def test_bases_slots(self): + create = _testlimitedcapi.type_from_base_slots + + # Py_tp_bases overrides Py_tp_base + cls = create(base=int, bases=float) + self.assertEqual(cls.mro(), [cls, float, object]) + + # type is equivalent to one-element tuple + cls = create(base=None, bases=int) + self.assertEqual(cls.mro(), [cls, int, object]) + + cls = create(base=None, bases=(int,)) + self.assertEqual(cls.mro(), [cls, int, object]) + + cls = create(base=int) + self.assertEqual(cls.mro(), [cls, int, object]) + + cls = create(base=(int,)) + self.assertEqual(cls.mro(), [cls, int, object]) + + # Tuple of bases works + class Custom: + pass + cls = create(bases=int) + sub = create(base=float, bases=(Custom, cls, int)) + self.assertEqual(sub.mro(), [sub, Custom, cls, int, object]) + + # Reasonable error message for non-types + with self.assertRaisesRegex(TypeError, + "bases must be types; got 'NoneType'"): + create(base=None) + with self.assertRaisesRegex(TypeError, + "bases must be types; got 'str'"): + create(bases="a string") diff --git a/Misc/NEWS.d/next/C_API/2026-06-10-15-22-44.gh-issue-149044.O7KEcs.rst b/Misc/NEWS.d/next/C_API/2026-06-10-15-22-44.gh-issue-149044.O7KEcs.rst new file mode 100644 index 00000000000000..fe0730b1bf87c4 --- /dev/null +++ b/Misc/NEWS.d/next/C_API/2026-06-10-15-22-44.gh-issue-149044.O7KEcs.rst @@ -0,0 +1,3 @@ +Improved error message when specifying non-type base classes in +:c:macro:`Py_tp_bases`, :c:macro:`Py_tp_base`, and *bases* argument to +:c:func:`PyType_FromMetaclass` and other ``PyType_From*`` functions. diff --git a/Modules/_testlimitedcapi/slots.c b/Modules/_testlimitedcapi/slots.c index 7a8d6466e53a09..9abe53d2115464 100644 --- a/Modules/_testlimitedcapi/slots.c +++ b/Modules/_testlimitedcapi/slots.c @@ -607,6 +607,47 @@ module_from_null_slot(PyObject* Py_UNUSED(module), PyObject *args) }, spec); } + + +static PyObject * +type_from_base_slots( + PyObject *self, PyObject *args, PyObject *kwargs) +{ + PyObject *base = NULL; + PyObject *bases = NULL; + if (!PyArg_ParseTupleAndKeywords( + args, kwargs, "|OO", + (char*[]){"base", "bases", NULL}, + &base, &bases)) + { + return NULL; + } + + PySlot empty_slots[] = { + PySlot_END + }; + + PySlot base_slots[] = { + PySlot_DATA(Py_tp_base, base), + PySlot_END + }; + + PySlot bases_slots[] = { + PySlot_DATA(Py_tp_bases, bases), + PySlot_END + }; + + PySlot slots[] = { + PySlot_STATIC_DATA(Py_tp_name, "_testcapi.HeapCTypeWithBases"), + PySlot_UINT64(Py_tp_flags, Py_TPFLAGS_BASETYPE), + PySlot_DATA(Py_slot_subslots, base ? base_slots: empty_slots), + PySlot_DATA(Py_slot_subslots, bases ? bases_slots: empty_slots), + PySlot_END + }; + + return PyType_FromSlots(slots); +} + static PyMethodDef _TestMethods[] = { {"type_from_slots", type_from_slots, METH_VARARGS}, {"module_from_gil_slot", module_from_gil_slot, METH_VARARGS}, @@ -614,6 +655,8 @@ static PyMethodDef _TestMethods[] = { {"type_from_null_spec_slot", type_from_null_spec_slot, METH_VARARGS}, {"module_from_slots", module_from_slots, METH_VARARGS}, {"module_from_null_slot", module_from_null_slot, METH_VARARGS}, + {"type_from_base_slots", _PyCFunction_CAST(type_from_base_slots), + METH_VARARGS | METH_KEYWORDS}, {NULL}, }; static PyMethodDef *TestMethods = _TestMethods; diff --git a/Objects/typeobject.c b/Objects/typeobject.c index e0464fe6475cfd..12821b134d9709 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -3712,9 +3712,9 @@ find_best_base(PyObject *bases) for (i = 0; i < n; i++) { PyObject *base_proto = PyTuple_GET_ITEM(bases, i); if (!PyType_Check(base_proto)) { - PyErr_SetString( + PyErr_Format( PyExc_TypeError, - "bases must be types"); + "bases must be types; got '%T'", base_proto); return NULL; } PyTypeObject *base_i = (PyTypeObject *)base_proto; @@ -4162,8 +4162,9 @@ _PyType_CalculateMetaclass(PyTypeObject *metatype, PyObject *bases) for (i = 0; i < nbases; i++) { tmp = PyTuple_GET_ITEM(bases, i); tmptype = Py_TYPE(tmp); - if (PyType_IsSubtype(winner, tmptype)) + if (PyType_IsSubtype(winner, tmptype)) { continue; + } if (PyType_IsSubtype(tmptype, winner)) { winner = tmptype; continue; @@ -5524,6 +5525,12 @@ type_from_slots_or_spec( } } + /* Calculate best base, and check that all bases are type objects */ + PyTypeObject *base = find_best_base(bases); // borrowed ref + if (base == NULL) { + goto finally; + } + /* Calculate the metaclass */ if (!metaclass) { @@ -5546,11 +5553,6 @@ type_from_slots_or_spec( goto finally; } - /* Calculate best base, and check that all bases are type objects */ - PyTypeObject *base = find_best_base(bases); // borrowed ref - if (base == NULL) { - goto finally; - } // find_best_base() should check Py_TPFLAGS_BASETYPE & raise a proper // exception, here we just check its work assert(_PyType_HasFeature(base, Py_TPFLAGS_BASETYPE)); From 7aa41c406b33ef96e92cd628825e0a70be9e3697 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 18 Jun 2026 10:48:56 +0200 Subject: [PATCH 352/818] [3.15] gh-151623: Improve curses documentation and docstrings (GH-151625) (GH-151628) Fix errors and clarify the curses, curses.panel and curses.ascii docs against X/Open Curses and ncurses, and sync the affected docstrings. (cherry picked from commit 65afcdd8dfb3621ac696fce076e6282c76a04b2b) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> --- Doc/library/curses.ascii.rst | 5 +- Doc/library/curses.panel.rst | 6 +- Doc/library/curses.rst | 128 +++++++++++++++++++++---------- Lib/curses/textpad.py | 3 +- Modules/_curses_panel.c | 8 +- Modules/_cursesmodule.c | 27 ++++--- Modules/clinic/_curses_panel.c.h | 10 ++- Modules/clinic/_cursesmodule.c.h | 16 ++-- 8 files changed, 132 insertions(+), 71 deletions(-) diff --git a/Doc/library/curses.ascii.rst b/Doc/library/curses.ascii.rst index 8f8e3ddda8ef52..3ac76edd38dcc8 100644 --- a/Doc/library/curses.ascii.rst +++ b/Doc/library/curses.ascii.rst @@ -114,7 +114,7 @@ C library: .. function:: isblank(c) - Checks for an ASCII whitespace character; space or horizontal tab. + Checks for an ASCII blank character; space or horizontal tab. .. function:: iscntrl(c) @@ -168,7 +168,8 @@ C library: .. function:: isctrl(c) - Checks for an ASCII control character (ordinal values 0 to 31). + Checks for an ASCII control character (ordinal values 0 to 31). Unlike + :func:`iscntrl`, this does not include the delete character (0x7f). .. function:: ismeta(c) diff --git a/Doc/library/curses.panel.rst b/Doc/library/curses.panel.rst index 5bc6b74b7f07ca..9f2f3a42580b9e 100644 --- a/Doc/library/curses.panel.rst +++ b/Doc/library/curses.panel.rst @@ -26,7 +26,8 @@ The module :mod:`!curses.panel` defines the following functions: .. function:: new_panel(win) - Returns a panel object, associating it with the given window *win*. Be aware + Returns a panel object, associating it with the given window *win* and + placing the new panel on top of the panel stack. Be aware that you need to keep the returned panel object referenced explicitly. If you don't, the panel object is garbage collected and removed from the panel stack. @@ -99,7 +100,8 @@ Panel objects have the following methods: .. method:: Panel.show() - Display the panel (which might have been hidden). + Display the panel (which might have been hidden), placing it on top of + the panel stack. .. method:: Panel.top() diff --git a/Doc/library/curses.rst b/Doc/library/curses.rst index 0f1449873fcf73..634debd23e3926 100644 --- a/Doc/library/curses.rst +++ b/Doc/library/curses.rst @@ -80,6 +80,8 @@ The module :mod:`!curses` defines the following functions: * Change the definition of the color-pair ``0`` to ``(fg, bg)``. + This is an ncurses extension. + .. versionadded:: 3.14 @@ -116,7 +118,8 @@ The module :mod:`!curses` defines the following functions: Return the intensity of the red, green, and blue (RGB) components in the color *color_number*, which must be between ``0`` and ``COLORS - 1``. Return a 3-tuple, containing the R,G,B values for the given color, which will be between - ``0`` (no component) and ``1000`` (maximum amount of component). + ``0`` (no component) and ``1000`` (maximum amount of component). Raise an + exception if the color is not supported. .. function:: color_pair(pair_number) @@ -162,7 +165,7 @@ The module :mod:`!curses` defines the following functions: Update the physical screen. The curses library keeps two data structures, one representing the current physical screen contents and a virtual screen - representing the desired next state. The :func:`doupdate` ground updates the + representing the desired next state. The :func:`doupdate` function updates the physical screen to match the virtual screen. The virtual screen may be updated by a :meth:`~window.noutrefresh` call after write @@ -194,7 +197,7 @@ The module :mod:`!curses` defines the following functions: .. function:: filter() The :func:`.filter` routine, if used, must be called before :func:`initscr` is - called. The effect is that, during those calls, :envvar:`LINES` is set to ``1``; the + called. The effect is that, during the initialization, :envvar:`LINES` is set to ``1``; the capabilities ``clear``, ``cup``, ``cud``, ``cud1``, ``cuu1``, ``cuu``, ``vpa`` are disabled; and the ``home`` string is set to the value of ``cr``. The effect is that the cursor is confined to the current line, and so are screen updates. This may be used for enabling @@ -240,9 +243,10 @@ The module :mod:`!curses` defines the following functions: .. function:: getwin(file) - Read window related data stored in the file by an earlier :func:`window.putwin` call. + Read window related data stored in the file by an earlier :meth:`window.putwin` call. The routine then creates and initializes a new window using that data, returning - the new window object. + the new window object. The *file* argument must be a file object opened for + reading in binary mode. .. function:: has_colors() @@ -347,6 +351,8 @@ The module :mod:`!curses` defines the following functions: bytes object consisting of the prefix ``b'M-'`` followed by the name of the corresponding ASCII character. + Raise a :exc:`ValueError` if *k* is negative. + .. function:: killchar() @@ -372,7 +378,8 @@ The module :mod:`!curses` defines the following functions: Set the maximum time in milliseconds that can elapse between press and release events in order for them to be recognized as a click, and return the previous - interval value. The default value is 200 milliseconds, or one fifth of a second. + interval value. The default value is 166 milliseconds, or one sixth of a second. + Use a negative *interval* to obtain the interval value without changing it. .. function:: mousemask(mousemask) @@ -380,7 +387,7 @@ The module :mod:`!curses` defines the following functions: Set the mouse events to be reported, and return a tuple ``(availmask, oldmask)``. *availmask* indicates which of the specified mouse events can be reported; on complete failure it returns ``0``. *oldmask* is the previous value of - the given window's mouse event mask. If this function is never called, no mouse + the mouse event mask. If this function is never called, no mouse events are ever reported. @@ -417,12 +424,14 @@ The module :mod:`!curses` defines the following functions: right corner of the screen. -.. function:: nl() +.. function:: nl(flag=True) Enter newline mode. This mode translates the return key into newline on input, and translates newline into return and line-feed on output. Newline mode is initially on. + If *flag* is ``False``, the effect is the same as calling :func:`nonl`. + .. function:: nocbreak() @@ -475,6 +484,8 @@ The module :mod:`!curses` defines the following functions: terminfo capability for the current terminal. Note that the output of :func:`putp` always goes to standard output. + :func:`setupterm` (or :func:`initscr`) must be called first. + .. function:: qiflush([flag]) @@ -571,6 +582,10 @@ The module :mod:`!curses` defines the following functions: file descriptor to which any initialization sequences will be sent; if not supplied or ``-1``, the file descriptor for ``sys.stdout`` will be used. + Raise a :exc:`curses.error` if the terminal could not be found or its + terminfo database entry could not be read. If the terminal has already + been initialized, this function has no effect. + .. function:: start_color() @@ -605,6 +620,8 @@ The module :mod:`!curses` defines the following functions: Boolean capability, or ``0`` if it is canceled or absent from the terminal description. + :func:`setupterm` (or :func:`initscr`) must be called first. + .. function:: tigetnum(capname) @@ -613,6 +630,8 @@ The module :mod:`!curses` defines the following functions: numeric capability, or ``-1`` if it is canceled or absent from the terminal description. + :func:`setupterm` (or :func:`initscr`) must be called first. + .. function:: tigetstr(capname) @@ -621,13 +640,17 @@ The module :mod:`!curses` defines the following functions: is not a terminfo "string capability", or is canceled or absent from the terminal description. + :func:`setupterm` (or :func:`initscr`) must be called first. + .. function:: tparm(str[, ...]) Instantiate the bytes object *str* with the supplied parameters, where *str* should be a parameterized string obtained from the terminfo database. E.g. ``tparm(tigetstr("cup"), 5, 3)`` could result in ``b'\033[6;4H'``, the exact - result depending on terminal type. + result depending on terminal type. Up to nine integer parameters may be supplied. + + :func:`setupterm` (or :func:`initscr`) must be called first. .. function:: typeahead(fd) @@ -756,12 +779,11 @@ Window Objects Attempting to write to the lower right corner of a window, subwindow, or pad will cause an exception to be raised after the string is printed. - * A `bug in ncurses <https://bugs.python.org/issue35924>`_, the backend - for this Python module, can cause SegFaults when resizing windows. This - is fixed in ncurses-6.1-20190511. If you are stuck with an earlier - ncurses, you can avoid triggering this if you do not call :func:`addstr` - with a *str* that has embedded newlines. Instead, call :func:`addstr` - separately for each line. + * A bug in ncurses, the backend for this Python module, could cause + segfaults when resizing windows. This was fixed in ncurses-6.1-20190511. + If you are stuck with an earlier ncurses, you can avoid triggering it by + not calling :meth:`!addstr` with a *str* that has embedded newlines; + instead, call :meth:`!addstr` separately for each line. .. method:: window.attroff(attr) @@ -888,7 +910,8 @@ Window Objects .. method:: window.delch([y, x]) - Delete any character at ``(y, x)``. + Delete the character under the cursor, or at ``(y, x)`` if specified. All + characters to the right on the same line are shifted one position left. .. method:: window.deleteln() @@ -990,6 +1013,7 @@ Window Objects window.getstr(y, x, n) Read a bytes object from the user, with primitive line editing capacity. + At most *n* characters are read (2047 by default). The maximum value for *n* is 2047. .. versionchanged:: 3.14 @@ -1002,11 +1026,12 @@ Window Objects upper-left corner. -.. method:: window.hline(ch, n) - window.hline(y, x, ch, n) +.. method:: window.hline(ch, n[, attr]) + window.hline(y, x, ch, n[, attr]) Display a horizontal line starting at ``(y, x)`` with length *n* consisting of - the character *ch*. + the character *ch* with attributes *attr*. The line stops at the right edge + of the window if fewer than *n* cells are available. .. method:: window.idcok(flag) @@ -1019,8 +1044,8 @@ Window Objects .. method:: window.idlok(flag) - If *flag* is ``True``, :mod:`!curses` will try and use hardware line - editing facilities. Otherwise, line insertion/deletion are disabled. + If *flag* is ``True``, :mod:`!curses` will try to use hardware line + editing facilities. Otherwise, curses will not use them. .. method:: window.immedok(flag) @@ -1040,8 +1065,10 @@ Window Objects .. method:: window.insch(ch[, attr]) window.insch(y, x, ch[, attr]) - Paint character *ch* at ``(y, x)`` with attributes *attr*, moving the line from - position *x* right by one character. + Insert character *ch* with attributes *attr* before the character under the + cursor, or at ``(y, x)`` if specified. All characters to the right of the + cursor are shifted one position right, with the rightmost character on the + line being lost. The cursor position does not change. .. method:: window.insdelln(nlines) @@ -1082,7 +1109,8 @@ Window Objects window.instr(y, x[, n]) Return a bytes object of characters, extracted from the window starting at the - current cursor position, or at *y*, *x* if specified. Attributes are stripped + current cursor position, or at *y*, *x* if specified, and stopping at the end + of the line. Attributes and color information are stripped from the characters. If *n* is specified, :meth:`instr` returns a string at most *n* characters long (exclusive of the trailing NUL). The maximum value for *n* is 2047. @@ -1114,8 +1142,7 @@ Window Objects .. method:: window.leaveok(flag) If *flag* is ``True``, cursor is left where it is on update, instead of being at "cursor - position." This reduces cursor movement where possible. If possible the cursor - will be made invisible. + position." This reduces cursor movement where possible. If *flag* is ``False``, cursor will always be at "cursor position" after an update. @@ -1136,6 +1163,9 @@ Window Objects Move the window so its upper-left corner is at ``(new_y, new_x)``. + Moving the window so that any part of it would be off the screen is an error: + the window is not moved and :exc:`curses.error` is raised. + .. method:: window.nodelay(flag) @@ -1151,11 +1181,16 @@ Window Objects .. method:: window.noutrefresh() + window.noutrefresh(pminrow, pmincol, sminrow, smincol, smaxrow, smaxcol) Mark for refresh but wait. This function updates the data structure representing the desired state of the window, but does not force an update of the physical screen. To accomplish that, call :func:`doupdate`. + The 6 arguments can only be specified, and are then required, when the window + is a pad created with :func:`newpad`; they have the same meaning as for + :meth:`refresh`. + .. method:: window.overlay(destwin[, sminrow, smincol, dminrow, dmincol, dmaxrow, dmaxcol]) @@ -1206,8 +1241,8 @@ Window Objects Update the display immediately (sync actual screen with previous drawing/deleting methods). - The 6 optional arguments can only be specified when the window is a pad created - with :func:`newpad`. The additional parameters are needed to indicate what part + The 6 arguments can only be specified, and are then required, when the window + is a pad created with :func:`newpad`. The additional parameters are needed to indicate what part of the pad and screen are involved. *pminrow* and *pmincol* specify the upper left-hand corner of the rectangle to be displayed in the pad. *sminrow*, *smincol*, *smaxrow*, and *smaxcol* specify the edges of the rectangle to be @@ -1228,7 +1263,9 @@ Window Objects .. method:: window.scroll([lines=1]) - Scroll the screen or scrolling region upward by *lines* lines. + Scroll the screen or scrolling region. Scroll upward by *lines* lines if + *lines* is positive, or downward if it is negative. Scrolling has no effect + unless it has been enabled for the window with :meth:`scrollok`. .. method:: window.scrollok(flag) @@ -1261,15 +1298,17 @@ Window Objects .. method:: window.subpad(begin_y, begin_x) window.subpad(nlines, ncols, begin_y, begin_x) - Return a sub-window, whose upper-left corner is at ``(begin_y, begin_x)``, and - whose width/height is *ncols*/*nlines*. + Return a sub-pad, whose upper-left corner is at ``(begin_y, begin_x)``, and + whose width/height is *ncols*/*nlines*. The coordinates are relative to the + parent pad (unlike :meth:`subwin`, which uses screen coordinates). This + method is only available for pads created with :func:`newpad`. .. method:: window.subwin(begin_y, begin_x) window.subwin(nlines, ncols, begin_y, begin_x) - Return a sub-window, whose upper-left corner is at ``(begin_y, begin_x)``, and - whose width/height is *ncols*/*nlines*. + Return a sub-window, whose upper-left corner is at the screen-relative + coordinates ``(begin_y, begin_x)``, and whose width/height is *ncols*/*nlines*. By default, the sub-window will extend from the specified position to the lower right corner of the window. @@ -1792,7 +1831,7 @@ The following table lists mouse button constants used by :meth:`getmouse`: +----------------------------------+---------------------------------------------+ | .. data:: BUTTON_CTRL | Control was down during button state change | +----------------------------------+---------------------------------------------+ -| .. data:: BUTTON_ALT | Control was down during button state change | +| .. data:: BUTTON_ALT | Alt was down during button state change | +----------------------------------+---------------------------------------------+ .. versionchanged:: 3.10 @@ -1857,32 +1896,36 @@ Textbox objects You can instantiate a :class:`Textbox` object as follows: -.. class:: Textbox(win) +.. class:: Textbox(win, insert_mode=False) Return a textbox widget object. The *win* argument should be a curses :ref:`window <curses-window-objects>` object in which the textbox is to - be contained. The edit cursor of the textbox is initially located at the + be contained. If *insert_mode* is true, the textbox inserts typed + characters, shifting existing text to the right, rather than overwriting it. + The edit cursor of the textbox is initially located at the upper left hand corner of the containing window, with coordinates ``(0, 0)``. The instance's :attr:`stripspaces` flag is initially on. :class:`Textbox` objects have the following methods: - .. method:: edit([validator]) + .. method:: edit(validate=None) This is the entry point you will normally use. It accepts editing keystrokes until one of the termination keystrokes is entered. If - *validator* is supplied, it must be a function. It will be called for + *validate* is supplied, it must be a function. It will be called for each keystroke entered with the keystroke as a parameter; command dispatch - is done on the result. This method returns the window contents as a + is done on the result. If it returns a false value, the keystroke is + ignored. This method returns the window contents as a string; whether blanks in the window are included is affected by the :attr:`stripspaces` attribute. .. method:: do_command(ch) - Process a single command keystroke. Here are the supported special - keystrokes: + Process a single command keystroke. Returns ``1`` to continue editing, + or ``0`` if a termination keystroke was processed. Here are the supported + special keystrokes: +------------------+-------------------------------------------+ | Keystroke | Action | @@ -1905,7 +1948,8 @@ You can instantiate a :class:`Textbox` object as follows: | :kbd:`Control-H` | Delete character backward. | +------------------+-------------------------------------------+ | :kbd:`Control-J` | Terminate if the window is 1 line, | - | | otherwise insert newline. | + | | otherwise move to the start of the next | + | | line. | +------------------+-------------------------------------------+ | :kbd:`Control-K` | If line is blank, delete it, otherwise | | | clear to end of line. | diff --git a/Lib/curses/textpad.py b/Lib/curses/textpad.py index 3a98fd6043a124..c8dbf9fb614fcb 100644 --- a/Lib/curses/textpad.py +++ b/Lib/curses/textpad.py @@ -28,7 +28,8 @@ class Textbox: Ctrl-F Cursor right, wrapping to next line when appropriate. Ctrl-G Terminate, returning the window contents. Ctrl-H Delete character backward. - Ctrl-J Terminate if the window is 1 line, otherwise insert newline. + Ctrl-J Terminate if the window is 1 line, otherwise move to start + of next line. Ctrl-K If line is blank, delete it, otherwise clear to end of line. Ctrl-L Refresh screen. Ctrl-N Cursor down; move down one line. diff --git a/Modules/_curses_panel.c b/Modules/_curses_panel.c index 52411e413533ce..411e8187e5b447 100644 --- a/Modules/_curses_panel.c +++ b/Modules/_curses_panel.c @@ -380,11 +380,13 @@ _curses_panel_panel_hide_impl(PyCursesPanelObject *self) _curses_panel.panel.show Display the panel (which might have been hidden). + +The panel is placed on top of the panel stack. [clinic start generated code]*/ static PyObject * _curses_panel_panel_show_impl(PyCursesPanelObject *self) -/*[clinic end generated code: output=6b4553ab45c97769 input=57b167bbefaa3755]*/ +/*[clinic end generated code: output=6b4553ab45c97769 input=9997cf364ca71422]*/ { int rtn = show_panel(self->pan); return curses_panel_panel_check_err(self, rtn, "show_panel", "show"); @@ -724,11 +726,13 @@ _curses_panel.new_panel / Return a panel object, associating it with the given window win. + +The new panel is placed on top of the panel stack. [clinic start generated code]*/ static PyObject * _curses_panel_new_panel_impl(PyObject *module, PyCursesWindowObject *win) -/*[clinic end generated code: output=45e948e0176a9bd2 input=74d4754e0ebe4800]*/ +/*[clinic end generated code: output=45e948e0176a9bd2 input=3b6fea647b808fd7]*/ { PANEL *pan = new_panel(win->win); if (pan == NULL) { diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index 4438e384aab9b2..cce93bea5751c2 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -1574,13 +1574,16 @@ _curses.window.delch ] / -Delete any character at (y, x). +Delete the character under the cursor, or at (y, x) if specified. + +All characters to the right on the same line are shifted one +position left. [clinic start generated code]*/ static PyObject * _curses_window_delch_impl(PyCursesWindowObject *self, int group_right_1, int y, int x) -/*[clinic end generated code: output=22e77bb9fa11b461 input=d2f79e630a4fc6d0]*/ +/*[clinic end generated code: output=22e77bb9fa11b461 input=61db3c7f4885e90c]*/ { int rtn; const char *funcname; @@ -2120,10 +2123,12 @@ PyDoc_STRVAR(_curses_window_instr__doc__, " n\n" " Maximal number of characters.\n" "\n" -"Return a string of characters, extracted from the window starting at the\n" -"current cursor position, or at y, x if specified. Attributes are stripped\n" -"from the characters. If n is specified, instr() returns a string at most\n" -"n characters long (exclusive of the trailing NUL)."); +"Return a string of characters, extracted from the window starting\n" +"at the current cursor position, or at y, x if specified, and\n" +"stopping at the end of the line. Attributes and color\n" +"information are stripped from the characters. If n is specified,\n" +"instr() returns a string at most n characters long (exclusive of\n" +"the trailing NUL)."); static PyObject * PyCursesWindow_instr(PyObject *op, PyObject *args) @@ -4153,24 +4158,22 @@ _curses_mouseinterval_impl(PyObject *module, int interval) } /*[clinic input] -@permit_long_summary _curses.mousemask newmask: unsigned_long(bitwise=True) / -Set the mouse events to be reported, and return a tuple (availmask, oldmask). +Set the mouse events to be reported, and return (availmask, oldmask). Return a tuple (availmask, oldmask). availmask indicates which of the specified mouse events can be reported; on complete failure it returns -0. oldmask is the previous value of the given window's mouse event -mask. If this function is never called, no mouse events are ever -reported. +0. oldmask is the previous value of the mouse event mask. If this +function is never called, no mouse events are ever reported. [clinic start generated code]*/ static PyObject * _curses_mousemask_impl(PyObject *module, unsigned long newmask) -/*[clinic end generated code: output=9406cf1b8a36e485 input=78990ec6c52aa888]*/ +/*[clinic end generated code: output=9406cf1b8a36e485 input=b8a9a4ccbce633f4]*/ { mmask_t oldmask, availmask; diff --git a/Modules/clinic/_curses_panel.c.h b/Modules/clinic/_curses_panel.c.h index d8b2cba7fd3f89..316264db80a658 100644 --- a/Modules/clinic/_curses_panel.c.h +++ b/Modules/clinic/_curses_panel.c.h @@ -47,7 +47,9 @@ PyDoc_STRVAR(_curses_panel_panel_show__doc__, "show($self, /)\n" "--\n" "\n" -"Display the panel (which might have been hidden)."); +"Display the panel (which might have been hidden).\n" +"\n" +"The panel is placed on top of the panel stack."); #define _CURSES_PANEL_PANEL_SHOW_METHODDEF \ {"show", (PyCFunction)_curses_panel_panel_show, METH_NOARGS, _curses_panel_panel_show__doc__}, @@ -280,7 +282,9 @@ PyDoc_STRVAR(_curses_panel_new_panel__doc__, "new_panel($module, win, /)\n" "--\n" "\n" -"Return a panel object, associating it with the given window win."); +"Return a panel object, associating it with the given window win.\n" +"\n" +"The new panel is placed on top of the panel stack."); #define _CURSES_PANEL_NEW_PANEL_METHODDEF \ {"new_panel", (PyCFunction)_curses_panel_new_panel, METH_O, _curses_panel_new_panel__doc__}, @@ -343,4 +347,4 @@ _curses_panel_update_panels(PyObject *module, PyObject *Py_UNUSED(ignored)) { return _curses_panel_update_panels_impl(module); } -/*[clinic end generated code: output=62f20ef03eefdf44 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=ec3fe619150e512e input=a9049054013a1b77]*/ diff --git a/Modules/clinic/_cursesmodule.c.h b/Modules/clinic/_cursesmodule.c.h index eec9e82739b778..d46cc4cf768c34 100644 --- a/Modules/clinic/_cursesmodule.c.h +++ b/Modules/clinic/_cursesmodule.c.h @@ -540,12 +540,15 @@ _curses_window_box(PyObject *self, PyObject *args) PyDoc_STRVAR(_curses_window_delch__doc__, "delch([y, x])\n" -"Delete any character at (y, x).\n" +"Delete the character under the cursor, or at (y, x) if specified.\n" "\n" " y\n" " Y-coordinate.\n" " x\n" -" X-coordinate."); +" X-coordinate.\n" +"\n" +"All characters to the right on the same line are shifted one\n" +"position left."); #define _CURSES_WINDOW_DELCH_METHODDEF \ {"delch", (PyCFunction)_curses_window_delch, METH_VARARGS, _curses_window_delch__doc__}, @@ -3147,13 +3150,12 @@ PyDoc_STRVAR(_curses_mousemask__doc__, "mousemask($module, newmask, /)\n" "--\n" "\n" -"Set the mouse events to be reported, and return a tuple (availmask, oldmask).\n" +"Set the mouse events to be reported, and return (availmask, oldmask).\n" "\n" "Return a tuple (availmask, oldmask). availmask indicates which of the\n" "specified mouse events can be reported; on complete failure it returns\n" -"0. oldmask is the previous value of the given window\'s mouse event\n" -"mask. If this function is never called, no mouse events are ever\n" -"reported."); +"0. oldmask is the previous value of the mouse event mask. If this\n" +"function is never called, no mouse events are ever reported."); #define _CURSES_MOUSEMASK_METHODDEF \ {"mousemask", (PyCFunction)_curses_mousemask, METH_O, _curses_mousemask__doc__}, @@ -4470,4 +4472,4 @@ _curses_has_extended_color_support(PyObject *module, PyObject *Py_UNUSED(ignored #ifndef _CURSES_ASSUME_DEFAULT_COLORS_METHODDEF #define _CURSES_ASSUME_DEFAULT_COLORS_METHODDEF #endif /* !defined(_CURSES_ASSUME_DEFAULT_COLORS_METHODDEF) */ -/*[clinic end generated code: output=e7c7932f4a4e9bce input=a9049054013a1b77]*/ +/*[clinic end generated code: output=ab9b5057eeaf0f33 input=a9049054013a1b77]*/ From 7170c951a15e8234d97afbf65bb86eda060f645b Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 18 Jun 2026 11:57:03 +0200 Subject: [PATCH 353/818] [3.15] gh-151623: Improve curses documentation style (GH-151635) (#151636) Co-authored-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> --- Doc/library/curses.panel.rst | 2 +- Doc/library/curses.rst | 50 ++++++++++++++++++------------------ 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/Doc/library/curses.panel.rst b/Doc/library/curses.panel.rst index 9f2f3a42580b9e..2cfd522f34879a 100644 --- a/Doc/library/curses.panel.rst +++ b/Doc/library/curses.panel.rst @@ -45,7 +45,7 @@ The module :mod:`!curses.panel` defines the following functions: .. _curses-panel-objects: -Panel Objects +Panel objects ------------- Panel objects, as returned by :func:`new_panel` above, are windows with a diff --git a/Doc/library/curses.rst b/Doc/library/curses.rst index 634debd23e3926..085500860d127e 100644 --- a/Doc/library/curses.rst +++ b/Doc/library/curses.rst @@ -243,7 +243,7 @@ The module :mod:`!curses` defines the following functions: .. function:: getwin(file) - Read window related data stored in the file by an earlier :meth:`window.putwin` call. + Read window-related data stored in the file by an earlier :meth:`window.putwin` call. The routine then creates and initializes a new window using that data, returning the new window object. The *file* argument must be a file object opened for reading in binary mode. @@ -257,7 +257,7 @@ The module :mod:`!curses` defines the following functions: Return ``True`` if the module supports extended colors; otherwise, return ``False``. Extended color support allows more than 256 color pairs for - terminals that support more than 16 colors (e.g. xterm-256color). + terminals that support more than 16 colors (for example, xterm-256color). Extended color support requires ncurses version 6.1 or later. @@ -409,7 +409,7 @@ The module :mod:`!curses` defines the following functions: methods of a pad require 6 arguments to specify the part of the pad to be displayed and the location on the screen to be used for the display. The arguments are *pminrow*, *pmincol*, *sminrow*, *smincol*, *smaxrow*, *smaxcol*; the *p* - arguments refer to the upper left corner of the pad region to be displayed and + arguments refer to the upper-left corner of the pad region to be displayed and the *s* arguments define a clipping box on the screen within which the pad region is to be displayed. @@ -646,7 +646,7 @@ The module :mod:`!curses` defines the following functions: .. function:: tparm(str[, ...]) Instantiate the bytes object *str* with the supplied parameters, where *str* should - be a parameterized string obtained from the terminfo database. E.g. + be a parameterized string obtained from the terminfo database. For example, ``tparm(tigetstr("cup"), 5, 3)`` could result in ``b'\033[6;4H'``, the exact result depending on terminal type. Up to nine integer parameters may be supplied. @@ -736,7 +736,7 @@ The module :mod:`!curses` defines the following functions: .. _curses-window-objects: -Window Objects +Window objects -------------- .. class:: window @@ -755,7 +755,7 @@ Window Objects .. note:: Writing outside the window, subwindow, or pad raises a :exc:`curses.error`. - Attempting to write to the lower right corner of a window, subwindow, + Attempting to write to the lower-right corner of a window, subwindow, or pad will cause an exception to be raised after the character is printed. @@ -776,7 +776,7 @@ Window Objects .. note:: * Writing outside the window, subwindow, or pad raises :exc:`curses.error`. - Attempting to write to the lower right corner of a window, subwindow, + Attempting to write to the lower-right corner of a window, subwindow, or pad will cause an exception to be raised after the string is printed. * A bug in ncurses, the backend for this Python module, could cause @@ -1013,8 +1013,8 @@ Window Objects window.getstr(y, x, n) Read a bytes object from the user, with primitive line editing capacity. - At most *n* characters are read (2047 by default). - The maximum value for *n* is 2047. + At most *n* characters are read; + *n* defaults to and cannot exceed 2047. .. versionchanged:: 3.14 The maximum value for *n* was increased from 1023 to 2047. @@ -1243,10 +1243,10 @@ Window Objects The 6 arguments can only be specified, and are then required, when the window is a pad created with :func:`newpad`. The additional parameters are needed to indicate what part - of the pad and screen are involved. *pminrow* and *pmincol* specify the upper - left-hand corner of the rectangle to be displayed in the pad. *sminrow*, + of the pad and screen are involved. *pminrow* and *pmincol* specify the + upper-left corner of the rectangle to be displayed in the pad. *sminrow*, *smincol*, *smaxrow*, and *smaxcol* specify the edges of the rectangle to be - displayed on the screen. The lower right-hand corner of the rectangle to be + displayed on the screen. The lower-right corner of the rectangle to be displayed in the pad is calculated from the screen coordinates, since the rectangles must be the same size. Both rectangles must be entirely contained within their respective structures. Negative values of *pminrow*, *pmincol*, @@ -1415,14 +1415,14 @@ The :mod:`!curses` module defines the following data members: .. data:: COLS - The width of the screen, i.e., the number of columns. + The width of the screen, that is, the number of columns. It is defined only after the call to :func:`initscr`. Updated by :func:`update_lines_cols`, :func:`resizeterm` and :func:`resize_term`. .. data:: LINES - The height of the screen, i.e., the number of lines. + The height of the screen, that is, the number of lines. It is defined only after the call to :func:`initscr`. Updated by :func:`update_lines_cols`, :func:`resizeterm` and :func:`resize_term`. @@ -1725,7 +1725,7 @@ falls back on a crude printable ASCII approximation. +------------------------+------------------------------------------+ | ACS code | Meaning | +========================+==========================================+ -| .. data:: ACS_BBSS | alternate name for upper right corner | +| .. data:: ACS_BBSS | alternate name for upper-right corner | +------------------------+------------------------------------------+ | .. data:: ACS_BLOCK | solid square block | +------------------------+------------------------------------------+ @@ -1733,7 +1733,7 @@ falls back on a crude printable ASCII approximation. +------------------------+------------------------------------------+ | .. data:: ACS_BSBS | alternate name for horizontal line | +------------------------+------------------------------------------+ -| .. data:: ACS_BSSB | alternate name for upper left corner | +| .. data:: ACS_BSSB | alternate name for upper-left corner | +------------------------+------------------------------------------+ | .. data:: ACS_BSSS | alternate name for top tee | +------------------------+------------------------------------------+ @@ -1759,9 +1759,9 @@ falls back on a crude printable ASCII approximation. +------------------------+------------------------------------------+ | .. data:: ACS_LEQUAL | less-than-or-equal-to | +------------------------+------------------------------------------+ -| .. data:: ACS_LLCORNER | lower left-hand corner | +| .. data:: ACS_LLCORNER | lower-left corner | +------------------------+------------------------------------------+ -| .. data:: ACS_LRCORNER | lower right-hand corner | +| .. data:: ACS_LRCORNER | lower-right corner | +------------------------+------------------------------------------+ | .. data:: ACS_LTEE | left tee | +------------------------+------------------------------------------+ @@ -1785,13 +1785,13 @@ falls back on a crude printable ASCII approximation. +------------------------+------------------------------------------+ | .. data:: ACS_S9 | scan line 9 | +------------------------+------------------------------------------+ -| .. data:: ACS_SBBS | alternate name for lower right corner | +| .. data:: ACS_SBBS | alternate name for lower-right corner | +------------------------+------------------------------------------+ | .. data:: ACS_SBSB | alternate name for vertical line | +------------------------+------------------------------------------+ | .. data:: ACS_SBSS | alternate name for right tee | +------------------------+------------------------------------------+ -| .. data:: ACS_SSBB | alternate name for lower left corner | +| .. data:: ACS_SSBB | alternate name for lower-left corner | +------------------------+------------------------------------------+ | .. data:: ACS_SSBS | alternate name for bottom tee | +------------------------+------------------------------------------+ @@ -1805,9 +1805,9 @@ falls back on a crude printable ASCII approximation. +------------------------+------------------------------------------+ | .. data:: ACS_UARROW | up arrow | +------------------------+------------------------------------------+ -| .. data:: ACS_ULCORNER | upper left corner | +| .. data:: ACS_ULCORNER | upper-left corner | +------------------------+------------------------------------------+ -| .. data:: ACS_URCORNER | upper right corner | +| .. data:: ACS_URCORNER | upper-right corner | +------------------------+------------------------------------------+ | .. data:: ACS_VLINE | vertical line | +------------------------+------------------------------------------+ @@ -1880,9 +1880,9 @@ The module :mod:`!curses.textpad` defines the following function: Draw a rectangle. The first argument must be a window object; the remaining arguments are coordinates relative to that window. The second and third - arguments are the y and x coordinates of the upper left hand corner of the + arguments are the y and x coordinates of the upper-left corner of the rectangle to be drawn; the fourth and fifth arguments are the y and x - coordinates of the lower right hand corner. The rectangle will be drawn using + coordinates of the lower-right corner. The rectangle will be drawn using VT100/IBM PC forms characters on terminals that make this possible (including xterm and most other software terminal emulators). Otherwise it will be drawn with ASCII dashes, vertical bars, and plus signs. @@ -1903,7 +1903,7 @@ You can instantiate a :class:`Textbox` object as follows: be contained. If *insert_mode* is true, the textbox inserts typed characters, shifting existing text to the right, rather than overwriting it. The edit cursor of the textbox is initially located at the - upper left hand corner of the containing window, with coordinates ``(0, 0)``. + upper-left corner of the containing window, with coordinates ``(0, 0)``. The instance's :attr:`stripspaces` flag is initially on. :class:`Textbox` objects have the following methods: From d9a1bff40b13590afdc9be13b7ca5c8047b56d59 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 18 Jun 2026 13:23:06 +0200 Subject: [PATCH 354/818] [3.15] gh-151623: Add missing curses docstrings and document intrflush() (GH-151632) (GH-151641) (cherry picked from commit 12add3822f458a3e107dff4176b4c4b991764ea7) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> --- Doc/library/curses.rst | 7 ++ Modules/_cursesmodule.c | 160 +++++++++++++++++++++++-------- Modules/clinic/_cursesmodule.c.h | 22 ++++- 3 files changed, 147 insertions(+), 42 deletions(-) diff --git a/Doc/library/curses.rst b/Doc/library/curses.rst index 085500860d127e..5726aee5af89b1 100644 --- a/Doc/library/curses.rst +++ b/Doc/library/curses.rst @@ -330,6 +330,13 @@ The module :mod:`!curses` defines the following functions: cause the interpreter to exit. +.. function:: intrflush(flag) + + If *flag* is ``True``, pressing an interrupt key (interrupt, break, or quit) + will flush all output in the terminal driver queue. If *flag* is ``False``, + no flushing is done. + + .. function:: is_term_resized(nlines, ncols) Return ``True`` if :func:`resize_term` would modify the window structure, diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index cce93bea5751c2..01cb6786e88aec 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -2937,39 +2937,71 @@ static PyMethodDef PyCursesWindow_methods[] = { _CURSES_WINDOW_BKGDSET_METHODDEF _CURSES_WINDOW_BORDER_METHODDEF _CURSES_WINDOW_BOX_METHODDEF - {"clear", PyCursesWindow_wclear, METH_NOARGS}, - {"clearok", PyCursesWindow_clearok, METH_VARARGS}, - {"clrtobot", PyCursesWindow_wclrtobot, METH_NOARGS}, - {"clrtoeol", PyCursesWindow_wclrtoeol, METH_NOARGS}, - {"cursyncup", PyCursesWindow_wcursyncup, METH_NOARGS}, + {"clear", PyCursesWindow_wclear, METH_NOARGS, + "clear($self, /)\n--\n\n" + "Clear the window and repaint it completely on the next refresh()."}, + {"clearok", PyCursesWindow_clearok, METH_VARARGS, + "clearok($self, flag, /)\n--\n\n" + "Clear the window on the next refresh() if flag is true."}, + {"clrtobot", PyCursesWindow_wclrtobot, METH_NOARGS, + "clrtobot($self, /)\n--\n\n" + "Erase from the cursor to the end of the window."}, + {"clrtoeol", PyCursesWindow_wclrtoeol, METH_NOARGS, + "clrtoeol($self, /)\n--\n\n" + "Erase from the cursor to the end of the line."}, + {"cursyncup", PyCursesWindow_wcursyncup, METH_NOARGS, + "cursyncup($self, /)\n--\n\n" + "Update the cursor position of all ancestor windows to match."}, _CURSES_WINDOW_DELCH_METHODDEF - {"deleteln", PyCursesWindow_wdeleteln, METH_NOARGS}, + {"deleteln", PyCursesWindow_wdeleteln, METH_NOARGS, + "deleteln($self, /)\n--\n\n" + "Delete the line under the cursor; move following lines up by one."}, _CURSES_WINDOW_DERWIN_METHODDEF _CURSES_WINDOW_ECHOCHAR_METHODDEF _CURSES_WINDOW_ENCLOSE_METHODDEF - {"erase", PyCursesWindow_werase, METH_NOARGS}, - {"getbegyx", PyCursesWindow_getbegyx, METH_NOARGS}, + {"erase", PyCursesWindow_werase, METH_NOARGS, + "erase($self, /)\n--\n\n" + "Clear the window."}, + {"getbegyx", PyCursesWindow_getbegyx, METH_NOARGS, + "getbegyx($self, /)\n--\n\n" + "Return a tuple (y, x) of the upper-left corner coordinates."}, _CURSES_WINDOW_GETBKGD_METHODDEF _CURSES_WINDOW_GETCH_METHODDEF _CURSES_WINDOW_GETKEY_METHODDEF _CURSES_WINDOW_GET_WCH_METHODDEF - {"getmaxyx", PyCursesWindow_getmaxyx, METH_NOARGS}, - {"getparyx", PyCursesWindow_getparyx, METH_NOARGS}, + {"getmaxyx", PyCursesWindow_getmaxyx, METH_NOARGS, + "getmaxyx($self, /)\n--\n\n" + "Return a tuple (y, x) of the window height and width."}, + {"getparyx", PyCursesWindow_getparyx, METH_NOARGS, + "getparyx($self, /)\n--\n\n" + "Return (y, x) relative to the parent window, or (-1, -1) if none."}, { "getstr", PyCursesWindow_getstr, METH_VARARGS, _curses_window_getstr__doc__ }, - {"getyx", PyCursesWindow_getyx, METH_NOARGS}, + {"getyx", PyCursesWindow_getyx, METH_NOARGS, + "getyx($self, /)\n--\n\n" + "Return a tuple (y, x) of the current cursor position."}, _CURSES_WINDOW_HLINE_METHODDEF - {"idcok", PyCursesWindow_idcok, METH_VARARGS}, - {"idlok", PyCursesWindow_idlok, METH_VARARGS}, + {"idcok", PyCursesWindow_idcok, METH_VARARGS, + "idcok($self, flag, /)\n--\n\n" + "Enable or disable the hardware insert/delete character feature."}, + {"idlok", PyCursesWindow_idlok, METH_VARARGS, + "idlok($self, flag, /)\n--\n\n" + "Enable or disable the hardware insert/delete line feature."}, #ifdef HAVE_CURSES_IMMEDOK - {"immedok", PyCursesWindow_immedok, METH_VARARGS}, + {"immedok", PyCursesWindow_immedok, METH_VARARGS, + "immedok($self, flag, /)\n--\n\n" + "If flag is true, refresh the window on every change to it."}, #endif _CURSES_WINDOW_INCH_METHODDEF _CURSES_WINDOW_INSCH_METHODDEF - {"insdelln", PyCursesWindow_winsdelln, METH_VARARGS}, - {"insertln", PyCursesWindow_winsertln, METH_NOARGS}, + {"insdelln", PyCursesWindow_winsdelln, METH_VARARGS, + "insdelln($self, nlines, /)\n--\n\n" + "Insert (nlines > 0) or delete (nlines < 0) lines above the cursor."}, + {"insertln", PyCursesWindow_winsertln, METH_NOARGS, + "insertln($self, /)\n--\n\n" + "Insert a blank line under the cursor; move following lines down."}, _CURSES_WINDOW_INSNSTR_METHODDEF _CURSES_WINDOW_INSSTR_METHODDEF { @@ -2977,40 +3009,78 @@ static PyMethodDef PyCursesWindow_methods[] = { _curses_window_instr__doc__ }, _CURSES_WINDOW_IS_LINETOUCHED_METHODDEF - {"is_wintouched", PyCursesWindow_is_wintouched, METH_NOARGS}, - {"keypad", PyCursesWindow_keypad, METH_VARARGS}, - {"leaveok", PyCursesWindow_leaveok, METH_VARARGS}, - {"move", PyCursesWindow_wmove, METH_VARARGS}, - {"mvderwin", PyCursesWindow_mvderwin, METH_VARARGS}, - {"mvwin", PyCursesWindow_mvwin, METH_VARARGS}, - {"nodelay", PyCursesWindow_nodelay, METH_VARARGS}, - {"notimeout", PyCursesWindow_notimeout, METH_VARARGS}, + {"is_wintouched", PyCursesWindow_is_wintouched, METH_NOARGS, + "is_wintouched($self, /)\n--\n\n" + "Return True if the window changed since the last refresh()."}, + {"keypad", PyCursesWindow_keypad, METH_VARARGS, + "keypad($self, flag, /)\n--\n\n" + "Interpret escape sequences for special keys if flag is true."}, + {"leaveok", PyCursesWindow_leaveok, METH_VARARGS, + "leaveok($self, flag, /)\n--\n\n" + "If flag is true, leave the cursor where the update leaves it."}, + {"move", PyCursesWindow_wmove, METH_VARARGS, + "move($self, new_y, new_x, /)\n--\n\n" + "Move the cursor to (new_y, new_x)."}, + {"mvderwin", PyCursesWindow_mvderwin, METH_VARARGS, + "mvderwin($self, y, x, /)\n--\n\n" + "Move the window inside its parent window."}, + {"mvwin", PyCursesWindow_mvwin, METH_VARARGS, + "mvwin($self, new_y, new_x, /)\n--\n\n" + "Move the window so its upper-left corner is at (new_y, new_x)."}, + {"nodelay", PyCursesWindow_nodelay, METH_VARARGS, + "nodelay($self, flag, /)\n--\n\n" + "If flag is true, getch() becomes non-blocking."}, + {"notimeout", PyCursesWindow_notimeout, METH_VARARGS, + "notimeout($self, flag, /)\n--\n\n" + "If flag is true, do not time out escape sequences."}, _CURSES_WINDOW_NOUTREFRESH_METHODDEF _CURSES_WINDOW_OVERLAY_METHODDEF _CURSES_WINDOW_OVERWRITE_METHODDEF _CURSES_WINDOW_PUTWIN_METHODDEF _CURSES_WINDOW_REDRAWLN_METHODDEF - {"redrawwin", PyCursesWindow_redrawwin, METH_NOARGS}, + {"redrawwin", PyCursesWindow_redrawwin, METH_NOARGS, + "redrawwin($self, /)\n--\n\n" + "Mark the entire window for redraw on the next refresh()."}, _CURSES_WINDOW_REFRESH_METHODDEF #ifndef STRICT_SYSV_CURSES - {"resize", PyCursesWindow_wresize, METH_VARARGS}, + {"resize", PyCursesWindow_wresize, METH_VARARGS, + "resize($self, nlines, ncols, /)\n--\n\n" + "Resize the window to nlines rows and ncols columns."}, #endif _CURSES_WINDOW_SCROLL_METHODDEF - {"scrollok", PyCursesWindow_scrollok, METH_VARARGS}, + {"scrollok", PyCursesWindow_scrollok, METH_VARARGS, + "scrollok($self, flag, /)\n--\n\n" + "Control whether the window scrolls when the cursor moves off it."}, _CURSES_WINDOW_SETSCRREG_METHODDEF - {"standend", PyCursesWindow_wstandend, METH_NOARGS}, - {"standout", PyCursesWindow_wstandout, METH_NOARGS}, + {"standend", PyCursesWindow_wstandend, METH_NOARGS, + "standend($self, /)\n--\n\n" + "Turn off the standout attribute."}, + {"standout", PyCursesWindow_wstandout, METH_NOARGS, + "standout($self, /)\n--\n\n" + "Turn on the A_STANDOUT attribute."}, {"subpad", _curses_window_subwin, METH_VARARGS, _curses_window_subwin__doc__}, _CURSES_WINDOW_SUBWIN_METHODDEF - {"syncdown", PyCursesWindow_wsyncdown, METH_NOARGS}, + {"syncdown", PyCursesWindow_wsyncdown, METH_NOARGS, + "syncdown($self, /)\n--\n\n" + "Touch each location changed in any ancestor of the window."}, #ifdef HAVE_CURSES_SYNCOK - {"syncok", PyCursesWindow_syncok, METH_VARARGS}, + {"syncok", PyCursesWindow_syncok, METH_VARARGS, + "syncok($self, flag, /)\n--\n\n" + "If flag is true, call syncup() on every change to the window."}, #endif - {"syncup", PyCursesWindow_wsyncup, METH_NOARGS}, - {"timeout", PyCursesWindow_wtimeout, METH_VARARGS}, + {"syncup", PyCursesWindow_wsyncup, METH_NOARGS, + "syncup($self, /)\n--\n\n" + "Touch locations in ancestors that changed in this window."}, + {"timeout", PyCursesWindow_wtimeout, METH_VARARGS, + "timeout($self, delay, /)\n--\n\n" + "Set blocking or non-blocking read behavior for the window."}, _CURSES_WINDOW_TOUCHLINE_METHODDEF - {"touchwin", PyCursesWindow_touchwin, METH_NOARGS}, - {"untouchwin", PyCursesWindow_untouchwin, METH_NOARGS}, + {"touchwin", PyCursesWindow_touchwin, METH_NOARGS, + "touchwin($self, /)\n--\n\n" + "Mark the whole window as changed."}, + {"untouchwin", PyCursesWindow_untouchwin, METH_NOARGS, + "untouchwin($self, /)\n--\n\n" + "Mark all lines in the window as unchanged since last refresh()."}, _CURSES_WINDOW_VLINE_METHODDEF {NULL, NULL} /* sentinel */ }; @@ -3127,11 +3197,17 @@ static PyType_Spec PyCursesWindow_Type_spec = { /*[clinic input] _curses.filter +Restrict screen updates to the current line. + +Must be called before initscr(). Afterwards curses confines the cursor +and screen updates to a single line, which is useful for enabling +character-at-a-time line editing without touching the rest of the +screen. [clinic start generated code]*/ static PyObject * _curses_filter_impl(PyObject *module) -/*[clinic end generated code: output=fb5b8a3642eb70b5 input=668c75a6992d3624]*/ +/*[clinic end generated code: output=fb5b8a3642eb70b5 input=e3c64d6ab2106132]*/ { /* not checking for PyCursesInitialised here since filter() must be called before initscr() */ @@ -4004,11 +4080,16 @@ _curses.intrflush flag: bool / +Control flushing of the output buffer when an interrupt key is pressed. + +If flag is true, pressing an interrupt key (interrupt, break, or quit) +flushes all output in the terminal driver queue. If flag is false, no +flushing is done. [clinic start generated code]*/ static PyObject * _curses_intrflush_impl(PyObject *module, int flag) -/*[clinic end generated code: output=c1986df35e999a0f input=c65fe2ef973fe40a]*/ +/*[clinic end generated code: output=c1986df35e999a0f input=66588c2bccc7e8fa]*/ { PyCursesStatefulInitialised(module); @@ -4525,11 +4606,14 @@ update_lines_cols(PyObject *private_module) /*[clinic input] _curses.update_lines_cols +Update the LINES and COLS module variables. + +This is useful for detecting manual screen resize. [clinic start generated code]*/ static PyObject * _curses_update_lines_cols_impl(PyObject *module) -/*[clinic end generated code: output=423f2b1e63ed0f75 input=5f065ab7a28a5d90]*/ +/*[clinic end generated code: output=423f2b1e63ed0f75 input=1d8ea7c356b61a8b]*/ { if (!update_lines_cols(module)) { return NULL; diff --git a/Modules/clinic/_cursesmodule.c.h b/Modules/clinic/_cursesmodule.c.h index d46cc4cf768c34..cab9b068a561da 100644 --- a/Modules/clinic/_cursesmodule.c.h +++ b/Modules/clinic/_cursesmodule.c.h @@ -1844,7 +1844,13 @@ _curses_window_vline(PyObject *self, PyObject *args) PyDoc_STRVAR(_curses_filter__doc__, "filter($module, /)\n" "--\n" -"\n"); +"\n" +"Restrict screen updates to the current line.\n" +"\n" +"Must be called before initscr(). Afterwards curses confines the cursor\n" +"and screen updates to a single line, which is useful for enabling\n" +"character-at-a-time line editing without touching the rest of the\n" +"screen."); #define _CURSES_FILTER_METHODDEF \ {"filter", (PyCFunction)_curses_filter, METH_NOARGS, _curses_filter__doc__}, @@ -2917,7 +2923,12 @@ _curses_set_tabsize(PyObject *module, PyObject *arg) PyDoc_STRVAR(_curses_intrflush__doc__, "intrflush($module, flag, /)\n" "--\n" -"\n"); +"\n" +"Control flushing of the output buffer when an interrupt key is pressed.\n" +"\n" +"If flag is true, pressing an interrupt key (interrupt, break, or quit)\n" +"flushes all output in the terminal driver queue. If flag is false, no\n" +"flushing is done."); #define _CURSES_INTRFLUSH_METHODDEF \ {"intrflush", (PyCFunction)_curses_intrflush, METH_O, _curses_intrflush__doc__}, @@ -3608,7 +3619,10 @@ _curses_qiflush(PyObject *module, PyObject *const *args, Py_ssize_t nargs) PyDoc_STRVAR(_curses_update_lines_cols__doc__, "update_lines_cols($module, /)\n" "--\n" -"\n"); +"\n" +"Update the LINES and COLS module variables.\n" +"\n" +"This is useful for detecting manual screen resize."); #define _CURSES_UPDATE_LINES_COLS_METHODDEF \ {"update_lines_cols", (PyCFunction)_curses_update_lines_cols, METH_NOARGS, _curses_update_lines_cols__doc__}, @@ -4472,4 +4486,4 @@ _curses_has_extended_color_support(PyObject *module, PyObject *Py_UNUSED(ignored #ifndef _CURSES_ASSUME_DEFAULT_COLORS_METHODDEF #define _CURSES_ASSUME_DEFAULT_COLORS_METHODDEF #endif /* !defined(_CURSES_ASSUME_DEFAULT_COLORS_METHODDEF) */ -/*[clinic end generated code: output=ab9b5057eeaf0f33 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=11ab7c93cbc13e75 input=a9049054013a1b77]*/ From c0582dbe7fcfcd5ed71232f88c6fce022f08eabb Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 18 Jun 2026 14:45:25 +0200 Subject: [PATCH 355/818] [3.15] gh-151229: Finalize JIT tracer in test eval-frame stub (gh-151609) (gh-151648) gh-151229: Finalize JIT tracer in test eval-frame stub (gh-151609) (cherry picked from commit 3fa92e7c55d74aea062c4b32d895e84d7aaa3bce) Co-authored-by: Donghee Na <donghee.na@python.org> --- Modules/_testinternalcapi/interpreter.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Modules/_testinternalcapi/interpreter.c b/Modules/_testinternalcapi/interpreter.c index 99dcd18393fb87..4afa028cd87527 100644 --- a/Modules/_testinternalcapi/interpreter.c +++ b/Modules/_testinternalcapi/interpreter.c @@ -18,8 +18,13 @@ int Test_EvalFrame_Resumes, Test_EvalFrame_Loads; static int stop_tracing_and_jit(PyThreadState *tstate, _PyInterpreterFrame *frame) { - (void)(tstate); (void)(frame); + // Don't actually JIT-compile in this test eval-frame, but we still must + // finalize the tracer so the thread-global is_tracing flag is reset. + // Otherwise a trace started inside this duplicated interpreter loop + // (reachable under low JIT thresholds, e.g. PYTHON_JIT_STRESS=1) would + // leave is_tracing stuck true and permanently disable the JIT. + _PyJit_FinalizeTracing(tstate, 0); return 0; } #endif From 82b757071e7048bf874816b99e7ed7d1d42f2a6e Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 18 Jun 2026 14:47:36 +0200 Subject: [PATCH 356/818] [3.15] gh-86726: Document the full public API of tkinter (GH-151579) (GH-151649) Replace the previously sparse reference documentation with full coverage of the public API of the tkinter package, written from the Tcl/Tk manual pages, the existing documentation and the module docstrings. * Doc/library/tkinter.rst gains a "Reference" section documenting every public class, method, function and constant of the core module -- the widgets, the Misc, Wm, Pack, Place, Grid, XView and YView mix-ins, the Variable and image classes, the module-level functions and the symbolic constants. * Doc/library/tkinter.ttk.rst, dialog.rst, tkinter.font.rst and the other module pages document their remaining classes, methods and functions. The descriptions are Python-oriented (correct return types -- tuples rather than Tcl lists, booleans, integers, None on cancellation, and so on) and were checked against the Tcl/Tk 9.1 manual pages and the implementation. versionadded, versionchanged and deprecated directives are added for the public API, determined from the git history relative to Python 3.0: the tkinter.ttk module (3.1); the Text, Wm, Menu and Misc methods exposing Tk 8.5 features (3.3); and the many later additions and behavior changes up to 3.15. The Tk version required by features added after Tk 8.6 is noted as well. The bundled Tcl/Tk version is updated to 9.0 and the manual-page links point at the tcl9.0 reference. -------- (cherry picked from commit 8b270b72a2d20bf4b7fb457141cd68a38808f7d9) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> --- Doc/library/dialog.rst | 115 +- Doc/library/tkinter.colorchooser.rst | 18 +- Doc/library/tkinter.dnd.rst | 7 +- Doc/library/tkinter.font.rst | 34 +- Doc/library/tkinter.messagebox.rst | 17 +- Doc/library/tkinter.rst | 5530 ++++++++++++++++- Doc/library/tkinter.scrolledtext.rst | 12 +- Doc/library/tkinter.ttk.rst | 479 +- Doc/tools/.nitignore | 3 - ...6-06-17-12-00-00.gh-issue-86726.__bOgH.rst | 4 + 10 files changed, 5983 insertions(+), 236 deletions(-) create mode 100644 Misc/NEWS.d/next/Documentation/2026-06-17-12-00-00.gh-issue-86726.__bOgH.rst diff --git a/Doc/library/dialog.rst b/Doc/library/dialog.rst index 5d522556235a02..952fd1f0783671 100644 --- a/Doc/library/dialog.rst +++ b/Doc/library/dialog.rst @@ -1,4 +1,4 @@ -Tkinter Dialogs +Tkinter dialogs =============== :mod:`!tkinter.simpledialog` --- Standard Tkinter input dialogs @@ -36,6 +36,42 @@ functions for creating simple modal dialogs to get a value from the user. Default behaviour adds OK and Cancel buttons. Override for custom button layouts. + .. method:: validate() + + Validate the data entered by the user. + Return true if it is valid, in which case the dialog proceeds to + :meth:`apply`; return false to keep the dialog open. + The default implementation always returns true; override it to check the + input. + + .. method:: apply() + + Process the data entered by the user. + Called after :meth:`validate` succeeds and just before the dialog is + destroyed. + The default implementation does nothing; override it to act on or store + the result. + + .. method:: destroy() + + Destroy the dialog window, clearing the reference to the widget that had + the initial focus. + + +.. class:: SimpleDialog(master, text='', buttons=[], default=None, cancel=None, title=None, class_=None) + + A simple modal dialog that displays the message *text* above a row of push + buttons whose labels are given by *buttons*, and returns the index of the + button the user presses. + *default* is the index of the button activated by the Return key, *cancel* + the index returned when the window is closed through the window manager, + *title* the window title, and *class_* the Tk class name of the window. + + .. method:: go() + + Display the dialog, wait until the user presses a button or closes the + window, and return the index of the chosen button. + :mod:`!tkinter.filedialog` --- File selection dialogs @@ -51,7 +87,7 @@ functions for creating simple modal dialogs to get a value from the user. The :mod:`!tkinter.filedialog` module provides classes and factory functions for creating file/directory selection windows. -Native Load/Save Dialogs +Native load/save dialogs ------------------------ The following classes and functions provide file dialog windows that combine a @@ -77,34 +113,46 @@ listed below: **Static factory functions** The below functions when called create a modal, native look-and-feel dialog, -wait for the user's selection, then return the selected value(s) or ``None`` to the -caller. +wait for the user's selection, and return it. +The exact return value depends on the function (see below); when the dialog is +cancelled it is an empty string, an empty tuple, an empty list or ``None``. .. function:: askopenfile(mode="r", **options) askopenfiles(mode="r", **options) - The above two functions create an :class:`Open` dialog and return the opened - file object(s) in read-only mode. + Create an :class:`Open` dialog. + :func:`askopenfile` returns the opened file object, or ``None`` if the + dialog is cancelled. + :func:`askopenfiles` returns a list of the opened file objects, or an empty + list if cancelled. + The files are opened in mode *mode* (read-only ``'r'`` by default). .. function:: asksaveasfile(mode="w", **options) - Create a :class:`SaveAs` dialog and return a file object opened in write-only mode. + Create a :class:`SaveAs` dialog and return the opened file object, or + ``None`` if the dialog is cancelled. + The file is opened in mode *mode* (``'w'`` by default). .. function:: askopenfilename(**options) askopenfilenames(**options) - The above two functions create an :class:`Open` dialog and return the - selected filename(s) that correspond to existing file(s). + Create an :class:`Open` dialog. + :func:`askopenfilename` returns the selected filename as a string, or an + empty string if the dialog is cancelled. + :func:`askopenfilenames` returns a tuple of the selected filenames, or an + empty tuple if cancelled. .. function:: asksaveasfilename(**options) - Create a :class:`SaveAs` dialog and return the selected filename. + Create a :class:`SaveAs` dialog and return the selected filename as a + string, or an empty string if the dialog is cancelled. .. function:: askdirectory(**options) - | Prompt user to select a directory. - | Additional keyword option: - | *mustexist* - determines if selection must be an existing directory. + Prompt the user to select a directory, and return its path as a string, or + an empty string if the dialog is cancelled. + Additional keyword option: *mustexist* - if true, the user may only select + an existing directory (false by default). .. class:: Open(master=None, **options) SaveAs(master=None, **options) @@ -168,6 +216,13 @@ These do not emulate the native look-and-feel of the platform. Exit dialog returning current selection. + .. method:: ok_command() + + Called when the user confirms the current selection. + The base implementation accepts the selection and closes the dialog; + :class:`LoadFileDialog` and :class:`SaveFileDialog` override it to check + the selection first. + .. method:: quit(how=None) Exit dialog returning filename, if any. @@ -222,6 +277,40 @@ is the base class for dialogs defined in other supporting modules. Render the Dialog window. +:mod:`!tkinter.dialog` --- Classic Tk dialog boxes +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. module:: tkinter.dialog + :synopsis: A simple dialog box built on the classic Tk widgets. + +**Source code:** :source:`Lib/tkinter/dialog.py` + +-------------- + +The :mod:`!tkinter.dialog` module provides a simple modal dialog box built on +the classic (non-themed) Tk widgets. + +.. data:: DIALOG_ICON + + The name of the default bitmap (``'questhead'``) displayed by a + :class:`Dialog`. + +.. class:: Dialog(master=None, cnf={}, **kw) + + Display a modal dialog box built from the classic (non-themed) Tk widgets + and wait for the user to press one of its buttons. + The options, given through *cnf* or as keyword arguments, include *title* + (the window title), *text* (the message), *bitmap* (an icon, + :data:`DIALOG_ICON` by default), *default* (the index of the default button) + and *strings* (the sequence of button labels). + After construction, the :attr:`!num` attribute holds the index of the button + the user pressed. + + .. method:: destroy() + + Destroy the dialog window. + + .. seealso:: Modules :mod:`tkinter.messagebox`, :ref:`tut-files` diff --git a/Doc/library/tkinter.colorchooser.rst b/Doc/library/tkinter.colorchooser.rst index 73f8f76a21044b..e1e04d04a08b80 100644 --- a/Doc/library/tkinter.colorchooser.rst +++ b/Doc/library/tkinter.colorchooser.rst @@ -15,14 +15,26 @@ the :class:`~tkinter.commondialog.Dialog` class. .. class:: Chooser(master=None, **options) + The class implementing the modal color-choosing dialog. + Most applications use the :func:`askcolor` convenience function rather than + instantiating this class directly. + .. function:: askcolor(color=None, **options) - Create a color choosing dialog. A call to this method will show the window, - wait for the user to make a selection, and return the selected color (or - ``None``) to the caller. + Show a modal color-choosing dialog and return the chosen color. + *color* is the color selected when the dialog opens. + The return value is a tuple ``((r, g, b), hexstr)``, where ``r``, ``g`` and + ``b`` are the red, green and blue components as integers in the range 0–255 + and *hexstr* is the equivalent Tk color string, such as ``'#ff8000'``. + If the user cancels the dialog, ``(None, None)`` is returned. + + .. versionchanged:: 3.10 + The RGB values in the returned color are now integers in the range 0–255 + instead of floats. .. seealso:: Module :mod:`tkinter.commondialog` Tkinter standard dialog module + diff --git a/Doc/library/tkinter.dnd.rst b/Doc/library/tkinter.dnd.rst index 48d16ccb204b9d..ba267c0e3840fe 100644 --- a/Doc/library/tkinter.dnd.rst +++ b/Doc/library/tkinter.dnd.rst @@ -48,7 +48,8 @@ Selection of a target object occurs as follows: .. method:: on_motion(event) - Inspect area below mouse for target objects while drag is performed. + Inspect area below mouse for target objects while a drag + is performed. .. method:: on_release(event) @@ -56,7 +57,9 @@ Selection of a target object occurs as follows: .. function:: dnd_start(source, event) - Factory function for drag-and-drop process. + Factory function for the drag-and-drop process. + Return the :class:`DndHandler` instance managing the drag, or ``None`` if a + drag could not be started. .. seealso:: diff --git a/Doc/library/tkinter.font.rst b/Doc/library/tkinter.font.rst index 9eecb803c3aedc..2a9563fffab1f7 100644 --- a/Doc/library/tkinter.font.rst +++ b/Doc/library/tkinter.font.rst @@ -26,6 +26,10 @@ The different font weights and slants are: fonts as a single object, rather than specifying a font by its attributes with each occurrence. + .. versionchanged:: 3.10 + Two fonts now compare equal (``==``) only when both are :class:`Font` + instances with the same name belonging to the same Tcl interpreter. + arguments: | *font* - font specifier tuple (family, size, options) @@ -34,7 +38,7 @@ The different font weights and slants are: additional keyword options (ignored if *font* is specified): - | *family* - font family i.e. Courier, Times + | *family* - font family, for example, Courier, Times | *size* - font size | If *size* is positive it is interpreted as size in points. | If *size* is a negative number its absolute value is treated @@ -46,15 +50,24 @@ The different font weights and slants are: .. method:: actual(option=None, displayof=None) - Return the attributes of the font. + Return the actual attributes of the font, which may differ from the + requested ones because of platform limitations. + With no *option*, return a dictionary of all the attributes; if *option* + is given, return the value of that single attribute. .. method:: cget(option) Retrieve an attribute of the font. .. method:: config(**options) + :no-typesetting: + + .. method:: configure(**options) + + Modify one or more attributes of the font. + With no arguments, return a dictionary of the current attributes. - Modify attributes of the font. + :meth:`config` is an alias of :meth:`!configure`. .. method:: copy() @@ -63,12 +76,15 @@ The different font weights and slants are: .. method:: measure(text, displayof=None) Return amount of space the text would occupy on the specified display - when formatted in the current font. If no display is specified then the - main application window is assumed. + when formatted in the current font, as an integer number of pixels. + If no display is specified then the main application window is assumed. .. method:: metrics(*options, **kw) Return font-specific data. + With no options, return a dictionary mapping each metric name to its + integer value; if one option name is given, return that metric's value as + an integer. Options include: *ascent* - distance between baseline and highest point that a @@ -84,15 +100,17 @@ The different font weights and slants are: .. function:: families(root=None, displayof=None) - Return the different font families. + Return a tuple of the names of the available font families. .. function:: names(root=None) - Return the names of defined fonts. + Return a tuple of the names of all the defined fonts. .. function:: nametofont(name, root=None) - Return a :class:`Font` representation of a tk named font. + Return a :class:`Font` representation of the existing named font *name*. + *root* is the widget whose Tcl interpreter owns the font; if omitted, the + default root window is used. .. versionchanged:: 3.10 The *root* parameter was added. diff --git a/Doc/library/tkinter.messagebox.rst b/Doc/library/tkinter.messagebox.rst index 2a69d282638529..b4529e2329ebfb 100644 --- a/Doc/library/tkinter.messagebox.rst +++ b/Doc/library/tkinter.messagebox.rst @@ -9,11 +9,14 @@ -------------- The :mod:`!tkinter.messagebox` module provides a template base class as well as -a variety of convenience methods for commonly used configurations. The message -boxes are modal and will return a subset of (``True``, ``False``, ``None``, -:data:`OK`, :data:`CANCEL`, :data:`YES`, :data:`NO`) based on -the user's selection. Common message box styles and layouts include but are not -limited to: +a variety of convenience methods for commonly used configurations. +The message boxes are modal: each blocks until the user responds, then returns +a value that depends on the function. +The ``show*`` functions and :meth:`Message.show` return the symbolic name of +the button the user pressed, as a string (such as :data:`OK` or :data:`YES`), +while the ``ask*`` functions return a :class:`bool` or ``None`` (see each +function below). +Common message box styles and layouts include but are not limited to: .. figure:: tk_msg.png @@ -66,6 +69,10 @@ limited to: Arranges for a :ref:`predefined set of buttons <messagebox-types>` to be displayed. + .. note:: + + Tk 8.6 added the *command* option. + .. method:: show(**options) Display a message window and wait for the user to select one of the buttons. Then return the symbolic name of the selected button. diff --git a/Doc/library/tkinter.rst b/Doc/library/tkinter.rst index a34b74a088874f..6e26698d751226 100644 --- a/Doc/library/tkinter.rst +++ b/Doc/library/tkinter.rst @@ -17,10 +17,15 @@ demonstrating a simple Tk interface, letting you know that :mod:`!tkinter` is properly installed on your system, and also showing what version of Tcl/Tk is installed, so you can read the Tcl/Tk documentation specific to that version. -Tkinter supports a range of Tcl/Tk versions, built either with or -without thread support. The official Python binary release bundles Tcl/Tk 8.6 -threaded. See the source code for the :mod:`_tkinter` module -for more information about supported versions. +Tkinter supports a range of Tcl/Tk versions, built either with or without +thread support. +Tcl/Tk 8.5.12 is the minimum supported version; the official Python binary +release bundles Tcl/Tk 9.0. +See the source code for the :mod:`_tkinter` module for more information about +supported versions. + +.. versionchanged:: 3.11 + Support for Tcl/Tk versions older than 8.5.12 was removed. Tkinter is not a thin wrapper, but adds a fair amount of its own logic to make the experience more pythonic. This documentation will concentrate on these @@ -47,7 +52,7 @@ details that are unchanged. Tcl/Tk Resources: - * `Tk commands <https://www.tcl.tk/man/tcl8.6/TkCmd/contents.htm>`_ + * `Tk commands <https://www.tcl-lang.org/man/tcl9.0/TkCmd/index.html>`_ Comprehensive reference to each of the underlying Tcl/Tk commands used by Tkinter. * `Tcl/Tk Home Page <https://www.tcl.tk>`_ @@ -103,16 +108,16 @@ Ttk bindings are provided in a separate module, :mod:`tkinter.ttk`. Internally, Tk and Ttk use facilities of the underlying operating system, -i.e., Xlib on Unix/X11, Cocoa on macOS, GDI on Windows. +that is, Xlib on Unix/X11, Cocoa on macOS, GDI on Windows. -When your Python application uses a class in Tkinter, e.g., to create a widget, +When your Python application uses a class in Tkinter, for example, to create a widget, the :mod:`!tkinter` module first assembles a Tcl/Tk command string. It passes that Tcl command string to an internal :mod:`_tkinter` binary module, which then calls the Tcl interpreter to evaluate it. The Tcl interpreter will then call into the Tk and/or Ttk packages, which will in turn make calls to Xlib, Cocoa, or GDI. -Tkinter Modules +Tkinter modules --------------- Support for Tkinter is spread across several modules. Most applications will need the @@ -153,7 +158,7 @@ the modern themed widget set and API:: instead of it being created as an independent toplevel window. *id* must be specified in the same way as the value for the -use option for toplevel widgets (that is, it has a form like that returned by - :meth:`winfo_id`). + :meth:`~Misc.winfo_id`). Note that on some platforms this will only work correctly if *id* refers to a Tk frame or toplevel that has its -container option enabled. @@ -174,13 +179,15 @@ the modern themed widget set and API:: .. attribute:: master - The widget object that contains this widget. For :class:`Tk`, the - :attr:`!master` is :const:`None` because it is the main window. The terms - *master* and *parent* are similar and sometimes used interchangeably - as argument names; however, calling :meth:`winfo_parent` returns a - string of the widget name whereas :attr:`!master` returns the object. - *parent*/*child* reflects the tree-like relationship while - *master* (or *container*)/*content* reflects the container structure. + The widget object that contains this widget. + For :class:`Tk`, the :attr:`!master` is :const:`None` because it is the + main window. + The terms *master* and *parent* are similar and sometimes used + interchangeably as argument names; however, calling + :meth:`~Misc.winfo_parent` returns a string of the widget name whereas + :attr:`!master` returns the object. + *parent*/*child* reflects the tree-like relationship while *master* (or + *container*)/*content* reflects the container structure. .. attribute:: children @@ -188,16 +195,48 @@ the modern themed widget set and API:: child widget names as the keys and the child instance objects as the values. + .. method:: destroy() + + Destroy this and all descendant widgets and, for the main window, end the + connection to the underlying Tcl interpreter. + + .. method:: loadtk() + + Finish loading and initializing the Tk subsystem. + This is needed only when the interpreter was created without Tk (for + example through :func:`Tcl`); it is called automatically when *useTk* is + true. + + .. method:: readprofile(baseName, className) + + Read and source the user's profile files :file:`.{className}.tcl` and + :file:`.{baseName}.tcl` into the Tcl interpreter, and execute the + corresponding :file:`.{className}.py` and :file:`.{baseName}.py` files. + This is called during initialization; see the description of the + constructor above. + + .. method:: report_callback_exception(exc, val, tb) + + Report a callback exception. + This is called when an exception propagates out of a Tkinter callback; + *exc*, *val* and *tb* are the exception type, value and traceback as + returned by :func:`sys.exc_info`. + The default implementation prints a traceback to :data:`sys.stderr`. + It can be overridden to customize error handling, for example to display + the traceback in a dialog. + .. function:: Tcl(screenName=None, baseName=None, className='Tk', useTk=False) - The :func:`Tcl` function is a factory function which creates an object much like - that created by the :class:`Tk` class, except that it does not initialize the Tk - subsystem. This is most often useful when driving the Tcl interpreter in an - environment where one doesn't want to create extraneous toplevel windows, or - where one cannot (such as Unix/Linux systems without an X server). An object - created by the :func:`Tcl` object can have a Toplevel window created (and the Tk - subsystem initialized) by calling its :meth:`loadtk` method. + The :func:`Tcl` function is a factory function which creates an object much + like that created by the :class:`Tk` class, except that it does not + initialize the Tk subsystem. + This is most often useful when driving the Tcl interpreter in an environment + where one doesn't want to create extraneous toplevel windows, or where one + cannot (such as Unix/Linux systems without an X server). + An object created by the :func:`Tcl` object can have a Toplevel window + created (and the Tk subsystem initialized) by calling its :meth:`~Tk.loadtk` + method. The modules that provide Tk support include: @@ -246,7 +285,7 @@ Additional modules: Python's Integrated Development and Learning Environment (IDLE). Based on :mod:`!tkinter`. -:mod:`tkinter.constants` +:mod:`!tkinter.constants` Symbolic constants that can be used in place of strings when passing various parameters to Tkinter calls. Automatically imported by the main :mod:`!tkinter` module. @@ -258,8 +297,10 @@ Additional modules: :mod:`turtle` Turtle graphics in a Tk window. +.. currentmodule:: tkinter + -Tkinter Life Preserver +Tkinter life preserver ---------------------- This section is not designed to be an exhaustive tutorial on either Tk or @@ -274,7 +315,7 @@ find more detailed documentation on them, including in the official Tcl/Tk reference manual. -A Hello World Program +A Hello World program ^^^^^^^^^^^^^^^^^^^^^ We'll start by walking through a "Hello World" application in Tkinter. This @@ -302,19 +343,20 @@ The following line creates a frame widget, which in this case will contain a label and a button we'll create next. The frame is fit inside the root window. -The next line creates a label widget holding a static text string. The -:meth:`grid` method is used to specify the relative layout (position) of the -label within its containing frame widget, similar to how tables in HTML work. +The next line creates a label widget holding a static text string. +The :meth:`~Grid.grid` method is used to specify the relative layout (position) +of the label within its containing frame widget, similar to how tables in HTML +work. -A button widget is then created, and placed to the right of the label. When -pressed, it will call the :meth:`destroy` method of the root window. +A button widget is then created, and placed to the right of the label. +When pressed, it will call the :meth:`~Misc.destroy` method of the root window. Finally, the :meth:`mainloop` method puts everything on the display, and responds to user input until the program terminates. -Important Tk Concepts +Important Tk concepts ^^^^^^^^^^^^^^^^^^^^^ Even this simple program illustrates the following key Tk concepts: @@ -346,7 +388,7 @@ event loop isn't running the event loop, your user interface won't update. -Understanding How Tkinter Wraps Tcl/Tk +Understanding how Tkinter wraps Tcl/Tk ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ When your application uses Tkinter's classes and methods, internally Tkinter @@ -414,9 +456,9 @@ interactive Python shell or with :func:`print`, can help you identify what you need. To find out what configuration options are available on any widget, call its -:meth:`configure` method, which returns a dictionary containing a variety of -information about each object, including its default and current values. Use -:meth:`keys` to get just the names of each option. +:meth:`~Misc.configure` method, which returns a dictionary containing a variety +of information about each object, including its default and current values. +Use :meth:`~Misc.keys` to get just the names of each option. :: @@ -443,18 +485,20 @@ is helpful. print(set(dir(btn)) - set(dir(frm))) -Navigating the Tcl/Tk Reference Manual +Navigating the Tcl/Tk reference manual ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -As noted, the official `Tk commands <https://www.tcl.tk/man/tcl8.6/TkCmd/contents.htm>`_ -reference manual (man pages) is often the most accurate description of what -specific operations on widgets do. Even when you know the name of the option -or method that you need, you may still have a few places to look. +As noted, the official +`Tk commands <https://www.tcl-lang.org/man/tcl9.0/TkCmd/index.html>`_ reference +manual (man pages) is often the most accurate description of what specific +operations on widgets do. +Even when you know the name of the option or method that you need, you may +still have a few places to look. While all operations in Tkinter are implemented as method calls on widget objects, you've seen that many Tcl/Tk operations appear as commands that take a widget pathname as its first parameter, followed by optional -parameters, e.g. +parameters, for example :: @@ -473,22 +517,23 @@ name of a method to call). In the official Tcl/Tk reference documentation, you'll find most operations -that look like method calls on the man page for a specific widget (e.g., -you'll find the :meth:`invoke` method on the -`ttk::button <https://www.tcl.tk/man/tcl8.6/TkCmd/ttk_button.htm>`_ +that look like method calls on the man page for a specific widget (for example, +you'll find the :meth:`~tkinter.ttk.Button.invoke` method on the +`ttk::button <https://www.tcl-lang.org/man/tcl9.0/TkCmd/ttk_button.html>`_ man page), while functions that take a widget as a parameter often have -their own man page (e.g., -`grid <https://www.tcl.tk/man/tcl8.6/TkCmd/grid.htm>`_). +their own man page (for example, +`grid <https://www.tcl-lang.org/man/tcl9.0/TkCmd/grid.html>`_). You'll find many common options and methods in the -`options <https://www.tcl.tk/man/tcl8.6/TkCmd/options.htm>`_ or -`ttk::widget <https://www.tcl.tk/man/tcl8.6/TkCmd/ttk_widget.htm>`_ man +`options <https://www.tcl-lang.org/man/tcl9.0/TkCmd/options.html>`_ or +`ttk::widget <https://www.tcl-lang.org/man/tcl9.0/TkCmd/ttk_widget.html>`_ man pages, while others are found in the man page for a specific widget class. -You'll also find that many Tkinter methods have compound names, e.g., -:func:`winfo_x`, :func:`winfo_height`, :func:`winfo_viewable`. You'd find -documentation for all of these in the -`winfo <https://www.tcl.tk/man/tcl8.6/TkCmd/winfo.htm>`_ man page. +You'll also find that many Tkinter methods have compound names, for example, +:meth:`~Misc.winfo_x`, :meth:`~Misc.winfo_height`, +:meth:`~Misc.winfo_viewable`. +You'd find documentation for all of these in the +`winfo <https://www.tcl-lang.org/man/tcl9.0/TkCmd/winfo.html>`_ man page. .. note:: Somewhat confusingly, there are also methods on all Tkinter widgets @@ -517,14 +562,16 @@ from a thread other than the one that created the :class:`Tk` object, an event is posted to the interpreter's event queue, and when executed, the result is returned to the calling Python thread. -Tcl/Tk applications are normally event-driven, meaning that after initialization, -the interpreter runs an event loop (i.e. :func:`Tk.mainloop`) and responds to events. -Because it is single-threaded, event handlers must respond quickly, otherwise they -will block other events from being processed. To avoid this, any long-running -computations should not run in an event handler, but are either broken into smaller -pieces using timers, or run in another thread. This is different from many GUI -toolkits where the GUI runs in a completely separate thread from all application -code including event handlers. +Tcl/Tk applications are normally event-driven, meaning that after +initialization, the interpreter runs an event loop (that is, +:meth:`Tk.mainloop <Misc.mainloop>`) and responds to events. +Because it is single-threaded, event handlers must respond quickly, otherwise +they will block other events from being processed. +To avoid this, any long-running computations should not run in an event +handler, but are either broken into smaller pieces using timers, or run in +another thread. +This is different from many GUI toolkits where the GUI runs in a completely +separate thread from all application code including event handlers. If the Tcl interpreter is not running the event loop and processing events, any :mod:`!tkinter` calls made from threads other than the one running the Tcl @@ -532,7 +579,9 @@ interpreter will fail. A number of special cases exist: -* Tcl/Tk libraries can be built so they are not thread-aware. In this case, +* Tcl/Tk libraries built without thread support are now rare: Tcl/Tk 9.0 (the + bundled version) is always thread-aware, so this case only arises with some + older 8.x builds. When the library is not thread-aware, :mod:`!tkinter` calls the library from the originating Python thread, even if this is different than the thread that created the Tcl interpreter. A global lock ensures only one call occurs at a time. @@ -552,13 +601,13 @@ A number of special cases exist: called from the thread that created the Tcl interpreter. -Handy Reference +Handy reference --------------- .. _tkinter-setting-options: -Setting Options +Setting options ^^^^^^^^^^^^^^^ Options control things like the color and border width of a widget. Options can @@ -594,11 +643,11 @@ document. Some options don't apply to some kinds of widgets. Whether a given widget responds to a particular option depends on the class of the widget; buttons have a ``command`` option, labels do not. -The options supported by a given widget are listed in that widget's man page, or -can be queried at runtime by calling the :meth:`config` method without -arguments, or by calling the :meth:`keys` method on that widget. The return -value of these calls is a dictionary whose key is the name of the option as a -string (for example, ``'relief'``) and whose values are 5-tuples. +The options supported by a given widget are listed in that widget's man page, +or can be queried at runtime by calling the :meth:`~Misc.config` method without +arguments, or by calling the :meth:`~Misc.keys` method on that widget. +The return value of these calls is a dictionary whose key is the name of the +option as a string (for example, ``'relief'``) and whose values are 5-tuples. Some options, like ``bg`` are synonyms for common options with long names (``bg`` is shorthand for "background"). Passing the ``config()`` method the name @@ -630,7 +679,9 @@ Of course, the dictionary printed will include all the options available and their values. This is meant only as an example. -The Packer +.. _pack-the-packer: + +The packer ^^^^^^^^^^ .. index:: single: packing (widgets) @@ -650,10 +701,11 @@ Additionally, the arrangement is dynamically adjusted to accommodate incremental changes to the configuration, once it is packed. Note that widgets do not appear until they have had their geometry specified -with a geometry manager. It's a common early mistake to leave out the geometry -specification, and then be surprised when the widget is created but nothing -appears. A widget will appear only after it has had, for example, the packer's -:meth:`pack` method applied to it. +with a geometry manager. +It's a common early mistake to leave out the geometry specification, and then +be surprised when the widget is created but nothing appears. +A widget will appear only after it has had, for example, the packer's +:meth:`~Pack.pack` method applied to it. The pack() method can be called with keyword-option/value pairs that control where the widget is to appear within its container, and how it is to behave when @@ -664,7 +716,7 @@ the main application window is resized. Here are some examples:: fred.pack(expand=1) -Packer Options +Packer options ^^^^^^^^^^^^^^ For more extensive information on the packer and the options that it can take, @@ -674,7 +726,7 @@ anchor Anchor type. Denotes where the packer is to place each content in its parcel. expand - Boolean, ``0`` or ``1``. + boolean, ``0`` or ``1``. fill Legal values: ``'x'``, ``'y'``, ``'both'``, ``'none'``. @@ -689,7 +741,9 @@ side Legal values are: ``'left'``, ``'right'``, ``'top'``, ``'bottom'``. -Coupling Widget Variables +.. _coupling-widget-variables: + +Coupling widget variables ^^^^^^^^^^^^^^^^^^^^^^^^^ The current-value setting of some widgets (like text entry widgets) can be @@ -706,10 +760,11 @@ defined in :mod:`!tkinter`. There are many useful subclasses of Variable already defined: :class:`StringVar`, :class:`IntVar`, :class:`DoubleVar`, and -:class:`BooleanVar`. To read the current value of such a variable, call the -:meth:`get` method on it, and to change its value you call the :meth:`!set` -method. If you follow this protocol, the widget will always track the value of -the variable, with no further intervention on your part. +:class:`BooleanVar`. +To read the current value of such a variable, call the :meth:`~Variable.get` +method on it, and to change its value you call the :meth:`!set` method. +If you follow this protocol, the widget will always track the value of the +variable, with no further intervention on your part. For example:: @@ -743,7 +798,7 @@ For example:: myapp = App(root) myapp.mainloop() -The Window Manager +The window manager ^^^^^^^^^^^^^^^^^^ .. index:: single: window manager (widgets) @@ -756,11 +811,16 @@ subclassed from the :class:`Wm` class, and so can call the :class:`Wm` methods directly. To get at the toplevel window that contains a given widget, you can often just -refer to the widget's :attr:`master`. Of course if the widget has been packed inside of -a frame, the :attr:`!master` won't represent a toplevel window. To get at the toplevel -window that contains an arbitrary widget, you can call the :meth:`_root` method. -This method begins with an underscore to denote the fact that this function is -part of the implementation, and not an interface to Tk functionality. +refer to the widget's :attr:`~Tk.master`. +Of course if the widget has been packed inside of a frame, the :attr:`!master` +won't represent a toplevel window. +To get at the toplevel window that contains an arbitrary widget, you can call +the :meth:`~Misc.winfo_toplevel` method. +There is also a :meth:`!_root` method; it begins with an underscore to denote +the fact that this function is part of the implementation, and not an interface +to Tk functionality. +It returns the application's root window rather than the nearest enclosing +toplevel. Here are some examples of typical usage:: @@ -784,7 +844,7 @@ Here are some examples of typical usage:: myapp.mainloop() -Tk Option Data Types +Tk option data types ^^^^^^^^^^^^^^^^^^^^ .. index:: single: Tk Option Data Types @@ -794,10 +854,11 @@ anchor ``"s"``, ``"sw"``, ``"w"``, ``"nw"``, and also ``"center"``. bitmap - There are eight built-in, named bitmaps: ``'error'``, ``'gray25'``, - ``'gray50'``, ``'hourglass'``, ``'info'``, ``'questhead'``, ``'question'``, - ``'warning'``. To specify an X bitmap filename, give the full path to the file, - preceded with an ``@``, as in ``"@/usr/contrib/bitmap/gumby.bit"``. + There are ten built-in, named bitmaps: ``'error'``, ``'gray12'``, + ``'gray25'``, ``'gray50'``, ``'gray75'``, ``'hourglass'``, ``'info'``, + ``'questhead'``, ``'question'``, ``'warning'``. To specify an X bitmap + filename, give the full path to the file, preceded with an ``@``, as in + ``"@/usr/contrib/bitmap/gumby.bit"``. boolean You can pass integers 0 or 1 or the strings ``"yes"`` or ``"no"``. @@ -817,7 +878,7 @@ color cursor The standard X cursor names from :file:`cursorfont.h` can be used, without the - ``XC_`` prefix. For example to get a hand cursor (:const:`XC_hand2`), use the + ``XC_`` prefix. For example to get a hand cursor (``XC_hand2``), use the string ``"hand2"``. You can also specify a bitmap and mask file of your own. See page 179 of Ousterhout's book. @@ -829,9 +890,11 @@ distance as ``"3.5i"``. font - Tk uses a list font name format, such as ``{courier 10 bold}``. Font sizes with - positive numbers are measured in points; sizes with negative numbers are - measured in pixels. + Tk uses a font description such as ``{courier 10 bold}``; in + :mod:`!tkinter` this is most naturally passed as a tuple of + ``(family, size, *styles)`` (or as the equivalent string + ``"Courier 10 bold"``). Font sizes with positive numbers are measured in + points; sizes with negative numbers are measured in pixels. geometry This is a string of the form ``widthxheight``, where width and height are @@ -848,7 +911,8 @@ region relief Determines what the border style of a widget will be. Legal values are: - ``"raised"``, ``"sunken"``, ``"flat"``, ``"groove"``, and ``"ridge"``. + ``"raised"``, ``"sunken"``, ``"flat"``, ``"groove"``, ``"ridge"``, and + ``"solid"``. scrollcommand This is almost always the :meth:`!set` method of some scrollbar widget, but can @@ -859,7 +923,7 @@ wrap .. _Bindings-and-Events: -Bindings and Events +Bindings and events ^^^^^^^^^^^^^^^^^^^ .. index:: @@ -875,7 +939,10 @@ of the bind method is:: where: sequence - is a string that denotes the target kind of event. (See the + is a string that denotes the target kind of event. Physical events use the + ``<modifier-modifier-type-detail>`` form (for example ``"<Enter>"`` or + ``"<Control-Button-1>"``); application-defined virtual events use double angle + brackets, as in ``"<<Paste>>"``. (See the :manpage:`bind(3tk)` man page, and page 201 of John Ousterhout's book, :title-reference:`Tcl and the Tk Toolkit (2nd edition)`, for details). @@ -921,9 +988,13 @@ they are denoted in Tk, which can be useful when referring to the Tk man pages. +----+---------------------+----+---------------------+ | %y | y | %Y | y_root | +----+---------------------+----+---------------------+ +| %# | serial | %b | num | ++----+---------------------+----+---------------------+ +| %d | detail | %D | delta | ++----+---------------------+----+---------------------+ -The index Parameter +The index parameter ^^^^^^^^^^^^^^^^^^^ A number of widgets require "index" parameters to be passed. These are used to @@ -988,7 +1059,7 @@ option (other options are available as well). :meth:`!copy`. The image object can then be used wherever an ``image`` option is supported by -some widget (e.g. labels, buttons, menus). In these cases, Tk will not keep a +some widget (for example, labels, buttons, menus). In these cases, Tk will not keep a reference to the image. When the last Python reference to the image object is deleted, the image data is deleted as well, and Tk will display an empty box wherever the image was used. @@ -1000,7 +1071,7 @@ wherever the image was used. .. _tkinter-file-handlers: -File Handlers +File handlers ------------- Tk allows you to register and unregister a callback function which will be @@ -1046,3 +1117,5258 @@ use raw reads or ``os.read(file.fileno(), maxbytecount)``. EXCEPTION Constants used in the *mask* arguments. + + +Reference +--------- + +.. currentmodule:: tkinter + +This section documents the classes, methods, functions and constants of the +:mod:`!tkinter` module. +Most of them wrap Tcl/Tk commands; consult the official Tcl/Tk manual pages for +the full list of widget options and further details. + +.. exception:: TclError + + The exception raised when a call into the Tcl interpreter fails, for example + when a widget is given an unknown option or an invalid value. + +Base and mixin classes +^^^^^^^^^^^^^^^^^^^^^^ + +.. class:: Misc() + + The :class:`!Misc` class is a mix-in inherited by :class:`Tk` and, through + :class:`BaseWidget`, by every widget. + It provides the large set of methods common to all Tk objects: querying + window information, managing event bindings and the event loop, controlling + the keyboard focus and pointer grabs, accessing the selection, clipboard and + option database, and assorted utility and introspection services. + Because they are inherited, these methods are available on every widget and + on the :class:`Tk` application object, and are documented here once rather + than repeated for each widget. + + .. method:: cget(key) + + Return the current value of the configuration option named *key* for this + widget, as a string. + The expression ``widget[key]`` is equivalent and may be used instead. + + .. method:: config(cnf=None, **kw) + :no-typesetting: + + .. method:: configure(cnf=None, **kw) + + Query or modify the configuration options of the widget. + With no arguments, return a dictionary mapping every available option + name to a tuple describing it (its name, X resource name, X resource + class, default value and current value). + If a single option name is given as a string, return the tuple for just + that option. + If one or more keyword arguments are given, or a dictionary is passed as + *cnf*, set each named option to the corresponding value; the expression + ``widget[key] = value`` sets a single option in the same way. + + :meth:`config` is an alias of :meth:`!configure`. + + .. method:: keys() + + Return a list of the names of all configuration options of this widget. + + .. method:: getboolean(s) + + Interpret the string *s* as a Tcl boolean and return the corresponding + :class:`bool`. + Tcl accepts values such as ``'1'``, ``'0'``, ``'yes'``, ``'no'``, + ``'true'`` and ``'false'``. + Raise :exc:`ValueError` if *s* is not a valid boolean. + + .. method:: getdouble(s) + + Interpret the string *s* as a Tcl floating-point number and return it as + a :class:`float`. + Raise :exc:`ValueError` if *s* is not a valid number. + + .. versionadded:: 3.5 + + + .. method:: getint(s) + + Interpret the string *s* as a Tcl integer and return it as an + :class:`int`. + Raise :exc:`ValueError` if *s* is not a valid integer. + + .. method:: getvar(name='PY_VAR') + + Return the value of the Tcl global variable named *name*. + + .. method:: setvar(name='PY_VAR', value='1') + + Set the Tcl global variable named *name* to *value*. + + The :meth:`!getvar` and :meth:`!setvar` methods give direct access to Tcl + variables. + In most code you will instead use a :class:`Variable` subclass such as + :class:`StringVar` or :class:`IntVar`, which wraps a Tcl variable and + converts its value to and from a Python type. + + .. method:: register(func, subst=None, needcleanup=1) + + Register the Python callable *func* as a Tcl command and return the name + of the new command as a string. + Whenever Tcl invokes that command, *func* is called; if *subst* is given, + it is applied to the command's arguments first. + This is the mechanism used internally to turn Python callbacks into the + command names passed to Tk options such as *command*. + Unless *needcleanup* is false, the command is deleted automatically when + the widget is destroyed. + + .. versionchanged:: 3.13 + The arguments passed to *func* are no longer converted to strings. + + .. method:: deletecommand(name) + + Delete the Tcl command named *name*, such as one previously returned by + :meth:`register`. + + .. method:: nametowidget(name) + + Return the widget instance corresponding to the Tk pathname *name*. + + .. method:: send(interp, cmd, *args) + + Send the Tcl command *cmd*, with the given *args*, to the Tcl interpreter + registered under the name *interp*, and return its result. + This is not available on all platforms. + + .. method:: destroy() + + Destroy this widget and all of its descendant widgets, and delete the Tcl + commands associated with them. + + .. method:: lift(aboveThis=None) + :no-typesetting: + + .. method:: tkraise(aboveThis=None) + + Raise this widget in the stacking order so that it is drawn on top of its + siblings. + If *aboveThis* is given, the widget is moved to be just above it in the + stacking order instead. + + :meth:`lift` is an alias of :meth:`!tkraise`. + + .. method:: lower(belowThis=None) + + Lower this widget in the stacking order so that it is drawn beneath its + siblings. + If *belowThis* is given, the widget is moved to be just below it in the + stacking order instead. + + .. method:: image_names() + + Return the names of all images that currently exist in the Tcl + interpreter. + + .. method:: image_types() + + Return the available image types, such as ``'photo'`` and ``'bitmap'``. + + .. method:: anchor(anchor=None) + :no-typesetting: + + .. method:: grid_anchor(anchor=None) + + Set the anchor that controls where the grid is placed inside this + container when the container is larger than the grid and no row or column + has a non-zero weight. + *anchor* is one of the usual anchor strings, such as ``'nw'`` (the + default) or ``'center'``. + Called with no argument, this method has no effect. + + :meth:`anchor` is an alias of :meth:`!grid_anchor`. + + .. versionadded:: 3.3 + + .. method:: bbox(column=None, row=None, col2=None, row2=None) + :no-typesetting: + + .. method:: grid_bbox(column=None, row=None, col2=None, row2=None) + + Return the bounding box, in pixels, of a region of the grid laid out in + this container, as a 4-tuple ``(xoffset, yoffset, width, height)``. + With no arguments the bounding box of the whole grid is returned. + If *column* and *row* are given, the box spans from the cell at row and + column 0 to that cell; if *col2* and *row2* are also given, it spans from + the cell (*column*, *row*) to the cell (*col2*, *row2*). + + :meth:`bbox` is an alias of :meth:`!grid_bbox`. + + .. method:: columnconfigure(index, cnf={}, **kw) + :no-typesetting: + + .. method:: grid_columnconfigure(index, cnf={}, **kw) + + Query or set the properties of the column (or columns) *index* of the + grid managed by this container. + *index* may be a column number; when setting options it may also be a + list of column numbers, the string ``'all'`` to affect every column, or + a child widget whose occupied columns are affected. + The supported options are: + + *minsize* + The column's minimum size, in pixels. + + *weight* + An integer setting how much of any extra space is apportioned to the + column. + A weight of ``0`` keeps the column at its requested size, and a column + of weight two grows twice as fast as a column of weight one. + + *uniform* + The name of a uniform group. + Columns sharing a non-empty group name are kept in sizes that are + strictly proportional to their weights. + + *pad* + Extra space, in pixels, added to the largest widget in the column when + computing the column's size. + + With a single option name, return that option's value; with no options, + return a dictionary of all of them. + + :meth:`columnconfigure` is an alias of :meth:`!grid_columnconfigure`. + + .. method:: rowconfigure(index, cnf={}, **kw) + :no-typesetting: + + .. method:: grid_rowconfigure(index, cnf={}, **kw) + + Query or set the properties of the row (or rows) *index* of the grid + managed by this container. + *index* is interpreted as for :meth:`grid_columnconfigure`, and the + supported options (*minsize*, *weight*, *uniform* and *pad*) are the + same, applied to a row instead of a column. + + :meth:`rowconfigure` is an alias of :meth:`!grid_rowconfigure`. + + .. method:: grid_location(x, y) + + Return the ``(column, row)`` of the grid cell that contains the pixel at + position (*x*, *y*), given in pixels relative to this container. + For locations above or to the left of the grid, ``-1`` is returned for + the corresponding coordinate. + + .. method:: grid_propagate() + grid_propagate(flag) + + Enable or disable geometry propagation for this container when it manages + its children with the grid geometry manager. + When *flag* is true, the container resizes itself to fit the requested + sizes of its children; when it is false, its size is left under your + control. + Called with no argument, return the current setting as a boolean. + + .. method:: size() + :no-typesetting: + + .. method:: grid_size() + + Return the size of the grid managed by this container as a + ``(columns, rows)`` tuple. + + :meth:`size` is an alias of :meth:`!grid_size`. + + .. method:: grid_slaves(row=None, column=None) + + Return a list of the child widgets managed in this container's grid, most + recently managed first. + If *row* or *column* is given, only the children in that row or column + are returned. + + .. method:: grid_content(row=None, column=None) + + Same as :meth:`grid_slaves`: return the child widgets managed in this + container's grid, optionally restricted to a given *row* or *column*. + + .. versionadded:: 3.15 + + + .. method:: propagate() + propagate(flag) + :no-typesetting: + + .. method:: pack_propagate() + pack_propagate(flag) + + Enable or disable geometry propagation for this container when it manages + its children with the pack geometry manager. + When *flag* is true, the container resizes itself to fit the requested + sizes of its children; when it is false, its size is left under your + control. + Called with no argument, return the current setting as a boolean. + + :meth:`propagate` is an alias of :meth:`!pack_propagate`. + + .. method:: slaves() + :no-typesetting: + + .. method:: pack_slaves() + + Return a list of the child widgets managed by this container with the + pack geometry manager, in packing order. + + :meth:`slaves` is an alias of :meth:`!pack_slaves`. + + .. method:: content() + :no-typesetting: + + .. method:: pack_content() + + Same as :meth:`pack_slaves`: return the child widgets managed by this + container with the pack geometry manager, in packing order. + + :meth:`content` is an alias of :meth:`!pack_content`. + + .. versionadded:: 3.15 + + + .. method:: place_slaves() + + Return a list of the child widgets managed by this container with the + place geometry manager. + + .. method:: place_content() + + Same as :meth:`place_slaves`: return the child widgets managed by this + container with the place geometry manager. + + .. versionadded:: 3.15 + + .. method:: bind(sequence=None, func=None, add=None) + + Bind the event pattern *sequence* on this widget to the callable *func*. + + *sequence* is an event pattern, such as ``'<Button-1>'`` (a mouse click) + or ``'<KeyPress-a>'``, optionally a concatenation of several such + patterns that must occur shortly after one another. + When the event occurs, *func* is called with an :class:`Event` instance + describing it as its only argument; if *func* returns the string + ``'break'``, no further bindings for the event are invoked. + + If *add* is true, *func* is added to any functions already bound to + *sequence*; otherwise it replaces them. + The binding applies only to this widget. + + :meth:`!bind` returns a string identifier (a *funcid*) that can later be + passed to :meth:`unbind` to remove the binding without leaking the + associated Tcl command. + + If *func* is omitted, return the binding currently associated with + *sequence*; if *sequence* is also omitted, return a list of all the + sequences for which bindings exist on this widget. + + .. method:: bind_class(className, sequence=None, func=None, add=None) + + Like :meth:`bind`, but bind *func* to the binding tag *className* rather + than to a single widget, so that the binding applies to every widget + having that tag. + *className* is usually the name of a widget class, such as ``'Button'``, + in which case the binding affects all widgets of that class. + The set of binding tags for a widget can be inspected and changed with + :meth:`bindtags`. + + The remaining arguments and the return value are as for :meth:`bind`. + + .. method:: bind_all(sequence=None, func=None, add=None) + + Like :meth:`bind`, but bind *func* to the special binding tag ``'all'``, + so that the binding applies to every widget in the application. + + The remaining arguments and the return value are as for :meth:`bind`. + + .. method:: unbind(sequence, funcid=None) + + Remove bindings for the event pattern *sequence* on this widget. + + If *funcid* is given, only the function identified by it (a value + returned from a previous call to :meth:`bind`) is removed, and its + associated Tcl command is deleted. + Otherwise all bindings for *sequence* are destroyed, leaving it unbound. + + .. versionchanged:: 3.13 + If *funcid* is given, only that callback is unbound; other callbacks + bound to *sequence* are kept. + + + .. method:: unbind_class(className, sequence) + + Remove all bindings for the event pattern *sequence* from the binding tag + *className*. + See :meth:`bind_class`. + + .. method:: unbind_all(sequence) + + Remove all bindings for the event pattern *sequence* from the special + binding tag ``'all'``. + See :meth:`bind_all`. + + .. method:: bindtags(tagList=None) + + If *tagList* is omitted, return a tuple of the binding tags associated + with this widget. + When an event occurs in a widget, it is applied to each of the widget's + binding tags in order, and for each tag the most specific matching + binding is executed. + By default a widget has four binding tags: its own pathname, its widget + class, the pathname of its nearest toplevel ancestor, and ``'all'``, in + that order. + + If *tagList* is given, it must be a sequence of strings; the widget's + binding tags are set to its elements, which determines the order in which + bindings are evaluated. + + .. method:: event_add(virtual, *sequences) + + Associate the virtual event *virtual*, whose name has the form + ``'<<Paste>>'``, with each of the physical event patterns given by + *sequences*, so that the virtual event triggers whenever any of them + occurs. + If *virtual* is already defined, the new sequences are added to its + existing ones. + + .. method:: event_delete(virtual, *sequences) + + Remove each of *sequences* from those associated with the virtual event + *virtual*. + Sequences that are not currently associated with *virtual* are ignored. + If no *sequences* are given, all physical event sequences are removed, so + that *virtual* no longer triggers. + + .. method:: event_generate(sequence, **kw) + + Generate the event *sequence* on this widget and arrange for it to be + processed just as if it had come from the window system. + *sequence* must be a single event pattern, such as ``'<Button-1>'`` or + ``'<<Paste>>'``, not a concatenation of several. + Keyword arguments specify additional fields of the event, for example *x* + and *y* for the pointer position, or *when* to control when the event is + processed; refer to the Tk ``event`` manual page for the full list. + + .. method:: event_info(virtual=None) + + If *virtual* is omitted, return a tuple of all the virtual events that + are currently defined. + If *virtual* is given, return a tuple of the physical event sequences + currently associated with it, or an empty tuple if it is not defined. + + .. method:: after(ms, func=None, *args, **kw) + + Schedule the callable *func* to be called after *ms* milliseconds, with + *args* and *kw* passed to it as positional and keyword arguments. + Return an identifier that can be passed to :meth:`after_cancel` to cancel + the call. + + If *func* is omitted, sleep for *ms* milliseconds instead, processing no + events during that time, and return ``None``. + + .. versionchanged:: 3.10 + *func* can now be any callable object, not only a function. + + .. versionchanged:: 3.14 + Keyword arguments are now passed to *func*. + + + .. method:: after_cancel(id) + + Cancel a callback previously scheduled with :meth:`after` or + :meth:`after_idle`. + *id* must be an identifier returned by one of those methods; passing a + value that is not such an identifier raises :exc:`ValueError`. + If the callback has already run or been cancelled, this has no effect. + + .. versionchanged:: 3.7 + Passing ``None`` (or any false value) as *id* now raises + :exc:`ValueError`. + + + .. method:: after_idle(func, *args, **kw) + + Schedule the callable *func* to be called, with *args* and *kw* passed to + it, when the Tk main loop next becomes idle, that is, when it has no + other events to process. + Return an identifier that can be passed to :meth:`after_cancel` to cancel + the call. + + .. versionchanged:: 3.14 + Keyword arguments are now passed to *func*. + + + .. method:: after_info(id=None) + + If *id* is omitted, return a tuple of the identifiers of all callbacks + currently scheduled with :meth:`after` and :meth:`after_idle` for this + interpreter. + + If *id* is given, it must identify a callback that has not yet run or + been cancelled, and the return value is a tuple ``(script, type)``, where + *script* refers to the function to be called and *type* is either + ``'idle'`` or ``'timer'``. + A :exc:`TclError` is raised if *id* does not exist. + + .. versionadded:: 3.13 + + + .. method:: mainloop(n=0) + + Enter the Tk event loop, which processes events until all windows are + destroyed. + This is normally called once, on the root window, to run the application. + + .. method:: quit() + + Quit the Tcl interpreter, causing :meth:`mainloop` to return. + + .. method:: update() + + Enter the event loop until all pending events, including idle callbacks, + have been processed. + This brings the display up to date and handles any events that are + already queued, then returns. + + .. method:: update_idletasks() + + Enter the event loop until all pending idle callbacks have been called. + This updates the display of windows, for example after geometry changes, + but does not process events caused by the user. + + .. method:: waitvar(name='PY_VAR') + :no-typesetting: + + .. method:: wait_variable(name='PY_VAR') + + Wait until the Tcl variable *name* is modified, continuing to process + events in the meantime so that the application stays responsive. + *name* is usually a :class:`Variable` instance, such as an + :class:`IntVar` or :class:`StringVar`. + + :meth:`waitvar` is an alias of :meth:`!wait_variable`. + + .. method:: wait_window(window=None) + + Wait until *window* is destroyed, continuing to process events in the + meantime. + If *window* is omitted, this widget is used. + This is typically used to wait for the user to finish interacting with a + dialog box. + + .. method:: wait_visibility(window=None) + + Wait until the visibility state of *window* changes, for example when it + first appears on the screen, continuing to process events in the + meantime. + If *window* is omitted, this widget is used. + This is typically used to wait for a newly created window to become + visible before acting on it. + .. method:: focus_set() + :no-typesetting: + + .. method:: focus() + + Direct the keyboard input focus for this widget's display to this widget. + If the application does not currently have the input focus on this + widget's display, the widget is remembered as the focus window for its + top level, and the focus will be redirected to it the next time the + window manager gives the focus to the top level. + :meth:`focus` is an alias of :meth:`!focus_set`. + + .. method:: focus_force() + + Direct the keyboard input focus to this widget even if the application + does not currently have the input focus for the widget's display. + This method should be used sparingly, if at all; normally an application + should wait for the window manager to give it the focus rather than + claiming it. + + .. method:: focus_get() + + Return the widget that currently has the keyboard focus in the + application, or ``None`` if no widget in the application has the focus. + Use :meth:`focus_displayof` to work correctly with several displays. + + .. method:: focus_displayof() + + Return the widget that currently has the keyboard focus on the display + where this widget is located, or ``None`` if no widget in the application + has the focus on that display. + + .. method:: focus_lastfor() + + Return the most recent widget to have had the keyboard focus among all + the widgets in the same top level as this widget; this is the widget that + will receive the focus the next time the window manager gives the focus + to the top level. + If no widget in that top level has ever had the focus, or if the most + recent focus widget has been deleted, the top level itself is returned. + + .. method:: tk_focusFollowsMouse() + + Reconfigure Tk to use an implicit focus model in which the focus is set + to a widget whenever the mouse pointer enters it. + This cannot easily be disabled once enabled. + + .. method:: tk_focusNext() + + Return the next widget after this one in the keyboard traversal order, or + ``None`` if there is none. + The traversal order goes first to the next child, then recursively to the + children of that child, and then to the next sibling higher in the + stacking order. + A widget is skipped if its ``takefocus`` option is set to ``0``. + This method is used in the default bindings for the :kbd:`Tab` key. + + .. method:: tk_focusPrev() + + Return the previous widget before this one in the keyboard traversal + order, or ``None`` if there is none. + See :meth:`tk_focusNext` for how the order is defined. + This method is used in the default bindings for the :kbd:`Shift-Tab` key. + + .. method:: grab_set() + + Set a local grab on this widget. + A grab confines pointer events to this widget and its descendants: while + the pointer is outside the widget's subtree, button presses and releases + and pointer motion are reported to the grab widget, and windows outside + the subtree become insensitive until the grab is released. + A local grab affects only the grabbing application. + Any grab previously set by this application on the widget's display is + automatically released. + Setting a grab is the usual way to make a dialog modal: while the grab is + in effect the user cannot interact with the other windows of the + application. + + .. method:: grab_set_global() + + Set a global grab on this widget. + A global grab is like the local grab set by :meth:`grab_set`, but it + locks out all other applications on the screen, so that only this + widget's subtree is sensitive to pointer events, and it also grabs the + keyboard. + Use with caution: it is easy to render a display unusable with a global + grab, since other applications stop receiving events until it is + released. + + .. method:: grab_release() + + Release the grab on this widget if there is one; otherwise do nothing. + + .. method:: grab_current() + + Return the widget that currently holds the grab in this application for + this widget's display, or ``None`` if there is no such widget. + + .. method:: grab_status() + + Return ``None`` if no grab is currently set on this widget, ``"local"`` + if a local grab is set, or ``"global"`` if a global grab is set. + + .. method:: selection_clear(**kw) + + Clear the X selection, so that no window owns it anymore. + The selection to clear is given by the keyword argument *selection*, an + atom name such as ``'PRIMARY'`` or ``'CLIPBOARD'``; it defaults to + ``PRIMARY``. + The *displayof* keyword argument names a widget that determines the + display on which to operate, and defaults to this widget. + + .. method:: selection_get(**kw) + + Return the contents of the current X selection. + The keyword argument *selection* names the selection and defaults to + ``PRIMARY``. + The keyword argument *type* specifies the form in which the data is to be + returned (the desired conversion target), an atom name such as + ``'STRING'`` or ``'FILE_NAME'``; it defaults to ``STRING``, except on + X11, where ``UTF8_STRING`` is tried first and ``STRING`` is used as a + fallback. + The *displayof* keyword argument names a widget that determines the + display from which to retrieve the selection, and defaults to this + widget. + + .. method:: selection_handle(command, **kw) + + Register *command* as a handler to supply the X selection owned by this + widget when another application requests it. + When the selection is retrieved, *command* is called with two arguments, + the starting character offset and the maximum number of characters to + return, and must return at most that many characters of the selection + starting at that offset; for very long selections it is called repeatedly + with increasing offsets. + The keyword argument *selection* names the selection (default + ``PRIMARY``) and the keyword argument *type* gives the form of the + selection that the handler supplies (such as ``'STRING'`` or + ``'FILE_NAME'``, default ``STRING``). + + .. method:: selection_own(**kw) + + Make this widget the owner of the X selection on its display. + The previous owner, if any, is notified that it has lost the selection. + The keyword argument *selection* names the selection and defaults to + ``PRIMARY``. + + .. method:: selection_own_get(**kw) + + Return the widget in this application that owns the X selection on the + display containing this widget, or ``None`` if no widget in this + application owns the selection. + The keyword argument *selection* names the selection and defaults to + ``PRIMARY``. + The *displayof* keyword argument names a widget that determines the + display to query, and defaults to this widget. + + .. method:: clipboard_append(string, **kw) + + Append *string* to the Tk clipboard and claim ownership of the clipboard + on this widget's display. + Before appending, the clipboard should be emptied with + :meth:`clipboard_clear`; all appends should be completed before returning + to the event loop so that the clipboard is updated atomically. + The keyword argument *type* specifies the form of the data, an atom name + such as ``'STRING'`` or ``'FILE_NAME'`` (default ``STRING``), and the + keyword argument *format* specifies the representation used to transmit + it (default ``STRING``). + The *displayof* keyword argument names a widget that determines the + target display, and defaults to this widget. + The contents can be retrieved with :meth:`clipboard_get` or + :meth:`selection_get`. + + .. method:: clipboard_clear(**kw) + + Claim ownership of the clipboard on this widget's display and remove any + previous contents. + The *displayof* keyword argument names a widget that determines the + target display, and defaults to this widget. + + .. method:: clipboard_get(**kw) + + Retrieve data from the clipboard on this widget's display. + The keyword argument *type* specifies the form in which the data is to be + returned, an atom name such as ``'STRING'`` or ``'FILE_NAME'``; it + defaults to ``STRING``, except on X11, where ``UTF8_STRING`` is tried + first and ``STRING`` is used as a fallback. + The *displayof* keyword argument names a widget that determines the + display, and defaults to the root window of the application. + This is equivalent to ``selection_get(selection= 'CLIPBOARD')``. + + .. method:: option_add(pattern, value, priority=None) + + Add an option to the Tk option database that associates *value* with + *pattern*. + *pattern* consists of names and/or classes separated by asterisks or + dots, in the usual X format. + *priority* is an integer between 0 and 100, or one of the symbolic names + ``'widgetDefault'`` (20), ``'startupFile'`` (40), ``'userDefault'`` (60), + or ``'interactive'`` (80); it defaults to ``interactive``. + + .. method:: option_clear() + + Clear the Tk option database. + Default options from the :envvar:`!RESOURCE_MANAGER` property or the + :file:`.Xdefaults` file are reloaded automatically the next time an + option is added to or removed from the database. + + .. method:: option_get(name, className) + + Return the value of the option matching this widget under *name* and + *className* from the Tk option database, or an empty string if there is + no matching entry. + When several entries match, the one with the highest priority is + returned, and among entries of equal priority the most recently added + one. + + .. method:: option_readfile(fileName, priority=None) + + Read the file named *fileName*, which should have the standard format for + an X resource database such as :file:`.Xdefaults`, and add all the + options it specifies to the Tk option database. + *priority* is interpreted as for :meth:`option_add` and defaults to + ``interactive``. + + .. method:: bell(displayof=0) + + Ring the bell on the display for this widget, using the display's current + bell-related settings, and reset the screen saver for the screen. + If *displayof* is given as a widget, the bell is rung on that widget's + display instead. + + .. method:: tk_setPalette(background, /) + tk_setPalette(*args, **kw) + + Set a new color scheme for all Tk widget elements. + Existing widgets are updated and the option database is changed so that + future widgets use the new colors. + A single color argument is taken as the normal background color, from + which a complete palette is computed. + Alternatively, the arguments may be given as keyword *name*/*value* pairs + naming individual options in the option database. + The recognized option names are ``activeBackground``, + ``activeForeground``, ``background``, ``disabledForeground``, + ``foreground``, ``highlightBackground``, ``highlightColor``, + ``insertBackground``, ``selectColor``, ``selectBackground``, + ``selectForeground``, and ``troughColor``; reasonable defaults are + computed for any that are not specified. + + .. method:: tk_bisque() + + Restore the application's colors to the light brown (bisque) color scheme + used in Tk 3.6 and earlier versions. + Provided for backward compatibility. + + .. method:: tk_strictMotif(boolean=None) + + Query or set whether Tk's look and feel should strictly adhere to Motif. + A true *boolean* value enables strict Motif compliance (for example, no + color change when the mouse passes over a slider). + Return the resulting setting. + .. method:: busy(**kw) + :no-typesetting: + + .. method:: busy_hold(**kw) + :no-typesetting: + + .. method:: tk_busy(**kw) + :no-typesetting: + + .. method:: tk_busy_hold(**kw) + + Make this widget appear busy. + A transparent window is placed in front of the widget, so that it and all + of its descendants in the widget hierarchy are blocked from pointer + events and display a busy cursor. + Normally :meth:`update` should be called immediately afterwards to ensure + that the hold operation is in effect before the application starts its + processing. + + The only supported configuration option is *cursor*, the cursor to be + displayed while the widget is busy; it may have any of the values + accepted by :meth:`!configure`. + + :meth:`busy_hold`, :meth:`busy` and :meth:`tk_busy` are aliases of + :meth:`!tk_busy_hold`. + + .. versionadded:: 3.13 + + + .. method:: busy_configure(cnf=None, **kw) + :no-typesetting: + + .. method:: busy_config(cnf=None, **kw) + :no-typesetting: + + .. method:: tk_busy_config(cnf=None, **kw) + :no-typesetting: + + .. method:: tk_busy_configure(cnf=None, **kw) + + Query or modify the configuration options of the busy window. + The widget must have been previously made busy by :meth:`tk_busy_hold`. + With no arguments, return a dictionary describing all of the available + options; if *cnf* is the name of an option, return a tuple describing + that one option. + Otherwise set the given options to the given values. + Options may have any of the values accepted by :meth:`tk_busy_hold`. + + The option database is referenced through the widget name or class. + For example, if a :class:`Frame` widget named ``frame`` is to be made + busy, the busy cursor can be specified for it by either of the calls:: + + w.option_add('*frame.busyCursor', 'gumby') + w.option_add('*Frame.BusyCursor', 'gumby') + + :meth:`busy_configure`, :meth:`busy_config` and :meth:`tk_busy_config` + are aliases of :meth:`!tk_busy_configure`. + + .. versionadded:: 3.13 + + + .. method:: busy_cget(option) + :no-typesetting: + + .. method:: tk_busy_cget(option) + + Return the current value of the busy configuration *option*. + The widget must have been previously made busy by :meth:`tk_busy_hold`, + and *option* may have any of the values accepted by that method. + + :meth:`busy_cget` is an alias of :meth:`!tk_busy_cget`. + + .. versionadded:: 3.13 + + + .. method:: busy_forget() + :no-typesetting: + + .. method:: tk_busy_forget() + + Make this widget no longer busy, releasing the resources (including the + transparent window) allocated when it was made busy. + User events will again be received by the widget. + These resources are also released when the widget is destroyed. + + :meth:`busy_forget` is an alias of :meth:`!tk_busy_forget`. + + .. versionadded:: 3.13 + + + .. method:: busy_status() + :no-typesetting: + + .. method:: tk_busy_status() + + Return ``True`` if the widget is currently busy, ``False`` otherwise. + + :meth:`busy_status` is an alias of :meth:`!tk_busy_status`. + + .. versionadded:: 3.13 + + + .. method:: busy_current(pattern=None) + :no-typesetting: + + .. method:: tk_busy_current(pattern=None) + + Return a list of widgets that are currently busy. + If *pattern* is given, only busy widgets whose path names match the + pattern are returned. + + :meth:`busy_current` is an alias of :meth:`!tk_busy_current`. + + .. versionadded:: 3.13 + + .. method:: winfo_atom(name, displayof=0) + + Return the integer identifier for the atom whose name is *name*, creating + a new atom if none exists. + If *displayof* is given, the atom is looked up on the display of that + window; otherwise it is looked up on the display of the application's + main window. + + .. method:: winfo_atomname(id, displayof=0) + + Return the textual name for the atom whose integer identifier is *id*. + This is the inverse of :meth:`winfo_atom`. + If *displayof* is given, the identifier is looked up on the display of + that window; otherwise it is looked up on the display of the + application's main window. + + .. method:: winfo_cells() + + Return the number of cells in the colormap for the widget. + + .. method:: winfo_children() + + Return a list containing the widgets that are children of the widget, in + stacking order from lowest to highest. + Toplevel windows are returned as children of their logical parents. + + .. method:: winfo_class() + + Return the class name of the widget. + + .. method:: winfo_colormapfull() + + Return ``True`` if the colormap for the widget is known to be full, + ``False`` otherwise. + + .. method:: winfo_containing(rootX, rootY, displayof=0) + + Return the widget containing the point given by *rootX* and *rootY*, or + ``None`` if no window in this application contains the point. + The coordinates are in screen units in the coordinate system of the root + window. + If *displayof* is given, the coordinates refer to the screen containing + that window; otherwise they refer to the screen of the application's main + window. + + .. method:: winfo_depth() + + Return the depth of the widget, that is, the number of bits per pixel. + + .. method:: winfo_exists() + + Return ``1`` if the widget exists, ``0`` otherwise. + + .. method:: winfo_fpixels(number) + + Return a floating-point value giving the number of pixels in the widget + corresponding to the screen distance *number* (for example, + ``"2.0c"`` or ``"1i"``). + The result may be fractional; for a rounded integer value use + :meth:`winfo_pixels`. + + .. method:: winfo_geometry() + + Return the geometry of the widget, in the form ``widthxheight+x+y``. + All dimensions are in pixels. + + .. method:: winfo_height() + + Return the height of the widget in pixels. + When a window is first created its height is 1 pixel; it is eventually + changed by a geometry manager. + See also :meth:`winfo_reqheight`. + + .. method:: winfo_id() + + Return a low-level platform-specific identifier for the widget. + On Unix this is the X window identifier, and on Windows it is the window + handle. + + .. method:: winfo_interps(displayof=0) + + Return a tuple of the names of all Tcl interpreters currently registered + for a particular display. + If *displayof* is given, the return value refers to the display of that + window; otherwise it refers to the display of the application's main + window. + + .. method:: winfo_ismapped() + + Return ``1`` if the widget is currently mapped, ``0`` otherwise. + + .. method:: winfo_manager() + + Return the name of the geometry manager currently responsible for the + widget, or an empty string if it is not managed by any geometry manager. + + .. method:: winfo_name() + + Return the widget's name within its parent, as opposed to its full path + name. + + .. method:: winfo_parent() + + Return the path name of the widget's parent, or an empty string if the + widget is the main window of the application. + + .. method:: winfo_pathname(id, displayof=0) + + Return the path name of the window whose identifier is *id*. + If *displayof* is given, the identifier is looked up on the display of + that window; otherwise it is looked up on the display of the + application's main window. + + .. method:: winfo_pixels(number) + + Return the number of pixels in the widget corresponding to the screen + distance *number* (for example, ``"2.0c"`` or ``"1i"``). + The result is rounded to the nearest integer; for a fractional result use + :meth:`winfo_fpixels`. + + .. method:: winfo_pointerx() + + Return the pointer's *x* coordinate, in pixels, relative to the screen's + root window (or virtual root, if one is in use). + Return ``-1`` if the pointer is not on the same screen as the widget. + + .. method:: winfo_pointerxy() + + Return the pointer's coordinates as an ``(x, y)`` tuple, in pixels, + relative to the screen's root window (or virtual root, if one is in use). + Both coordinates are ``-1`` if the pointer is not on the same screen as + the widget. + + .. method:: winfo_pointery() + + Return the pointer's *y* coordinate, in pixels, relative to the screen's + root window (or virtual root, if one is in use). + Return ``-1`` if the pointer is not on the same screen as the widget. + + .. method:: winfo_reqheight() + + Return the widget's requested height in pixels. + This is the value used by the widget's geometry manager to compute its + geometry. + + .. method:: winfo_reqwidth() + + Return the widget's requested width in pixels. + This is the value used by the widget's geometry manager to compute its + geometry. + + .. method:: winfo_rgb(color) + + Return an ``(r, g, b)`` tuple of the red, green, and blue intensities, in + the range 0 to 65535, that correspond to *color* in the widget. + *color* may be specified in any of the forms acceptable for a color + option. + + .. method:: winfo_rootx() + + Return the *x* coordinate, in the root window of the screen, of the + upper-left corner of the widget's border (or of the widget itself if it + has no border). + + .. method:: winfo_rooty() + + Return the *y* coordinate, in the root window of the screen, of the + upper-left corner of the widget's border (or of the widget itself if it + has no border). + + .. method:: winfo_screen() + + Return the name of the screen associated with the widget, in the form + ``displayName.screenIndex``. + + .. method:: winfo_screencells() + + Return the number of cells in the default colormap for the widget's + screen. + + .. method:: winfo_screendepth() + + Return the depth of the root window of the widget's screen, that is, the + number of bits per pixel. + + .. method:: winfo_screenheight() + + Return the height of the widget's screen in pixels. + + .. method:: winfo_screenmmheight() + + Return the height of the widget's screen in millimeters. + + .. method:: winfo_screenmmwidth() + + Return the width of the widget's screen in millimeters. + + .. method:: winfo_screenvisual() + + Return the default visual class for the widget's screen, one of + ``"directcolor"``, ``"grayscale"``, ``"pseudocolor"``, ``"staticcolor"``, + ``"staticgray"``, or ``"truecolor"``. + + .. method:: winfo_screenwidth() + + Return the width of the widget's screen in pixels. + + .. method:: winfo_server() + + Return a string containing information about the server for the widget's + display. + The exact format of this string may vary from platform to platform. + + .. method:: winfo_toplevel() + + Return the top-of-hierarchy window containing the widget. + In standard Tk this is always a :class:`Toplevel` widget. + + .. method:: winfo_viewable() + + Return ``1`` if the widget and all of its ancestors up through the + nearest toplevel window are mapped, ``0`` otherwise. + + .. method:: winfo_visual() + + Return the visual class for the widget, one of ``"directcolor"``, + ``"grayscale"``, ``"pseudocolor"``, ``"staticcolor"``, ``"staticgray"``, + or ``"truecolor"``. + + .. method:: winfo_visualid() + + Return the X identifier for the visual for the widget. + + .. method:: winfo_visualsavailable(includeids=False) + + Return a list describing the visuals available for the widget's screen. + Each item consists of a visual class (see :meth:`winfo_visual`) followed + by an integer depth. + If *includeids* is true, the X identifier for the visual is also + included. + + .. method:: winfo_vrootheight() + + Return the height of the virtual root window associated with the widget + if there is one; otherwise return the height of the widget's screen. + + .. method:: winfo_vrootwidth() + + Return the width of the virtual root window associated with the widget if + there is one; otherwise return the width of the widget's screen. + + .. method:: winfo_vrootx() + + Return the *x* offset of the virtual root window associated with the + widget, relative to the root window of its screen. + This is normally zero or negative, and is ``0`` if there is no virtual + root window. + + .. method:: winfo_vrooty() + + Return the *y* offset of the virtual root window associated with the + widget, relative to the root window of its screen. + This is normally zero or negative, and is ``0`` if there is no virtual + root window. + + .. method:: winfo_width() + + Return the width of the widget in pixels. + When a window is first created its width is 1 pixel; it is eventually + changed by a geometry manager. + See also :meth:`winfo_reqwidth`. + + .. method:: winfo_x() + + Return the *x* coordinate, in the widget's parent, of the upper-left + corner of the widget's border (or of the widget itself if it has no + border). + + .. method:: winfo_y() + + Return the *y* coordinate, in the widget's parent, of the upper-left + corner of the widget's border (or of the widget itself if it has no + border). + + .. method:: info_patchlevel() + + Return the Tcl/Tk patch level as a string, for example ``'9.1.0'``. + + .. versionadded:: 3.11 + + + +.. class:: Wm() + + The :class:`!Wm` mixin provides access to the window manager, allowing an + application to control such things as the title, geometry and icon of a + top-level window, the way it is resized, and how it responds to window + manager protocols. + It is mixed into :class:`Tk` and :class:`Toplevel`, so its methods are + available on every top-level window. + Each method has two equivalent spellings: a short name and a + ``wm_``-prefixed name (for example, :meth:`title` and :meth:`wm_title`). + + .. method:: wm_aspect(minNumer=None, minDenom=None, maxNumer=None, maxDenom=None) + :no-typesetting: + + .. method:: aspect(minNumer=None, minDenom=None, maxNumer=None, maxDenom=None) + + Constrain the aspect ratio (the ratio of width to height) of the window. + If all four arguments are given, the window manager keeps the ratio + between ``minNumer/minDenom`` and ``maxNumer/maxDenom``; passing empty + strings removes any existing restriction. + With no arguments, return a tuple of the four current values, or an empty + string if no aspect restriction is in effect. + :meth:`wm_aspect` is an alias of :meth:`!aspect`. + + .. method:: wm_attributes(*args, return_python_dict=False, **kwargs) + :no-typesetting: + + .. method:: attributes(*args, return_python_dict=False, **kwargs) + + Query or set platform-specific attributes of the window. + With no arguments, return the platform-specific flags and their values; + pass *return_python_dict* as true to get them as a dictionary. + A single option name such as ``'alpha'`` returns the value of that + option, and options are set using keyword arguments (``alpha=0.5``). + + The available attributes differ by platform. + All platforms support: + + *alpha* + The window's opacity, from ``0.0`` (fully transparent) to ``1.0`` + (opaque). + Where transparency is unsupported the value stays at ``1.0``. + + *appearance* + Whether the window is rendered in dark mode on Windows and macOS: + ``'auto'``, ``'light'`` or ``'dark'`` (this has no effect on X11). + + *fullscreen* + Whether the window takes up the entire screen and has no borders. + + *topmost* + Whether the window is displayed above all other windows. + + Windows additionally supports: + + *disabled* + Whether the window is in a disabled state. + + *toolwindow* + Whether the window uses the tool window style. + + *transparentcolor* + The color that is made fully transparent, or an empty string for none. + + macOS additionally supports: + + *class* + Whether the underlying Aqua window is an ``nswindow`` or an + ``nspanel``; this can only be set before the window is created. + + *modified* + The modification state shown by the window's close button and proxy + icon. + + *notify* + Whether the application's dock icon bounces to request attention. + + *stylemask* + The style mask of the underlying Aqua window, given as a list of bit + names such as ``titled`` or ``resizable``. + + *tabbingid* + The identifier of the tab group that the window belongs to. + + *tabbingmode* + Whether the window may be opened as a tab: ``'auto'``, ``'preferred'`` + or ``'disallowed'``. + + *titlepath* + The path of the file represented by the window's proxy icon. + + *transparent* + Whether the content area is transparent and the window shadow is + turned off. + + X11 additionally supports: + + *type* + The window type, or a list of types in order of preference, that the + window manager should use to interpret the window, such as + ``'dialog'`` or ``'splash'``. + + *zoomed* + Whether the window is maximized. + + .. note:: + + Tk 8.6 added the *type* attribute, and Tk 9.0 added the *appearance*, + *class*, *stylemask*, *tabbingid* and *tabbingmode* attributes. + + On X11 changes are applied asynchronously, so a queried value may not yet + reflect the most recent request. + :meth:`wm_attributes` is an alias of :meth:`!attributes`. + + .. versionchanged:: 3.13 + A single attribute may now be queried by name without the leading + ``-``, and attributes may be set using keyword arguments. + The *return_python_dict* parameter was added. + + .. deprecated:: next + Setting an attribute by passing the option name (with a leading + ``-``) and its value as two positional arguments, as in + ``w.attributes('-alpha', 0.5)``, is deprecated; use keyword arguments + instead. + + + .. method:: wm_client(name=None) + :no-typesetting: + + .. method:: client(name=None) + + Store *name*, which should be the name of the host on which the + application is running, in the window's ``WM_CLIENT_MACHINE`` property + for use by the window or session manager. + An empty string deletes the property. + With no argument, return the last name set, or an empty string. + :meth:`wm_client` is an alias of :meth:`!client`. + + .. method:: wm_colormapwindows(*wlist) + :no-typesetting: + + .. method:: colormapwindows(*wlist) + + Manipulate the ``WM_COLORMAP_WINDOWS`` property, which tells the window + manager about windows that have private colormaps. + If *wlist* is given, overwrite the property with those windows (their + order is a priority order for installing colormaps). + With no arguments, return the list of windows currently named in the + property. + :meth:`wm_colormapwindows` is an alias of :meth:`!colormapwindows`. + + .. method:: wm_command(value=None) + :no-typesetting: + + .. method:: command(value=None) + + Store *value* in the window's ``WM_COMMAND`` property for use by the + window or session manager; it should be a list giving the words of the + command used to invoke the application. + An empty string deletes the property. + With no argument, return the last value set, or an empty string. + :meth:`wm_command` is an alias of :meth:`!command`. + + .. method:: wm_deiconify() + :no-typesetting: + + .. method:: deiconify() + + Display the window in normal (non-iconified) form by mapping it. + If the window has never been mapped, this ensures it appears de-iconified + when it is first mapped. + On Windows the window is also raised and given the focus. + :meth:`wm_deiconify` is an alias of :meth:`!deiconify`. + + .. method:: wm_focusmodel(model=None) + :no-typesetting: + + .. method:: focusmodel(model=None) + + Set or query the focus model for the window. + *model* is either ``'active'`` (the window claims the input focus for + itself or its descendants, even when the focus is in another application) + or ``'passive'`` (the window relies on the window manager to give it the + focus). + With no argument, return the current model. + The default is ``'passive'``, which is what the :meth:`!focus` command + assumes. + :meth:`wm_focusmodel` is an alias of :meth:`!focusmodel`. + + .. method:: wm_forget(window) + :no-typesetting: + + .. method:: forget(window) + + Unmap *window* from the screen so that it is no longer managed by the + window manager. + A :class:`Toplevel` is then treated like a :class:`Frame`, although its + ``-menu`` configuration is remembered and the menu reappears if the + widget is managed again. + :meth:`wm_forget` is an alias of :meth:`!forget`. + + .. versionadded:: 3.3 + + .. method:: wm_frame() + :no-typesetting: + + .. method:: frame() + + Return the platform-specific window identifier for the outermost + decorative frame containing the window, if the window manager has + reparented it into such a frame; otherwise return the identifier of the + window itself. + :meth:`wm_frame` is an alias of :meth:`!frame`. + + .. method:: wm_geometry(newGeometry=None) + :no-typesetting: + + .. method:: geometry(newGeometry=None) + + Set or query the geometry of the window. + *newGeometry* has the form ``=widthxheight+x+y``, where any of ``=``, + ``widthxheight`` and the ``+x+y`` position may be omitted. + *width* and *height* are in pixels (or grid units for a gridded window); + a position preceded by ``+`` is measured from the left or top edge of the + screen and one preceded by ``-`` from the right or bottom edge. + An empty string cancels any user-specified geometry, letting the window + revert to its natural size. + With no argument, return the current geometry as a string of the form + ``'200x200+10+10'``. + :meth:`wm_geometry` is an alias of :meth:`!geometry`. + + .. method:: wm_grid(baseWidth=None, baseHeight=None, widthInc=None, heightInc=None) + :no-typesetting: + + .. method:: grid(baseWidth=None, baseHeight=None, widthInc=None, heightInc=None) + + Manage the window as a gridded window and define the relationship between + grid units and pixels. + *baseWidth* and *baseHeight* are the numbers of grid units for the + window's internally requested size, and *widthInc* and *heightInc* are + the pixel sizes of a horizontal and vertical grid unit. + Empty strings turn off gridded management. + With no arguments, return a tuple of the four current values, or an empty + string if the window is not gridded. + :meth:`wm_grid` is an alias of :meth:`!grid`. + + .. method:: wm_group(pathName=None) + :no-typesetting: + + .. method:: group(pathName=None) + + Set or query the leader of a group of related windows. + *pathName* gives the path name of the group leader; the window manager + may, for example, unmap all windows in the group when the leader is + iconified. + An empty string removes the window from any group. + With no argument, return the path name of the current group leader, or an + empty string. + :meth:`wm_group` is an alias of :meth:`!group`. + + .. method:: wm_iconbitmap(bitmap=None, default=None) + :no-typesetting: + + .. method:: iconbitmap(bitmap=None, default=None) + + Set or query the bitmap used by the window manager for the window's icon. + *bitmap* names a bitmap in one of the standard forms accepted by Tk; an + empty string cancels the current icon bitmap. + With no argument, return the name of the current icon bitmap, or an empty + string. + On Windows the *default* argument names an icon (for example an ``.ico`` + file) applied to all top-level windows that have no icon of their own. + :meth:`wm_iconbitmap` is an alias of :meth:`!iconbitmap`. + + .. method:: wm_iconify() + :no-typesetting: + + .. method:: iconify() + + Iconify the window. + If the window has not yet been mapped for the first time, arrange for it + to appear in the iconified state when it is eventually mapped. + :meth:`wm_iconify` is an alias of :meth:`!iconify`. + + .. method:: wm_iconmask(bitmap=None) + :no-typesetting: + + .. method:: iconmask(bitmap=None) + + Set or query the bitmap used as a mask for the icon (see + :meth:`iconbitmap`). + Where the mask is zero no icon is displayed; where it is one, the + corresponding bits of the icon bitmap are shown. + An empty string cancels the current mask. + With no argument, return the name of the current icon mask, or an empty + string. + :meth:`wm_iconmask` is an alias of :meth:`!iconmask`. + + .. method:: wm_iconname(newName=None) + :no-typesetting: + + .. method:: iconname(newName=None) + + Set or query the name displayed by the window manager inside the window's + icon. + With no argument, return the current icon name, or an empty string if + none has been set (in which case the window manager normally displays the + window's title). + :meth:`wm_iconname` is an alias of :meth:`!iconname`. + + .. method:: wm_iconphoto(default=False, *images) + :no-typesetting: + + .. method:: iconphoto(default=False, *images) + + Set the titlebar icon for the window from one or more :class:`PhotoImage` + objects given in *images*. + Several images of different sizes (for example 16x16 and 32x32) may be + supplied so that the window manager can choose an appropriate one. + The image data is taken as a snapshot at the time of the call; later + changes to the images are not reflected. + If *default* is true, the icon is also applied to all top-level windows + created in the future. + On macOS only the first image is used. + :meth:`wm_iconphoto` is an alias of :meth:`!iconphoto`. + + .. versionadded:: 3.3 + + .. method:: wm_iconposition(x=None, y=None) + :no-typesetting: + + .. method:: iconposition(x=None, y=None) + + Set or query a hint to the window manager about where the window's icon + should be positioned. + Empty strings cancel an existing hint. + With no arguments, return a tuple of the two current values, or an empty + string if no hint is in effect. + :meth:`wm_iconposition` is an alias of :meth:`!iconposition`. + + .. method:: wm_iconwindow(pathName=None) + :no-typesetting: + + .. method:: iconwindow(pathName=None) + + Set or query the window used as the icon for the window. + When the window is iconified, *pathName* is mapped to serve as its icon + and unmapped again when it is de-iconified. + An empty string cancels the association. + With no argument, return the path name of the current icon window, or an + empty string. + Not all window managers support icon windows, and the concept is + meaningless on non-X11 platforms. + :meth:`wm_iconwindow` is an alias of :meth:`!iconwindow`. + + .. method:: wm_manage(widget) + :no-typesetting: + + .. method:: manage(widget) + + Make *widget* a stand-alone top-level window, decorated by the window + manager with a title bar and so on. + Only :class:`Frame`, :class:`LabelFrame` and :class:`Toplevel` widgets + may be used; passing any other widget type raises an error. + :meth:`wm_manage` is an alias of :meth:`!manage`. + + .. versionadded:: 3.3 + + .. method:: wm_maxsize(width=None, height=None) + :no-typesetting: + + .. method:: maxsize(width=None, height=None) + + Set or query the maximum permissible dimensions of the window, in pixels + (or grid units for a gridded window). + The window manager restricts the window to be no larger than *width* and + *height*. + With no arguments, return a tuple of the current maximum width and + height. + The maximum size defaults to the size of the screen. + :meth:`wm_maxsize` is an alias of :meth:`!maxsize`. + + .. method:: wm_minsize(width=None, height=None) + :no-typesetting: + + .. method:: minsize(width=None, height=None) + + Set or query the minimum permissible dimensions of the window, in pixels + (or grid units for a gridded window). + The window manager restricts the window to be no smaller than *width* and + *height*. + With no arguments, return a tuple of the current minimum width and + height. + The minimum size defaults to one pixel in each dimension. + :meth:`wm_minsize` is an alias of :meth:`!minsize`. + + .. method:: wm_overrideredirect(boolean=None) + :no-typesetting: + + .. method:: overrideredirect(boolean=None) + + Set or query the override-redirect flag for the window. + When this flag is set, the window is ignored by the window manager: it is + not reparented into a decorative frame and the user cannot manipulate it + through the usual window manager controls. + With no argument, return a boolean indicating whether the flag is set. + The flag is reliably honored only when the window is first mapped or + remapped from the withdrawn state. + :meth:`wm_overrideredirect` is an alias of :meth:`!overrideredirect`. + + .. method:: wm_positionfrom(who=None) + :no-typesetting: + + .. method:: positionfrom(who=None) + + Set or query the source of the window's current position. + *who* is either ``'program'`` or ``'user'`` and indicates whether the + position was requested by the program or by the user; an empty string + cancels the current source. + With no argument, return the current source, or an empty string if none + has been set. + Tk automatically sets the source to ``'user'`` when :meth:`geometry` is + called, unless it has been set explicitly to ``'program'``. + :meth:`wm_positionfrom` is an alias of :meth:`!positionfrom`. + + .. method:: wm_protocol(name=None, func=None) + :no-typesetting: + + .. method:: protocol(name=None, func=None) + + Register *func* as the handler for the window manager protocol *name*, an + atom such as ``'WM_DELETE_WINDOW'``, ``'WM_SAVE_YOURSELF'`` or + ``'WM_TAKE_FOCUS'``; *func* is then called whenever the window manager + sends a message of that protocol. + Tk installs a default ``WM_DELETE_WINDOW`` handler that destroys the + window, which this method can replace. + If *func* is an empty string, the handler is removed. + With only *name*, return the name of its registered handler command, or + an empty string if none is set (the default ``WM_DELETE_WINDOW`` handler + is not reported); with no arguments, return a tuple of the protocols that + currently have handlers. + :meth:`wm_protocol` is an alias of :meth:`!protocol`. + + .. method:: wm_resizable(width=None, height=None) + :no-typesetting: + + .. method:: resizable(width=None, height=None) + + Control whether the user may interactively resize the window. + *width* and *height* are boolean values that determine whether the + window's width and height may be changed. + With no arguments, return a tuple of two ``0``/``1`` values indicating + whether each dimension is currently resizable. + By default a window is resizable in both dimensions. + :meth:`wm_resizable` is an alias of :meth:`!resizable`. + + .. method:: wm_sizefrom(who=None) + :no-typesetting: + + .. method:: sizefrom(who=None) + + Set or query the source of the window's current size. + *who* is either ``'program'`` or ``'user'`` and indicates whether the + size was requested by the program or by the user; an empty string cancels + the current source. + With no argument, return the current source, or an empty string if none + has been set. + :meth:`wm_sizefrom` is an alias of :meth:`!sizefrom`. + + .. method:: wm_state(newstate=None) + :no-typesetting: + + .. method:: state(newstate=None) + + Set or query the state of the window. + With no argument, return the current state: one of ``'normal'``, + ``'iconic'``, ``'withdrawn'``, ``'icon'`` or, on Windows and macOS only, + ``'zoomed'``. + ``'iconic'`` refers to a window that has been iconified, while ``'icon'`` + refers to a window serving as the icon for another window (see + :meth:`iconwindow`); the ``'icon'`` state cannot be set. + :meth:`wm_state` is an alias of :meth:`!state`. + + .. method:: wm_title(string=None) + :no-typesetting: + + .. method:: title(string=None) + + Set or query the title for the window, which the window manager should + display in the window's title bar. + With no argument, return the current title. + The title defaults to the window's name. + :meth:`wm_title` is an alias of :meth:`!title`. + + .. method:: wm_transient(master=None) + :no-typesetting: + + .. method:: transient(master=None) + + Mark the window as a transient window (such as a pull-down menu or + dialog) working on behalf of *master*, the path name of another top-level + window. + An empty string clears the transient status. + With no argument, return the path name of the current master, or an empty + string. + A transient window mirrors state changes in its master and may be + decorated differently by the window manager; it is an error to make a + window a transient of itself. + :meth:`wm_transient` is an alias of :meth:`!transient`. + + .. method:: wm_withdraw() + :no-typesetting: + + .. method:: withdraw() + + Withdraw the window from the screen, unmapping it and causing the window + manager to forget about it. + If the window has never been mapped, it is instead mapped in the + withdrawn state. + It is sometimes necessary to withdraw a window and then re-map it (for + example with :meth:`deiconify`) to make some window managers notice + changes to window attributes. + :meth:`wm_withdraw` is an alias of :meth:`!withdraw`. + + +.. class:: Pack() + + Geometry manager that arranges widgets by packing them against the sides of + their container. + The :class:`!Pack` mix-in is inherited by all widgets (through + :class:`Widget`) and provides the methods for managing a widget with the + *pack* geometry manager. + See also :ref:`pack-the-packer`. + + .. method:: configure(cnf={}, **kw) + :no-typesetting: + + .. method:: config(cnf={}, **kw) + :no-typesetting: + + .. method:: pack_configure(cnf={}, **kw) + pack(cnf={}, **kw) + + Pack the widget inside its container, positioning it relative to the + siblings already packed there. + The supported options are: + + *side* + Which side of the container to pack the widget against: ``'top'`` (the + default), ``'bottom'``, ``'left'`` or ``'right'``. + + *fill* + Whether to stretch the widget to fill its parcel: ``'none'`` (the + default), ``'x'``, ``'y'`` or ``'both'``. + + *expand* + Whether the widget should expand to consume any extra space in its + container (a boolean, default false). + + *anchor* + Where to position the widget in its parcel when the parcel is larger + than the widget: an anchor such as ``'n'`` or ``'sw'`` (default + ``'center'``). + + *ipadx*, *ipady* + Internal padding added on the left and right (*ipadx*) or top and + bottom (*ipady*) of the widget, as a screen distance (default ``0``). + + *padx*, *pady* + External padding left on the left and right (*padx*) or top and bottom + (*pady*) of the widget, as a screen distance or a pair of two + distances for the two sides (default ``0``). + + *after* + Pack the widget after the given widget in the packing order, using the + same container. + + *before* + Pack the widget before the given widget in the packing order, using + the same container. + + *in_* + The container in which to pack the widget; it defaults to the parent + widget. + + :meth:`pack`, :meth:`configure` and :meth:`config` are aliases of + :meth:`!pack_configure`. + + .. method:: forget() + :no-typesetting: + + .. method:: pack_forget() + + Unmap the widget and remove it from the packing order, forgetting its + packing options. + It can be packed again later with :meth:`pack_configure`. + :meth:`forget` is an alias of :meth:`!pack_forget`. + + .. method:: info() + :no-typesetting: + + .. method:: pack_info() + + Return a dictionary of the widget's current packing options. + :meth:`info` is an alias of :meth:`!pack_info`. + + .. method:: propagate() + propagate(flag) + :no-typesetting: + + .. method:: pack_propagate() + pack_propagate(flag) + + Same as :meth:`Misc.pack_propagate`, treating this widget as a container: + enable or disable geometry propagation. + :meth:`propagate` is an alias of :meth:`!pack_propagate`. + + .. method:: slaves() + :no-typesetting: + + .. method:: pack_slaves() + + Same as :meth:`Misc.pack_slaves`: return the list of widgets packed in + this widget. + :meth:`slaves` is an alias of :meth:`!pack_slaves`. + + .. method:: content() + :no-typesetting: + + .. method:: pack_content() + + Same as :meth:`Misc.pack_content`. + :meth:`content` is an alias of :meth:`!pack_content`. + + +.. class:: Place() + + Geometry manager that places widgets at explicit positions and sizes within + their container. + The :class:`!Place` mix-in is inherited by all widgets (through + :class:`Widget`). + + .. method:: configure(cnf={}, **kw) + :no-typesetting: + + .. method:: config(cnf={}, **kw) + :no-typesetting: + + .. method:: place_configure(cnf={}, **kw) + place(cnf={}, **kw) + + Place the widget inside its container at an absolute or relative + position. + The supported options are: + + *x*, *y* + The absolute horizontal and vertical position of the widget's anchor + point, as a screen distance (default ``0``). + + *relx*, *rely* + The horizontal and vertical position of the widget's anchor point as a + fraction of the container's width and height, where ``0.0`` is the + left or top edge and ``1.0`` is the right or bottom edge. + If both the absolute and the relative option are given, their values + are summed. + + *anchor* + Which point of the widget is placed at the given position: an anchor + such as ``'n'`` or ``'se'`` (default ``'nw'``). + + *width*, *height* + The absolute width and height of the widget, as a screen distance. + By default the widget's requested size is used. + + *relwidth*, *relheight* + The width and height of the widget as a fraction of the container's + width and height. + If both the absolute and the relative option are given, their values + are summed. + + *bordermode* + How the container's border affects placement: ``'inside'`` (the + default) measures the area inside the border, ``'outside'`` measures + the area including the border, and ``'ignore'`` uses the official X + area. + + *in_* + The container relative to which the widget is placed; it must be the + widget's parent or a descendant of the parent, and defaults to the + parent. + + :meth:`place`, :meth:`configure` and :meth:`config` are aliases of + :meth:`!place_configure`. + + .. method:: forget() + :no-typesetting: + + .. method:: place_forget() + + Unmap the widget and remove it from the placement, forgetting its place + options. + :meth:`forget` is an alias of :meth:`!place_forget`. + + .. method:: info() + :no-typesetting: + + .. method:: place_info() + + Return a dictionary of the widget's current place options. + :meth:`info` is an alias of :meth:`!place_info`. + + .. method:: slaves() + :no-typesetting: + + .. method:: place_slaves() + + Same as :meth:`Misc.place_slaves`: return the list of widgets placed in + this widget. + :meth:`slaves` is an alias of :meth:`!place_slaves`. + + .. method:: content() + :no-typesetting: + + .. method:: place_content() + + Same as :meth:`Misc.place_content`. + :meth:`content` is an alias of :meth:`!place_content`. + + +.. class:: Grid() + + Geometry manager that arranges widgets in a two-dimensional grid of rows and + columns within their container. + The :class:`!Grid` mix-in is inherited by all widgets (through + :class:`Widget`). + + .. method:: configure(cnf={}, **kw) + :no-typesetting: + + .. method:: config(cnf={}, **kw) + :no-typesetting: + + .. method:: grid_configure(cnf={}, **kw) + grid(cnf={}, **kw) + + Position the widget in a cell of its container's grid. + The supported options are: + + *row*, *column* + The row and column of the cell to place the widget in, counting from + ``0``. + *column* defaults to the column after the previous widget placed in + the same :meth:`!grid_configure` call (or ``0``), and *row* defaults + to the next empty row. + + *rowspan*, *columnspan* + The number of rows and columns the widget should span (default ``1``). + + *sticky* + How to position or stretch the widget when its cell is larger than the + widget: a string containing zero or more of the characters ``'n'``, + ``'s'``, ``'e'`` and ``'w'``, naming the cell sides the widget sticks + to. + Specifying both ``'n'`` and ``'s'`` (or ``'e'`` and ``'w'``) stretches + the widget to fill the height (or width) of the cell. + The default is ``''``, which centers the widget at its requested size. + + *ipadx*, *ipady* + Internal padding added on the left and right (*ipadx*) or top and + bottom (*ipady*) of the widget, as a screen distance (default ``0``). + + *padx*, *pady* + External padding left on the left and right (*padx*) or top and bottom + (*pady*) of the widget, as a screen distance or a pair of two + distances for the two sides (default ``0``). + + *in_* + The container in whose grid to place the widget; it defaults to the + parent widget. + + :meth:`grid`, :meth:`configure` and :meth:`config` are aliases of + :meth:`!grid_configure`. + + .. method:: forget() + :no-typesetting: + + .. method:: grid_forget() + + Unmap the widget and remove it from the grid, forgetting its grid + options. + :meth:`forget` is an alias of :meth:`!grid_forget`. + + .. method:: grid_remove() + + Unmap the widget and remove it from the grid, but remember its grid + options so that it is restored to the same cell if it is gridded again. + + .. method:: info() + :no-typesetting: + + .. method:: grid_info() + + Return a dictionary of the widget's current grid options. + :meth:`info` is an alias of :meth:`!grid_info`. + + .. method:: bbox(column=None, row=None, col2=None, row2=None) + :no-typesetting: + + .. method:: grid_bbox(column=None, row=None, col2=None, row2=None) + + Same as :meth:`Misc.grid_bbox`. + :meth:`bbox` is an alias of :meth:`!grid_bbox`. + + .. method:: columnconfigure(index, cnf={}, **kw) + :no-typesetting: + + .. method:: grid_columnconfigure(index, cnf={}, **kw) + + Same as :meth:`Misc.grid_columnconfigure`: query or set the options (such + as *weight*, *minsize*, *pad* and *uniform*) of a grid column. + :meth:`columnconfigure` is an alias of :meth:`!grid_columnconfigure`. + + .. method:: rowconfigure(index, cnf={}, **kw) + :no-typesetting: + + .. method:: grid_rowconfigure(index, cnf={}, **kw) + + Same as :meth:`Misc.grid_rowconfigure`: query or set the options of a + grid row. + :meth:`rowconfigure` is an alias of :meth:`!grid_rowconfigure`. + + .. method:: location(x, y) + :no-typesetting: + + .. method:: grid_location(x, y) + + Same as :meth:`Misc.grid_location`: return the ``(column, row)`` of the + cell that covers the pixel at *x*, *y*. + :meth:`location` is an alias of :meth:`!grid_location`. + + .. method:: size() + :no-typesetting: + + .. method:: grid_size() + + Same as :meth:`Misc.grid_size`: return a ``(columns, rows)`` tuple giving + the size of the grid. + :meth:`size` is an alias of :meth:`!grid_size`. + + .. method:: propagate() + propagate(flag) + :no-typesetting: + + .. method:: grid_propagate() + grid_propagate(flag) + + Same as :meth:`Misc.grid_propagate`. + :meth:`propagate` is an alias of :meth:`!grid_propagate`. + + .. method:: slaves(row=None, column=None) + :no-typesetting: + + .. method:: grid_slaves(row=None, column=None) + + Same as :meth:`Misc.grid_slaves`: return the widgets managed in the grid, + optionally restricted to a *row* and/or *column*. + :meth:`slaves` is an alias of :meth:`!grid_slaves`. + + .. method:: content(row=None, column=None) + :no-typesetting: + + .. method:: grid_content(row=None, column=None) + + Same as :meth:`Misc.grid_content`. + :meth:`content` is an alias of :meth:`!grid_content`. + + +.. class:: XView() + + Mix-in providing the horizontal-scrolling interface shared by widgets such + as :class:`Entry`, :class:`Canvas`, :class:`Listbox`, :class:`Text` and + :class:`Spinbox`. + A widget's :meth:`xview` method is registered as the *command* of a + horizontal :class:`Scrollbar`. + + .. method:: xview(*args) + + Query or change the horizontal position of the view. + With no arguments, return a tuple ``(first, last)`` of two fractions + between 0 and 1 giving the portion of the document that is currently + visible. + Otherwise the arguments are passed to the Tk ``xview`` widget command and + are usually generated by a scrollbar; :meth:`xview_moveto` and + :meth:`xview_scroll` provide a more convenient interface. + + .. method:: xview_moveto(fraction) + + Adjust the view so that *fraction* of the total width of the document is + off-screen to the left. + *fraction* is a number between 0 and 1. + + .. method:: xview_scroll(number, what) + + Shift the view left or right by *number* units. + *what* is either ``'units'`` or ``'pages'``; a negative *number* scrolls + left and a positive one scrolls right. + + +.. class:: YView() + + Mix-in providing the vertical-scrolling interface shared by widgets such as + :class:`Canvas`, :class:`Listbox` and :class:`Text`. + A widget's :meth:`yview` method is registered as the *command* of a vertical + :class:`Scrollbar`. + + .. method:: yview(*args) + + Query or change the vertical position of the view. + With no arguments, return a tuple ``(first, last)`` of two fractions + between 0 and 1 giving the portion of the document that is currently + visible. + Otherwise the arguments are passed to the Tk ``yview`` widget command, + usually generated by a scrollbar; :meth:`yview_moveto` and + :meth:`yview_scroll` provide a more convenient interface. + + .. method:: yview_moveto(fraction) + + Adjust the view so that *fraction* of the total height of the document is + off-screen above the top. + *fraction* is a number between 0 and 1. + + .. method:: yview_scroll(number, what) + + Shift the view up or down by *number* units. + *what* is either ``'units'`` or ``'pages'``; a negative *number* scrolls + up and a positive one scrolls down. + + +.. class:: BaseWidget(master, widgetName, cnf={}, kw={}, extra=()) + + Internal base class for all widgets. + It inherits from :class:`Misc` and adds the machinery that creates the + underlying Tk widget; application code normally uses :class:`Widget` or a + concrete widget class rather than instantiating :class:`!BaseWidget` + directly. + + .. method:: destroy() + + Destroy this widget and all of its children, removing the corresponding + Tk widgets and deleting the associated Tcl commands. + + +.. class:: Widget(master, widgetName, cnf={}, kw={}, extra=()) + + Internal base class for the standard widgets. + It combines :class:`BaseWidget` with the geometry-manager mix-ins + :class:`Pack`, :class:`Place` and :class:`Grid`, so that every widget can be + managed by any of the three geometry managers. + The concrete widget classes (:class:`Button`, :class:`Label`, and so on) + derive from :class:`!Widget`. + + +.. class:: Toplevel(master=None, cnf={}, **kw) + + A :class:`!Toplevel` widget is a top-level window, similar to a + :class:`Frame` except that its X parent is the root window of a screen + rather than its logical parent. + Its primary purpose is to serve as a container for dialog boxes and other + collections of widgets; its only visible features are its background and an + optional 3-D border. + Notable options include *menu*, which installs a :class:`Menu` as the + window's menubar. + Inherits from :class:`BaseWidget` and :class:`Wm`, so a toplevel is managed + by the window manager. + Refer to the Tk ``toplevel`` manual page for the full list of options. + + +Widget classes +^^^^^^^^^^^^^^ + +.. class:: Button(master=None, cnf={}, **kw) + + A :class:`!Button` widget displays a textual string, bitmap or image and + invokes a command when the user presses it (by clicking mouse button 1 over + the button or, when the button has focus, by pressing the space key). + Inherits from :class:`Widget`. + In addition to the standard widget options, a button accepts the options + documented in the Tk ``button`` manual page, such as *command* (the callback + invoked when the button is pressed), *textvariable*, *state* and *default*. + + .. method:: invoke() + + Invoke the command associated with the button, if there is one, and + return its result, or an empty string if no command is associated with + the button. + This is ignored if the button's state is ``disabled``. + + .. method:: flash() + + Flash the button by redisplaying it several times, alternating between + the active and normal colors. + At the end of the flash the button is left in the same normal or active + state as when the method was called. + This is ignored if the button's state is ``disabled``. + + +.. class:: Canvas(master=None, cnf={}, **kw) + + A :class:`!Canvas` widget implements structured graphics. + It displays any number of *items*, such as arcs, lines, ovals, polygons, + rectangles, text, bitmaps, images and embedded windows, which may be drawn, + moved, re-colored and bound to events. + Inherits from :class:`Widget`, :class:`XView` and :class:`YView`, so the + view can be scrolled horizontally and vertically with :meth:`~XView.xview` + and :meth:`~YView.yview`. + Refer to the Tk ``canvas`` manual page for the full list of widget and item + options. + + Each item has a unique integer *id*, assigned when it is created, and zero + or more string *tags*. + A tag is an arbitrary string that does not have the form of an integer; the + same tag may be shared by many items, which makes tags convenient for + grouping items. + The special tag ``'all'`` matches every item in the canvas, and + ``'current'`` matches the topmost item under the mouse pointer. + Most methods take a *tagOrId* argument that may be an integer id naming a + single item, or a tag naming zero or more items; as described in the Tk + ``canvas`` manual page, a tag may also be a logical expression of tags + combined with the operators ``&&``, ``||``, ``^``, ``!`` and parentheses. + When a method that operates on a single item is given a *tagOrId* matching + several items, it normally uses the lowest matching item in the display + list. + + The items are kept in a *display list* that determines drawing order: items + later in the list are drawn on top of earlier ones. + A newly created item is placed at the top of the list; the order can be + changed with :meth:`tag_raise` and :meth:`tag_lower`. + + .. method:: create_arc(*args, **kw) + create_bitmap(*args, **kw) + create_image(*args, **kw) + create_line(*args, **kw) + create_oval(*args, **kw) + create_polygon(*args, **kw) + create_rectangle(*args, **kw) + create_text(*args, **kw) + create_window(*args, **kw) + + Create a new item of the corresponding type and return its integer id. + Each method is called as ``create_TYPE(coord..., **options)``: the + leading positional arguments give the coordinates that define the item + (as separate numbers, as a single sequence of numbers, or as coordinate + pairs), and the keyword arguments set item-specific options. + Coordinates and screen distances may be given as numbers (interpreted as + pixels) or as strings with a unit suffix (``'m'``, ``'c'``, ``'i'`` or + ``'p'`` for millimetres, centimetres, inches or printer's points), but + are always stored and returned in pixels. + + The item types are: ``arc`` (an arc-shaped region that is a section of an + oval, defined by two diagonally opposite corners ``x1, y1, x2, y2`` of + the enclosing rectangle); ``bitmap`` (a two-color bitmap positioned at a + point ``x, y``); ``image`` (a Tk image positioned at a point ``x, y``); + ``line`` (a line or curve through the points ``x1, y1, ..., xn, yn``); + ``oval`` (a circle or ellipse inscribed in the rectangle + ``x1, y1, x2, y2``); ``polygon`` (a closed polygon through the points + ``x1, y1, ..., xn, yn``); ``rectangle`` (a rectangle with corners + ``x1, y1, x2, y2``); ``text`` (a string of text positioned at a point + ``x, y``); and ``window`` (a child widget embedded in the canvas at a + point ``x, y``, specified with the *window* option). + + Most item types accept a common set of *standard item options*, plus a + few options specific to each type. + Option names are passed as keyword arguments, without the leading + hyphen. + + The standard item options are: + + *fill* + The color used to fill the item's interior, or to draw a *line* + item or the characters of a *text* item. + An empty string (the default for all types except *line* and *text*) + leaves the item unfilled. + + *outline* + The color used to draw the item's outline. + An empty string draws no outline. + + *width* + The width of the outline, defaulting to ``1.0``. + Has no effect if *outline* is empty. + + *dash* + A dash pattern for the outline, given either as a sequence of + segment lengths in pixels or as a string of the characters + ``'.'``, ``','``, ``'-'``, ``'_'`` and space. + An empty pattern (the default) draws a solid outline. + + *dashoffset* + The starting offset in pixels into the *dash* pattern. + Ignored if there is no *dash* pattern. + + *stipple* + A bitmap used as a stipple pattern when filling the item. + Only well supported on X11. + + *outlinestipple* + A bitmap used as a stipple pattern when drawing the outline. + Has no effect if *outline* is empty. + + *offset*, *outlineoffset* + The offset of the fill and outline stipple patterns, given as + ``'x,y'`` or as a side such as ``'n'``, ``'se'`` or ``'center'``. + Stipple offsets are only supported on X11. + + *state* + Overrides the canvas state for this item; one of ``'normal'``, + ``'disabled'`` or ``'hidden'``. + + *tags* + A single tag or a sequence of tags to associate with the item, + replacing any existing tags. + + Many of these options have *active...* and *disabled...* variants + (such as *activefill*, *disabledfill*, *activewidth*, *disableddash*, + *activeoutline*, *disabledstipple*) that override the base option when + the item is the active item (under the mouse pointer) or is in the + disabled state. + + The following item types support additional options. + + For ``arc`` items: + + *start* + The start of the arc's angular range, in degrees measured + counter-clockwise from the 3-o'clock position. + + *extent* + The size of the angular range, in degrees counter-clockwise from + *start*. + + *style* + How the arc is drawn: ``'pieslice'`` (the default), ``'chord'`` or + ``'arc'``. + + For ``line`` items: + + *arrow* + Where to draw arrowheads: ``'none'`` (the default), ``'first'``, + ``'last'`` or ``'both'``. + + *arrowshape* + A sequence of three distances describing the shape of the + arrowheads. + + *capstyle* + How line ends are drawn: ``'butt'`` (the default), ``'projecting'`` + or ``'round'``. + + *joinstyle* + How line vertices are drawn: ``'round'`` (the default), ``'bevel'`` + or ``'miter'``. + + *smooth* + The smoothing method: a false value (the default) for no smoothing, + or ``'true'``/``'bezier'`` or ``'raw'`` to draw the line as a curve. + + *splinesteps* + The number of line segments approximating each spline when + *smooth* is enabled. + + For ``polygon`` items: + + *joinstyle*, *smooth*, *splinesteps* + As for ``line`` items, applied to the polygon's outline. + + For ``text`` items: + + *text* + The string to display; newline characters start new lines. + + *font* + The font used for the text. + + *justify* + How lines are justified: ``'left'`` (the default), ``'right'`` or + ``'center'``. + + *anchor* + How the text is positioned relative to its point, defaulting to + ``'center'``. + + *width* + The maximum line length; if non-zero, lines are wrapped at spaces. + + *angle* + How many degrees to rotate the text counter-clockwise about its + positioning point, from ``0.0`` to ``360.0`` (default ``0.0``). + + *underline* + The index of a character to underline, or ``-1`` for none. + + For ``bitmap`` items: + + *bitmap* + The bitmap to display. + + *anchor* + How the bitmap is positioned relative to its point. + + *background*, *foreground* + The colors used for the bitmap's ``0`` and ``1`` pixels; an empty + *background* makes the ``0`` pixels transparent. + Both have *active...* and *disabled...* variants, and *bitmap* has + *activebitmap* and *disabledbitmap* variants. + + For ``image`` items: + + *image* + The Tk image to display, previously created with the image + protocols. + + *anchor* + How the image is positioned relative to its point. + + Both options have *active...* and *disabled...* variants + (*activeimage*, *disabledimage*) used in the active and disabled + states. + + For ``window`` items: + + *window* + The widget to embed; it must be a child of the canvas or of one of + its ancestors, and may not be a top-level window. + + *anchor* + How the window is positioned relative to its point. + + *width*, *height* + The size to assign to the window; if zero (the default), the window + is given its requested size. + + ``oval`` and ``rectangle`` items have no type-specific options; they + use only the standard item options. + + .. note:: + + Tk 8.6 added the *angle* option and Tk 9.0 added the *underline* + option for ``text`` items. + + .. method:: coords(tagOrId) + coords(tagOrId, coordList, /) + coords(tagOrId, /, *coordList) + + Query or modify the coordinates of an item. + With only *tagOrId*, return a list of the floating-point coordinates of + the item given by *tagOrId* (the first matching item if it matches + several). + Given new coordinates, replace the coordinates of that item with them; + like the ``create_*`` methods, the coordinates may be given as separate + numbers, as a single sequence, or as coordinate pairs. + The returned coordinates are always in pixels, regardless of the units + used to specify them; for rectangles, ovals and arcs they are ordered + left, top, right, bottom. + + .. versionchanged:: 3.12 + The arguments are now flattened: the coordinates may be given as + separate arguments, as a single sequence, or grouped in pairs, like + the ``create_*`` methods. + + + .. method:: move(tagOrId, xAmount, yAmount, /) + + Move each of the items given by *tagOrId* in the canvas coordinate space + by adding *xAmount* to every x-coordinate and *yAmount* to every + y-coordinate of the item. + + .. method:: moveto(tagOrId, x='', y='') + + Move the items given by *tagOrId* so that the first coordinate pair (the + upper-left corner of the bounding box) of the lowest matching item is at + position (*x*, *y*). + *x* or *y* may be an empty string, in which case the corresponding + coordinate is unchanged. + All matching items keep their positions relative to each other. + + .. versionadded:: 3.8 + + + .. method:: scale(tagOrId, xOrigin, yOrigin, xScale, yScale, /) + + Rescale the coordinates of all items given by *tagOrId* in canvas + coordinate space. + Each x-coordinate is adjusted so that its distance from *xOrigin* changes + by a factor of *xScale*, and each y-coordinate so that its distance from + *yOrigin* changes by a factor of *yScale* (a factor of ``1.0`` leaves the + coordinate unchanged). + + .. method:: delete(*tagOrIds) + + Delete each of the items given by the *tagOrIds* arguments. + + .. method:: dchars(tagOrId, first, /) + dchars(tagOrId, first, last, /) + + Delete from each of the items given by *tagOrId* the characters (for text + items) or coordinates (for line and polygon items) in the range from + *first* to *last* inclusive; *last* defaults to *first*. + Items that do not support indexing ignore this operation. + + .. method:: insert(tagOrId, beforeThis, string, /) + + Insert *string* into each of the items given by *tagOrId* just before the + character or coordinate whose index is *beforeThis*. + For line and polygon items *string* must be a valid sequence of + coordinates. + + .. method:: itemcget(tagOrId, option) + + Return the current value of the configuration option *option* for the + item given by *tagOrId* (the lowest matching item if it matches several). + This is like :meth:`~Misc.cget` but applies to an individual item. + + .. method:: itemconfig(tagOrId, cnf=None, **kw) + :no-typesetting: + + .. method:: itemconfigure(tagOrId, cnf=None, **kw) + + Query or modify the configuration options of the items given by + *tagOrId*. + This mirrors :meth:`~Misc.configure`, except that it applies to + individual items rather than to the canvas as a whole. + With no options, it returns a dictionary describing the current options + of the first matching item; otherwise it sets the given options on every + matching item. + The legal options are those accepted by the corresponding ``create_*`` + method. + :meth:`itemconfig` is an alias of :meth:`!itemconfigure`. + + .. method:: type(tagOrId) + + Return the type of the item given by *tagOrId* (the first matching item + if it matches several), such as ``'rectangle'`` or ``'text'``, or + ``None`` if *tagOrId* does not match any item. + + .. method:: gettags(tagOrId, /) + + Return a tuple of the tags associated with the item given by *tagOrId* + (the first matching item in display-list order if it matches several). + Return an empty tuple if no item matches or the item has no tags. + + .. method:: dtag(tagOrId, /) + dtag(tagOrId, tagToDelete, /) + + Remove the tag *tagToDelete* (which defaults to *tagOrId*) from each of + the items given by *tagOrId*. + Items that do not have that tag are unaffected. + + .. method:: addtag(newtag, searchSpec, /, *args) + + Add the tag *newtag* to each item selected by the search specification + *searchSpec* (and any further *args*). + *searchSpec* is one of ``'above'``, ``'all'``, ``'below'``, + ``'closest'``, ``'enclosed'``, ``'overlapping'`` or ``'withtag'``; the + ``addtag_*`` methods below are convenient wrappers that supply each of + these forms. + + .. method:: addtag_above(newtag, tagOrId) + + Add the tag *newtag* to the item just above (after) *tagOrId* in the + display list. + + .. method:: addtag_all(newtag) + + Add the tag *newtag* to all items in the canvas. + + .. method:: addtag_below(newtag, tagOrId) + + Add the tag *newtag* to the item just below (before) *tagOrId* in the + display list. + + .. method:: addtag_closest(newtag, x, y, halo=None, start=None) + + Add the tag *newtag* to the item closest to the point (*x*, *y*). + If *halo* is given, any item within that distance of the point is treated + as overlapping it. + If *start* is given (a tag or id), select the topmost closest item that + lies below *start* in the display list, which can be used to step through + all the closest items. + + .. method:: addtag_enclosed(newtag, x1, y1, x2, y2) + + Add the tag *newtag* to every item completely enclosed within the + rectangle (*x1*, *y1*, *x2*, *y2*), where *x1* <= *x2* and *y1* <= *y2*. + + .. method:: addtag_overlapping(newtag, x1, y1, x2, y2) + + Add the tag *newtag* to every item that overlaps or is enclosed within + the rectangle (*x1*, *y1*, *x2*, *y2*), where *x1* <= *x2* and *y1* <= + *y2*. + + .. method:: addtag_withtag(newtag, tagOrId) + + Add the tag *newtag* to every item given by *tagOrId*. + + .. method:: find(searchSpec, /, *args) + + Return a tuple of the ids of all items selected by the search + specification *searchSpec* (and any further *args*), in stacking order + with the lowest item first. + The search specification has any of the forms accepted by :meth:`addtag`. + The ``find_*`` methods below are more convenient wrappers around it. + + .. method:: find_above(tagOrId) + + Return a tuple containing the id of the item just above *tagOrId* in the + display list. + + .. method:: find_all() + + Return a tuple of the ids of all items in the canvas, in stacking order. + + .. method:: find_below(tagOrId) + + Return a tuple containing the id of the item just below *tagOrId* in the + display list. + + .. method:: find_closest(x, y, halo=None, start=None) + + Return a tuple containing the id of the item closest to the point (*x*, + *y*). + *halo* and *start* are interpreted as for :meth:`addtag_closest`. + + .. method:: find_enclosed(x1, y1, x2, y2) + + Return a tuple of the ids of all items completely enclosed within the + rectangle (*x1*, *y1*, *x2*, *y2*). + + .. method:: find_overlapping(x1, y1, x2, y2) + + Return a tuple of the ids of all items that overlap or are enclosed + within the rectangle (*x1*, *y1*, *x2*, *y2*). + + .. method:: find_withtag(tagOrId) + + Return a tuple of the ids of all items given by *tagOrId*. + + .. method:: lift(tagOrId, aboveThis=None, /) + :no-typesetting: + + .. method:: tkraise(tagOrId, aboveThis=None, /) + :no-typesetting: + + .. method:: tag_raise(tagOrId, aboveThis=None, /) + + Move all items given by *tagOrId* to a new position in the display list + just above the item given by *aboveThis*, or to the top of the display + list if *aboveThis* is omitted. + When several items are moved their relative order is preserved. + This has no effect on embedded window items, whose stacking order is + controlled by :meth:`Misc.tkraise` and :meth:`Misc.lower` instead. + :meth:`lift` and :meth:`tkraise` are aliases of :meth:`!tag_raise`. + + .. method:: lower(tagOrId, belowThis=None, /) + :no-typesetting: + + .. method:: tag_lower(tagOrId, belowThis=None, /) + + Move all items given by *tagOrId* to a new position in the display list + just below the item given by *belowThis*, or to the bottom of the display + list if *belowThis* is omitted. + When several items are moved their relative order is preserved. + This has no effect on embedded window items. + :meth:`lower` is an alias of :meth:`!tag_lower`. + + .. method:: tag_bind(tagOrId, sequence=None, func=None, add=None) + + Bind the callback *func* to the event *sequence* for all items given by + *tagOrId*, so that *func* is invoked whenever that event occurs for one + of the items. + This is like :meth:`Widget.bind <Misc.bind>` but operates on canvas items + rather than on whole widgets; only mouse, keyboard and virtual events may + be bound. + Mouse events are directed to the current item and keyboard events to the + focus item (see :meth:`focus`). + If *add* is true the new binding is added to any existing bindings for + the same sequence, rather than replacing them. + Return the identifier of the bound function, which can be passed to + :meth:`tag_unbind`. + + .. method:: tag_unbind(tagOrId, sequence, funcid=None) + + Remove for all items given by *tagOrId* the binding for the event + *sequence*. + If *funcid* is given, only that callback (as returned by + :meth:`tag_bind`) is unbound and deregistered. + + .. versionchanged:: 3.13 + If *funcid* is given, only that callback is unbound. + + + .. method:: bbox(tagOrId, /, *tagOrIds) + + Return a 4-tuple ``(x1, y1, x2, y2)`` giving an approximate bounding box, + in pixels, that encloses all the items given by *tagOrId* and any further + *tagOrIds*. + The result may overestimate the true bounding box by a few pixels. + Return ``None`` if no item matches or the matching items have nothing to + display. + + .. method:: canvasx(screenx, gridspacing=None) + + Given a window x-coordinate *screenx*, return the canvas x-coordinate + displayed at that location. + If *gridspacing* is given, the result is rounded to the nearest multiple + of *gridspacing* units. + + .. method:: canvasy(screeny, gridspacing=None) + + Given a window y-coordinate *screeny*, return the canvas y-coordinate + displayed at that location. + If *gridspacing* is given, the result is rounded to the nearest multiple + of *gridspacing* units. + + .. method:: focus() + focus(tagOrId, /) + + With *tagOrId*, set the keyboard focus for the canvas to the first item + given by *tagOrId* that supports the insertion cursor; the focus is left + unchanged if no such item exists. + If *tagOrId* is an empty string, reset the focus so that no item has it. + With no argument, return the id of the item that currently has the focus, + or an empty string if none does. + An item only displays the insertion cursor when both it is the focus item + and its canvas has the input focus. + + .. method:: icursor(tagOrId, index, /) + + Set the insertion cursor of the items given by *tagOrId* to just before + the character given by *index*. + Items that do not support an insertion cursor are unaffected. + The cursor is only displayed when the item has the focus, but its + position may be set at any time. + + .. method:: index(tagOrId, index, /) + + Return as an integer the numerical index within *tagOrId* corresponding + to *index*, which is a textual description of a position (for text items + an index into the characters, for line and polygon items an index into + the coordinates). + If *tagOrId* matches several items, the first one that supports indexing + is used. + + .. method:: select_adjust(tagOrId, index) + + Adjust the end of the selection in *tagOrId* nearest to *index* so that + it is at *index*, and make the other end the anchor point for future + :meth:`select_to` calls. + If the selection is not currently in *tagOrId*, this behaves like + :meth:`select_to`. + + .. method:: select_clear() + + Clear the selection if it is in this canvas; otherwise do nothing. + + .. method:: select_from(tagOrId, index) + + Set the selection anchor point to just before the character given by + *index* in the item given by *tagOrId*. + This does not change the selection itself; it sets the fixed end for + future :meth:`select_to` calls. + + .. method:: select_item() + + Return the id of the item that holds the selection, or ``None`` if the + selection is not in this canvas. + Unlike :meth:`find` and the ``find_*`` methods, this returns the id as a + string rather than an integer. + + .. method:: select_to(tagOrId, index) + + Set the selection to the characters of *tagOrId* between the selection + anchor point and *index*, inclusive of *index*. + The anchor point is the one set by the most recent :meth:`select_adjust` + or :meth:`select_from` call. + + .. method:: scan_mark(x, y) + + Record *x*, *y* and the current view, for use with later + :meth:`scan_dragto` calls. + This is typically bound to a mouse button press in the widget. + + .. method:: scan_dragto(x, y, gain=10) + + Scroll the canvas by *gain* times the difference between *x*, *y* and the + coordinates passed to the last :meth:`scan_mark` call. + This is typically bound to mouse motion events in the widget, producing + the effect of dragging the canvas at high speed through its window. + + .. method:: postscript(cnf={}, **kw) + + Generate a PostScript (Encapsulated PostScript, version 3.0) + representation of part or all of the canvas. + If the *file* or *channel* option is given, the PostScript is written + there and an empty string is returned; otherwise it is returned as a + string. + By default only the area currently visible in the window is generated, so + it is usually necessary either to call :meth:`~Misc.update` first or to + use the *width* and *height* options. + Supported options include *colormap*, *colormode*, *file*, *fontmap*, + *height*, *pageanchor*, *pageheight*, *pagewidth*, *pagex*, *pagey*, + *rotate*, *width*, *x* and *y*. + + +.. class:: Checkbutton(master=None, cnf={}, **kw) + + A :class:`!Checkbutton` widget displays a textual string, bitmap or image + together with a square indicator, and toggles a boolean selection when + pressed. + It has all the behavior of a simple button and, in addition, can be + selected: when selected the indicator is drawn with a check mark and the + associated variable is set to the ``onvalue``, and when deselected the + indicator is drawn empty and the variable is set to the ``offvalue``. + Inherits from :class:`Widget`. + In addition to the standard widget options, a checkbutton accepts the + options documented in the Tk ``checkbutton`` manual page, such as + *variable*, *onvalue*, *offvalue* and *command*. + + .. method:: invoke() + + Do just what would happen if the user pressed the checkbutton with the + mouse: toggle the selection state of the button and invoke the associated + command, if there is one. + Return the result of the command, or an empty string if no command is + associated with the checkbutton. + This is ignored if the checkbutton's state is ``disabled``. + + .. method:: select() + + Select the checkbutton and set the associated variable to its + ``onvalue``. + + .. method:: deselect() + + Deselect the checkbutton and set the associated variable to its + ``offvalue``. + + .. method:: toggle() + + Toggle the selection state of the button, redisplaying it and modifying + its associated variable to reflect the new state. + + .. method:: flash() + + Flash the checkbutton by redisplaying it several times, alternating + between the active and normal colors. + At the end of the flash the checkbutton is left in the same normal or + active state as when the method was called. + This is ignored if the checkbutton's state is ``disabled``. + + +.. class:: Entry(master=None, cnf={}, **kw) + + An :class:`!Entry` widget displays a single line of text and lets the user + edit it. + Inherits from :class:`Widget` and :class:`XView`; since entries can hold + strings too long to fit in the window, they support horizontal scrolling + through :meth:`~XView.xview`. + + In addition to the standard widget options, an entry accepts the options + documented in the Tk ``entry`` manual page. + Notable ones are *textvariable* (the name of a variable kept in sync with + the entry's contents), *show* (if set, each character is displayed as the + given character rather than its true value, useful for password entry), + *validate* and *validatecommand* (which together let a callback accept or + reject edits), and *state* (one of ``'normal'``, ``'disabled'`` or + ``'readonly'``). + + Many of the methods below take an *index* argument that selects a character + in the entry's string. + As described in the Tk ``entry`` manual page, *index* may be a number + (counting from 0), ``'insert'`` (the character just after the insertion + cursor), ``'end'`` (just after the last character), ``'anchor'`` (the + selection anchor point), ``'sel.first'`` and ``'sel.last'`` (the ends of the + selection), or ``@x`` (the character covering pixel x-coordinate *x* in the + window). + Out-of-range indices are rounded to the nearest legal value. + + .. method:: delete(first, last=None) + + Delete the characters from index *first* up to but not including index + *last*. + If *last* is omitted, only the single character at *first* is deleted. + + .. method:: get() + + Return the entry's current string. + + .. method:: insert(index, string) + + Insert *string* just before the character given by *index*. + + .. method:: icursor(index) + + Arrange for the insertion cursor to be displayed just before the + character given by *index*. + + .. method:: index(index) + + Return the numerical index corresponding to *index*. + + .. method:: select_adjust(index) + :no-typesetting: + + .. method:: selection_adjust(index) + + Locate the end of the selection nearest to the character given by + *index*, and adjust that end to be at *index* (including but not going + beyond it); the other end becomes the anchor point for future + :meth:`selection_to` calls. + If there is no selection in the entry, a new one is created between + *index* and the most recent anchor point, inclusive. + :meth:`select_adjust` is an alias of :meth:`!selection_adjust`. + + .. method:: select_clear() + :no-typesetting: + + .. method:: selection_clear() + + Clear the selection if it is currently in this widget. + If the selection is not in this widget the method has no effect. + :meth:`select_clear` is an alias of :meth:`!selection_clear`. + + .. method:: select_from(index) + :no-typesetting: + + .. method:: selection_from(index) + + Set the selection anchor point to just before the character given by + *index*, without changing the selection. + :meth:`select_from` is an alias of :meth:`!selection_from`. + + .. method:: select_present() + :no-typesetting: + + .. method:: selection_present() + + Return ``True`` if there are characters selected in the entry, ``False`` + otherwise. + :meth:`select_present` is an alias of :meth:`!selection_present`. + + .. method:: select_range(start, end) + :no-typesetting: + + .. method:: selection_range(start, end) + + Set the selection to include the characters starting with the one indexed + by *start* and ending with the one just before *end*. + If *end* refers to the same character as *start* or an earlier one, the + selection is cleared. + :meth:`select_range` is an alias of :meth:`!selection_range`. + + .. method:: select_to(index) + :no-typesetting: + + .. method:: selection_to(index) + + Set the selection between the anchor point and *index*: if *index* is + before the anchor point, the selection runs from *index* up to but not + including the anchor; if *index* is after it, from the anchor up to but + not including *index*; if they coincide, nothing happens. + The anchor point is the one set by the most recent :meth:`selection_from` + or :meth:`selection_adjust` call. + If there is no selection in the entry, a new one is created using the + most recent anchor point. + :meth:`select_to` is an alias of :meth:`!selection_to`. + + .. method:: scan_mark(x) + + Record *x* and the current view in the entry window, for use with later + :meth:`scan_dragto` calls. + Typically associated with a mouse button press in the widget. + + .. method:: scan_dragto(x) + + Compute the difference between *x* and the *x* given to the last + :meth:`scan_mark` call, and adjust the view left or right by 10 times + that difference. + Typically associated with mouse motion events, to produce the effect of + dragging the entry at high speed through the window. + + +.. class:: Frame(master=None, cnf={}, **kw) + + A :class:`!Frame` widget is a simple container. + Its primary purpose is to act as a spacer or container for complex window + layouts; its only features are its background and an optional 3-D border to + make the frame appear raised or sunken. + Inherits from :class:`Widget`. + Refer to the Tk ``frame`` manual page for the full list of options. + + +.. class:: Label(master=None, cnf={}, **kw) + + A :class:`!Label` widget displays a non-interactive textual string, bitmap + or image. + The displayed text is set with the *text* option or linked to a variable + through *textvariable*, and an image can be shown using the *image* option. + Text must all be in a single font but may occupy multiple lines, and one + character may be underlined with the *underline* option. + Inherits from :class:`Widget`. + Refer to the Tk ``label`` manual page for the full list of options. + + +.. class:: LabelFrame(master=None, cnf={}, **kw) + + A :class:`!LabelFrame` widget is a container that has the features of a + :class:`Frame` plus the ability to display a label. + The label text is set with the *text* option and positioned with + *labelanchor*, or an arbitrary widget may be used as the label by giving it + as the *labelwidget* option. + Inherits from :class:`Widget`. + Refer to the Tk ``labelframe`` manual page for the full list of options. + + +.. class:: Listbox(master=None, cnf={}, **kw) + + A :class:`!Listbox` widget displays a list of single-line text items, one + per line, of which the user can select one or more. + The way the selection behaves is governed by the *selectmode* option, which + is one of ``browse`` (the default; at most one item, which may be dragged + with the mouse), ``single`` (at most one item), ``multiple`` (any number of + items, toggled individually), or ``extended`` (any number of items, + including discontiguous ranges, selected by clicking and dragging). + Inherits from :class:`Widget`, :class:`XView` and :class:`YView`, so the + view can be scrolled horizontally and vertically with :meth:`~XView.xview` + and :meth:`~YView.yview`. + Refer to the Tk ``listbox`` manual page for the full list of options. + + Many of the methods take an *index* argument identifying a particular item. + As described in the Tk ``listbox`` manual page, *index* may be a numeric + index (counting from 0 at the top), ``'active'`` (the item with the location + cursor, set with :meth:`activate`), ``'anchor'`` (the selection anchor, set + with :meth:`selection_anchor`), ``'end'`` (the last item, or for + :meth:`index` and :meth:`insert` the position just after it), or ``@x,y`` + (the item covering pixel coordinates *x*, *y* in the listbox window). + Arguments named *first* and *last* are indices of the same forms. + + .. method:: insert(index, *elements) + + Insert the given *elements* as new items just before the item given by + *index*. + If *index* is ``'end'``, the new items are appended to the end of the + list. + + .. method:: delete(first, last=None) + + Delete the items in the range from *first* to *last* inclusive. + If *last* is omitted, it defaults to *first*, so that a single item is + deleted. + + .. method:: get(first, last=None) + + If *last* is omitted, return the contents of the item given by *first*, + or an empty string if *first* refers to a non-existent item. + If *last* is given, return a tuple of all the items in the range from + *first* to *last* inclusive. + + .. method:: size() + + Return the total number of items in the listbox. + + .. method:: index(index) + + Return the integer index value corresponding to *index*, or ``None`` if + *index* is out of range. + If *index* is ``'end'``, the result is a count of the number of items in + the listbox (not the index of the last item). + + .. method:: bbox(index) + + Return a tuple ``(x, y, width, height)`` describing the bounding box, in + pixels relative to the widget, of the text of the item given by *index*. + Return ``None`` if no part of that item is visible on the screen, or if + *index* refers to a non-existent item; if the item is only partly + visible, the result still gives the full area of the item, including the + parts that are not visible. + + .. method:: nearest(y) + + Given a y-coordinate within the listbox window, return the index of the + visible item nearest to that y-coordinate. + + .. method:: see(index) + + Adjust the view so that the item given by *index* is visible. + If the item is already visible the method has no effect; if it is near an + edge of the window the listbox scrolls just enough to bring it into view + at that edge, otherwise the listbox scrolls to center the item. + + .. method:: activate(index) + + Set the active item to the one given by *index*. + If *index* is outside the range of items, the closest item is activated + instead. + The active item is drawn as specified by the *activestyle* option when + the widget has the input focus, and its index may be retrieved with the + ``'active'`` index. + + .. method:: curselection() + + Return a tuple containing the numerical indices of all of the items that + are currently selected, or an empty tuple if no items are selected. + + .. method:: select_anchor(index) + :no-typesetting: + + .. method:: selection_anchor(index) + + Set the selection anchor to the item given by *index*. + If *index* refers to a non-existent item, the closest item is used. + The selection anchor is the end of the selection that is fixed while + dragging out a selection with the mouse, and may afterwards be referred + to with the ``'anchor'`` index. + :meth:`select_anchor` is an alias of :meth:`!selection_anchor`. + + .. method:: select_clear(first, last=None) + :no-typesetting: + + .. method:: selection_clear(first, last=None) + + Deselect any of the items in the range from *first* to *last* inclusive + that are selected. + The selection state of items outside this range is not changed. + :meth:`select_clear` is an alias of :meth:`!selection_clear`. + + .. method:: select_includes(index) + :no-typesetting: + + .. method:: selection_includes(index) + + Return ``True`` if the item given by *index* is currently selected, + ``False`` otherwise. + :meth:`select_includes` is an alias of :meth:`!selection_includes`. + + .. method:: select_set(first, last=None) + :no-typesetting: + + .. method:: selection_set(first, last=None) + + Select all of the items in the range from *first* to *last* inclusive, + without affecting the selection state of items outside that range. + :meth:`select_set` is an alias of :meth:`!selection_set`. + + .. method:: itemcget(index, option) + + Return the current value of the configuration option *option* for the + item given by *index*. + + .. method:: itemconfig(index, cnf=None, **kw) + :no-typesetting: + + .. method:: itemconfigure(index, cnf=None, **kw) + + Query or modify the configuration options of the item given by *index*. + This mirrors :meth:`~Misc.configure`, except that it applies to an + individual item rather than to the listbox as a whole. + With no options, it returns a dictionary describing the current options + of the item; otherwise it sets the given options. + The supported item options are *background*, *foreground*, + *selectbackground* and *selectforeground*. + :meth:`itemconfig` is an alias of :meth:`!itemconfigure`. + + .. method:: scan_mark(x, y) + + Record *x*, *y* and the current view, for use with later + :meth:`scan_dragto` calls. + This is typically bound to a mouse button press in the widget. + + .. method:: scan_dragto(x, y) + + Scroll the listbox by 10 times the difference between *x*, *y* and the + coordinates passed to the last :meth:`scan_mark` call. + This is typically bound to mouse motion events in the widget, producing + the effect of dragging the list at high speed through the window. + + +.. class:: Menu(master=None, cnf={}, **kw) + + A :class:`!Menu` widget displays a column of entries, each of which may be a + command, a checkbutton, a radiobutton, a cascade (which posts an associated + submenu) or a separator. + Menus are used as the menubar of a toplevel window, as pulldown menus posted + from a cascade entry or menubutton, and as popup menus. + Inherits from :class:`Widget`. + + Many of the entry methods take an *index* argument that selects which entry + to operate on. + As described in the Tk ``menu`` manual page, *index* may be a numeric index + (counting from 0 at the top), ``'active'`` (the currently active entry), + ``'end'`` or ``'last'`` (the bottommost entry), ``'none'`` (no entry at all, + written ``{}`` in Tcl), ``@y`` (the entry covering pixel y-coordinate *y* in + the menu window), or a pattern matched against the labels of the entries + from the top down. + + .. method:: add(itemType, cnf={}, **kw) + + Add a new entry to the bottom of the menu. + *itemType* is one of ``'command'``, ``'cascade'``, ``'checkbutton'``, + ``'radiobutton'`` or ``'separator'`` and determines the type of the new + entry; the remaining options configure it. + The :meth:`!add_command`, :meth:`!add_cascade`, :meth:`!add_checkbutton`, + :meth:`!add_radiobutton` and :meth:`!add_separator` convenience methods + call this method with the corresponding *itemType*. + + The entry is configured by the following options, although not every + option applies to every entry type (a separator accepts none of them): + + *label* + The text to display in the entry. + + *command* + The function to call when the entry is invoked (command, checkbutton + and radiobutton entries). + + *accelerator* + A string displayed at the right of the entry to advertise an + accelerator keystroke; it does not itself create the binding. + + *underline* + The index of a character in the label to underline for keyboard + traversal. + + *state* + One of ``'normal'``, ``'active'`` or ``'disabled'``. + + *image* + An image to display instead of, or together with, the text label. + + *compound* + Where to show the image relative to the text: ``'none'`` (the + default), ``'text'``, ``'image'``, ``'top'``, ``'bottom'``, ``'left'`` + or ``'right'``. + + *bitmap* + A bitmap to display instead of the text label. + + *font* + The font to use for the text. + + *background*, *foreground* + The entry's background and foreground colors in its normal state + (ignored on macOS). + + *activebackground*, *activeforeground* + The background and foreground colors used when the entry is active + (ignored on macOS). + + *columnbreak* + If true, the entry starts a new column instead of being placed below + the previous entry. + + *hidemargin* + If true, the standard margin around the entry is omitted, which is + useful when a menu is used as a palette. + + *menu* + The submenu posted by a cascade entry; it must be a child of this + menu. + + *variable* + The variable associated with a checkbutton or radiobutton entry. + + *onvalue*, *offvalue* + The values stored in *variable* when a checkbutton entry is selected + or cleared. + + *value* + The value stored in *variable* when a radiobutton entry is selected. + + *indicatoron* + Whether to display the indicator of a checkbutton or radiobutton + entry. + + *selectcolor* + The color of the indicator of a checkbutton or radiobutton entry when + it is selected. + + *selectimage* + The image displayed when a checkbutton or radiobutton entry is + selected and *image* is also given. + + .. method:: add_cascade(cnf={}, **kw) + + Add a new cascade entry to the bottom of the menu. + A cascade entry has an associated submenu, given by its *menu* option, + which must be a child of this menu; posting the entry posts the submenu + next to it. + + .. method:: add_checkbutton(cnf={}, **kw) + + Add a new checkbutton entry to the bottom of the menu. + When invoked, a checkbutton entry toggles between its *onvalue* and + *offvalue*, storing the result in its associated *variable*, and displays + an indicator showing whether it is selected. + + .. method:: add_command(cnf={}, **kw) + + Add a new command entry to the bottom of the menu. + A command entry behaves much like a button: when it is invoked, the + callback given by its *command* option is called. + + .. method:: add_radiobutton(cnf={}, **kw) + + Add a new radiobutton entry to the bottom of the menu. + Radiobutton entries sharing the same *variable* form a group of which + only one may be selected at a time; selecting an entry stores its *value* + in the variable. + + .. method:: add_separator(cnf={}, **kw) + + Add a separator to the bottom of the menu. + A separator is displayed as a horizontal dividing line and cannot be + activated or invoked. + + .. method:: insert(index, itemType, cnf={}, **kw) + + Same as :meth:`add`, except that the new entry is inserted just before + the entry given by *index* instead of being appended to the end of the + menu. + *itemType* is one of ``'command'``, ``'cascade'``, ``'checkbutton'``, + ``'radiobutton'`` or ``'separator'``. + The :meth:`!insert_command`, :meth:`!insert_cascade`, + :meth:`!insert_checkbutton`, :meth:`!insert_radiobutton` and + :meth:`!insert_separator` convenience methods call this method with the + corresponding *itemType*. + + .. method:: insert_cascade(index, cnf={}, **kw) + + Insert a new cascade entry before the entry given by *index* (see + :meth:`add_cascade`). + + .. method:: insert_checkbutton(index, cnf={}, **kw) + + Insert a new checkbutton entry before the entry given by *index* (see + :meth:`add_checkbutton`). + + .. method:: insert_command(index, cnf={}, **kw) + + Insert a new command entry before the entry given by *index* (see + :meth:`add_command`). + + .. method:: insert_radiobutton(index, cnf={}, **kw) + + Insert a new radiobutton entry before the entry given by *index* (see + :meth:`add_radiobutton`). + + .. method:: insert_separator(index, cnf={}, **kw) + + Insert a separator before the entry given by *index* (see + :meth:`add_separator`). + + .. method:: delete(index1, index2=None) + + Delete all of the menu entries between *index1* and *index2* inclusive. + If *index2* is omitted, it defaults to *index1*, so that a single entry + is deleted. + Attempts to delete a tear-off entry are ignored; remove it by changing + the *tearoff* option instead. + + .. method:: entrycget(index, option) + + Return the current value of the configuration option *option* for the + entry given by *index*. + + .. method:: entryconfig(index, cnf=None, **kw) + :no-typesetting: + + .. method:: entryconfigure(index, cnf=None, **kw) + + Query or modify the configuration options of the entry given by *index*. + This mirrors :meth:`~Misc.configure`, except that it applies to an + individual entry rather than to the menu as a whole. + With no options, it returns a dictionary describing the current options + of the entry; otherwise it sets the given options. + The supported options are those accepted by :meth:`add` for the entry's + type. + :meth:`entryconfig` is an alias of :meth:`!entryconfigure`. + + .. method:: index(index) + + Return the numerical index corresponding to *index*, or ``None`` if + *index* selects no entry. + + .. method:: type(index) + + Return the type of the entry given by *index*: one of ``'command'``, + ``'cascade'``, ``'checkbutton'``, ``'radiobutton'``, ``'separator'`` or + ``'tearoff'`` (for the tear-off entry). + + .. method:: activate(index) + + Make the entry given by *index* the active entry, redisplaying it with + its active colors, and deactivate any previously active entry. + If *index* selects no entry, or the selected entry is disabled, the menu + ends up with no active entry. + + .. method:: invoke(index) + + Invoke the action of the entry given by *index*, as if it had been + clicked. + Nothing happens if the entry is disabled. + If the entry has a *command* associated with it, the result of that + command is returned; otherwise the result is an empty string. + + .. method:: post(x, y) + + Display the menu on the screen at the root-window coordinates *x* and + *y*, adjusting them if necessary so that the whole menu is visible. + If the *postcommand* option has been specified, it is evaluated before + the menu is posted. + + .. method:: tk_popup(x, y, entry='') + + Post the menu as a popup at the root-window coordinates *x* and *y*. + If *entry* is given, the menu is positioned so that this entry is + displayed under the pointer. + + .. method:: unpost() + + Unmap the menu so that it is no longer displayed, also unposting any + posted lower-level cascaded submenu. + This has no effect on Windows and macOS, which manage the unposting of + menus themselves. + + .. method:: xposition(index) + + Return the x-coordinate, within the menu window, of the leftmost pixel of + the entry given by *index*. + + .. versionadded:: 3.3 + + .. method:: yposition(index) + + Return the y-coordinate, within the menu window, of the topmost pixel of + the entry given by *index*. + + +.. class:: Menubutton(master=None, cnf={}, **kw) + + A :class:`!Menubutton` widget displays a textual string, bitmap or image and + posts an associated :class:`Menu`, given by its *menu* option, when the user + presses it. + Like a :class:`Label` it can show *text*, a *textvariable*, or an *image*, + and the *direction* option controls where the menu appears relative to the + button. + Inherits from :class:`Widget`. + Refer to the Tk ``menubutton`` manual page for the full list of options. + + +.. class:: Message(master=None, cnf={}, **kw) + + A :class:`!Message` widget displays a non-interactive textual string, given + by the *text* option or linked to a variable through *textvariable*. + Unlike a :class:`Label`, it breaks the string into multiple lines in order + to produce a given aspect ratio, choosing line breaks at word boundaries, + and it can justify the text left, centered or right. + Inherits from :class:`Widget`. + Refer to the Tk ``message`` manual page for the full list of options. + + +.. class:: OptionMenu(master, variable, value, *values, **kwargs) + + A helper subclass of :class:`Menubutton` that displays a pop-up menu of + mutually exclusive choices. + *variable* is a :class:`Variable` kept in sync with the selection, *value* + is the initial choice, and *values* are the remaining menu entries. + The keyword argument *command* may be given a callback that is invoked with + the selected value, and the keyword argument *name* sets the Tk widget name. + + .. method:: destroy() + + Destroy the widget, also cleaning up the associated pop-up menu. + + .. versionchanged:: 3.14 + Added support for the *name* keyword argument. + + + +.. class:: PanedWindow(master=None, cnf={}, **kw) + + A :class:`!PanedWindow` is a geometry-manager widget that arranges any + number of child *panes* in a row (when *orient* is ``'horizontal'``) or a + column (when *orient* is ``'vertical'``). + Each pane holds one widget, and each pair of adjacent panes is separated by + a movable *sash* that the user can drag with the mouse to resize the widgets + on either side of it. + Inherits from :class:`Widget`. + + The *orient* option selects the layout direction, *sashwidth* sets the width + of each sash and *sashrelief* its relief. + When *showhandle* is true a small handle is drawn on each sash that the user + can grab to drag it. + Refer to the Tk ``panedwindow`` manual page for the full list of options. + + .. method:: add(child, **kw) + + Add *child* to the panedwindow as a new pane, placed after any existing + panes. + The keyword arguments specify per-pane management options for *child*; + they may be any of the options accepted by :meth:`paneconfigure`. + + .. method:: forget(child) + :no-typesetting: + + .. method:: remove(child) + + Remove the pane containing *child* from the panedwindow. + All geometry management options for *child* are forgotten. + :meth:`forget` is an alias of :meth:`!remove`. + + .. method:: panes() + + Return a tuple of the widgets managed by the panedwindow, one per pane, + in order. + + .. method:: panecget(child, option) + + Return the current value of the management option *option* for the pane + containing *child*. + *option* may be any value allowed by :meth:`paneconfigure`. + + .. method:: paneconfig(tagOrId, cnf=None, **kw) + :no-typesetting: + + .. method:: paneconfigure(tagOrId, cnf=None, **kw) + + Query or modify the management options of the pane containing the widget + *tagOrId*. + With no options, it returns a dictionary describing all of the available + options for the pane; given a single option name as a string, it returns + a description of that one option; otherwise it sets the given options. + The supported options include *after* and *before* (insert the pane after + or before another managed window), *height* and *width* (the outer + dimensions of the window, including any border), *minsize* (the minimum + size in the paned dimension), *padx* and *pady* (extra space to leave on + each side of the window), *sticky* (position or stretch the window within + an oversized pane, using a string of the characters ``n``, ``s``, ``e`` + and ``w``), *hide* (hide the pane while keeping it in the list of panes) + and *stretch* (how extra space is allocated to the pane: one of + ``'always'``, ``'first'``, ``'last'``, ``'middle'`` or ``'never'``). + :meth:`paneconfig` is an alias of :meth:`!paneconfigure`. + + .. method:: identify(x, y) + + Identify the panedwindow component underneath the point given by *x* and + *y*, in window coordinates. + If the point is over a sash or a sash handle, the result is a two-element + tuple containing the index of the sash or handle and a word indicating + whether it is over a sash or a handle, such as ``(0, 'sash')`` or + ``(2, 'handle')``. + If the point is over any other part of the panedwindow, the result is an + empty string. + + .. method:: sash(*args) + + Query or change the position of the sashes in the panedwindow. + This is a thin wrapper around the Tk ``sash`` subcommand; the convenience + methods :meth:`sash_coord`, :meth:`sash_mark` and :meth:`sash_place` + should normally be used instead. + + .. method:: sash_coord(index) + + Return the current x and y coordinate pair for the sash given by *index*, + which must be an integer between 0 and one less than the number of panes + in the panedwindow. + The coordinates returned are those of the top left corner of the region + containing the sash. + + .. method:: sash_mark(index) + + Record the current mouse position for the sash given by *index*, for use + together with later sash-drag operations to move the sash. + + .. method:: sash_place(index, x, y) + + Place the sash given by *index* at the coordinates *x* and *y*. + + .. method:: proxy(*args) + + Query or change the position of the sash proxy, the "ghost" sash shown + while a sash is being dragged with non-opaque resizing. + This is a thin wrapper around the Tk ``proxy`` subcommand; the + convenience methods :meth:`proxy_coord`, :meth:`proxy_forget` and + :meth:`proxy_place` should normally be used instead. + + .. method:: proxy_coord() + + Return a tuple containing the x and y coordinates of the most recent + proxy location. + + .. method:: proxy_forget() + + Remove the proxy from the display. + + .. method:: proxy_place(x, y) + + Place the proxy at the coordinates *x* and *y*. + + +.. class:: Radiobutton(master=None, cnf={}, **kw) + + A :class:`!Radiobutton` widget displays a textual string, bitmap or image + together with a diamond or circular indicator, and selects one choice out of + several. + It has all the behavior of a simple button and, in addition, can be + selected: typically several radiobuttons share a single *variable*, and + selecting one sets that variable to the radiobutton's *value*; each + radiobutton also monitors the variable and automatically selects or + deselects itself when the variable changes. + Inherits from :class:`Widget`. + In addition to the standard widget options, a radiobutton accepts the + options documented in the Tk ``radiobutton`` manual page, such as + *variable*, *value* and *command*. + + .. method:: invoke() + + Do just what would happen if the user pressed the radiobutton with the + mouse: select the button and invoke the associated command, if there is + one. + Return the result of the command, or an empty string if no command is + associated with the radiobutton. + This is ignored if the radiobutton's state is ``disabled``. + + .. method:: select() + + Select the radiobutton and set the associated variable to the value + corresponding to this widget. + + .. method:: deselect() + + Deselect the radiobutton and set the associated variable to an empty + string. + If this radiobutton was not currently selected, this has no effect. + + .. method:: flash() + + Flash the radiobutton by redisplaying it several times, alternating + between the active and normal colors. + At the end of the flash the radiobutton is left in the same normal or + active state as when the method was called. + This is ignored if the radiobutton's state is ``disabled``. + + +.. class:: Scale(master=None, cnf={}, **kw) + + A :class:`!Scale` widget lets the user select a numerical value by moving a + slider along a trough. + It can be oriented vertically or horizontally and can optionally display a + label and the current value. + Inherits from :class:`Widget`. + + In addition to the standard widget options, a scale accepts the options + documented in the Tk ``scale`` manual page, such as *from_*, *to*, + *resolution*, *orient*, *tickinterval*, *variable* and *command*. + As elsewhere in :mod:`!tkinter`, the leading ``-`` of the Tk option name is + dropped; *from* is spelled ``from_`` because :keyword:`from` is a Python + keyword. + + .. method:: get() + + Return the current value of the scale. + The result is an integer if the scale's *resolution* yields whole + numbers, and a float otherwise. + + .. method:: set(value) + + Set the scale to *value*, moving the slider accordingly. + This has no effect if the scale is disabled. + + .. method:: coords(value=None) + + Return a tuple ``(x, y)`` giving the pixel coordinates, relative to the + widget, of the point on the centerline of the trough that corresponds to + *value*. + If *value* is omitted, the scale's current value is used. + + .. method:: identify(x, y) + + Return a string describing the part of the scale at the pixel coordinates + *x*, *y*: ``'slider'``, ``'trough1'`` (the part of the trough above or to + the left of the slider), ``'trough2'`` (below or to the right of the + slider), or an empty string if the point is not over any of these + elements. + + +.. class:: Scrollbar(master=None, cnf={}, **kw) + + A :class:`!Scrollbar` widget displays a slider and two arrows that let the + user scroll an associated widget, such as a :class:`Listbox`, :class:`Text`, + :class:`Canvas` or :class:`Entry`. + It is connected to the scrolled widget by setting that widget's + *xscrollcommand* or *yscrollcommand* option to the scrollbar's :meth:`set` + method, and the scrollbar's *command* option to the scrolled widget's + :meth:`~XView.xview` or :meth:`~YView.yview` method. + Inherits from :class:`Widget`. + + .. method:: get() + + Return the current scrollbar settings as a tuple ``(first, last)`` of two + fractions between 0 and 1, describing the portion of the document that is + currently visible, as last passed to :meth:`set`. + + .. method:: set(first, last) + + Set the scrollbar. + *first* and *last* are fractions between 0 and 1 giving the positions of + the start and end of the visible portion of the associated document. + This method is normally registered as the scrolled widget's + *xscrollcommand* or *yscrollcommand* and called by that widget. + + .. method:: activate(index=None) + + Mark the element *index* (one of ``'arrow1'``, ``'slider'`` or + ``'arrow2'``) as active, displaying it according to the + *activebackground* and *activerelief* options. + If *index* is omitted, return the name of the currently active element, + or ``None`` if no element is active. + + .. versionchanged:: 3.5 + The *index* argument is now optional. + + .. method:: delta(deltax, deltay) + + Return a float indicating the fractional change in the scrollbar setting + that corresponds to moving the slider by *deltax* pixels horizontally + (for horizontal scrollbars) or *deltay* pixels vertically (for vertical + scrollbars). + + .. method:: fraction(x, y) + + Return a float between 0 and 1 indicating where the point at pixel + coordinates *x*, *y* lies in the trough: 0 corresponds to the top or left + of the trough and 1 to the bottom or right. + + .. method:: identify(x, y) + + Return the name of the element under the pixel coordinates *x*, *y* (such + as ``'arrow1'``), or an empty string if the point does not lie in any + element of the scrollbar. + + +.. class:: Spinbox(master=None, cnf={}, **kw) + + A :class:`!Spinbox` widget is an :class:`Entry`-like widget with a pair of + up/down arrow buttons that let the user step through a range of values in + addition to editing the value directly. + The set of values may be a numeric range given by the *from_*, *to* and + *increment* options, or an explicit list of strings given by the *values* + option (which takes precedence over the range). + Each time an arrow is invoked the *command* callback, if any, is called; the + *wrap* option controls whether stepping past either end of the range wraps + around to the other end; the *format* option specifies how numeric values + are formatted; and the *validate* option enables validation of the entered + text. + Inherits from :class:`Widget` and :class:`XView`. + + Many of the methods take an *index* argument identifying a character in the + spinbox's string. + As described in the Tk ``spinbox`` manual page, *index* may be a numeric + index (counting from 0), ``'anchor'`` (the selection anchor point), + ``'end'`` (just after the last character), ``'insert'`` (the character just + after the insertion cursor), ``'sel.first'`` or ``'sel.last'`` (the ends of + the selection), or ``@x`` (the character covering pixel x-coordinate *x* in + the window). + + .. method:: get() + + Return the spinbox's string. + + .. method:: insert(index, s) + + Insert the characters of the string *s* just before the character given + by *index*. + + .. method:: delete(first, last=None) + + Delete one or more characters of the spinbox. + *first* is the index of the first character to delete, and *last* is the + index of the character just after the last one to delete. + If *last* is omitted, a single character at *first* is deleted. + + .. method:: icursor(index) + + Arrange for the insertion cursor to be displayed just before the + character given by *index*. + + .. method:: index(index) + + Return the numerical index corresponding to *index*, as a string. + + .. method:: bbox(index) + + Return a tuple of four integers ``(x, y, width, height)`` describing the + bounding box of the character given by *index*. + *x* and *y* are the pixel coordinates of the upper-left corner of the + character relative to the widget, and *width* and *height* are its size + in pixels. + The bounding box may refer to a region outside the visible area of the + window. + + .. method:: identify(x, y) + + Return the name of the window element at the pixel coordinates *x*, *y*: + one of ``'buttondown'``, ``'buttonup'``, ``'entry'`` or ``'none'``. + + .. method:: invoke(element) + + Invoke the spin button given by *element*, either ``'buttonup'`` or + ``'buttondown'``, triggering the action associated with it. + + .. method:: scan(*args) + + A thin wrapper around the Tk ``scan`` widget subcommand, used to + implement fast dragging of the view: ``scan('mark', x)`` records *x* and + the current view, and ``scan('dragto', x)`` adjusts the view relative to + that mark. + The :meth:`scan_mark` and :meth:`scan_dragto` methods wrap the two forms. + + .. method:: scan_mark(x) + + Record *x* and the current view in the spinbox window, for use with a + later :meth:`scan_dragto` call. + This is typically associated with a mouse button press in the widget. + + .. method:: scan_dragto(x) + + Adjust the view by 10 times the difference between *x* and the *x* passed + to the last :meth:`scan_mark` call. + This is typically associated with mouse motion events, producing the + effect of dragging the spinbox at high speed through the window. + + .. method:: selection(*args) + + A thin wrapper around the Tk ``selection`` widget subcommand, used to + adjust the selection within the spinbox. + It has several forms depending on the first argument, such as + ``selection('adjust', index)``, ``selection('clear')``, + ``selection('element', ?elem?)``, ``selection('from', index)``, + ``selection('present')``, ``selection('range', start, end)`` and + ``selection('to', index)``. + The :meth:`selection_adjust`, :meth:`selection_clear`, + :meth:`selection_element`, :meth:`selection_from`, + :meth:`selection_present`, :meth:`selection_range` and + :meth:`selection_to` methods wrap these forms. + + .. method:: selection_adjust(index) + + Locate the end of the selection nearest to the character given by *index* + and adjust that end of the selection to be at *index* (including but not + going beyond *index*). + The other end becomes the anchor point for future :meth:`selection_to` + calls. + If the selection is not currently in the spinbox, a new selection is + created to include the characters between *index* and the most recent + anchor point, inclusive. + + .. method:: selection_clear() + + Clear the selection if it is currently in this widget. + If the selection is not in this widget, the method has no effect. + + .. method:: selection_element(element=None) + + Set or get the currently selected element. + If *element* (one of ``'buttonup'``, ``'buttondown'`` or ``'none'``) is + given, that spin button is selected and displayed depressed; otherwise + the name of the currently selected element is returned. + + .. method:: selection_from(index) + + Set the selection anchor point to just before the character given by + *index*, without changing the selection itself. + + .. versionadded:: 3.8 + + + .. method:: selection_present() + + Return ``True`` if there are characters selected in the spinbox, + ``False`` otherwise. + + .. versionadded:: 3.8 + + + .. method:: selection_range(start, end) + + Set the selection to include the characters starting with the one indexed + by *start* and ending with the one just before *end*. + If *end* refers to the same character as *start* or an earlier one, the + selection is cleared. + + .. versionadded:: 3.8 + + + .. method:: selection_to(index) + + Set the selection between *index* and the anchor point. + If *index* is before the anchor point, the selection runs from *index* up + to but not including the anchor point; if it is after, the selection runs + from the anchor point up to but not including *index*; if it is the same, + nothing happens. + The anchor point is the one set by the most recent :meth:`selection_from` + or :meth:`selection_adjust` call. + If the selection is not in this widget, a new selection is created using + the most recent anchor point. + + .. versionadded:: 3.8 + + + +.. class:: Text(master=None, cnf={}, **kw) + + A :class:`!Text` widget displays and edits multi-line text. + Portions of the text may be styled with **tags**, particular positions may + be annotated with floating **marks**, and arbitrary images and other widgets + may be embedded in the text. + The widget also provides an unlimited undo/redo mechanism and supports peer + widgets that share the same underlying data. + Inherits from :class:`Widget`, :class:`XView` and :class:`YView`, so the + view can be scrolled horizontally and vertically with :meth:`~XView.xview` + and :meth:`~YView.yview`. + Refer to the Tk ``text`` manual page for the full list of options. + + Most of the methods take one or more *index* arguments that identify a + position within the text. + As described in the Tk ``text`` manual page, an index is a string consisting + of a base, optionally followed by one or more modifiers. + The base may be ``'line.char'`` (line *line*, character *char*, where lines + are counted from 1 and characters within a line from 0; ``'line.end'`` + refers to the newline ending the line), ``'end'`` (the position just after + the last newline), the name of a mark, ``'tag.first'`` or ``'tag.last'`` + (the first character tagged with *tag*, or the position just after the last + such character), the name of an embedded image or window, or ``@x,y`` (the + character covering pixel coordinates *x*, *y* in the widget). + A modifier such as ``'+5 chars'``, ``'-3 lines'``, ``'linestart'``, + ``'lineend'``, ``'wordstart'`` or ``'wordend'`` adjusts the index relative + to its base; several modifiers may be combined and are applied from left to + right, for example ``'insert wordstart - 1 c'``. + + .. method:: insert(index, chars, *args) + + Insert the string *chars* just before the character at *index* (if + *index* is ``'end'``, just before the final newline). + By default the new text inherits any tags present on both sides of the + insertion point. + If *args* is given, it consists of alternating *tagList*, *chars* values: + the preceding *chars* receives exactly the tags listed (a tag list may be + a single tag name or a sequence of names), overriding the surrounding + tags. + + .. method:: delete(index1, index2=None) + + Delete the range of characters from *index1* up to but not including + *index2*. + If *index2* is omitted, the single character at *index1* is deleted. + The widget always keeps a newline as its last character, so a deletion + that would remove it is adjusted accordingly. + + .. method:: replace(index1, index2, chars, *args) + + Replace the range of characters from *index1* up to but not including + *index2* with *chars*. + This is equivalent to a :meth:`delete` followed by an :meth:`insert` at + *index1*; *args* is interpreted as for :meth:`insert`. + + .. versionadded:: 3.3 + + .. method:: get(index1, index2=None) + + Return the text from *index1* up to but not including *index2* as a + string. + If *index2* is omitted, return the single character at *index1*. + Embedded images and windows are omitted from the result. + + .. method:: index(index) + + Return the position corresponding to *index* in the canonical + ``'line.char'`` form. + + .. method:: compare(index1, op, index2) + + Compare the positions of *index1* and *index2* using the relational + operator *op*, which must be one of ``'<'``, ``'<='``, ``'=='``, + ``'>='``, ``'>'`` or ``'!='``, and return the boolean result. + + .. method:: count(index1, index2, *options, return_ints=False) + + Count the number of items of the requested kinds between *index1* and + *index2*; the count is negative if *index1* is after *index2*. + Each of *options* names a kind of item to count: ``'chars'``, + ``'displaychars'``, ``'displayindices'``, ``'displaylines'``, + ``'indices'``, ``'lines'``, ``'xpixels'`` or ``'ypixels'`` (the default, + used when no option is given, is ``'indices'``). + The pseudo-option ``'update'`` forces any out-of-date layout information + to be recalculated before the following options are evaluated. + When *return_ints* is true and a single counting option is given, return + a plain integer; otherwise return a tuple with one integer per counting + option (or ``None`` if the result is empty). + + .. versionadded:: 3.3 + + .. versionchanged:: 3.13 + Added the *return_ints* parameter. + + + .. method:: see(index) + + Adjust the view so that the character given by *index* is visible. + If it is already visible the method has no effect; if it is a short + distance out of view the widget scrolls just enough to bring it to the + nearest edge, otherwise it scrolls to center *index* in the window. + + .. method:: bbox(index) + + Return a tuple ``(x, y, width, height)`` giving the bounding box, in + pixels, of the visible part of the character at *index*, or ``None`` if + that character is not visible on the screen. + + .. method:: dlineinfo(index) + + Return a tuple ``(x, y, width, height, baseline)`` describing the display + line that contains *index*: the first four values give the bounding box + of the line in pixels and *baseline* gives the offset of the baseline + measured down from the top of the area. + Return ``None`` if that display line is not visible on the screen. + + .. method:: mark_set(markName, index) + + Set the mark named *markName* to the position just before the character + at *index*, creating the mark if it does not already exist. + A mark created this way has right gravity by default. + + .. method:: mark_unset(*markNames) + + Remove each of the marks named in *markNames*. + The special ``insert`` and ``current`` marks may not be removed. + + .. method:: mark_names() + + Return a tuple of the names of all marks currently set in the widget. + + .. method:: mark_gravity(markName, direction=None) + + If *direction* is omitted, return the gravity of mark *markName*, either + ``'left'`` or ``'right'``. + Otherwise set its gravity to *direction*. + The gravity determines on which side of the mark text inserted at the + mark's position appears: a mark with right gravity (the default) stays to + the right of such text. + + .. method:: mark_next(index) + + Return the name of the first mark at or after *index*, or ``None`` if + there is none. + When *index* is the name of a mark, the search starts just after that + mark. + + .. method:: mark_previous(index) + + Return the name of the last mark at or before *index*, or ``None`` if + there is none. + When *index* is the name of a mark, the search starts just before that + mark. + + .. method:: tag_add(tagName, index1, *args) + + Add the tag *tagName* to the range of characters from *index1* up to but + not including the next index in *args*. + Further pairs of indices may follow in *args* to tag additional ranges; a + trailing single index tags just the character at that index. + + .. method:: tag_remove(tagName, index1, index2=None) + + Remove the tag *tagName* from the characters from *index1* up to but not + including *index2* (or from the single character at *index1* if *index2* + is omitted). + The tag itself continues to exist even if no characters carry it. + + .. method:: tag_delete(*tagNames) + + Delete each of the tags named in *tagNames*, removing them from all + characters and discarding their options and bindings. + + .. method:: tag_config(tagName, cnf=None, **kw) + :no-typesetting: + + .. method:: tag_configure(tagName, cnf=None, **kw) + + Query or modify the configuration options of the tag *tagName*. + This mirrors :meth:`~Misc.configure`, except that it applies to a tag + rather than to the widget as a whole: with no options it returns a + dictionary describing the current options, otherwise it sets the given + options. + Defining a tag this way also gives it a priority higher than any existing + tag. + + The supported tag options, all controlling the appearance of the tagged + text, are: + + *font* + The font to use for the text. + + *foreground* + The color to use for the text. + + *background* + The color to use for the area behind the text. + + *fgstipple*, *bgstipple* + Bitmaps used to stipple the foreground (text) and the background; + only well supported on X11. + + *borderwidth* + The width of the border drawn around the text according to *relief* + (default ``0``). + + *relief* + The 3-D appearance of the text's border: ``'flat'`` (the default), + ``'raised'``, ``'sunken'``, ``'ridge'``, ``'groove'`` or ``'solid'``. + + *offset* + How far the text is raised above (or, if negative, lowered below) the + baseline, for superscripts and subscripts. + + *underline* + Whether to underline the text. + + *underlinefg* + The color of the underline; it defaults to the text color. + + *overstrike* + Whether to draw a line through the middle of the text. + + *overstrikefg* + The color of the overstrike line; it defaults to the text color. + + *elide* + Whether the text is elided (hidden). + + *justify* + How to justify the first character of a display line: ``'left'`` (the + default), ``'right'`` or ``'center'``. + + *wrap* + How to wrap lines that are too long: ``'char'``, ``'word'`` or + ``'none'``. + + *lmargin1*, *lmargin2* + The indentation, in pixels, of the first display line of a logical + line and of the remaining display lines. + + *lmargincolor* + The color of the left margin area. + + *rmargin* + The right-hand margin, in pixels. + + *rmargincolor* + The color of the right margin area. + + *spacing1*, *spacing2*, *spacing3* + Extra space, in pixels, above the first display line of a logical + line, between its display lines, and below its last display line. + + *tabs* + The set of tab stops, in the same form as the widget's *tabs* option. + + *tabstyle* + How tab stops are interpreted: ``'tabular'`` or ``'wordprocessor'``. + + *selectbackground*, *selectforeground* + The background and foreground colors used for the text while it is + selected. + + .. note:: + + Tk 8.6 added the *lmargincolor*, *overstrikefg*, *rmargincolor*, + *selectbackground*, *selectforeground* and *underlinefg* options. + + :meth:`tag_config` is an alias of :meth:`!tag_configure`. + + .. method:: tag_cget(tagName, option) + + Return the current value of the configuration option *option* for the tag + *tagName*. + + .. method:: tag_names(index=None) + + If *index* is omitted, return a tuple of the names of all tags defined in + the widget; otherwise return only the names of the tags applied to the + character at *index*. + The names are ordered from lowest to highest priority. + + .. method:: tag_ranges(tagName) + + Return a tuple of indices describing all ranges of text tagged with + *tagName*. + The result alternates start and end indices, so that elements ``2*i`` and + ``2*i+1`` bound the *i*-th range. + + .. method:: tag_nextrange(tagName, index1, index2=None) + + Search forward from *index1* (up to *index2* if given) for the first + range of characters tagged with *tagName*, and return a two-element tuple + of its start and end indices, or an empty tuple if there is no such + range. + + .. method:: tag_prevrange(tagName, index1, index2=None) + + Search backward from *index1* (down to *index2* if given) for the nearest + preceding range of characters tagged with *tagName*, and return a + two-element tuple of its start and end indices, or an empty tuple if + there is no such range. + + .. method:: tag_raise(tagName, aboveThis=None) + + Raise the priority of tag *tagName* so that it is just above the priority + of *aboveThis*, or to the highest priority of all tags if *aboveThis* is + omitted. + When the display options of overlapping tags conflict, the + higher-priority tag wins. + + .. method:: tag_lower(tagName, belowThis=None) + + Lower the priority of tag *tagName* so that it is just below the priority + of *belowThis*, or to the lowest priority of all tags if *belowThis* is + omitted. + + .. method:: tag_bind(tagName, sequence, func, add=None) + + Bind the event *sequence* on characters tagged with *tagName* to the + callback *func*, so that *func* is invoked when that event occurs over + such a character. + If *add* is true the binding is added alongside any existing bindings for + *sequence*, otherwise it replaces them. + Works like :meth:`~Misc.bind` and returns the identifier of the new + binding. + + .. method:: tag_unbind(tagName, sequence, funcid=None) + + Remove the bindings of the event *sequence* on characters tagged with + *tagName*. + If *funcid* is given, only that binding (as returned by :meth:`tag_bind`) + is removed and its callback is unregistered. + + .. versionchanged:: 3.13 + If *funcid* is given, only that callback is unbound. + + + .. method:: image_create(index, cnf={}, **kw) + + Embed an image at *index* and return the name assigned to this image + instance, which may then be used as an index or passed to the other + ``image_*`` methods. + The options, given in *cnf* and *kw*, include *image* (the Tk image to + display), *name* (a base name for the instance), *align*, *padx* and + *pady*. + + .. method:: image_cget(index, option) + + Return the current value of the configuration option *option* for the + embedded image at *index*. + + .. method:: image_configure(index, cnf=None, **kw) + + Query or modify the configuration options of the embedded image at + *index*, like :meth:`~Misc.configure` but applied to that image. + + .. method:: image_names() + + Return a tuple of the names of all images embedded in the widget. + + .. method:: window_create(index, cnf={}, **kw) + + Embed a window (any widget) at *index*. + The options, given in *cnf* and *kw*, include *window* (the widget to + embed), *create* (a callback that creates the widget on demand), *align*, + *stretch*, *padx* and *pady*. + The embedded widget must be a descendant of the text widget's parent. + + .. method:: window_cget(index, option) + + Return the current value of the configuration option *option* for the + embedded window at *index*. + + .. method:: window_config(index, cnf=None, **kw) + :no-typesetting: + + .. method:: window_configure(index, cnf=None, **kw) + + Query or modify the configuration options of the embedded window at + *index*, like :meth:`~Misc.configure` but applied to that window. + + :meth:`window_config` is an alias of :meth:`!window_configure`. + + .. method:: window_names() + + Return a tuple of the names of all windows embedded in the widget. + + .. method:: edit(*args) + + Low-level wrapper around the Tk ``edit`` widget command that controls the + undo/redo mechanism and the modified flag; *args* is the ``edit`` + subcommand and its arguments. + The :meth:`!edit_\*` methods below are thin wrappers around it and are + usually more convenient. + + .. method:: edit_modified(arg=None) + + If *arg* is omitted, return the current state of the modified flag as + ``0`` or ``1``; the flag is set automatically whenever the text is + inserted or deleted. + Otherwise set the flag to the boolean *arg*. + + .. method:: edit_undo() + + Undo the most recent edit action, that is, all the inserts and deletes + recorded on the undo stack since the previous separator, and move it to + the redo stack. + Raises :exc:`TclError` if the undo stack is empty. + Has no effect unless the *undo* option is true. + Since Tk 9.0, returns a tuple of indices delimiting the ranges of text + that were changed. + + .. method:: edit_redo() + + Reapply the most recently undone edit action, provided no further edits + have been made since, and move it back to the undo stack. + Raises :exc:`TclError` if the redo stack is empty. + Has no effect unless the *undo* option is true. + Since Tk 9.0, returns a tuple of indices delimiting the ranges of text + that were changed. + + .. method:: edit_reset() + + Clear the undo and redo stacks. + + .. method:: edit_separator() + + Push a separator onto the undo stack, marking a boundary between edit + actions for undo and redo. + Has no effect unless the *undo* option is true. + Separators are inserted automatically when the *autoseparators* option is + true. + + .. method:: search(pattern, index, stopindex=None, forwards=None, backwards=None, exact=None, regexp=None, nocase=None, count=None, elide=None, *, nolinestop=None, strictlimits=None) + + Search for *pattern* starting at *index* and return the index of the + first character of the first match, or an empty string if there is no + match. + Searching stops at *stopindex* if given; otherwise it wraps around the + ends of the text until the starting position is reached again. + The following boolean keyword flags control the search: *forwards* or + *backwards* select the direction (forward is the default); *exact* (the + default) or *regexp* select literal or regular-expression matching; + *nocase* makes the match case-insensitive; *elide* causes hidden text to + be searched as well; *nolinestop* (regexp only) lets ``.`` and ``[^`` + match newlines; and *strictlimits* requires the whole match to lie within + *index* and *stopindex*. + If *count* is a :class:`Variable`, the number of index positions in the + match is stored in it. + + .. versionchanged:: 3.15 + Added the *nolinestop* and *strictlimits* parameters. + + + .. method:: search_all(pattern, index, stopindex=None, *, forwards=None, backwards=None, exact=None, regexp=None, nocase=None, count=None, elide=None, nolinestop=None, overlap=None, strictlimits=None) + + Like :meth:`search`, but find every match in the searched range and + return a tuple of the starting indices of all matches (empty if there are + none). + By default overlapping matches are not reported; passing a true *overlap* + returns every match that is not wholly contained in another. + If *count* is a :class:`Variable`, it receives a list with one element + per match. + + .. versionadded:: 3.15 + + + .. method:: scan_mark(x, y) + + Record *x*, *y* and the current view, for use with later + :meth:`scan_dragto` calls. + This is typically bound to a mouse button press in the widget. + + .. method:: scan_dragto(x, y) + + Scroll the widget by 10 times the difference between *x*, *y* and the + coordinates passed to the last :meth:`scan_mark` call. + This is typically bound to mouse motion events, producing the effect of + dragging the text at high speed through the window. + + .. method:: debug(boolean=None) + + If *boolean* is omitted, return whether internal consistency checks of + the B-tree data structure are enabled. + Otherwise enable or disable them. + The setting is shared by all text widgets and may noticeably slow down + widgets holding large amounts of text. + + .. method:: dump(index1, index2=None, command=None, **kw) + + Return the contents of the widget from *index1* up to but not including + *index2* (or just the segment at *index1* if *index2* is omitted), + including text and information about marks, tags, images and windows. + The result is a list of ``(key, value, index)`` triples, where *key* is + one of ``'text'``, ``'mark'``, ``'tagon'``, ``'tagoff'``, ``'image'`` or + ``'window'``. + By default all kinds are reported; passing any of the keyword arguments + *all*, *text*, *mark*, *tag*, *image* or *window* as true restricts the + dump to the selected kinds. + If *command* is given, it is called once per triple with the three values + as arguments and nothing is returned. + + .. method:: peer_create(newPathName, cnf={}, **kw) + + Create a peer text widget with the path name *newPathName* that shares + this widget's underlying data (text, marks, tags, images and the undo + stack). + Changes made through any peer are reflected in all of them. + By default the peer covers the same lines as this widget; standard text + options, including *startline* and *endline*, may be given to override + this. + + .. versionadded:: 3.3 + + .. method:: peer_names() + + Return a tuple of the path names of this widget's peers, not including + the widget itself. + + .. versionadded:: 3.3 + + .. method:: yview_pickplace(*what) + + Adjust the view so that the location given by *what* is visible. + This is an obsolete equivalent of :meth:`see`, which should be used + instead. + + +Variable classes +^^^^^^^^^^^^^^^^ + +.. class:: Variable(master=None, value=None, name=None) + + The base class for the Tk variable wrappers. + A Tk variable is a value stored in the Tcl interpreter that can be linked to + widgets through their *variable* or *textvariable* options (see + :ref:`coupling-widget-variables`), so that changes propagate both ways: + updating the variable updates every widget bound to it, and a user editing + such a widget updates the variable. + + *master* is the widget whose Tcl interpreter owns the variable; if omitted, + the default root window is used. + *value* is the initial value; if omitted, a type-specific default is used. + *name* is the name of the variable in the Tcl interpreter; if omitted, a + unique name of the form ``'PY_VARnum'`` is generated. + If *name* matches an existing variable and *value* is omitted, the existing + value is retained. + + In most cases you should use one of the typed subclasses below -- + :class:`StringVar`, :class:`IntVar`, :class:`DoubleVar` or + :class:`BooleanVar` -- rather than :class:`!Variable` directly. + + .. versionchanged:: 3.10 + Two variables now compare equal (``==``) only when they have the same + name, are of the same class, and belong to the same Tcl interpreter. + + .. method:: get() + + Return the current value of the variable. + For the base class the value is returned as a string; the typed + subclasses convert it to the appropriate Python type. + + .. method:: initialize(value) + :no-typesetting: + + .. method:: set(value) + + Set the variable to *value*. + + .. versionadded:: 3.3 + The *initialize* spelling. + + .. method:: trace_add(mode, callback) + + Register *callback* to be called when the variable is accessed according + to *mode*. + *mode* is one of the strings ``'array'``, ``'read'``, ``'write'`` or + ``'unset'``, or a list or tuple of such strings. + + When triggered, *callback* is called with three arguments: the name of + the Tcl variable, an index (or an empty string if the variable is not an + element of an array), and the *mode* that triggered the call. + + Return the internal name of the registered callback, which can be passed + to :meth:`trace_remove`. + + .. versionadded:: 3.6 + + .. method:: trace_remove(mode, cbname) + + Remove a trace callback from the variable. + *mode* must match the *mode* that was passed to :meth:`trace_add`, and + *cbname* is the callback name returned by :meth:`trace_add`. + + .. versionadded:: 3.6 + + .. method:: trace_info() + + Return a list of ``(modes, cbname)`` pairs describing all traces + currently set on the variable, where *modes* is a tuple of mode strings + and *cbname* is the internal callback name. + + .. versionadded:: 3.6 + + .. method:: trace(mode, callback) + :no-typesetting: + + .. method:: trace_variable(mode, callback) + + Register *callback* to be called when the variable is accessed according + to *mode*. + *mode* is one of the strings ``'r'``, ``'w'`` or ``'u'``, for read, write + or unset. + Return the internal name of the registered callback. + + .. deprecated:: 3.6 + Use :meth:`trace_add` instead. This method wraps a Tcl feature that + was removed in Tcl 9.0. + + .. method:: trace_vdelete(mode, cbname) + + Remove the trace callback named *cbname* registered for *mode* with + :meth:`trace_variable`. + + .. deprecated:: 3.6 + Use :meth:`trace_remove` instead. This method wraps a Tcl feature + that was removed in Tcl 9.0. + + .. method:: trace_vinfo() + + Return a list of ``(mode, cbname)`` pairs for all traces set on the + variable with :meth:`trace_variable`. + + .. deprecated:: 3.6 + Use :meth:`trace_info` instead. This method wraps a Tcl feature that + was removed in Tcl 9.0. + + +.. class:: StringVar(master=None, value=None, name=None) + + A :class:`Variable` subclass that holds a string. + The default value is ``''``. + + .. method:: get() + + Return the value of the variable as a :class:`str`. + + +.. class:: IntVar(master=None, value=None, name=None) + + A :class:`Variable` subclass that holds an integer. + The default value is ``0``. + + .. method:: get() + + Return the value of the variable as an :class:`int`. + + +.. class:: DoubleVar(master=None, value=None, name=None) + + A :class:`Variable` subclass that holds a float. + The default value is ``0.0``. + + .. method:: get() + + Return the value of the variable as a :class:`float`. + + +.. class:: BooleanVar(master=None, value=None, name=None) + + A :class:`Variable` subclass that holds a boolean. + The default value is ``False``. + + .. method:: get() + + Return the value of the variable as a :class:`bool`. + Raise a :exc:`ValueError` if the value cannot be interpreted as a + boolean. + + .. method:: initialize(value) + :no-typesetting: + + .. method:: set(value) + + Set the variable to *value*, converting it to a boolean. + + .. versionadded:: 3.3 + The *initialize* spelling. + + +Image classes +^^^^^^^^^^^^^ + +.. class:: Image(imgtype, name=None, cnf={}, master=None, **kw) + + Base class for Tk images. + *imgtype* is the Tk image type, one of ``'photo'`` or ``'bitmap'``. + An image is a named object that can be displayed by widgets through their + *image* option; deleting all references to the :class:`!Image` object + deletes the underlying Tk image. + Usually you create a :class:`PhotoImage` or :class:`BitmapImage` rather than + an :class:`!Image` directly. + + The image's configuration options are given by *cnf* and *kw* and may be + queried and changed later with the mapping protocol (using ``image[key]``) + or with the :meth:`configure` method. + + .. method:: config(**kw) + :no-typesetting: + + .. method:: configure(**kw) + + Modify one or more configuration options of the image. + The valid options depend on the image type; see :class:`PhotoImage` and + :class:`BitmapImage`. + :meth:`config` is an alias of :meth:`!configure`. + + .. method:: height() + + Return the height of the image, in pixels. + + .. method:: width() + + Return the width of the image, in pixels. + + .. method:: type() + + Return the type of the image, that is the value of *imgtype* with which + it was created (for example ``'photo'`` or ``'bitmap'``). + + +.. class:: PhotoImage(name=None, cnf={}, master=None, **kw) + + A full-color image (the Tk ``photo`` image type), stored internally with a + varying degree of transparency per pixel. + It can read and write GIF, PPM/PGM and (in Tk 8.6 and later) PNG files, read + SVG files (in Tk 9.0 and later), and be drawn in widgets. + Inherits from :class:`Image`. + + The configuration options include *data* (the image contents as a string), + *file* (the name of a file to read the contents from), *format* (the name of + the file format handler), *width* and *height* (the size of the image, used + when building it up piece by piece), *gamma* and *palette*. + + .. method:: blank() + + Blank the image; that is, set the entire image to have no data, so that + it is displayed as transparent and the background of whatever window it + is displayed in shows through. + + .. method:: cget(option) + + Return the current value of the configuration option *option*. + + .. method:: copy(*, from_coords=None, zoom=None, subsample=None) + + Return a new :class:`PhotoImage` with a copy of this image. + + *from_coords* specifies a rectangular sub-region of the source image to + be copied. + It must be a tuple or a list of 1 to 4 integers ``(x1, y1, x2, y2)``. + ``(x1, y1)`` and ``(x2, y2)`` specify diagonally opposite corners of the + rectangle. + If *x2* and *y2* are not specified, they default to the bottom-right + corner of the source image. + The pixels copied include the left and top edges of the rectangle but not + the bottom or right edges. + If *from_coords* is not given, the whole source image is copied. + + If *zoom* or *subsample* are specified, the image is transformed as in + the :meth:`zoom` or :meth:`subsample` methods. + The value must be a single integer or a pair of integers. + + .. versionchanged:: 3.13 + Added the *from_coords*, *zoom* and *subsample* parameters. + + + .. method:: copy_replace(sourceImage, *, from_coords=None, to=None, \ + shrink=False, zoom=None, subsample=None, \ + compositingrule=None) + + Copy a region from *sourceImage* (which must be a :class:`PhotoImage`) + into this image, possibly with pixel zooming and/or subsampling. + If no options are specified, the whole of *sourceImage* is copied into + this image, starting at coordinates ``(0, 0)``. + + *from_coords* specifies a rectangular sub-region of the source image to + be copied, as in the :meth:`copy` method. + + *to* specifies a rectangular sub-region of the destination image to be + affected. + It must be a tuple or a list of 1 to 4 integers ``(x1, y1, x2, y2)``. + If *x2* and *y2* are not specified, they default to ``(x1, y1)`` plus the + size of the source region (after subsampling and zooming, if specified). + If *x2* and *y2* are specified, the source region is replicated if + necessary to fill the destination region in a tiled fashion. + + If *shrink* is true, the size of the destination image is reduced, if + necessary, so that the region being copied into is at the bottom-right + corner of the image. + + If *zoom* or *subsample* are specified, the image is transformed as in + the :meth:`zoom` or :meth:`subsample` methods. + The value must be a single integer or a pair of integers. + + *compositingrule* specifies how transparent pixels in the source image + are combined with the destination image. + With ``'overlay'`` (the default), the old contents of the destination + image remain visible, as if the source image were printed on a piece of + transparent film and placed over the top of the destination. + With ``'set'``, the old contents of the destination image are discarded + and the source image is used as-is. + + .. versionadded:: 3.13 + + + .. method:: data(format=None, *, from_coords=None, background=None, \ + grayscale=False) + + Return the image data. + + *format* specifies the name of the image file format handler to use. + If it is not given, the data is returned as a tuple (one element per row) + of strings containing space-separated (one element per pixel/column) + colors in ``#RRGGBB`` format. + + *from_coords* specifies a rectangular region of the image to be returned. + It must be a tuple or a list of 1 to 4 integers ``(x1, y1, x2, y2)``. + If only *x1* and *y1* are specified, the region extends from ``(x1, y1)`` + to the bottom-right corner of the image. + If all four coordinates are given, they specify diagonally opposite + corners of the region, including ``(x1, y1)`` and excluding ``(x2, y2)``. + If *from_coords* is not given, the whole image is returned. + + If *background* is specified, the data does not contain any transparency + information; in all transparent pixels the color is replaced by the + specified color. + + If *grayscale* is true, the data does not contain color information; all + pixel data is transformed into grayscale. + + .. versionadded:: 3.13 + + + .. method:: get(x, y) + + Return the color of the pixel at coordinates (*x*, *y*) as an + ``(r, g, b)`` tuple of three integers between 0 and 255, representing the + red, green and blue components respectively. + + .. method:: put(data, to=None) + + Set pixels of the image to the colors given in *data*, which must be a + string or a nested sequence of horizontal rows of pixel colors (for + example ``"{red green} {blue yellow}"``). + + *to* specifies the coordinates of the region of the image into which the + data are copied. + It must be a tuple or a list of 2 or 4 integers ``(x1, y1)`` or + ``(x1, y1, x2, y2)`` giving the top-left corner, and optionally the + bottom-right corner, of the region. + The default position is ``(0, 0)``. + + .. method:: read(filename, format=None, *, from_coords=None, to=None, \ + shrink=False) + + Read image data from the file named *filename* into the image. + + *format* specifies the format of the image data in the file. + + *from_coords* specifies a rectangular sub-region of the image file data + to be copied to the destination image. + It must be a tuple or a list of 1 to 4 integers ``(x1, y1, x2, y2)``. + If only *x1* and *y1* are specified, the region extends from ``(x1, y1)`` + to the bottom-right corner of the image in the file. + If all four coordinates are given, they specify diagonally opposite + corners of the region. + If *from_coords* is not given, the whole of the image in the file is + read. + + *to* specifies the coordinates of the top-left corner of the region of + the image into which the data are read. + The default is ``(0, 0)``. + + If *shrink* is true, the size of the image is reduced, if necessary, so + that the region into which the file data are read is at the bottom-right + corner of the image. + + .. versionadded:: 3.13 + + + .. method:: subsample(x, y='', *, from_coords=None) + + Return a new :class:`PhotoImage` based on this image but using only every + *x*-th pixel in the X direction and every *y*-th pixel in the Y + direction. + If *y* is not given, it defaults to the same value as *x*. + + *from_coords* specifies a rectangular sub-region of the source image to + be copied, as in the :meth:`copy` method. + + .. versionchanged:: 3.13 + Added the *from_coords* parameter. + + + .. method:: transparency_get(x, y) + + Return ``True`` if the pixel at coordinates (*x*, *y*) is fully + transparent, ``False`` otherwise. + + .. versionadded:: 3.8 + + + .. method:: transparency_set(x, y, boolean) + + Make the pixel at coordinates (*x*, *y*) fully transparent if *boolean* + is true, fully opaque otherwise. + + .. versionadded:: 3.8 + + + .. method:: write(filename, format=None, from_coords=None, *, \ + background=None, grayscale=False) + + Write image data from the image to the file named *filename*. + + *format* specifies the name of the image file format handler to use. + If it is not given, the format is guessed from the file extension. + + *from_coords* specifies a rectangular region of the image to be written. + It must be a tuple or a list of 1 to 4 integers ``(x1, y1, x2, y2)``. + If only *x1* and *y1* are specified, the region extends from ``(x1, y1)`` + to the bottom-right corner of the image. + If all four coordinates are given, they specify diagonally opposite + corners of the region. + If *from_coords* is not given, the whole image is written. + + If *background* is specified, the data does not contain any transparency + information; in all transparent pixels the color is replaced by the + specified color. + + If *grayscale* is true, the data does not contain color information; all + pixel data is transformed into grayscale. + + .. versionchanged:: 3.13 + Added the *background* and *grayscale* parameters. + + + .. method:: zoom(x, y='', *, from_coords=None) + + Return a new :class:`PhotoImage` with this image magnified by a factor of + *x* in the X direction and *y* in the Y direction. + If *y* is not given, it defaults to the same value as *x*. + + *from_coords* specifies a rectangular sub-region of the source image to + be copied, as in the :meth:`copy` method. + + .. versionchanged:: 3.13 + Added the *from_coords* parameter. + + + +.. class:: BitmapImage(name=None, cnf={}, master=None, **kw) + + A two-color image (the Tk ``bitmap`` image type) created from an X11 bitmap. + Each pixel displays a foreground color, a background color, or nothing + (producing a transparent effect). + Inherits from :class:`Image`. + + The configuration options are *data* or *file* (the source bitmap, given as + a string in X11 bitmap format or as the name of a file in that format), + *maskdata* or *maskfile* (the mask bitmap, in the same forms), and + *foreground* and *background* (the two colors). + For pixels where the mask is zero the image displays nothing; for other + pixels it displays the foreground color where the source is one and the + background color where the source is zero. + If *background* is set to an empty string, the background pixels are + transparent. + + :class:`!BitmapImage` has no methods of its own beyond those inherited from + :class:`Image`. + + +Other classes +^^^^^^^^^^^^^ + +.. class:: Event() + + A container for the attributes of an event passed to a callback bound with + :meth:`Misc.bind`. + An :class:`!Event` instance has the following attributes, each corresponding + to a field of the underlying Tk event; depending on the event type, some + attributes may be set to the string ``'??'`` to indicate that they are not + meaningful. + See :ref:`bindings-and-events`. + + .. attribute:: serial + + The serial number of the event. + + .. attribute:: num + + The mouse button that was pressed or released (for button events). + + .. attribute:: focus + + Whether the window has the focus (for ``Enter`` and ``Leave`` events). + + .. attribute:: height + width + + The new height and width of the window (for ``Configure`` and ``Expose`` + events). + + .. attribute:: keycode + + The keycode of the key that was pressed or released. + + .. attribute:: state + + The state of the event, as a number (for most events) or a string (for + ``Visibility`` events). + + .. attribute:: time + + The timestamp of the event, in milliseconds. + + .. attribute:: x + y + + The pointer position relative to the widget, in pixels. + + .. attribute:: x_root + y_root + + The pointer position relative to the top-left corner of the screen, in + pixels. + + .. attribute:: char + + The character typed, as a string (for key events). + + .. attribute:: send_event + + ``True`` if the event was sent by another application. + + .. attribute:: keysym + + The symbolic name of the key that was pressed or released. + + .. attribute:: keysym_num + + The numeric value of :attr:`keysym`. + + .. attribute:: type + + The :class:`EventType` of the event. + + .. attribute:: widget + + The widget on which the event occurred. + + .. attribute:: delta + + The amount the mouse wheel was rotated (for ``MouseWheel`` events). + + .. attribute:: user_data + + The data string of a virtual event, as passed to the *data* option of + :meth:`Misc.event_generate`. + It is ``'??'`` for non-virtual events. + + .. versionadded:: 3.15 + + .. attribute:: detail + + A fixed detail string for ``Enter``, ``Leave``, ``FocusIn``, ``FocusOut`` + and ``ConfigureRequest`` events (see the Tcl/Tk documentation). + It is ``'??'`` for other events. + + .. versionadded:: 3.15 + + +.. class:: EventType(*values) + + An :class:`enum.StrEnum` enumerating the Tk event types, used as the value + of :attr:`Event.type`. + Its members include, among others, ``KeyPress``, ``KeyRelease``, + ``ButtonPress``, ``ButtonRelease``, ``Motion``, ``Enter``, ``Leave``, + ``FocusIn``, ``FocusOut``, ``Configure``, ``Map``, ``Unmap``, ``Expose``, + ``Destroy`` and ``MouseWheel``. + + .. versionadded:: 3.6 + + + +.. class:: CallWrapper(func, subst, widget) + + Internal helper that wraps a Python callback so that it can be invoked from + Tcl. + *func* is the Python function, *subst* is an optional function that + pre-processes the Tcl arguments, and *widget* is the widget used for error + reporting. + Instances are created automatically by :meth:`Misc.register`; this class is + not normally used directly. + + +Module-level functions +^^^^^^^^^^^^^^^^^^^^^^ + +.. function:: NoDefaultRoot() + + Inhibit the creation of an implicit default root window. + Afterwards :mod:`!tkinter` no longer creates a shared default root + automatically, and operations that rely on one --- such as constructing a + widget without an explicit *master* --- raise a :exc:`RuntimeError`. + Call this early in larger applications to make the root window explicit. + +.. function:: mainloop(n=0) + + Run the Tk main event loop on the default root window until all windows are + destroyed. + Equivalent to calling :meth:`Misc.mainloop` on the default root. + +.. function:: getboolean(s) + + Convert the Tcl boolean string *s* (one of ``'1'``, ``'true'``, ``'yes'``, + ``'on'`` and similar, or their false counterparts) to a Python + :class:`bool`. + Raise :exc:`TclError` for an invalid value. + +.. function:: getdouble(s) + + Convert *s* to a floating-point number. + This is the built-in :class:`float`. + +.. function:: getint(s) + + Convert *s* to an integer. + This is the built-in :class:`int`. + +.. function:: image_names() + + Return the names of all existing images in the default root's interpreter. + +.. function:: image_types() + + Return the available image types (such as ``'photo'`` and ``'bitmap'``) in + the default root's interpreter. + +Constants +^^^^^^^^^ + +The following symbolic constants are available in both the :mod:`!tkinter` +and :mod:`!tkinter.constants` namespaces. + +.. data:: TRUE + YES + ON + + Truthy values, all equal to the integer ``1``. + +.. data:: FALSE + NO + OFF + + Falsy values, all equal to the integer ``0``. + +.. data:: N + S + E + W + NE + NW + SE + SW + NS + EW + NSEW + CENTER + + Compass directions (``'n'``, ``'s'``, ``'e'``, ``'w'`` and the diagonals and + edges) plus ``CENTER`` (``'center'``), used as values for the *anchor* and + *sticky* options and by methods such as :meth:`Misc.grid_anchor`. + +.. data:: LEFT + RIGHT + TOP + BOTTOM + + Sides for the *side* option of the packer (see :meth:`Pack.pack_configure`). + +.. data:: X + Y + BOTH + NONE + + Values for the *fill* option of the packer: ``'x'``, ``'y'``, ``'both'`` or + ``'none'``. + +.. data:: RAISED + SUNKEN + FLAT + RIDGE + GROOVE + SOLID + + Values for the *relief* option, which controls a widget's 3-D border. + +.. data:: HORIZONTAL + VERTICAL + + Values for the *orient* option of widgets such as :class:`Scale`, + :class:`Scrollbar` and :class:`PanedWindow`. + +.. data:: CHAR + WORD + + Values for the *wrap* option of the :class:`Text` widget, selecting line + wrapping on character or word boundaries. + +.. data:: BASELINE + + The text-alignment value ``'baseline'``. + +.. data:: INSIDE + OUTSIDE + + Values for the *bordermode* option of the placer (see + :meth:`Place.place_configure`). + +.. data:: INSERT + CURRENT + END + ANCHOR + SEL + SEL_FIRST + SEL_LAST + + Symbolic indices used by the :class:`Text`, :class:`Entry`, :class:`Listbox` + and :class:`Canvas` widgets, such as ``'insert'`` (the insertion cursor), + ``'current'``, ``'end'``, ``'anchor'`` and the bounds of the selection + (``'sel.first'`` and ``'sel.last'``). + +.. data:: ALL + + The special tag ``'all'``, which matches every item of a :class:`Canvas` or + every character of a :class:`Text` (for example ``canvas.delete(ALL)``). + +.. data:: NORMAL + DISABLED + ACTIVE + HIDDEN + + Values for the *state* option of various widgets and items. + +.. data:: CASCADE + CHECKBUTTON + COMMAND + RADIOBUTTON + SEPARATOR + + Menu entry types, used as the *itemType* argument of :meth:`Menu.add` and + :meth:`Menu.insert`. + +.. data:: SINGLE + BROWSE + MULTIPLE + EXTENDED + + Values for the *selectmode* option of the :class:`Listbox` widget. + +.. data:: PIESLICE + CHORD + ARC + + Values for the *style* option of :class:`Canvas` arc items. + +.. data:: BUTT + PROJECTING + ROUND + BEVEL + MITER + + Values for the *capstyle* (``'butt'``, ``'projecting'``, ``'round'``) and + *joinstyle* (``'round'``, ``'bevel'``, ``'miter'``) options of + :class:`Canvas` line items. + +.. data:: FIRST + LAST + + Values for the *arrow* option of :class:`Canvas` line items, indicating + which ends have arrowheads. + +.. data:: MOVETO + SCROLL + + The first argument passed by a :class:`Scrollbar` to the :meth:`XView.xview` + or :meth:`YView.yview` method of the scrolled widget. + +.. data:: UNITS + PAGES + + Values for the *what* argument of :meth:`XView.xview_scroll` and + :meth:`YView.yview_scroll`. + +.. data:: UNDERLINE + NUMERIC + DOTBOX + + Other option values: ``'underline'``, ``'numeric'`` and ``'dotbox'``. diff --git a/Doc/library/tkinter.scrolledtext.rst b/Doc/library/tkinter.scrolledtext.rst index eb30b9c3eacc1b..30aef8748edb72 100644 --- a/Doc/library/tkinter.scrolledtext.rst +++ b/Doc/library/tkinter.scrolledtext.rst @@ -1,4 +1,4 @@ -:mod:`!tkinter.scrolledtext` --- Scrolled Text Widget +:mod:`!tkinter.scrolledtext` --- Scrolled text widget ===================================================== .. module:: tkinter.scrolledtext @@ -13,10 +13,12 @@ implements a basic text widget which has a vertical scroll bar configured to do the "right thing." Using the :class:`ScrolledText` class is a lot easier than setting up a text widget and scroll bar directly. -The text widget and scrollbar are packed together in a :class:`Frame`, and the -methods of the :class:`Grid` and :class:`Pack` geometry managers are acquired -from the :class:`Frame` object. This allows the :class:`ScrolledText` widget to -be used directly to achieve most normal geometry management behavior. +The text widget and scrollbar are packed together in a :class:`~tkinter.Frame`, +and the methods of the :class:`~tkinter.Pack`, :class:`~tkinter.Grid` and +:class:`~tkinter.Place` geometry managers are acquired from the +:class:`~tkinter.Frame` object. +This allows the :class:`ScrolledText` widget to be used directly to achieve +most normal geometry management behavior. Should more specific control be necessary, the following attributes are available: diff --git a/Doc/library/tkinter.ttk.rst b/Doc/library/tkinter.ttk.rst index e1383e189a31a2..9d90770a5840ee 100644 --- a/Doc/library/tkinter.ttk.rst +++ b/Doc/library/tkinter.ttk.rst @@ -19,6 +19,8 @@ The basic idea for :mod:`!tkinter.ttk` is to separate, to the extent possible, the code implementing a widget's behavior from the code implementing its appearance. +.. versionadded:: 3.1 + .. seealso:: @@ -44,12 +46,12 @@ That code causes several :mod:`!tkinter.ttk` widgets (:class:`Button`, :class:`Radiobutton`, :class:`Scale` and :class:`Scrollbar`) to automatically replace the Tk widgets. -This has the direct benefit of using the new widgets which gives a better -look and feel across platforms; however, the replacement widgets are not -completely compatible. The main difference is that widget options such as -"fg", "bg" and others related to widget styling are no -longer present in Ttk widgets. Instead, use the :class:`ttk.Style` class -for improved styling effects. +This has the direct benefit of using the new widgets which gives a better look +and feel across platforms; however, the replacement widgets are not completely +compatible. +The main difference is that widget options such as "fg", "bg" and others +related to widget styling are no longer present in Ttk widgets. +Instead, use the :class:`ttk.Style <Style>` class for improved styling effects. .. seealso:: @@ -59,7 +61,7 @@ for improved styling effects. encountered when moving applications to use the new widgets. -Ttk Widgets +Ttk widgets ----------- Ttk comes with 18 widgets, twelve of which already existed in tkinter: @@ -93,14 +95,14 @@ documentation. Widget ------ -:class:`ttk.Widget` defines standard options and methods supported by Tk -themed widgets and is not supposed to be directly instantiated. +:class:`ttk.Widget <Widget>` defines standard options and methods supported by +Tk themed widgets and is not supposed to be directly instantiated. -Standard Options +Standard options ^^^^^^^^^^^^^^^^ -All the :mod:`ttk` Widgets accept the following options: +All the :mod:`!ttk` Widgets accept the following options: .. tabularcolumns:: |l|L| @@ -116,7 +118,7 @@ All the :mod:`ttk` Widgets accept the following options: +-----------+--------------------------------------------------------------+ | cursor | Specifies the mouse cursor to be used for the widget. If set | | | to the empty string (the default), the cursor is inherited | -| | for the parent widget. | +| | from the parent widget. | +-----------+--------------------------------------------------------------+ | takefocus | Determines whether the window accepts the focus during | | | keyboard traversal. 0, 1 or an empty string is returned. | @@ -131,7 +133,7 @@ All the :mod:`ttk` Widgets accept the following options: +-----------+--------------------------------------------------------------+ -Scrollable Widget Options +Scrollable widget options ^^^^^^^^^^^^^^^^^^^^^^^^^ The following options are supported by widgets that are controlled by a @@ -144,20 +146,20 @@ scrollbar. +================+=========================================================+ | xscrollcommand | Used to communicate with horizontal scrollbars. | | | | -| | When the view in the widget's window change, the widget | -| | will generate a Tcl command based on the scrollcommand. | +| | When the view in the widget's window changes, the widget| +| | calls the *xscrollcommand* callback. | | | | | | Usually this option consists of the method | -| | :meth:`Scrollbar.set` of some scrollbar. This will cause| -| | the scrollbar to be updated whenever the view in the | -| | window changes. | +| | :meth:`Scrollbar.set <tkinter.Scrollbar.set>` of some | +| | scrollbar. This will cause the scrollbar to be updated | +| | whenever the view in the window changes. | +----------------+---------------------------------------------------------+ | yscrollcommand | Used to communicate with vertical scrollbars. | | | For some more information, see above. | +----------------+---------------------------------------------------------+ -Label Options +Label options ^^^^^^^^^^^^^ The following options are supported by labels, buttons and other button-like @@ -203,7 +205,7 @@ widgets. +--------------+-----------------------------------------------------------+ -Compatibility Options +Compatibility options ^^^^^^^^^^^^^^^^^^^^^ .. tabularcolumns:: |l|L| @@ -217,7 +219,7 @@ Compatibility Options | | affect this option. | +--------+----------------------------------------------------------------+ -Widget States +Widget states ^^^^^^^^^^^^^ The widget state is a bitmap of independent state flags. @@ -258,8 +260,9 @@ an exclamation point indicating that the bit is off. ttk.Widget ^^^^^^^^^^ -Besides the methods described below, the :class:`ttk.Widget` supports the -methods :meth:`tkinter.Widget.cget` and :meth:`tkinter.Widget.configure`. +Besides the methods described below, the :class:`ttk.Widget <Widget>` supports +the methods :meth:`tkinter.Widget.cget <tkinter.Misc.cget>` and +:meth:`tkinter.Widget.configure <tkinter.Misc.configure>`. .. class:: Widget @@ -292,16 +295,19 @@ methods :meth:`tkinter.Widget.cget` and :meth:`tkinter.Widget.configure`. Combobox -------- -The :class:`ttk.Combobox` widget combines a text field with a pop-down list of -values. This widget is a subclass of :class:`Entry`. +The :class:`ttk.Combobox <Combobox>` widget combines a text field with a +pop-down list of values. +This widget is a subclass of :class:`Entry`. -Besides the methods inherited from :class:`Widget`: :meth:`Widget.cget`, -:meth:`Widget.configure`, :meth:`Widget.identify`, :meth:`Widget.instate` -and :meth:`Widget.state`, and the following inherited from :class:`Entry`: -:meth:`Entry.bbox`, :meth:`Entry.delete`, :meth:`Entry.icursor`, -:meth:`Entry.index`, :meth:`Entry.insert`, :meth:`Entry.selection`, -:meth:`Entry.xview`, it has some other methods, described at -:class:`ttk.Combobox`. +Besides the methods inherited from :class:`Widget`: :meth:`~tkinter.Misc.cget`, +:meth:`~tkinter.Misc.configure`, :meth:`~Widget.identify`, +:meth:`~Widget.instate` and :meth:`~Widget.state`, and the following inherited +from :class:`Entry`: :meth:`~Entry.bbox`, :meth:`~tkinter.Entry.delete`, +:meth:`~tkinter.Entry.icursor`, :meth:`~tkinter.Entry.index`, +:meth:`~tkinter.Entry.insert`, +:meth:`selection* <tkinter.Entry.selection_adjust>`, +:meth:`xview* <tkinter.XView.xview>`, it has some other methods, described at +:class:`ttk.Combobox <Combobox>`. Options @@ -315,7 +321,7 @@ This widget accepts the following specific options: | Option | Description | +=================+========================================================+ | exportselection | Boolean value. If set, the widget selection is linked | -| | to the Window Manager selection (which can be returned | +| | to the X selection (which can be returned | | | by invoking Misc.selection_get, for example). | +-----------------+--------------------------------------------------------+ | justify | Specifies how the text is aligned within the widget. | @@ -329,7 +335,7 @@ This widget accepts the following specific options: +-----------------+--------------------------------------------------------+ | state | One of "normal", "readonly", or "disabled". In the | | | "readonly" state, the value may not be edited directly,| -| | and the user can only selection of the values from the | +| | and the user can only select one of the values from the| | | dropdown list. In the "normal" state, the text field is| | | directly editable. In the "disabled" state, no | | | interaction is possible. | @@ -347,6 +353,11 @@ This widget accepts the following specific options: | | widget's font. | +-----------------+--------------------------------------------------------+ +.. note:: + + Tk 9.1 added the *locale* option, which selects the locale used to determine + word and character boundaries within the text (``"C"`` by default). + Virtual events ^^^^^^^^^^^^^^ @@ -379,16 +390,18 @@ ttk.Combobox Spinbox ------- -The :class:`ttk.Spinbox` widget is a :class:`ttk.Entry` enhanced with increment -and decrement arrows. It can be used for numbers or lists of string values. -This widget is a subclass of :class:`Entry`. -Besides the methods inherited from :class:`Widget`: :meth:`Widget.cget`, -:meth:`Widget.configure`, :meth:`Widget.identify`, :meth:`Widget.instate` -and :meth:`Widget.state`, and the following inherited from :class:`Entry`: -:meth:`Entry.bbox`, :meth:`Entry.delete`, :meth:`Entry.icursor`, -:meth:`Entry.index`, :meth:`Entry.insert`, :meth:`Entry.xview`, -it has some other methods, described at :class:`ttk.Spinbox`. +The :class:`ttk.Spinbox <Spinbox>` widget is a :class:`ttk.Entry <Entry>` +enhanced with increment and decrement arrows. +It can be used for numbers or lists of string values. +This widget is a subclass of :class:`Entry`. +Besides the methods inherited from :class:`Widget`: :meth:`~tkinter.Misc.cget`, +:meth:`~tkinter.Misc.configure`, :meth:`~Widget.identify`, +:meth:`~Widget.instate` and :meth:`~Widget.state`, and the following inherited +from :class:`Entry`: :meth:`~Entry.bbox`, :meth:`~tkinter.Entry.delete`, +:meth:`~tkinter.Entry.icursor`, :meth:`~tkinter.Entry.index`, +:meth:`~tkinter.Entry.insert`, :meth:`xview* <tkinter.XView.xview>`, it has +some other methods, described at :class:`ttk.Spinbox <Spinbox>`. Options ^^^^^^^ @@ -448,6 +461,8 @@ ttk.Spinbox .. class:: Spinbox + .. versionadded:: 3.8 + .. method:: get() Returns the current value of the spinbox. @@ -458,6 +473,7 @@ ttk.Spinbox Sets the value of the spinbox to *value*. + Notebook -------- @@ -492,7 +508,7 @@ This widget accepts the following specific options: +---------+----------------------------------------------------------------+ -Tab Options +Tab options ^^^^^^^^^^^ There are also specific options for tabs: @@ -510,7 +526,8 @@ There are also specific options for tabs: | | area. Value is a string containing zero or more of the | | | characters "n", "s", "e" or "w". Each letter refers to a | | | side (north, south, east or west) that the child window will | -| | stick to, as per the :meth:`grid` geometry manager. | +| | stick to, as per the :meth:`grid <tkinter.Grid.grid>` | +| | geometry manager. | +-----------+--------------------------------------------------------------+ | padding | Specifies the amount of extra space to add between the | | | notebook and this pane. Syntax is the same as for the option | @@ -532,11 +549,11 @@ There are also specific options for tabs: +-----------+--------------------------------------------------------------+ -Tab Identifiers +Tab identifiers ^^^^^^^^^^^^^^^ -The tab_id present in several methods of :class:`ttk.Notebook` may take any -of the following forms: +The tab_id present in several methods of :class:`ttk.Notebook <Notebook>` may +take any of the following forms: * An integer between zero and the number of tabs * The name of a child window @@ -546,7 +563,7 @@ of the following forms: :meth:`Notebook.index`) -Virtual Events +Virtual events ^^^^^^^^^^^^^^ This widget generates a **<<NotebookTabChanged>>** virtual event after a new @@ -626,7 +643,7 @@ ttk.Notebook .. method:: tabs() - Returns a list of windows managed by the notebook. + Returns a tuple of windows managed by the notebook. .. method:: enable_traversal() @@ -642,16 +659,18 @@ ttk.Notebook select that tab. Multiple notebooks in a single toplevel may be enabled for traversal, - including nested notebooks. However, notebook traversal only works - properly if all panes have the notebook they are in as master. + including nested notebooks. + However, notebook traversal only works properly if all panes are direct + children of the notebook. Progressbar ----------- -The :class:`ttk.Progressbar` widget shows the status of a long-running -operation. It can operate in two modes: 1) the determinate mode which shows the -amount completed relative to the total amount of work to be done and 2) the +The :class:`ttk.Progressbar <Progressbar>` widget shows the status of a +long-running operation. +It can operate in two modes: 1) the determinate mode which shows the amount +completed relative to the total amount of work to be done and 2) the indeterminate mode which provides an animated display to let the user know that work is progressing. @@ -721,10 +740,11 @@ ttk.Progressbar Separator --------- -The :class:`ttk.Separator` widget displays a horizontal or vertical separator -bar. +The :class:`ttk.Separator <Separator>` widget displays a horizontal or vertical +separator bar. -It has no other methods besides the ones inherited from :class:`ttk.Widget`. +It has no other methods besides the ones inherited from +:class:`ttk.Widget <Widget>`. Options @@ -745,11 +765,12 @@ This widget accepts the following specific option: Sizegrip -------- -The :class:`ttk.Sizegrip` widget (also known as a grow box) allows the user to -resize the containing toplevel window by pressing and dragging the grip. +The :class:`ttk.Sizegrip <Sizegrip>` widget (also known as a grow box) allows +the user to resize the containing toplevel window by pressing and dragging the +grip. This widget has neither specific options nor specific methods, besides the -ones inherited from :class:`ttk.Widget`. +ones inherited from :class:`ttk.Widget <Widget>`. Platform-specific notes @@ -764,18 +785,19 @@ Bugs ^^^^ * If the containing toplevel's position was specified relative to the right - or bottom of the screen (e.g. ....), the :class:`Sizegrip` widget will - not resize the window. + or bottom of the screen (for example, ....), the :class:`Sizegrip` widget + will not resize the window. * This widget supports only "southeast" resizing. Treeview -------- -The :class:`ttk.Treeview` widget displays a hierarchical collection of items. +The :class:`ttk.Treeview <Treeview>` widget displays a hierarchical collection +of items. Each item has a textual label, an optional image, and an optional list of data -values. The data values are displayed in successive columns after the tree -label. +values. +The data values are displayed in successive columns after the tree label. The order in which data values are displayed may be controlled by setting the widget option ``displaycolumns``. The tree widget can also display column @@ -837,15 +859,25 @@ This widget accepts the following specific options: | | * tree: display tree labels in column #0. | | | * headings: display the heading row. | | | | -| | The default is "tree headings", i.e., show all | +| | The default is "tree headings", that is, show all | | | elements. | | | | | | **Note**: Column #0 always refers to the tree column, | | | even if show="tree" is not specified. | +----------------+--------------------------------------------------------+ +.. note:: + + Tk 9.0 added several :class:`Treeview` features. + The *selectmode* option gained the values ``"single"`` and ``"multiple"``; + the new widget options *selecttype* (``"item"`` or ``"cell"`` selection), + *striped* (zebra-striped rows), and *titlecolumns* / *titleitems* (columns + or rows frozen against scrolling) were introduced; and items gained a + *hidden* option. + Tk 9.1 added the *rowheight* and *headingheight* options. + -Item Options +Item options ^^^^^^^^^^^^ The following item options may be specified for items in the insert and item @@ -874,7 +906,7 @@ widget commands. +--------+---------------------------------------------------------------+ -Tag Options +Tag options ^^^^^^^^^^^ The following options may be specified on tags: @@ -895,7 +927,7 @@ The following options may be specified on tags: +------------+-----------------------------------------------------------+ -Column Identifiers +Column identifiers ^^^^^^^^^^^^^^^^^^ Column identifiers take any of the following forms: @@ -919,7 +951,7 @@ then data column n is displayed in column #n+1. Again, **column #0 always refers to the tree column**. -Virtual Events +Virtual events ^^^^^^^^^^^^^^ The Treeview widget generates the following virtual events. @@ -953,20 +985,20 @@ ttk.Treeview the specified *item* in the form (x, y, width, height). If *column* is specified, returns the bounding box of that cell. If the - *item* is not visible (i.e., if it is a descendant of a closed item or is - scrolled offscreen), returns an empty string. + *item* is not visible (that is, if it is a descendant of a closed item + or is scrolled offscreen), returns an empty string. .. method:: get_children(item=None) - Returns the list of children belonging to *item*. + Returns a tuple of children belonging to *item*. If *item* is not specified, returns root children. .. method:: set_children(item, *newchildren) - Replaces *item*'s child with *newchildren*. + Replaces *item*'s children with *newchildren*. Children present in *item* that are not present in *newchildren* are detached from the tree. No items in *newchildren* may be an ancestor of @@ -1020,7 +1052,8 @@ ttk.Treeview .. method:: exists(item) - Returns ``True`` if the specified *item* is present in the tree. + Returns ``True`` if the specified *item* is present in the tree, + ``False`` otherwise. .. method:: focus(item=None) @@ -1066,7 +1099,7 @@ ttk.Treeview .. method:: identify_column(x) - Returns the data column identifier of the cell at position *x*. + Returns the display column identifier of the cell at position *x*. The tree column has ID #0. @@ -1129,6 +1162,9 @@ ttk.Treeview Otherwise, sets the options to the corresponding values as given by *kw*. + .. method:: reattach(item, parent, index) + :no-typesetting: + .. method:: move(item, parent, index) Moves *item* to position *index* in *parent*'s list of children. @@ -1138,6 +1174,8 @@ ttk.Treeview than or equal to the number of children, it is moved to the end. If *item* was detached it is reattached. + :meth:`reattach` is an alias of :meth:`!move`. + .. method:: next(item) @@ -1157,11 +1195,6 @@ ttk.Treeview the first child of its parent. - .. method:: reattach(item, parent, index) - - An alias for :meth:`Treeview.move`. - - .. method:: see(item) Ensure that *item* is visible. @@ -1239,9 +1272,9 @@ ttk.Treeview .. method:: tag_has(tagname, item=None) - If *item* is specified, returns 1 or 0 depending on whether the specified - *item* has the given *tagname*. Otherwise, returns a list of all items - that have the specified tag. + If *item* is specified, returns ``True`` if the specified *item* has the + given *tagname* and ``False`` otherwise. + Otherwise, returns a tuple of all items that have the specified tag. Availability: Tk 8.6 @@ -1258,15 +1291,16 @@ ttk.Treeview .. _TtkStyling: -Ttk Styling +Ttk styling ----------- -Each widget in :mod:`ttk` is assigned a style, which specifies the set of -elements making up the widget and how they are arranged, along with dynamic -and default settings for element options. By default the style name is the -same as the widget's class name, but it may be overridden by the widget's style -option. If you don't know the class name of a widget, use the method -:meth:`Misc.winfo_class` (somewidget.winfo_class()). +Each widget in :mod:`!ttk` is assigned a style, which specifies the set of +elements making up the widget and how they are arranged, along with dynamic and +default settings for element options. +By default the style name is the same as the widget's class name, but it may be +overridden by the widget's style option. +If you don't know the class name of a widget, use the method +:meth:`Misc.winfo_class <tkinter.Misc.winfo_class>` (somewidget.winfo_class()). .. seealso:: @@ -1335,6 +1369,12 @@ option. If you don't know the class name of a widget, use the method 'red')]`` in the foreground option, for example, the result would be a blue foreground when the widget were in active or pressed states. + When called to query the map (without specifying values to set), it + returns a dictionary mapping each option to its list of statespecs. + + .. versionchanged:: 3.10 + The value returned when querying the map was corrected. + .. method:: lookup(style, option, state=None, default=None) @@ -1498,12 +1538,12 @@ option. If you don't know the class name of a widget, use the method .. method:: element_names() - Returns the list of elements defined in the current theme. + Returns a tuple of elements defined in the current theme. .. method:: element_options(elementname) - Returns the list of *elementname*'s options. + Returns a tuple of *elementname*'s options. .. method:: theme_create(themename, parent=None, settings=None) @@ -1555,7 +1595,7 @@ option. If you don't know the class name of a widget, use the method .. method:: theme_names() - Returns a list of all known themes. + Returns a tuple of all known themes. .. method:: theme_use(themename=None) @@ -1594,3 +1634,252 @@ The valid options/values are: the layout name, and the other is a `Layout`_. .. _Layout: `Layouts`_ + + +Additional widgets +------------------ + +The following themed widgets complete the :mod:`tkinter.ttk` widget set. +Each is the themed counterpart of the like-named classic :mod:`tkinter` widget +and inherits the common methods of :class:`Widget`. + +.. class:: Button(master=None, **kw) + + Ttk :class:`Button` widget, displays a textual label and/or image, and + evaluates a command when pressed. + It is the themed counterpart of :class:`tkinter.Button` and inherits the + common widget methods from :class:`Widget`. + + .. method:: invoke() + + Invoke the command associated with the button and return its result. + + +.. class:: Checkbutton(master=None, **kw) + + Ttk :class:`Checkbutton` widget, used to control a boolean variable that is + toggled on and off. + It is the themed counterpart of :class:`tkinter.Checkbutton` and inherits + the common widget methods from :class:`Widget`. + + .. method:: invoke() + + Toggle the button between its selected and deselected states, invoke the + command associated with the button, and return its result. + + +.. class:: Entry(master=None, widget=None, **kw) + + Ttk :class:`Entry` widget, displays a one-line text string and allows the + user to edit it. + It is the themed counterpart of :class:`tkinter.Entry` and inherits the + common widget methods from :class:`Widget` as well as the editing methods + from :class:`tkinter.Entry`. + + .. method:: bbox(index) + + Return a tuple ``(x, y, width, height)`` giving the bounding box of the + character at the given *index*. + + .. method:: identify(x, y) + + Return the name of the element under the point given by *x* and *y*, or + the empty string if no element is present at that location. + + .. method:: validate() + + Force validation of the entry and return ``True`` if validation + succeeded, and ``False`` otherwise. + + +.. class:: Frame(master=None, **kw) + + Ttk :class:`Frame` widget, a container used to group and lay out other + widgets. + It is the themed counterpart of :class:`tkinter.Frame` and inherits the + common widget methods from :class:`Widget`. + + +.. class:: Label(master=None, **kw) + + Ttk :class:`Label` widget, displays a textual label and/or image. + It is the themed counterpart of :class:`tkinter.Label` and inherits the + common widget methods from :class:`Widget`. + + +.. class:: Labelframe(master=None, **kw) + + Ttk :class:`Labelframe` widget, a container that draws a border and a title + label around its contents. + It is the themed counterpart of :class:`tkinter.LabelFrame` and inherits the + common widget methods from :class:`Widget`. + + +.. class:: Menubutton(master=None, **kw) + + Ttk :class:`Menubutton` widget, displays a textual label and/or image, and + pops up a menu when pressed. + It is the themed counterpart of :class:`tkinter.Menubutton` and inherits the + common widget methods from :class:`Widget`. + + +.. class:: OptionMenu(master, variable, default=None, *values, **kwargs) + + Ttk :class:`OptionMenu` widget, a :class:`Menubutton` that pops up a menu of + mutually exclusive choices. + *variable* is the variable that tracks the currently selected value, + *default* is the value to set initially, and *values* are the entries to + display in the menu. + A *command* keyword argument may be given to specify a callable that is + invoked with the selected value whenever the selection changes; the *style* + keyword argument sets the style used by the underlying menubutton; and the + *name* keyword argument sets the Tk widget name. + + .. method:: set_menu(default=None, *values) + + Replace the entries of the menu with *values*. + If *default* is given, also set it as the current value of the + *variable*. + + .. method:: destroy() + + Destroy this widget and its associated menu. + + .. versionchanged:: 3.14 + Added support for the *name* keyword argument. + + + +.. class:: Panedwindow(master=None, **kw) + + Ttk :class:`Panedwindow` widget, displays a number of subwindows stacked + either vertically or horizontally. + The user may adjust the relative sizes of the subwindows by dragging the + sash between panes. + It is the themed counterpart of :class:`tkinter.PanedWindow` and inherits + the common widget methods from :class:`Widget`, as well as the :meth:`!add` + and :meth:`!panes` methods from :class:`tkinter.PanedWindow`. + + .. method:: insert(pos, child, **kw) + + Insert a pane containing *child* at the position *pos*. + *pos* is either the string ``'end'``, an integer index, or the name of a + managed subwindow. + If *child* is already managed by the paned window, move it to the + specified position. + Any keyword arguments set pane options. + + .. method:: forget(child) + + Remove *child*, which may be either an integer index or the name of a + managed subwindow, from the panes. + + .. method:: pane(pane, option=None, **kw) + + Query or modify the options of the specified *pane*, where *pane* is + either an integer index or the name of a managed subwindow. + If no arguments are given, return a dictionary of the pane option values. + If *option* is specified, return the value of that option. + Otherwise, set the options given as keyword arguments to their + corresponding values. + + .. method:: sashpos(index, newpos=None) + + If *newpos* is specified, set the position of sash number *index* and + return its new position. + This may adjust the positions of adjacent sashes to ensure that positions + are monotonically increasing; positions are also constrained to be + between 0 and the total size of the widget. + If *newpos* is omitted, return the current position of the sash. + + +.. class:: Radiobutton(master=None, **kw) + + Ttk :class:`Radiobutton` widget, used as part of a group to control a single + shared variable by selecting one of several mutually exclusive values. + It is the themed counterpart of :class:`tkinter.Radiobutton` and inherits + the common widget methods from :class:`Widget`. + + .. method:: invoke() + + Set the option variable to the button's value, select the button, invoke + the command associated with the button, and return its result. + + +.. class:: Scale(master=None, **kw) + + Ttk :class:`Scale` widget, displays a slider that lets the user select a + numeric value from a range by moving the slider along a trough. + It is the themed counterpart of :class:`tkinter.Scale` and inherits the + common widget methods from :class:`Widget`. + + .. method:: configure(cnf=None, **kw) + + Modify or query the widget options, like + :meth:`Widget.configure <tkinter.Misc.configure>`. + In addition, this method clips the ``from`` and ``to`` values so that the + current value stays within the range defined by them. + + .. versionchanged:: 3.9 + Now returns the configuration value, like + :meth:`Widget.configure <tkinter.Misc.configure>`. + + + .. method:: get(x=None, y=None) + + Return the current value of the scale. + If *x* and *y* are given, return the value corresponding to the pixel + coordinate *x*, *y* instead. + + +.. class:: Scrollbar(master=None, **kw) + + Ttk :class:`Scrollbar` widget, controls the viewport of an associated + scrollable widget such as a :class:`Treeview`, :class:`Entry` or + :class:`tkinter.Text`. + It is the themed counterpart of :class:`tkinter.Scrollbar` and inherits the + common widget methods from :class:`Widget`, as well as the :meth:`!set` and + :meth:`!get` methods from :class:`tkinter.Scrollbar`. + + +.. class:: Separator(master=None, **kw) + + Ttk :class:`Separator` widget, displays a horizontal or vertical separator + line. + It has no direct counterpart in :mod:`tkinter` and inherits the common + widget methods from :class:`Widget`. + + +.. class:: Sizegrip(master=None, **kw) + + Ttk :class:`Sizegrip` widget, displays a grip that allows the user to resize + the containing toplevel window by pressing and dragging the grip, typically + placed in the bottom-right corner. + It has no direct counterpart in :mod:`tkinter` and inherits the common + widget methods from :class:`Widget`. + + +.. class:: LabeledScale(master=None, variable=None, from_=0, to=10, **kw) + + A :class:`Frame` containing a :class:`Scale` and a :class:`Label` that shows + the scale's current value. + *variable* is the :class:`~tkinter.IntVar` tracked by the scale (one is + created if it is not given), and *from_* and *to* define the range of the + scale. + + .. method:: destroy() + + Destroy this widget and remove the trace callback registered on the + associated variable. + + +.. class:: LabelFrame(master=None, **kw) + + Alias of :class:`Labelframe`, kept for naming compatibility with + :class:`tkinter.LabelFrame`. + + +.. class:: PanedWindow(master=None, **kw) + + Alias of :class:`Panedwindow`, kept for naming compatibility with + :class:`tkinter.PanedWindow`. diff --git a/Doc/tools/.nitignore b/Doc/tools/.nitignore index aa08f7acb99197..51ce9b66fadc7f 100644 --- a/Doc/tools/.nitignore +++ b/Doc/tools/.nitignore @@ -26,9 +26,6 @@ Doc/library/socket.rst Doc/library/ssl.rst Doc/library/termios.rst Doc/library/test.rst -Doc/library/tkinter.rst -Doc/library/tkinter.scrolledtext.rst -Doc/library/tkinter.ttk.rst Doc/library/urllib.parse.rst Doc/library/urllib.request.rst Doc/library/wsgiref.rst diff --git a/Misc/NEWS.d/next/Documentation/2026-06-17-12-00-00.gh-issue-86726.__bOgH.rst b/Misc/NEWS.d/next/Documentation/2026-06-17-12-00-00.gh-issue-86726.__bOgH.rst new file mode 100644 index 00000000000000..787b95dbf23627 --- /dev/null +++ b/Misc/NEWS.d/next/Documentation/2026-06-17-12-00-00.gh-issue-86726.__bOgH.rst @@ -0,0 +1,4 @@ +Greatly expand the :mod:`tkinter` documentation to cover the full public API +of the package and its submodules. The descriptions are oriented towards +Python rather than Tcl/Tk, with corrected return types and +``versionadded``/``versionchanged`` information. From 0125168a81a9781561d231be37f18031cdb21ba8 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 18 Jun 2026 15:44:12 +0200 Subject: [PATCH 357/818] [3.15] gh-86726: Fix "deprecated" directive for wm_attributes (GH-151652) (GH-151654) (cherry picked from commit d47c27e47a6c6969737616f2f58036a5f536e60a) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> --- Doc/library/tkinter.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/tkinter.rst b/Doc/library/tkinter.rst index 6e26698d751226..5c40eadcf49c7c 100644 --- a/Doc/library/tkinter.rst +++ b/Doc/library/tkinter.rst @@ -2458,7 +2458,7 @@ Base and mixin classes ``-``, and attributes may be set using keyword arguments. The *return_python_dict* parameter was added. - .. deprecated:: next + .. deprecated:: 3.13 Setting an attribute by passing the option name (with a leading ``-``) and its value as two positional arguments, as in ``w.attributes('-alpha', 0.5)``, is deprecated; use keyword arguments From 821e97b999e2f1857921cf944adf86c815d1a599 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 18 Jun 2026 16:44:51 +0200 Subject: [PATCH 358/818] [3.15] gh-86726: Fix the documented return type of tkinter info_patchlevel() (GH-151655) (GH-151658) It returns a sys.version_info-like named tuple, not a string. (cherry picked from commit 3cd02a1c2da023974464fd1155982a16474f331b) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --- Doc/library/tkinter.rst | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Doc/library/tkinter.rst b/Doc/library/tkinter.rst index 5c40eadcf49c7c..8507656e50fa33 100644 --- a/Doc/library/tkinter.rst +++ b/Doc/library/tkinter.rst @@ -2333,7 +2333,13 @@ Base and mixin classes .. method:: info_patchlevel() - Return the Tcl/Tk patch level as a string, for example ``'9.1.0'``. + Return the Tcl/Tk patch level as a named tuple with the same five fields + as :data:`sys.version_info`: *major*, *minor*, *micro*, *releaselevel* + and *serial*. + *releaselevel* is ``'alpha'``, ``'beta'`` or ``'final'``. + Converting it to a string gives the version in the usual Tcl/Tk notation, + for example ``'9.0.3'`` for a final release or ``'9.1b2'`` for a + pre-release. .. versionadded:: 3.11 From cafe39f78acd82dac81ea7b443ebe3c73be48242 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 18 Jun 2026 17:56:14 +0200 Subject: [PATCH 359/818] [3.15] gh-86726: Add few missing versionadded directives (GH-151662) (GH-151663) Pack.pack_content, Place.place_content and Grid.grid_content were added in 3.15. (cherry picked from commit bfecfcc2a860071c8e5022ac512bde94e0fb5f76) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> --- Doc/library/tkinter.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Doc/library/tkinter.rst b/Doc/library/tkinter.rst index 8507656e50fa33..b0421721bf8d7e 100644 --- a/Doc/library/tkinter.rst +++ b/Doc/library/tkinter.rst @@ -2979,6 +2979,8 @@ Base and mixin classes Same as :meth:`Misc.pack_content`. :meth:`content` is an alias of :meth:`!pack_content`. + .. versionadded:: 3.15 + .. class:: Place() @@ -3073,6 +3075,8 @@ Base and mixin classes Same as :meth:`Misc.place_content`. :meth:`content` is an alias of :meth:`!place_content`. + .. versionadded:: 3.15 + .. class:: Grid() @@ -3221,6 +3225,8 @@ Base and mixin classes Same as :meth:`Misc.grid_content`. :meth:`content` is an alias of :meth:`!grid_content`. + .. versionadded:: 3.15 + .. class:: XView() From fd3c510827d5bc0f92571754ee7495078fc60086 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 18 Jun 2026 19:39:20 +0200 Subject: [PATCH 360/818] [3.15] gh-146353: Document `PyBytesWriter_GetData` pointer validity (GH-151418) (GH-151664) gh-146353: Document `PyBytesWriter_GetData` pointer validity (GH-151418) (cherry picked from commit e99b319682fe984074e32f52354dbec23ded4d0a) Co-authored-by: Harjoth Khara <harjoth.khara@gmail.com> --- Doc/c-api/bytes.rst | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Doc/c-api/bytes.rst b/Doc/c-api/bytes.rst index f56bcd6333a37d..fa77d3d38ff89f 100644 --- a/Doc/c-api/bytes.rst +++ b/Doc/c-api/bytes.rst @@ -384,14 +384,18 @@ Getters Get the writer size. + The function does not invalidate pointers returned by + :c:func:`PyBytesWriter_GetData`. + The function cannot fail. .. c:function:: void* PyBytesWriter_GetData(PyBytesWriter *writer) Get the writer data: start of the internal buffer. - The pointer is valid until :c:func:`PyBytesWriter_Finish` or - :c:func:`PyBytesWriter_Discard` is called on *writer*. + The pointer remains valid until a :c:type:`PyBytesWriter` function other + than :c:func:`PyBytesWriter_GetData` or :c:func:`PyBytesWriter_GetSize` is + called on *writer*. The function cannot fail. From 3b38caf2fef2bd0a2a355fa43459f01e668eb9bc Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 19 Jun 2026 09:34:16 +0200 Subject: [PATCH 361/818] [3.15] gh-101100: Document os.uname_result and os.statvfs_result with related constants (GH-151301) (GH-151692) (cherry picked from commit 9688d252d330b0b586760a121ee8c8f7215176e8) Co-authored-by: Cody Maloney <cmaloney@users.noreply.github.com> --- Doc/library/os.rst | 251 +++++++++++++++++++++++++++++++-------- Doc/tools/.nitignore | 1 - Misc/NEWS.d/3.10.0a4.rst | 2 +- Misc/NEWS.d/3.12.0a3.rst | 4 +- 4 files changed, 204 insertions(+), 54 deletions(-) diff --git a/Doc/library/os.rst b/Doc/library/os.rst index b65dbb4623af2a..edf9169a9c8003 100644 --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -800,29 +800,19 @@ process and user. single: gethostbyaddr() (in module socket) Returns information identifying the current operating system. - The return value is an object with five attributes: - - * :attr:`sysname` - operating system name - * :attr:`nodename` - name of machine on network (implementation-defined) - * :attr:`release` - operating system release - * :attr:`version` - operating system version - * :attr:`machine` - hardware identifier - - For backwards compatibility, this object is also iterable, behaving - like a five-tuple containing :attr:`sysname`, :attr:`nodename`, - :attr:`release`, :attr:`version`, and :attr:`machine` - in that order. - - Some systems truncate :attr:`nodename` to 8 characters or to the - leading component; a better way to get the hostname is - :func:`socket.gethostname` or even - ``socket.gethostbyaddr(socket.gethostname())``. + The return value is a :class:`uname_result`. On macOS, iOS and Android, this returns the *kernel* name and version (i.e., ``'Darwin'`` on macOS and iOS; ``'Linux'`` on Android). :func:`platform.uname` can be used to get the user-facing operating system name and version on iOS and Android. + .. seealso:: + :data:`sys.platform` which has finer granularity. + + The :mod:`platform` module provides detailed checks for the + system's identity. + .. availability:: Unix. .. versionchanged:: 3.3 @@ -830,6 +820,41 @@ process and user. with named attributes. +.. class:: uname_result + + Name and information about the system returned by :func:`os.uname`. + These attributes correspond to the members described in :manpage:`uname(2)`. + + For backwards compatibility, this object is also iterable, behaving + like a five-tuple containing :attr:`~uname_result.sysname`, + :attr:`~uname_result.nodename`, :attr:`~uname_result.release`, + :attr:`~uname_result.version`, and :attr:`~uname_result.machine` + in that order. + + .. attribute:: sysname + + Operating system name. + + .. attribute:: nodename + + Name of machine on network. Some systems truncate + :attr:`~uname_result.nodename` to 8 characters or to the leading + component; a better way to get the hostname is :func:`socket.gethostname` + or even ``socket.gethostbyaddr(socket.gethostname())``. + + .. attribute:: release + + Operating system release. + + .. attribute:: version + + Operating system version. + + .. attribute:: machine + + Hardware identifier. + + .. function:: unsetenv(key, /) .. index:: single: environment variables; deleting @@ -1112,8 +1137,8 @@ as internal buffering of data. .. function:: fstatvfs(fd, /) Return information about the filesystem containing the file associated with - file descriptor *fd*, like :func:`statvfs`. As of Python 3.3, this is - equivalent to ``os.statvfs(fd)``. + file descriptor *fd* in a :class:`statvfs_result`, like :func:`statvfs`. + As of Python 3.3, this is equivalent to ``os.statvfs(fd)``. .. availability:: Unix. @@ -3784,48 +3809,174 @@ features: .. function:: statvfs(path) - Perform a :c:func:`!statvfs` system call on the given path. The return value is - an object whose attributes describe the filesystem on the given path, and - correspond to the members of the :c:struct:`statvfs` structure, namely: - :attr:`f_bsize`, :attr:`f_frsize`, :attr:`f_blocks`, :attr:`f_bfree`, - :attr:`f_bavail`, :attr:`f_files`, :attr:`f_ffree`, :attr:`f_favail`, - :attr:`f_flag`, :attr:`f_namemax`, :attr:`f_fsid`. - - Two module-level constants are defined for the :attr:`f_flag` attribute's - bit-flags: if :const:`ST_RDONLY` is set, the filesystem is mounted - read-only, and if :const:`ST_NOSUID` is set, the semantics of - setuid/setgid bits are disabled or not supported. - - Additional module-level constants are defined for GNU/glibc based systems. - These are :const:`ST_NODEV` (disallow access to device special files), - :const:`ST_NOEXEC` (disallow program execution), :const:`ST_SYNCHRONOUS` - (writes are synced at once), :const:`ST_MANDLOCK` (allow mandatory locks on an FS), - :const:`ST_WRITE` (write on file/directory/symlink), :const:`ST_APPEND` - (append-only file), :const:`ST_IMMUTABLE` (immutable file), :const:`ST_NOATIME` - (do not update access times), :const:`ST_NODIRATIME` (do not update directory access - times), :const:`ST_RELATIME` (update atime relative to mtime/ctime). + Perform a :manpage:`statvfs(3)` system call on the given path. The return value + is a :class:`statvfs_result` whose attributes describe the filesystem + on the given path and correspond to the members of the :c:struct:`statvfs` + structure. This function can support :ref:`specifying a file descriptor <path_fd>`. .. availability:: Unix. - .. versionchanged:: 3.2 - The :const:`ST_RDONLY` and :const:`ST_NOSUID` constants were added. - .. versionchanged:: 3.3 Added support for specifying *path* as an open file descriptor. - .. versionchanged:: 3.4 - The :const:`ST_NODEV`, :const:`ST_NOEXEC`, :const:`ST_SYNCHRONOUS`, - :const:`ST_MANDLOCK`, :const:`ST_WRITE`, :const:`ST_APPEND`, - :const:`ST_IMMUTABLE`, :const:`ST_NOATIME`, :const:`ST_NODIRATIME`, - and :const:`ST_RELATIME` constants were added. - .. versionchanged:: 3.6 Accepts a :term:`path-like object`. - .. versionchanged:: 3.7 - Added the :attr:`f_fsid` attribute. + +.. class:: statvfs_result + + Filesystem statistics returned by :func:`os.statvfs` and :func:`os.fstatvfs`. + See :manpage:`statvfs(3)` for more details. + + .. attribute:: f_bsize + + Block size. + + .. attribute:: f_frsize + + Fragment size. + + .. attribute:: f_blocks + + Number of :attr:`~statvfs_result.f_frsize` sized blocks the filesystem + can contain. + + .. attribute:: f_bfree + + Number of free blocks. + + .. attribute:: f_bavail + + Number of free blocks for unprivileged users. + + .. attribute:: f_files + + Number of file entries, inodes, the filesystem can contain. + + .. attribute:: f_ffree + + Number of free files entries. + + .. attribute:: f_favail + + Number of free file entries for unprivileged users. + + .. attribute:: f_flag + + Bit-mask of mount flags. The following flags are defined: + :data:`ST_RDONLY`, :data:`ST_NOSUID`, :data:`ST_NODEV`, + :data:`ST_NOEXEC`, :data:`ST_SYNCHRONOUS`, :data:`ST_MANDLOCK`, + :data:`ST_WRITE`, :data:`ST_APPEND`, :data:`ST_IMMUTABLE`, + :data:`ST_NOATIME`, :data:`ST_NODIRATIME`, and :data:`ST_RELATIME`. + + .. attribute:: f_namemax + + Filesystem max filename length. OS specific limitations such as + :ref:`Windows MAX_PATH <max-path>` and those described in Linux + :manpage:`pathname(7)` may exist. + + .. attribute:: f_fsid + + Filesystem ID. + + .. versionadded:: 3.7 + + +The following flags are used in :attr:`statvfs_result.f_flag`. + +.. data:: ST_RDONLY + + Read-only filesystem. + + .. versionadded:: 3.2 + +.. data:: ST_NOSUID + + Setuid/setgid bits are disabled or not supported. + + .. versionadded:: 3.2 + +.. data:: ST_NODEV + + Disallow access to device special files. + + .. availability:: Linux. + + .. versionadded:: 3.4 + +.. data:: ST_NOEXEC + + Disallow program execution. + + .. availability:: Linux. + + .. versionadded:: 3.4 + +.. data:: ST_SYNCHRONOUS + + Writes are synced at once. + + .. availability:: Linux. + + .. versionadded:: 3.4 + +.. data:: ST_MANDLOCK + + Allow mandatory locks on an FS. + + .. availability:: Linux. + + .. versionadded:: 3.4 + +.. data:: ST_WRITE + + Write on file/directory/symlink. + + .. availability:: Linux. + + .. versionadded:: 3.4 + +.. data:: ST_APPEND + + Append-only file. + + .. availability:: Linux. + + .. versionadded:: 3.4 + +.. data:: ST_IMMUTABLE + + Immutable file. + + .. availability:: Linux. + + .. versionadded:: 3.4 + +.. data:: ST_NOATIME + + Do not update access times. + + .. availability:: Linux. + + .. versionadded:: 3.4 + +.. data:: ST_NODIRATIME + + Do not update directory access times. + + .. availability:: Linux. + + .. versionadded:: 3.4 + +.. data:: ST_RELATIME + + Update atime relative to mtime/ctime. + + .. availability:: Linux. + + .. versionadded:: 3.4 .. data:: supports_dir_fd diff --git a/Doc/tools/.nitignore b/Doc/tools/.nitignore index 51ce9b66fadc7f..2255c745c00383 100644 --- a/Doc/tools/.nitignore +++ b/Doc/tools/.nitignore @@ -18,7 +18,6 @@ Doc/library/lzma.rst Doc/library/mmap.rst Doc/library/multiprocessing.rst Doc/library/optparse.rst -Doc/library/os.rst Doc/library/pickletools.rst Doc/library/pyexpat.rst Doc/library/select.rst diff --git a/Misc/NEWS.d/3.10.0a4.rst b/Misc/NEWS.d/3.10.0a4.rst index cd419dfaaee2e8..16eca7a55db746 100644 --- a/Misc/NEWS.d/3.10.0a4.rst +++ b/Misc/NEWS.d/3.10.0a4.rst @@ -622,7 +622,7 @@ Harmonized :func:`random.randrange` argument handling to match :func:`range`. .. nonce: O4VcCY .. section: Library -Restore compatibility for ``uname_result`` around deepcopy and _replace. +Restore compatibility for :class:`os.uname_result` around deepcopy and _replace. .. diff --git a/Misc/NEWS.d/3.12.0a3.rst b/Misc/NEWS.d/3.12.0a3.rst index d2c717afcb6e8d..c71a66757c6566 100644 --- a/Misc/NEWS.d/3.12.0a3.rst +++ b/Misc/NEWS.d/3.12.0a3.rst @@ -454,8 +454,8 @@ event loop but the current event loop was set. .. nonce: humlhz .. section: Library -On ``uname_result``, restored expectation that ``_fields`` and ``_asdict`` -would include all six properties including ``processor``. +On :class:`os.uname_result`, restored expectation that ``_fields`` and +``_asdict`` would include all six properties including ``processor``. .. From 7a5f5f5b6e126ed9f6daa17b9acb82145e92c6f5 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 19 Jun 2026 10:18:49 +0200 Subject: [PATCH 362/818] [3.15] gh-151427: add 'not macOS' and 'not iOS' restrictions on availability state of some functions in `os` module. (GH-151537) (#151699) (cherry picked from commit da69fcf98de500b1e10bdce41a05c904e345d89f) Co-authored-by: Duprat <yduprat@gmail.com> --- Doc/library/os.rst | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/Doc/library/os.rst b/Doc/library/os.rst index edf9169a9c8003..778ab8714e1117 100644 --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -541,7 +541,7 @@ process and user. Return a tuple (ruid, euid, suid) denoting the current process's real, effective, and saved user ids. - .. availability:: Unix, not WASI. + .. availability:: Unix, not WASI, not macOS, not iOS. .. versionadded:: 3.2 @@ -551,7 +551,7 @@ process and user. Return a tuple (rgid, egid, sgid) denoting the current process's real, effective, and saved group ids. - .. availability:: Unix, not WASI. + .. availability:: Unix, not WASI, not macOS, not iOS. .. versionadded:: 3.2 @@ -725,7 +725,7 @@ process and user. Set the current process's real, effective, and saved group ids. - .. availability:: Unix, not WASI, not Android. + .. availability:: Unix, not WASI, not Android, not macOS, not iOS. .. versionadded:: 3.2 @@ -734,7 +734,7 @@ process and user. Set the current process's real, effective, and saved user ids. - .. availability:: Unix, not WASI, not Android. + .. availability:: Unix, not WASI, not Android, not macOS, not iOS. .. versionadded:: 3.2 @@ -1096,10 +1096,7 @@ as internal buffering of data. Force write of file with filedescriptor *fd* to disk. Does not force update of metadata. - .. availability:: Unix. - - .. note:: - This function is not available on MacOS. + .. availability:: Unix, not macOS, not iOS. .. function:: fpathconf(fd, name, /) @@ -1451,7 +1448,7 @@ or `the MSDN <https://msdn.microsoft.com/en-us/library/z0kc8e3z.aspx>`_ on Windo Return a pair of file descriptors ``(r, w)`` usable for reading and writing, respectively. - .. availability:: Unix, not WASI. + .. availability:: Unix, not WASI, not macOS, not iOS. .. versionadded:: 3.3 @@ -1461,7 +1458,7 @@ or `the MSDN <https://msdn.microsoft.com/en-us/library/z0kc8e3z.aspx>`_ on Windo Ensures that enough disk space is allocated for the file specified by *fd* starting from *offset* and continuing for *len* bytes. - .. availability:: Unix. + .. availability:: Unix, not macOS, not iOS. .. versionadded:: 3.3 @@ -1476,7 +1473,7 @@ or `the MSDN <https://msdn.microsoft.com/en-us/library/z0kc8e3z.aspx>`_ on Windo :data:`POSIX_FADV_RANDOM`, :data:`POSIX_FADV_NOREUSE`, :data:`POSIX_FADV_WILLNEED` or :data:`POSIX_FADV_DONTNEED`. - .. availability:: Unix. + .. availability:: Unix, not macOS, not iOS. .. versionadded:: 3.3 @@ -5246,7 +5243,7 @@ written in Python, such as a mail server's external command delivery program. Lock program segments into memory. The value of *op* (defined in ``<sys/lock.h>``) determines which segments are locked. - .. availability:: Unix, not WASI, not iOS. + .. availability:: Unix, not WASI, not macOS, not iOS. .. function:: popen(cmd, mode='r', buffering=-1) From 3135ab811dbe8f72a81aba370b7eb7f08e9913b1 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 19 Jun 2026 10:24:53 +0200 Subject: [PATCH 363/818] [3.15] gh-151436: Fix missing `tstate->last_profiled_frame` updates (GH-151437) (#151612) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gh-151436: Fix missing `tstate->last_profiled_frame` updates (GH-151437) (cherry picked from commit a8d74c062fe3c5cb2962dde8bee83704fcfa1bc9) Co-authored-by: Maurycy Pawłowski-Wieroński <maurycy@maurycy.com> --- Include/internal/pycore_interpframe.h | 14 ++++++++++++++ .../2026-06-13-11-57-48.gh-issue-151436.UEDowO.rst | 4 ++++ Modules/_testinternalcapi/test_cases.c.h | 3 +++ Objects/genobject.c | 3 +++ Python/bytecodes.c | 2 ++ Python/ceval.c | 10 ++-------- Python/executor_cases.c.h | 2 ++ Python/generated_cases.c.h | 3 +++ 8 files changed, 33 insertions(+), 8 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-06-13-11-57-48.gh-issue-151436.UEDowO.rst diff --git a/Include/internal/pycore_interpframe.h b/Include/internal/pycore_interpframe.h index 28370ababc47b9..3fc7c48ddececc 100644 --- a/Include/internal/pycore_interpframe.h +++ b/Include/internal/pycore_interpframe.h @@ -282,6 +282,20 @@ _PyThreadState_GetFrame(PyThreadState *tstate) return _PyFrame_GetFirstComplete(tstate->current_frame); } +// Update last_profiled_frame for remote profiler frame caching. +// Only update if we're removing the exact frame that was last profiled. +// This avoids corrupting the cache when transient frames (called and returned +// between profiler samples) update last_profiled_frame to addresses the +// profiler never saw. +#define _PyThreadState_UpdateLastProfiledFrame(tstate, frame, previous) \ + do { \ + PyThreadState *tstate_ = (tstate); \ + _PyInterpreterFrame *frame_ = (frame); \ + if (tstate_->last_profiled_frame == frame_) { \ + tstate_->last_profiled_frame = (previous); \ + } \ + } while (0) + /* For use by _PyFrame_GetFrameObject Do not call directly. */ PyAPI_FUNC(PyFrameObject *) diff --git a/Misc/NEWS.d/next/Library/2026-06-13-11-57-48.gh-issue-151436.UEDowO.rst b/Misc/NEWS.d/next/Library/2026-06-13-11-57-48.gh-issue-151436.UEDowO.rst new file mode 100644 index 00000000000000..1d1aadbf57be48 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-13-11-57-48.gh-issue-151436.UEDowO.rst @@ -0,0 +1,4 @@ +Fix skewed stack trackes in the Tachyon profiler when caching is enabled and +when generators and coroutines are profiled, by updating +``tstate->last_profiled_frame`` at every frame-removal site. The issue resulted +in total erasure of some callers. Patch by Maurycy Pawłowski-Wieroński. diff --git a/Modules/_testinternalcapi/test_cases.c.h b/Modules/_testinternalcapi/test_cases.c.h index aa4419b323e5b3..12f028618f5c69 100644 --- a/Modules/_testinternalcapi/test_cases.c.h +++ b/Modules/_testinternalcapi/test_cases.c.h @@ -7939,6 +7939,7 @@ gen->gi_exc_state.previous_item = NULL; _Py_LeaveRecursiveCallPy(tstate); _PyInterpreterFrame *gen_frame = frame; + _PyThreadState_UpdateLastProfiledFrame(tstate, gen_frame, gen_frame->previous); frame = tstate->current_frame = frame->previous; gen_frame->previous = NULL; ((_PyThreadStateImpl *)tstate)->generator_return_kind = GENERATOR_YIELD; @@ -11022,6 +11023,7 @@ gen_frame->owner = FRAME_OWNED_BY_GENERATOR; _Py_LeaveRecursiveCallPy(tstate); _PyInterpreterFrame *prev = frame->previous; + _PyThreadState_UpdateLastProfiledFrame(tstate, frame, prev); _PyThreadState_PopFrame(tstate, frame); frame = tstate->current_frame = prev; LOAD_IP(frame->return_offset); @@ -13050,6 +13052,7 @@ gen->gi_exc_state.previous_item = NULL; _Py_LeaveRecursiveCallPy(tstate); _PyInterpreterFrame *gen_frame = frame; + _PyThreadState_UpdateLastProfiledFrame(tstate, gen_frame, gen_frame->previous); frame = tstate->current_frame = frame->previous; gen_frame->previous = NULL; ((_PyThreadStateImpl *)tstate)->generator_return_kind = GENERATOR_YIELD; diff --git a/Objects/genobject.c b/Objects/genobject.c index 38d493343454fc..3cdc06733363d3 100644 --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -168,6 +168,7 @@ gen_clear_frame(PyGenObject *gen) { assert(FT_ATOMIC_LOAD_INT8_RELAXED(gen->gi_frame_state) == FRAME_CLEARED); _PyInterpreterFrame *frame = &gen->gi_iframe; + _PyThreadState_UpdateLastProfiledFrame(_PyThreadState_GET(), frame, frame->previous); frame->previous = NULL; _PyFrame_ClearExceptCode(frame); _PyErr_ClearExcState(&gen->gi_exc_state); @@ -681,6 +682,7 @@ _gen_throw(PyGenObject *gen, int close_on_genexit, 'yield from' or awaiting on with 'await'. */ ret = _gen_throw((PyGenObject *)yf, close_on_genexit, typ, val, tb); + _PyThreadState_UpdateLastProfiledFrame(tstate, frame, prev); tstate->current_frame = prev; frame->previous = NULL; } @@ -701,6 +703,7 @@ _gen_throw(PyGenObject *gen, int close_on_genexit, frame->previous = prev; tstate->current_frame = frame; ret = PyObject_CallFunctionObjArgs(meth, typ, val, tb, NULL); + _PyThreadState_UpdateLastProfiledFrame(tstate, frame, prev); tstate->current_frame = prev; frame->previous = NULL; Py_DECREF(meth); diff --git a/Python/bytecodes.c b/Python/bytecodes.c index c77823b78eadc1..4f8a67d33fff52 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -1859,6 +1859,7 @@ dummy_func( gen->gi_exc_state.previous_item = NULL; _Py_LeaveRecursiveCallPy(tstate); _PyInterpreterFrame *gen_frame = frame; + _PyThreadState_UpdateLastProfiledFrame(tstate, gen_frame, gen_frame->previous); frame = tstate->current_frame = frame->previous; gen_frame->previous = NULL; ((_PyThreadStateImpl *)tstate)->generator_return_kind = GENERATOR_YIELD; @@ -5880,6 +5881,7 @@ dummy_func( gen_frame->owner = FRAME_OWNED_BY_GENERATOR; _Py_LeaveRecursiveCallPy(tstate); _PyInterpreterFrame *prev = frame->previous; + _PyThreadState_UpdateLastProfiledFrame(tstate, frame, prev); _PyThreadState_PopFrame(tstate, frame); frame = tstate->current_frame = prev; LOAD_IP(frame->return_offset); diff --git a/Python/ceval.c b/Python/ceval.c index 3feb6ad0050d14..464a00860524fc 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -1988,15 +1988,8 @@ clear_gen_frame(PyThreadState *tstate, _PyInterpreterFrame * frame) void _PyEval_FrameClearAndPop(PyThreadState *tstate, _PyInterpreterFrame * frame) { - // Update last_profiled_frame for remote profiler frame caching. // By this point, tstate->current_frame is already set to the parent frame. - // Only update if we're popping the exact frame that was last profiled. - // This avoids corrupting the cache when transient frames (called and returned - // between profiler samples) update last_profiled_frame to addresses the - // profiler never saw. - if (tstate->last_profiled_frame != NULL && tstate->last_profiled_frame == frame) { - tstate->last_profiled_frame = tstate->current_frame; - } + _PyThreadState_UpdateLastProfiledFrame(tstate, frame, tstate->current_frame); if (frame->owner == FRAME_OWNED_BY_THREAD) { clear_thread_frame(tstate, frame); @@ -2022,6 +2015,7 @@ _PyEvalFramePushAndInit(PyThreadState *tstate, _PyStackRef func, _PyFrame_Initialize(tstate, frame, func, locals, code, 0, previous); if (initialize_locals(tstate, func_obj, frame->localsplus, args, argcount, kwnames)) { assert(frame->owner == FRAME_OWNED_BY_THREAD); + _PyThreadState_UpdateLastProfiledFrame(tstate, frame, tstate->current_frame); clear_thread_frame(tstate, frame); return NULL; } diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 882201bbc06c16..4d5a8ab6b8af0b 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -9339,6 +9339,7 @@ gen->gi_exc_state.previous_item = NULL; _Py_LeaveRecursiveCallPy(tstate); _PyInterpreterFrame *gen_frame = frame; + _PyThreadState_UpdateLastProfiledFrame(tstate, gen_frame, gen_frame->previous); frame = tstate->current_frame = frame->previous; gen_frame->previous = NULL; ((_PyThreadStateImpl *)tstate)->generator_return_kind = GENERATOR_YIELD; @@ -20442,6 +20443,7 @@ gen_frame->owner = FRAME_OWNED_BY_GENERATOR; _Py_LeaveRecursiveCallPy(tstate); _PyInterpreterFrame *prev = frame->previous; + _PyThreadState_UpdateLastProfiledFrame(tstate, frame, prev); _PyThreadState_PopFrame(tstate, frame); frame = tstate->current_frame = prev; LOAD_IP(frame->return_offset); diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 5033b994c33512..24ffb07830adf4 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -7938,6 +7938,7 @@ gen->gi_exc_state.previous_item = NULL; _Py_LeaveRecursiveCallPy(tstate); _PyInterpreterFrame *gen_frame = frame; + _PyThreadState_UpdateLastProfiledFrame(tstate, gen_frame, gen_frame->previous); frame = tstate->current_frame = frame->previous; gen_frame->previous = NULL; ((_PyThreadStateImpl *)tstate)->generator_return_kind = GENERATOR_YIELD; @@ -11019,6 +11020,7 @@ gen_frame->owner = FRAME_OWNED_BY_GENERATOR; _Py_LeaveRecursiveCallPy(tstate); _PyInterpreterFrame *prev = frame->previous; + _PyThreadState_UpdateLastProfiledFrame(tstate, frame, prev); _PyThreadState_PopFrame(tstate, frame); frame = tstate->current_frame = prev; LOAD_IP(frame->return_offset); @@ -13047,6 +13049,7 @@ gen->gi_exc_state.previous_item = NULL; _Py_LeaveRecursiveCallPy(tstate); _PyInterpreterFrame *gen_frame = frame; + _PyThreadState_UpdateLastProfiledFrame(tstate, gen_frame, gen_frame->previous); frame = tstate->current_frame = frame->previous; gen_frame->previous = NULL; ((_PyThreadStateImpl *)tstate)->generator_return_kind = GENERATOR_YIELD; From 40fa04e6cc5797bcef80eceb10a2b48b11b27650 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 19 Jun 2026 10:37:50 +0200 Subject: [PATCH 364/818] [3.15] gh-151229: Add CI to prevent JIT stress test regression (GH-151647) (gh-151670) --- .github/workflows/jit.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/jit.yml b/.github/workflows/jit.yml index 2f024ad52f3091..66bff36fe5e90c 100644 --- a/.github/workflows/jit.yml +++ b/.github/workflows/jit.yml @@ -183,6 +183,9 @@ jobs: - name: JIT without optimizations (Debug) configure_flags: --enable-experimental-jit --with-pydebug test_env: "PYTHON_UOPS_OPTIMIZE=0" + - name: JIT with stress testing (Debug) + configure_flags: --enable-experimental-jit --with-pydebug + test_env: "PYTHON_JIT_STRESS=1" - name: JIT with tail calling interpreter configure_flags: --enable-experimental-jit --with-tail-call-interp --with-pydebug use_clang: true From 7e368380f899c0b83b3b4b383371481021d9aabe Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 19 Jun 2026 10:45:02 +0200 Subject: [PATCH 365/818] [3.15] gh-141510 Document and test frozendict class matching behaviour (GH-150799) (#151701) gh-141510 Document and test frozendict class matching behaviour (GH-150799) Frozendict has `_Py_TPFLAGS_MATCH_SELF` set so works correctly with the single-arg class matching. However it isn't documented in the list of classes this works with and it isn't tested. The test is some way below the other similar tests but anything else would need a large renumbering. (cherry picked from commit fd53ae113911e5a7d83c04b08623df824f9d5d70) Co-authored-by: da-woods <dw-git@d-woods.co.uk> --- Doc/reference/compound_stmts.rst | 1 + Lib/test/test_patma.py | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/Doc/reference/compound_stmts.rst b/Doc/reference/compound_stmts.rst index 63baefd33e88c5..71bfb608dda728 100644 --- a/Doc/reference/compound_stmts.rst +++ b/Doc/reference/compound_stmts.rst @@ -1172,6 +1172,7 @@ subject value: * :class:`bytes` * :class:`dict` * :class:`float` + * :class:`frozendict` * :class:`frozenset` * :class:`int` * :class:`list` diff --git a/Lib/test/test_patma.py b/Lib/test/test_patma.py index 29cce4ee6d271f..e3aaea84ea7ce8 100644 --- a/Lib/test/test_patma.py +++ b/Lib/test/test_patma.py @@ -2852,6 +2852,15 @@ def test_patma_266(self): self.assertEqual(x, 0) self.assertEqual(y, 1) + def test_patma_frozendict_class_self(self): + x = frozendict() + match x: + case frozendict(z): + y = 0 + self.assertEqual(x, frozendict()) + self.assertEqual(y, 0) + self.assertIs(z, x) + def test_patma_runtime_checkable_protocol(self): # Runtime-checkable protocol from typing import Protocol, runtime_checkable From 022a018b5b85d98050610e80dc5b784ea26574e5 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 19 Jun 2026 11:07:51 +0200 Subject: [PATCH 366/818] [3.15] gh-151695: Fix use-after-free of the curses screen encoding (GH-151696) (GH-151703) The module-global curses_screen_encoding stored a borrowed pointer to the encoding owned by the window returned by the first initscr() call. That window can be deallocated while unctrl() and ungetch(), which have no window of their own, still use the pointer to encode non-ASCII characters. Keep a private copy of the encoding instead. (cherry picked from commit 551f8e16f8bb38a1e9c6df259a2a0969493de070) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --- ...-06-19-07-26-20.gh-issue-151695.IBDlkN.rst | 4 ++ Modules/_cursesmodule.c | 38 +++++++++++++++++-- 2 files changed, 39 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-06-19-07-26-20.gh-issue-151695.IBDlkN.rst diff --git a/Misc/NEWS.d/next/Library/2026-06-19-07-26-20.gh-issue-151695.IBDlkN.rst b/Misc/NEWS.d/next/Library/2026-06-19-07-26-20.gh-issue-151695.IBDlkN.rst new file mode 100644 index 00000000000000..f44cb6b9307165 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-19-07-26-20.gh-issue-151695.IBDlkN.rst @@ -0,0 +1,4 @@ +Fix a use-after-free in the :mod:`curses` module. The encoding of the initial +screen, used by :func:`curses.unctrl` and :func:`curses.ungetch` to encode +non-ASCII characters, is now kept as a private copy instead of a borrowed +pointer to a window object that may be deallocated. diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index 01cb6786e88aec..02a8e2c1b1bc10 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -208,7 +208,11 @@ static int curses_initscr_called = FALSE; /* Tells whether start_color() has been called to initialise color usage. */ static int curses_start_color_called = FALSE; -static const char *curses_screen_encoding = NULL; +/* Encoding of the initial screen, used by module-level functions that have + no window object to take it from (e.g. unctrl(), ungetch()). This is a + private copy: the window object that initscr() returns may be deallocated + while these functions are still in use. */ +static char *curses_screen_encoding = NULL; /* Utility Error Procedures */ @@ -3799,6 +3803,21 @@ _curses_init_pair_impl(PyObject *module, int pair_number, int fg, int bg) Py_RETURN_NONE; } +/* Refresh the private copy of the screen encoding from a freshly created + stdscr window object. Returns 0 on success, -1 with an exception set. */ +static int +curses_update_screen_encoding(PyObject *winobj) +{ + char *copy = _PyMem_Strdup(((PyCursesWindowObject *)winobj)->encoding); + if (copy == NULL) { + PyErr_NoMemory(); + return -1; + } + PyMem_Free(curses_screen_encoding); + curses_screen_encoding = copy; + return 0; +} + /*[clinic input] _curses.initscr @@ -3820,7 +3839,15 @@ _curses_initscr_impl(PyObject *module) _curses_set_null_error(state, "wrefresh", "initscr"); return NULL; } - return PyCursesWindow_New(state, stdscr, NULL, NULL); + PyObject *winobj = PyCursesWindow_New(state, stdscr, NULL, NULL); + if (winobj == NULL) { + return NULL; + } + if (curses_update_screen_encoding(winobj) < 0) { + Py_DECREF(winobj); + return NULL; + } + return winobj; } win = initscr(); @@ -3927,7 +3954,10 @@ _curses_initscr_impl(PyObject *module) if (winobj == NULL) { return NULL; } - curses_screen_encoding = ((PyCursesWindowObject *)winobj)->encoding; + if (curses_update_screen_encoding(winobj) < 0) { + Py_DECREF(winobj); + return NULL; + } return winobj; } @@ -5480,6 +5510,8 @@ static void cursesmodule_free(void *mod) { (void)cursesmodule_clear((PyObject *)mod); + PyMem_Free(curses_screen_encoding); + curses_screen_encoding = NULL; curses_module_loaded = 0; // allow reloading once garbage-collected } From 2c09c0ed29fe1d21cc5177b2cc1c0a27fb31f446 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 19 Jun 2026 11:08:08 +0200 Subject: [PATCH 367/818] [3.15] gh-141510 Add frozendict fast paths to abstract.c (GH-150692) (#151704) gh-141510 Add frozendict fast paths to abstract.c (GH-150692) Add frozendict to the fast paths of PyMapping_GetOptionalItem(), PyMapping_Keys(), PyMapping_Values(), and PyMapping_Items(). (cherry picked from commit a5568d0eb70f8ffbfc7815b58e24170787615931) Co-authored-by: da-woods <dw-git@d-woods.co.uk> Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com> --- Lib/test/test_capi/test_abstract.py | 14 +++++++++++++- .../2026-06-18-18-24-11.gh-issue-141510.-EOHJ1.rst | 1 + Objects/abstract.c | 8 ++++---- 3 files changed, 18 insertions(+), 5 deletions(-) create mode 100644 Misc/NEWS.d/next/C_API/2026-06-18-18-24-11.gh-issue-141510.-EOHJ1.rst diff --git a/Lib/test/test_capi/test_abstract.py b/Lib/test/test_capi/test_abstract.py index 3a2ed9f5db82f0..e455a863620924 100644 --- a/Lib/test/test_capi/test_abstract.py +++ b/Lib/test/test_capi/test_abstract.py @@ -411,6 +411,11 @@ def test_mapping_getoptionalitem(self): self.assertEqual(getitem(dct2, 'a'), 1) self.assertEqual(getitem(dct2, 'b'), KeyError) + frozendct = frozendict(dct) + self.assertEqual(getitem(frozendct, 'a'), 1) + self.assertEqual(getitem(frozendct, 'b'), KeyError) + self.assertEqual(getitem(frozendct, '\U0001f40d'), 2) + self.assertEqual(getitem(['a', 'b', 'c'], 1), 'b') self.assertRaises(TypeError, getitem, 42, 'a') @@ -431,6 +436,11 @@ def test_mapping_getoptionalitemstring(self): self.assertEqual(getitemstring(dct2, b'a'), 1) self.assertEqual(getitemstring(dct2, b'b'), KeyError) + frozendct = frozendict(dct) + self.assertEqual(getitemstring(frozendct, 'a'), 1) + self.assertEqual(getitemstring(frozendct, 'b'), KeyError) + self.assertEqual(getitemstring(frozendct, '\U0001f40d'.encode()), 2) + self.assertRaises(TypeError, getitemstring, 42, b'a') self.assertRaises(UnicodeDecodeError, getitemstring, {}, b'\xff') self.assertRaises(SystemError, getitemstring, {}, NULL) @@ -677,8 +687,10 @@ def items(self): dict_obj = {'foo': 1, 'bar': 2, 'spam': 3} for mapping in [{}, OrderedDict(), Mapping1(), Mapping2(), + frozendict(), dict_obj, OrderedDict(dict_obj), - Mapping1(dict_obj), Mapping2(dict_obj)]: + Mapping1(dict_obj), Mapping2(dict_obj), + frozendict(dict_obj)]: self.assertListEqual(_testlimitedcapi.mapping_keys(mapping), list(mapping.keys())) self.assertListEqual(_testlimitedcapi.mapping_values(mapping), diff --git a/Misc/NEWS.d/next/C_API/2026-06-18-18-24-11.gh-issue-141510.-EOHJ1.rst b/Misc/NEWS.d/next/C_API/2026-06-18-18-24-11.gh-issue-141510.-EOHJ1.rst new file mode 100644 index 00000000000000..c77b462e97bdd1 --- /dev/null +++ b/Misc/NEWS.d/next/C_API/2026-06-18-18-24-11.gh-issue-141510.-EOHJ1.rst @@ -0,0 +1 @@ +Add :class:`frozendict` to the fast paths of :c:func:`PyMapping_GetOptionalItem`, :c:func:`PyMapping_Keys`, :c:func:`PyMapping_Values`, and :c:func:`PyMapping_Items`. diff --git a/Objects/abstract.c b/Objects/abstract.c index 48b3137152e7bf..28f751965f36b9 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -208,7 +208,7 @@ PyObject_GetItem(PyObject *o, PyObject *key) int PyMapping_GetOptionalItem(PyObject *obj, PyObject *key, PyObject **result) { - if (PyDict_CheckExact(obj)) { + if (PyAnyDict_CheckExact(obj)) { return PyDict_GetItemRef(obj, key, result); } @@ -2462,7 +2462,7 @@ PyMapping_Keys(PyObject *o) if (o == NULL) { return null_error(); } - if (PyDict_CheckExact(o)) { + if (PyAnyDict_CheckExact(o)) { return PyDict_Keys(o); } return method_output_as_list(o, &_Py_ID(keys)); @@ -2474,7 +2474,7 @@ PyMapping_Items(PyObject *o) if (o == NULL) { return null_error(); } - if (PyDict_CheckExact(o)) { + if (PyAnyDict_CheckExact(o)) { return PyDict_Items(o); } return method_output_as_list(o, &_Py_ID(items)); @@ -2486,7 +2486,7 @@ PyMapping_Values(PyObject *o) if (o == NULL) { return null_error(); } - if (PyDict_CheckExact(o)) { + if (PyAnyDict_CheckExact(o)) { return PyDict_Values(o); } return method_output_as_list(o, &_Py_ID(values)); From cfe461944dac8e40e21ebc5bca8b73420c78527e Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 19 Jun 2026 11:28:03 +0200 Subject: [PATCH 368/818] [3.15] gh-151678: Add tests for tkinter.Menu (GH-151685) (GH-151709) Cover previously-untested Menu methods in MenuTest: adding, inserting and deleting items of every type, index resolution, invoking items, entry x/y positions, and post/unpost/tk_popup mapping. Also test per-entry configuration options and the errors raised for invalid indices, entry types, option names and option values. (cherry picked from commit ef5c32a40be50a33a9b7ac39ee64e6893bc22f60) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --- Lib/test/test_tkinter/test_widgets.py | 186 ++++++++++++++++++++++++++ 1 file changed, 186 insertions(+) diff --git a/Lib/test/test_tkinter/test_widgets.py b/Lib/test/test_tkinter/test_widgets.py index 1c400e970eb02d..fd3c70c97c3d5b 100644 --- a/Lib/test/test_tkinter/test_widgets.py +++ b/Lib/test/test_tkinter/test_widgets.py @@ -1542,6 +1542,192 @@ def test_entryconfigure_variable(self): m1.entryconfigure(1, variable=v2) self.assertEqual(str(m1.entrycget(1, 'variable')), str(v2)) + def test_add(self): + m = self.create(tearoff=False) + m.add_command(label='Command') + m.add_checkbutton(label='Checkbutton') + m.add_radiobutton(label='Radiobutton') + m.add_separator() + m.add_cascade(label='Cascade', menu=tkinter.Menu(m, tearoff=False)) + self.assertEqual(m.index('end'), 4) + self.assertEqual([m.type(i) for i in range(5)], + ['command', 'checkbutton', 'radiobutton', + 'separator', 'cascade']) + self.assertEqual(m.entrycget(0, 'label'), 'Command') + self.assertRaisesRegex(TclError, 'bad menu entry type "spam"', + m.add, 'spam') + + def test_insert(self): + m = self.create(tearoff=False) + m.add_command(label='A') + m.add_command(label='C') + m.insert_command(1, label='B') + m.insert_separator(0) + m.insert_checkbutton('end', label='D') + m.insert_radiobutton(0, label='top') + m.insert_cascade(2, label='sub', + menu=tkinter.Menu(m, tearoff=False)) + self.assertEqual( + [m.type(i) for i in range(m.index('end') + 1)], + ['radiobutton', 'separator', 'cascade', 'command', + 'command', 'command', 'checkbutton']) + self.assertEqual( + [m.entrycget(i, 'label') for i in (3, 4, 5)], + ['A', 'B', 'C']) + self.assertRaisesRegex(TclError, 'bad menu entry type "spam"', + m.insert, 0, 'spam') + self.assertRaisesRegex(TclError, 'bad menu entry index "spam"', + m.insert_command, 'spam', label='z') + + def test_delete(self): + m = self.create(tearoff=False) + commands = [] + for label in 'ABCDE': + m.add_command(label=label, + command=lambda label=label: commands.append(label)) + # The Tcl command for a deleted item is cleaned up. + funcid = str(m.entrycget(2, 'command')) + self.assertEqual( + m.tk.splitlist(m.tk.call('info', 'commands', funcid)), (funcid,)) + + m.delete(2) # Delete a single item ('C'). + self.assertEqual([m.entrycget(i, 'label') for i in range(4)], + ['A', 'B', 'D', 'E']) + self.assertEqual( + m.tk.splitlist(m.tk.call('info', 'commands', funcid)), ()) + + m.delete(1, 2) # Delete a range ('B' and 'D'). + self.assertEqual([m.entrycget(i, 'label') for i in range(2)], + ['A', 'E']) + self.assertRaises(TypeError, m.delete) + + def test_index(self): + m = self.create(tearoff=False) + self.assertIsNone(m.index('end')) + m.add_command(label='First') + m.add_command(label='Second') + self.assertEqual(m.index('end'), 1) + self.assertEqual(m.index('last'), 1) + self.assertEqual(m.index('Second'), 1) + self.assertEqual(m.index(0), 0) + # 'active' and 'none' map to None when no item is active. + self.assertIsNone(m.index('active')) + self.assertIsNone(m.index('none')) + self.assertRaisesRegex(TclError, 'bad menu entry index "spam"', + m.index, 'spam') + + def test_invoke(self): + m = self.create(tearoff=False) + commands = [] + m.add_command(label='Command', + command=lambda: commands.append('invoked')) + var = tkinter.IntVar(self.root) + m.add_checkbutton(label='Check', variable=var, + onvalue=1, offvalue=0) + rvar = tkinter.StringVar(self.root) + m.add_radiobutton(label='Radio', variable=rvar, value='on') + + m.invoke(0) + self.assertEqual(commands, ['invoked']) + m.invoke(1) + self.assertEqual(var.get(), 1) + m.invoke(1) + self.assertEqual(var.get(), 0) + m.invoke(2) + self.assertEqual(rvar.get(), 'on') + self.assertRaisesRegex(TclError, 'bad menu entry index "spam"', + m.invoke, 'spam') + + def test_xposition_yposition(self): + m = self.create(tearoff=False) + m.add_command(label='First') + m.add_command(label='Second') + m.update_idletasks() + self.assertIsInstance(m.xposition(0), int) + y0 = m.yposition(0) + y1 = m.yposition(1) + self.assertIsInstance(y0, int) + self.assertLess(y0, y1) + # An out-of-range index gives the position past the last item. + self.assertEqual(m.xposition('end'), m.xposition(1)) + self.assertRaisesRegex(TclError, 'bad menu entry index "spam"', + m.xposition, 'spam') + self.assertRaisesRegex(TclError, 'bad menu entry index "spam"', + m.yposition, 'spam') + + def test_post_unpost(self): + m = self.create(tearoff=False) + if m._windowingsystem != 'x11': + # Posting a menu is modal on Windows and uses a native, unmapped + # menu on Aqua, so it cannot be tested synchronously there. + self.skipTest('menu posting is not testable on this platform') + m.add_command(label='First') + m.add_command(label='Second') + self.assertFalse(m.winfo_ismapped()) + + m.post(0, 0) + m.update() + self.assertTrue(m.winfo_ismapped()) + m.unpost() + m.update() + self.assertFalse(m.winfo_ismapped()) + + m.tk_popup(0, 0) + m.update() + self.assertTrue(m.winfo_ismapped()) + m.unpost() + m.update() + self.assertFalse(m.winfo_ismapped()) + + def check_entry_option(self, m, index, option, value, expected=None): + if expected is None: + expected = value + m.entryconfigure(index, **{option: value}) + self.assertEqual(str(m.entrycget(index, option)), str(expected)) + self.assertEqual(str(m.entryconfigure(index, option)[4]), str(expected)) + + def test_entry_options(self): + m = self.create(tearoff=False) + m.add_command(label='Command') + self.check_entry_option(m, 0, 'accelerator', 'Ctrl+O') + self.check_entry_option(m, 0, 'underline', 2) + self.check_entry_option(m, 0, 'state', 'disabled') + self.check_entry_option(m, 0, 'background', 'red') + self.check_entry_option(m, 0, 'foreground', 'blue') + self.check_entry_option(m, 0, 'columnbreak', 1) + self.check_entry_option(m, 0, 'hidemargin', 1) + + m.add_checkbutton(label='Checkbutton') + self.check_entry_option(m, 1, 'onvalue', 'Y') + self.check_entry_option(m, 1, 'offvalue', 'N') + self.check_entry_option(m, 1, 'indicatoron', 0) + + m.add_radiobutton(label='Radiobutton') + self.check_entry_option(m, 2, 'value', 'V') + self.check_entry_option(m, 2, 'selectcolor', 'green') + + def test_entry_options_invalid(self): + m = self.create(tearoff=False) + m.add_command(label='Command') + self.assertRaisesRegex(TclError, 'unknown option "-spam"', + m.entrycget, 0, 'spam') + self.assertRaisesRegex(TclError, 'unknown option "-spam"', + m.entryconfigure, 0, spam='x') + self.assertRaisesRegex(TclError, 'bad state "spam"', + m.entryconfigure, 0, state='spam') + # Tk < 9 reports "expected integer but got ...", while Tk 9, where + # underline accepts an index, reports "bad index ...". + self.assertRaisesRegex(TclError, + r'(expected integer but got|bad index) "spam"', + m.entryconfigure, 0, underline='spam') + self.assertRaisesRegex(TclError, 'unknown color name "spam"', + m.entryconfigure, 0, background='spam') + self.assertRaisesRegex(TclError, 'expected boolean value but got "spam"', + m.entryconfigure, 0, columnbreak='spam') + # onvalue applies only to checkbutton and radiobutton entries. + self.assertRaisesRegex(TclError, 'unknown option "-onvalue"', + m.entrycget, 0, 'onvalue') + @add_configure_tests(PixelSizeTests, StandardOptionsTests) class MessageTest(AbstractWidgetTest, unittest.TestCase): From 1495415cb4e64fe1b461fedbaee6c038c86fdbd3 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 19 Jun 2026 11:30:55 +0200 Subject: [PATCH 369/818] [3.15] gh-151678: Add tests for tkinter.Listbox (GH-151686) (GH-151712) Cover previously-untested Listbox methods in ListboxTest: size, delete, index resolution, nearest, see, activate, and the selection methods (selection_set/clear/includes/anchor and their select_* aliases), including the errors raised for invalid indices. (cherry picked from commit cf3b3c11485a870d8e8c02579bed27a316838eb1) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --- Lib/test/test_tkinter/test_widgets.py | 100 ++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) diff --git a/Lib/test/test_tkinter/test_widgets.py b/Lib/test/test_tkinter/test_widgets.py index fd3c70c97c3d5b..3fea5773632ef5 100644 --- a/Lib/test/test_tkinter/test_widgets.py +++ b/Lib/test/test_tkinter/test_widgets.py @@ -1180,6 +1180,106 @@ def test_get(self): self.assertRaises(TypeError, lb.get, 1, 2, 3) self.assertRaises(TclError, lb.get, 2.4) + def test_size(self): + lb = self.create() + self.assertEqual(lb.size(), 0) + lb.insert(0, *('el%d' % i for i in range(8))) + self.assertEqual(lb.size(), 8) + lb.delete(0, 2) + self.assertEqual(lb.size(), 5) + self.assertRaises(TypeError, lb.size, 0) + + def test_delete(self): + lb = self.create() + lb.insert(0, *('el%d' % i for i in range(8))) + lb.delete(0) + self.assertEqual(lb.get(0, 'end'), + ('el1', 'el2', 'el3', 'el4', 'el5', 'el6', 'el7')) + lb.delete(2, 4) + self.assertEqual(lb.get(0, 'end'), ('el1', 'el2', 'el6', 'el7')) + lb.delete(0, 'end') + self.assertEqual(lb.size(), 0) + self.assertRaises(TclError, lb.delete, 'noindex') + self.assertRaises(TypeError, lb.delete) + + def test_index(self): + lb = self.create() + lb.insert(0, *('el%d' % i for i in range(8))) + self.assertEqual(lb.index(3), 3) + self.assertEqual(lb.index('end'), 8) # the number of elements + lb.activate(4) + self.assertEqual(lb.index('active'), 4) + lb.selection_anchor(2) + self.assertEqual(lb.index('anchor'), 2) + self.assertRaisesRegex(TclError, 'bad listbox index "spam"', + lb.index, 'spam') + + def test_nearest(self): + lb = self.create() + lb.insert(0, *('el%d' % i for i in range(8))) + lb.pack() + lb.wait_visibility() + lb.update() + # Derive the line height from the first item, which is always + # displayed (bbox() returns None for items that are not). + x, y, w, h = lb.bbox(0) + self.assertEqual(lb.nearest(y + h // 2), 0) + self.assertEqual(lb.nearest(y + 3 * h + h // 2), 3) + self.assertRaises(TclError, lb.nearest, 'spam') + self.assertRaises(TypeError, lb.nearest) + + def test_see(self): + lb = self.create(height=5) + lb.insert(0, *('el%d' % i for i in range(20))) + lb.pack() + lb.update_idletasks() + lb.see('end') + lb.update_idletasks() + self.assertEqual(lb.yview()[1], 1.0) + lb.see(0) + lb.update_idletasks() + self.assertEqual(lb.yview()[0], 0.0) + self.assertRaises(TclError, lb.see, 'spam') + + def test_activate(self): + lb = self.create() + lb.insert(0, *('el%d' % i for i in range(8))) + lb.activate(3) + self.assertEqual(lb.index('active'), 3) + lb.activate('end') + self.assertEqual(lb.index('active'), 7) + self.assertRaises(TclError, lb.activate, 'spam') + self.assertRaises(TypeError, lb.activate) + + def test_selection(self): + lb = self.create() + lb.insert(0, *('el%d' % i for i in range(8))) + self.assertEqual(lb.curselection(), ()) + self.assertFalse(lb.selection_includes(0)) + + lb.selection_set(2, 4) + lb.selection_set(6) + self.assertEqual(lb.curselection(), (2, 3, 4, 6)) + self.assertTrue(lb.selection_includes(3)) + self.assertFalse(lb.selection_includes(5)) + + lb.selection_clear(3, 4) + self.assertEqual(lb.curselection(), (2, 6)) + + lb.selection_anchor(5) + self.assertEqual(lb.index('anchor'), 5) + + # select_* are aliases of the selection_* methods. + lb.select_clear(0, 'end') + self.assertEqual(lb.curselection(), ()) + lb.select_set(1) + self.assertTrue(lb.select_includes(1)) + lb.select_anchor(1) + self.assertEqual(lb.index('anchor'), 1) + + self.assertRaisesRegex(TclError, 'bad listbox index "spam"', + lb.selection_includes, 'spam') + @add_configure_tests(PixelSizeTests, StandardOptionsTests) class ScaleTest(AbstractWidgetTest, unittest.TestCase): From 81e9c085187af9a823b305b4ae1b9e0f82b21820 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 19 Jun 2026 12:41:03 +0200 Subject: [PATCH 370/818] [3.15] gh-151678: Add tests for tkinter.Text (GH-151681) (GH-151702) Cover previously-untested Text methods (indices, content, marks, tags, undo/redo, dump, embedded images and windows, peers, and geometry) and the tag, embedded-image and embedded-window configuration options. (cherry picked from commit 4ac809e10bdb413d7dd8c7bab7e365b2b618ad91) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --- Lib/test/test_tkinter/test_text.py | 579 +++++++++++++++++++++++++++-- 1 file changed, 558 insertions(+), 21 deletions(-) diff --git a/Lib/test/test_tkinter/test_text.py b/Lib/test/test_tkinter/test_text.py index 453a4505a0a4da..0303c2ac1ed1da 100644 --- a/Lib/test/test_tkinter/test_text.py +++ b/Lib/test/test_tkinter/test_text.py @@ -1,8 +1,9 @@ import unittest import tkinter +from tkinter import TclError from test.support import requires from test.test_tkinter.support import setUpModule # noqa: F401 -from test.test_tkinter.support import AbstractTkTest +from test.test_tkinter.support import AbstractTkTest, requires_tk requires('gui') @@ -25,21 +26,557 @@ def test_debug(self): text.debug(olddebug) self.assertEqual(text.debug(), olddebug) + def test_index(self): + text = self.text + text.insert('1.0', 'Lorem ipsum\ndolor sit amet') + self.assertEqual(text.index('1.0'), '1.0') + self.assertEqual(text.index('1.end'), '1.11') + self.assertEqual(text.index('end'), '3.0') + self.assertEqual(text.index('2.5'), '2.5') + # Index past the end of a line is clamped to its end. + self.assertEqual(text.index('1.100'), '1.11') + self.assertRaises(TclError, text.index, 'invalid') + self.assertRaises(TypeError, text.index) + self.assertRaises(TypeError, text.index, '1.0', '2.5') + + def test_compare(self): + text = self.text + text.insert('1.0', 'Lorem ipsum\ndolor sit amet') + self.assertIs(text.compare('1.0', '<', '2.0'), True) + self.assertIs(text.compare('2.0', '<', '1.0'), False) + self.assertIs(text.compare('1.5', '==', '1.5'), True) + self.assertIs(text.compare('1.5', '!=', '1.5'), False) + self.assertIs(text.compare('2.0', '>=', '2.0'), True) + self.assertIs(text.compare('1.0', '<=', 'end'), True) + self.assertRaises(TclError, text.compare, '1.0', 'invalid', '2.0') + self.assertRaises(TypeError, text.compare, '1.0', '<') + self.assertRaises(TypeError, text.compare, '1.0', '<', '2.0', '3.0') + + def test_insert_get_delete(self): + text = self.text + text.insert('1.0', 'Lorem ipsum') + self.assertEqual(text.get('1.0', 'end'), 'Lorem ipsum\n') + self.assertEqual(text.get('1.0', '1.5'), 'Lorem') + self.assertEqual(text.get('1.6'), 'i') # single character + + # insert before an existing index + text.insert('1.0', '*** ') + self.assertEqual(text.get('1.0', 'end'), '*** Lorem ipsum\n') + + text.delete('1.0', '1.4') + self.assertEqual(text.get('1.0', 'end'), 'Lorem ipsum\n') + text.delete('1.5') # delete a single character + self.assertEqual(text.get('1.0', 'end'), 'Loremipsum\n') + self.assertRaises(TypeError, text.get) + self.assertRaises(TypeError, text.get, '1.0', '1.5', 'end') + self.assertRaises(TypeError, text.delete, '1.0', '1.5', 'end') + + def test_insert_with_tags(self): + text = self.text + text.insert('1.0', 'hello', 'a', ' ', ('a', 'b'), 'world', 'b') + self.assertEqual(text.get('1.0', 'end'), 'hello world\n') + self.assertEqual([str(i) for i in text.tag_ranges('a')], + ['1.0', '1.6']) + self.assertEqual([str(i) for i in text.tag_ranges('b')], + ['1.5', '1.11']) + + def test_replace(self): + text = self.text + text.insert('1.0', 'Lorem ipsum') + text.replace('1.0', '1.5', 'Hello') + self.assertEqual(text.get('1.0', 'end'), 'Hello ipsum\n') + text.replace('1.6', 'end - 1 char', 'world') + self.assertEqual(text.get('1.0', 'end'), 'Hello world\n') + self.assertRaises(TclError, text.replace, 'invalid', '1.5', 'x') + # The first index must not be after the second. + self.assertRaises(TclError, text.replace, '1.5', '1.0', 'x') + self.assertRaises(TypeError, text.replace, '1.0', '1.5') + + def test_mark(self): + text = self.text + text.insert('1.0', 'Lorem ipsum\ndolor sit amet') + # 'insert' and 'current' marks always exist. + self.assertIn('insert', text.mark_names()) + self.assertIn('current', text.mark_names()) + + text.mark_set('here', '1.5') + self.assertIn('here', text.mark_names()) + self.assertEqual(text.index('here'), '1.5') + text.mark_set('here', '2.3') + self.assertEqual(text.index('here'), '2.3') + + text.mark_unset('here') + self.assertNotIn('here', text.mark_names()) + + # Unsetting a non-existent mark is not an error. + text.mark_unset('nonexistent') + self.assertRaises(TclError, text.mark_set, 'm', 'invalid') + self.assertRaises(TypeError, text.mark_set, 'm') + self.assertRaises(TypeError, text.mark_set, 'm', '1.0', '2.0') + + def test_mark_gravity(self): + text = self.text + text.insert('1.0', 'Lorem ipsum') + text.mark_set('here', '1.5') + # The default gravity is right. + self.assertEqual(text.mark_gravity('here'), 'right') + text.mark_gravity('here', 'left') + self.assertEqual(text.mark_gravity('here'), 'left') + # With left gravity the mark stays before inserted text. + text.insert('here', 'XXX') + self.assertEqual(text.index('here'), '1.5') + # With right gravity the mark moves after inserted text. + text.mark_gravity('here', 'right') + text.insert('here', 'YYY') + self.assertEqual(text.index('here'), '1.8') + + self.assertRaises(TclError, text.mark_gravity, 'nonexistent') + self.assertRaises(TclError, text.mark_gravity, 'here', 'invalid') + self.assertRaises(TypeError, text.mark_gravity) + self.assertRaises(TypeError, text.mark_gravity, 'here', 'left', 'extra') + + def test_mark_next_previous(self): + text = self.text + text.insert('1.0', 'Lorem ipsum') + # Keep the builtin 'insert' and 'current' marks at 1.0 so they do + # not interfere with the queries below. + text.mark_set('insert', '1.0') + text.mark_set('current', '1.0') + text.mark_set('m1', '1.3') + text.mark_set('m2', '1.7') + # mark_next finds a mark at a position at or after the index, + # mark_previous finds one at a position strictly before it. + self.assertEqual(text.mark_next('1.1'), 'm1') + self.assertEqual(text.mark_next('1.3'), 'm1') + self.assertEqual(text.mark_next('1.4'), 'm2') + self.assertIsNone(text.mark_next('1.8')) + self.assertEqual(text.mark_previous('1.4'), 'm1') + self.assertEqual(text.mark_previous('1.7'), 'm1') + self.assertEqual(text.mark_previous('end'), 'm2') + self.assertIsNone(text.mark_previous('1.0')) + + self.assertRaises(TclError, text.mark_next, 'invalid') + self.assertRaises(TclError, text.mark_previous, 'invalid') + self.assertRaises(TypeError, text.mark_next) + self.assertRaises(TypeError, text.mark_previous) + self.assertRaises(TypeError, text.mark_next, '1.0', '2.0') + self.assertRaises(TypeError, text.mark_previous, '1.0', '2.0') + + def test_tag_add_remove_ranges(self): + text = self.text + text.insert('1.0', 'Lorem ipsum\ndolor sit amet') + self.assertEqual(text.tag_ranges('sel'), ()) + + text.tag_add('big', '1.0', '1.5') + self.assertEqual([str(i) for i in text.tag_ranges('big')], + ['1.0', '1.5']) + # Add a second, disjoint range. + text.tag_add('big', '2.0', '2.5') + self.assertEqual([str(i) for i in text.tag_ranges('big')], + ['1.0', '1.5', '2.0', '2.5']) + + text.tag_remove('big', '1.0', '1.3') + self.assertEqual([str(i) for i in text.tag_ranges('big')], + ['1.3', '1.5', '2.0', '2.5']) + + # tag_ranges of an undefined tag is empty, not an error. + self.assertEqual(text.tag_ranges('nonexistent'), ()) + self.assertRaises(TclError, text.tag_add, 'big', 'invalid') + self.assertRaises(TypeError, text.tag_add, 'big') + self.assertRaises(TclError, text.tag_remove, 'big', 'invalid') + self.assertRaises(TypeError, text.tag_remove, 'big', '1.0', '2.0', '3.0') + self.assertRaises(TypeError, text.tag_ranges, 'big', 'extra') + + def test_tag_names(self): + text = self.text + text.insert('1.0', 'Lorem ipsum') + text.tag_add('a', '1.0', '1.5') + text.tag_add('b', '1.3', '1.8') + # 'sel' always exists; order reflects priority (creation order). + self.assertEqual(set(text.tag_names()), {'sel', 'a', 'b'}) + # Tags applied to the character at the given index. + self.assertEqual(set(text.tag_names('1.4')), {'a', 'b'}) + self.assertEqual(set(text.tag_names('1.0')), {'a'}) + self.assertEqual(set(text.tag_names('1.10')), set()) + self.assertRaises(TclError, text.tag_names, 'invalid') + self.assertRaises(TypeError, text.tag_names, '1.0', '2.0') + + def test_tag_nextrange_prevrange(self): + text = self.text + text.insert('1.0', 'Lorem ipsum dolor') + text.tag_add('a', '1.0', '1.5') + text.tag_add('a', '1.12', '1.17') + + self.assertEqual([str(i) for i in text.tag_nextrange('a', '1.0')], + ['1.0', '1.5']) + self.assertEqual([str(i) for i in text.tag_nextrange('a', '1.5')], + ['1.12', '1.17']) + self.assertEqual(text.tag_nextrange('a', '1.17'), ()) + + self.assertEqual([str(i) for i in text.tag_prevrange('a', 'end')], + ['1.12', '1.17']) + self.assertEqual([str(i) for i in text.tag_prevrange('a', '1.12')], + ['1.0', '1.5']) + self.assertEqual(text.tag_prevrange('a', '1.0'), ()) + + # An undefined tag has no ranges, but the index must be valid. + self.assertEqual(text.tag_nextrange('nonexistent', '1.0'), ()) + self.assertRaises(TclError, text.tag_nextrange, 'a', 'invalid') + self.assertRaises(TclError, text.tag_prevrange, 'a', 'invalid') + self.assertRaises(TypeError, text.tag_nextrange, 'a') + self.assertRaises(TypeError, text.tag_prevrange, 'a') + self.assertRaises(TypeError, text.tag_nextrange, 'a', '1.0', '2.0', '3.0') + self.assertRaises(TypeError, text.tag_prevrange, 'a', '1.0', '2.0', '3.0') + + def test_tag_delete(self): + text = self.text + text.insert('1.0', 'Lorem ipsum') + text.tag_add('a', '1.0', '1.5') + text.tag_add('b', '1.6', '1.11') + self.assertEqual(set(text.tag_names()), {'sel', 'a', 'b'}) + text.tag_delete('a', 'b') + self.assertEqual(set(text.tag_names()), {'sel'}) + self.assertEqual(text.tag_ranges('a'), ()) + + def test_tag_raise_lower(self): + text = self.text + text.tag_configure('a', foreground='red') + text.tag_configure('b', foreground='green') + text.tag_configure('c', foreground='blue') + # Creation order is lowest-to-highest priority; tag_names lists + # them in increasing priority order. + self.assertEqual(text.tag_names(), ('sel', 'a', 'b', 'c')) + text.tag_raise('a') + self.assertEqual(text.tag_names(), ('sel', 'b', 'c', 'a')) + text.tag_lower('a') + self.assertEqual(text.tag_names(), ('a', 'sel', 'b', 'c')) + text.tag_raise('a', 'b') + self.assertEqual(text.tag_names(), ('sel', 'b', 'a', 'c')) + text.tag_lower('c', 'b') + self.assertEqual(text.tag_names(), ('sel', 'c', 'b', 'a')) + + self.assertRaises(TclError, text.tag_raise, 'nonexistent') + self.assertRaises(TclError, text.tag_lower, 'nonexistent') + self.assertRaises(TclError, text.tag_raise, 'a', 'nonexistent') + self.assertRaises(TypeError, text.tag_raise) + self.assertRaises(TypeError, text.tag_raise, 'a', 'b', 'c') + self.assertRaises(TypeError, text.tag_lower, 'a', 'b', 'c') + + def test_tag_cget_configure(self): + text = self.text + text.tag_configure('a', foreground='red', underline=True) + self.assertEqual(str(text.tag_cget('a', 'foreground')), 'red') + self.assertIn(text.tag_cget('a', 'underline'), (1, '1', True)) + # tag_cget normalizes the option name (no leading hyphen needed). + self.assertEqual(str(text.tag_cget('a', '-foreground')), 'red') + # configure() query returns the full option spec. + self.assertEqual(text.tag_configure('a', 'foreground')[-1], 'red') + text.tag_configure('a', foreground='blue') + self.assertEqual(str(text.tag_cget('a', 'foreground')), 'blue') + + self.assertRaises(TclError, text.tag_cget, 'nonexistent', + 'foreground') + self.assertRaises(TypeError, text.tag_cget, 'a') + self.assertRaises(TypeError, text.tag_cget, 'a', 'foreground', 'extra') + + def test_edit_modified(self): + text = self.text + self.assertEqual(text.edit_modified(), 0) + text.insert('1.0', 'spam') + self.assertEqual(text.edit_modified(), 1) + text.edit_modified(False) + self.assertEqual(text.edit_modified(), 0) + text.edit_modified(True) + self.assertEqual(text.edit_modified(), 1) + + def test_edit_undo_redo(self): + text = self.text + text.configure(undo=True) + text.insert('1.0', 'spam') + text.edit_separator() + text.insert('end', ' eggs') + self.assertEqual(text.get('1.0', 'end'), 'spam eggs\n') + + text.edit_undo() + self.assertEqual(text.get('1.0', 'end'), 'spam\n') + text.edit_redo() + self.assertEqual(text.get('1.0', 'end'), 'spam eggs\n') + + # An empty undo stack raises. + text.edit_reset() + self.assertRaises(TclError, text.edit_undo) + + def test_dump(self): + text = self.text + text.insert('1.0', 'hello') + text.tag_add('a', '1.0', '1.3') + text.mark_set('here', '1.2') + + dump = text.dump('1.0', 'end') + self.assertIsInstance(dump, list) + for item in dump: + self.assertIsInstance(item, tuple) + self.assertEqual(len(item), 3) + kinds = {item[0] for item in dump} + self.assertIn('text', kinds) + self.assertIn('tagon', kinds) + self.assertIn('mark', kinds) + + # Filtering by kind. + text_only = text.dump('1.0', 'end', text=True) + self.assertEqual({item[0] for item in text_only}, {'text'}) + self.assertEqual(''.join(item[1] for item in text_only), 'hello\n') + + # The command callback receives each triple and suppresses the result. + collected = [] + result = text.dump('1.0', 'end', text=True, + command=lambda *a: collected.append(a)) + self.assertIsNone(result) + self.assertEqual(''.join(key_value_index[1] + for key_value_index in collected), 'hello\n') + + self.assertRaises(TclError, text.dump, 'invalid') + self.assertRaises(TypeError, text.dump) + self.assertRaises(TypeError, text.dump, '1.0', 'end', None, 'extra') + + def test_image(self): + text = self.text + image = tkinter.PhotoImage(master=self.root, width=10, height=10) + text.insert('1.0', 'AB') + name = text.image_create('1.1', image=image) + self.assertIsInstance(name, str) + self.assertIn(name, self.root.splitlist(text.image_names())) + self.assertEqual(str(text.image_cget(name, 'image')), str(image)) + + text.image_configure(name, align='top') + self.assertEqual(str(text.image_cget(name, 'align')), 'top') + + # An embedded image occupies a single index position. + self.assertEqual(text.index('end - 1 char'), '1.3') + + # Either a name or an image is required, and the index must be valid. + self.assertRaises(TclError, text.image_create, '1.0') + self.assertRaises(TclError, text.image_create, 'invalid', + image=image) + self.assertRaises(TypeError, text.image_cget, name) + self.assertRaises(TypeError, text.image_cget, name, 'image', 'extra') + + def test_window(self): + text = self.text + button = tkinter.Button(text, text='ok') + text.insert('1.0', 'AB') + text.window_create('1.1', window=button) + self.assertEqual(self.root.splitlist(text.window_names()), + (str(button),)) + self.assertEqual(text.window_cget('1.1', 'window'), str(button)) + + text.window_configure('1.1', padx=5) + self.assertEqual(text.window_cget('1.1', 'padx'), 5) + + # No embedded window at this index, and the index must be valid. + self.assertRaises(TclError, text.window_cget, '1.0', 'window') + self.assertRaises(TclError, text.window_cget, 'invalid', 'window') + self.assertRaises(TypeError, text.window_cget, '1.1') + self.assertRaises(TypeError, text.window_cget, '1.1', 'window', 'extra') + button.destroy() + + def test_tag_configure(self): + text = self.text + tag = 'a' + getint = text.tk.getint + getboolean = text.tk.getboolean + + # Color options. + for opt in ('foreground', 'background'): + text.tag_configure(tag, **{opt: '#ff0000'}) + self.assertEqual(str(text.tag_cget(tag, opt)), '#ff0000') + + # Stipple (bitmap) options. + for opt in ('bgstipple', 'fgstipple'): + text.tag_configure(tag, **{opt: 'gray50'}) + self.assertEqual(str(text.tag_cget(tag, opt)), 'gray50') + + # Enumerated options. + for opt, value in (('justify', 'center'), ('wrap', 'word'), + ('relief', 'raised'), ('tabstyle', 'wordprocessor'), + ('offset', '5')): + text.tag_configure(tag, **{opt: value}) + self.assertEqual(str(text.tag_cget(tag, 'justify')), 'center') + self.assertEqual(str(text.tag_cget(tag, 'wrap')), 'word') + self.assertEqual(str(text.tag_cget(tag, 'relief')), 'raised') + self.assertEqual(str(text.tag_cget(tag, 'tabstyle')), 'wordprocessor') + + # Boolean options. + for opt in ('underline', 'overstrike', 'elide'): + text.tag_configure(tag, **{opt: True}) + self.assertIs(getboolean(text.tag_cget(tag, opt)), True) + text.tag_configure(tag, **{opt: False}) + self.assertIs(getboolean(text.tag_cget(tag, opt)), False) + + # Screen-distance (pixel) options. + for opt in ('borderwidth', 'lmargin1', 'lmargin2', 'rmargin', + 'spacing1', 'spacing2', 'spacing3'): + text.tag_configure(tag, **{opt: 7}) + self.assertEqual(getint(text.tag_cget(tag, opt)), 7) + + # Other options. + text.tag_configure(tag, font='Helvetica 12') + self.assertEqual(str(text.tag_cget(tag, 'font')), 'Helvetica 12') + text.tag_configure(tag, tabs=(10.2, '1i')) + self.assertEqual([str(x) for x in text.tag_ranges('sel')], []) + + self.assertRaises(TclError, text.tag_cget, tag, 'spam') + + @requires_tk(8, 6, 6) + def test_tag_configure_colors(self): + # Tag color options added in Tk 8.6.6. + text = self.text + tag = 'a' + for opt in ('selectforeground', 'selectbackground', + 'lmargincolor', 'rmargincolor', + 'underlinefg', 'overstrikefg'): + text.tag_configure(tag, **{opt: '#00ff00'}) + self.assertEqual(str(text.tag_cget(tag, opt)), '#00ff00') + + def test_tag_configure_query(self): + text = self.text + tag = 'a' + # Querying all options returns a dict keyed by option name. + cnf = text.tag_configure(tag) + self.assertIsInstance(cnf, dict) + self.assertIn('foreground', cnf) + # The value is the full 5-tuple option specification. + self.assertEqual(len(cnf['foreground']), 5) + + # Querying a single option returns its specification. + spec = text.tag_configure(tag, 'foreground') + self.assertEqual(spec[0], 'foreground') + self.assertEqual(spec[-1], '') # unset by default + + # Setting via keyword arguments and via a dict are equivalent. + text.tag_configure(tag, foreground='red') + self.assertEqual(str(text.tag_configure(tag, 'foreground')[-1]), 'red') + text.tag_configure(tag, {'foreground': 'blue'}) + self.assertEqual(str(text.tag_cget(tag, 'foreground')), 'blue') + + # tag_config is an alias of tag_configure. + self.assertEqual(text.tag_config, text.tag_configure) + + def test_image_configure(self): + text = self.text + image = tkinter.PhotoImage(master=self.root, width=10, height=10) + text.insert('1.0', 'AB') + name = text.image_create('1.1', image=image, name='img') + self.assertEqual(name, 'img') + + self.assertEqual(str(text.image_cget(name, 'name')), 'img') + self.assertEqual(str(text.image_cget(name, 'image')), str(image)) + for value in ('top', 'center', 'bottom', 'baseline'): + text.image_configure(name, align=value) + self.assertEqual(str(text.image_cget(name, 'align')), value) + text.image_configure(name, padx=3, pady=4) + self.assertEqual(text.tk.getint(text.image_cget(name, 'padx')), 3) + self.assertEqual(text.tk.getint(text.image_cget(name, 'pady')), 4) + + # Querying returns the full option set. + cnf = text.image_configure(name) + self.assertIsInstance(cnf, dict) + self.assertIn('align', cnf) + self.assertRaises(TclError, text.image_cget, name, 'spam') + + def test_window_configure(self): + text = self.text + button = tkinter.Button(text, text='ok') + text.insert('1.0', 'AB') + text.window_create('1.1', window=button) + + self.assertEqual(text.window_cget('1.1', 'window'), str(button)) + for value in ('top', 'center', 'bottom', 'baseline'): + text.window_configure('1.1', align=value) + self.assertEqual(str(text.window_cget('1.1', 'align')), value) + text.window_configure('1.1', padx=3, pady=4) + self.assertEqual(text.tk.getint(text.window_cget('1.1', 'padx')), 3) + self.assertEqual(text.tk.getint(text.window_cget('1.1', 'pady')), 4) + text.window_configure('1.1', stretch=True) + self.assertIs(text.tk.getboolean(text.window_cget('1.1', 'stretch')), + True) + + cnf = text.window_configure('1.1') + self.assertIsInstance(cnf, dict) + self.assertIn('stretch', cnf) + self.assertRaises(TclError, text.window_cget, '1.1', 'spam') + button.destroy() + + def test_peer(self): + text = self.text + text.insert('1.0', 'Lorem ipsum') + self.assertEqual(text.peer_names(), ()) + + text.peer_create('.peer1') + names = self.root.splitlist(text.tk.call('winfo', 'children', '.')) + self.assertIn('.peer1', [str(n) for n in names]) + self.assertEqual([str(p) for p in text.peer_names()], ['.peer1']) + # Peers share content. + self.assertEqual(text.tk.call('.peer1', 'get', '1.0', 'end'), + 'Lorem ipsum\n') + text.tk.call('destroy', '.peer1') + + def test_bbox(self): + text = self.text + text.insert('1.0', 'hello') + text.update() + bbox = text.bbox('1.0') + self.assertIsInstance(bbox, tuple) + self.assertEqual(len(bbox), 4) + for v in bbox: + self.assertIsInstance(v, int) + # A character that is not displayed has no bounding box. + self.assertIsNone(text.bbox('end')) + self.assertRaises(TclError, text.bbox, 'invalid') + self.assertRaises(TypeError, text.bbox) + self.assertRaises(TypeError, text.bbox, '1.0', '2.0') + + def test_dlineinfo(self): + text = self.text + text.insert('1.0', 'hello\nworld') + text.update() + info = text.dlineinfo('1.0') + self.assertIsInstance(info, tuple) + self.assertEqual(len(info), 5) + for v in info: + self.assertIsInstance(v, int) + self.assertRaises(TclError, text.dlineinfo, 'invalid') + self.assertRaises(TypeError, text.dlineinfo) + self.assertRaises(TypeError, text.dlineinfo, '1.0', '2.0') + + def test_see(self): + text = self.text + text.insert('1.0', '\n'.join('line %d' % i for i in range(200))) + text.update() + # Initially the last line is not visible. + self.assertIsNone(text.bbox('200.0')) + text.see('200.0') + text.update() + self.assertIsNotNone(text.bbox('200.0')) + self.assertRaises(TclError, text.see, 'invalid') + self.assertRaises(TypeError, text.see) + self.assertRaises(TypeError, text.see, '1.0', '2.0') + def test_search(self): text = self.text # pattern and index are obligatory arguments. - self.assertRaises(tkinter.TclError, text.search, None, '1.0') - self.assertRaises(tkinter.TclError, text.search, 'a', None) - self.assertRaises(tkinter.TclError, text.search, None, None) + self.assertRaises(TclError, text.search, None, '1.0') + self.assertRaises(TclError, text.search, 'a', None) + self.assertRaises(TclError, text.search, None, None) # Invalid text index. - self.assertRaises(tkinter.TclError, text.search, '', 0) - self.assertRaises(tkinter.TclError, text.search, '', '') - self.assertRaises(tkinter.TclError, text.search, '', 'invalid') - self.assertRaises(tkinter.TclError, text.search, '', '1.0', 0) - self.assertRaises(tkinter.TclError, text.search, '', '1.0', '') - self.assertRaises(tkinter.TclError, text.search, '', '1.0', 'invalid') + self.assertRaises(TclError, text.search, '', 0) + self.assertRaises(TclError, text.search, '', '') + self.assertRaises(TclError, text.search, '', 'invalid') + self.assertRaises(TclError, text.search, '', '1.0', 0) + self.assertRaises(TclError, text.search, '', '1.0', '') + self.assertRaises(TclError, text.search, '', '1.0', 'invalid') text.insert('1.0', 'This is a test. This is only a test.\n' @@ -88,20 +625,20 @@ def test_search_all(self): text = self.text # pattern and index are obligatory arguments. - self.assertRaises(tkinter.TclError, text.search_all, None, '1.0') - self.assertRaises(tkinter.TclError, text.search_all, 'a', None) - self.assertRaises(tkinter.TclError, text.search_all, None, None) + self.assertRaises(TclError, text.search_all, None, '1.0') + self.assertRaises(TclError, text.search_all, 'a', None) + self.assertRaises(TclError, text.search_all, None, None) # Keyword-only arguments self.assertRaises(TypeError, text.search_all, 'a', '1.0', 'end', None) # Invalid text index. - self.assertRaises(tkinter.TclError, text.search_all, '', 0) - self.assertRaises(tkinter.TclError, text.search_all, '', '') - self.assertRaises(tkinter.TclError, text.search_all, '', 'invalid') - self.assertRaises(tkinter.TclError, text.search_all, '', '1.0', 0) - self.assertRaises(tkinter.TclError, text.search_all, '', '1.0', '') - self.assertRaises(tkinter.TclError, text.search_all, '', '1.0', 'invalid') + self.assertRaises(TclError, text.search_all, '', 0) + self.assertRaises(TclError, text.search_all, '', '') + self.assertRaises(TclError, text.search_all, '', 'invalid') + self.assertRaises(TclError, text.search_all, '', '1.0', 0) + self.assertRaises(TclError, text.search_all, '', '1.0', '') + self.assertRaises(TclError, text.search_all, '', '1.0', 'invalid') def eq(res, expected): self.assertIsInstance(res, tuple) @@ -181,8 +718,8 @@ def test_count(self): self.assertEqual(text.count('1.0', 'end'), (124,)) self.assertEqual(text.count('1.0', 'end', 'indices', return_ints=True), 124) self.assertEqual(text.count('1.0', 'end', 'indices'), (124,)) - self.assertRaises(tkinter.TclError, text.count, '1.0', 'end', 'spam') - self.assertRaises(tkinter.TclError, text.count, '1.0', 'end', '-lines') + self.assertRaises(TclError, text.count, '1.0', 'end', 'spam') + self.assertRaises(TclError, text.count, '1.0', 'end', '-lines') self.assertIsInstance(text.count('1.3', '1.5', 'ypixels', return_ints=True), int) self.assertIsInstance(text.count('1.3', '1.5', 'ypixels'), tuple) From be26b8d67fb31090ae63531090b82d278bb8b4c0 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 19 Jun 2026 12:47:36 +0200 Subject: [PATCH 371/818] [3.15] gh-151678: Add tests for tkinter.Canvas (GH-151683) (GH-151716) Cover previously-untested Canvas methods in CanvasTest: * item creation and types, bbox, coordinate conversion, move/scale, find and addtag queries, tags, item configuration, stacking order, text-item editing, selection, focus, scan and postscript; * the create_arc, create_oval, create_bitmap, create_image, create_text and create_window item creation methods, checking coordinates, default and explicit options, valid enumerations and rejection of invalid values; * tag_bind() and tag_unbind(), checking the returned function id and binding script, querying bound sequences, the add parameter, event delivery to items via a tag, and removal of a single binding by id or all bindings for a sequence. (cherry picked from commit bb127c5a96a285f1f6b11261c1f0dc2b3c7f70ff) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --- Lib/test/test_tkinter/test_widgets.py | 501 ++++++++++++++++++++++++++ 1 file changed, 501 insertions(+) diff --git a/Lib/test/test_tkinter/test_widgets.py b/Lib/test/test_tkinter/test_widgets.py index 3fea5773632ef5..ea53382bfa2ab9 100644 --- a/Lib/test/test_tkinter/test_widgets.py +++ b/Lib/test/test_tkinter/test_widgets.py @@ -978,6 +978,122 @@ def test_create_polygon(self): self._test_option_smooth(c, lambda **kwargs: c.create_polygon(20, 30, 40, 50, 60, 10, **kwargs)) + def test_create_arc(self): + c = self.create() + i = c.create_arc(10, 20, 30, 40) + self.assertEqual(c.coords(i), [10.0, 20.0, 30.0, 40.0]) + self.assertEqual(c.itemcget(i, 'style'), 'pieslice') + self.assertEqual(float(c.itemcget(i, 'start')), 0.0) + self.assertEqual(float(c.itemcget(i, 'extent')), 90.0) + + for style in 'pieslice', 'chord', 'arc': + i = c.create_arc(10, 20, 30, 40, style=style) + self.assertEqual(c.itemcget(i, 'style'), style) + self.assertRaises(TclError, c.create_arc, 10, 20, 30, 40, style='spam') + + i = c.create_arc(10, 20, 30, 40, start=45, extent=120, + outline='red', fill='blue', width=3) + self.assertEqual(float(c.itemcget(i, 'start')), 45.0) + self.assertEqual(float(c.itemcget(i, 'extent')), 120.0) + self.assertEqual(str(c.itemcget(i, 'outline')), 'red') + self.assertEqual(str(c.itemcget(i, 'fill')), 'blue') + self.assertEqual(float(c.itemcget(i, 'width')), 3.0) + self.assertRaises(TclError, c.create_arc, 10, 20, 30, 40, extent='spam') + + def test_create_oval(self): + c = self.create() + i = c.create_oval(10, 20, 30, 40) + self.assertEqual(c.coords(i), [10.0, 20.0, 30.0, 40.0]) + self.assertEqual(c.bbox(i), (9, 19, 31, 41)) + self.assertEqual(c.itemcget(i, 'stipple'), '') + + i = c.create_oval(10, 20, 30, 40, fill='red', outline='blue', width=2) + self.assertEqual(str(c.itemcget(i, 'fill')), 'red') + self.assertEqual(str(c.itemcget(i, 'outline')), 'blue') + self.assertEqual(float(c.itemcget(i, 'width')), 2.0) + self.assertRaises(TclError, c.create_oval, 10, 20, 30, 40, width='spam') + + def test_create_bitmap(self): + c = self.create() + i = c.create_bitmap(10, 20, bitmap='gray50') + self.assertEqual(c.coords(i), [10.0, 20.0]) + self.assertEqual(c.itemcget(i, 'bitmap'), 'gray50') + self.assertEqual(c.itemcget(i, 'anchor'), 'center') + + for anchor in 'n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw', 'center': + i = c.create_bitmap(10, 20, bitmap='gray50', anchor=anchor) + self.assertEqual(c.itemcget(i, 'anchor'), anchor) + self.assertRaises(TclError, c.create_bitmap, 10, 20, + bitmap='gray50', anchor='spam') + + i = c.create_bitmap(10, 20, bitmap='gray50', + foreground='red', background='blue') + self.assertEqual(str(c.itemcget(i, 'foreground')), 'red') + self.assertEqual(str(c.itemcget(i, 'background')), 'blue') + if c._windowingsystem != 'aqua': + # Aqua resolves bitmaps lazily and does not report a bad name here. + self.assertRaises(TclError, c.create_bitmap, 10, 20, bitmap='spam') + + def test_create_image(self): + c = self.create() + image = tkinter.PhotoImage(master=self.root, width=10, height=10) + i = c.create_image(10, 20, image=image) + self.assertEqual(c.coords(i), [10.0, 20.0]) + self.assertEqual(str(c.itemcget(i, 'image')), str(image)) + self.assertEqual(c.itemcget(i, 'anchor'), 'center') + + for anchor in 'n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw', 'center': + i = c.create_image(10, 20, image=image, anchor=anchor) + self.assertEqual(c.itemcget(i, 'anchor'), anchor) + self.assertRaises(TclError, c.create_image, 10, 20, + image=image, anchor='spam') + + def test_create_text(self): + c = self.create() + i = c.create_text(10, 20, text='Hello') + self.assertEqual(c.coords(i), [10.0, 20.0]) + self.assertEqual(c.itemcget(i, 'text'), 'Hello') + self.assertEqual(c.itemcget(i, 'anchor'), 'center') + self.assertEqual(c.itemcget(i, 'justify'), 'left') + + for justify in 'left', 'right', 'center': + i = c.create_text(10, 20, text='Hello', justify=justify) + self.assertEqual(c.itemcget(i, 'justify'), justify) + self.assertRaises(TclError, c.create_text, 10, 20, justify='spam') + + for anchor in 'n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw', 'center': + i = c.create_text(10, 20, text='Hello', anchor=anchor) + self.assertEqual(c.itemcget(i, 'anchor'), anchor) + self.assertRaises(TclError, c.create_text, 10, 20, anchor='spam') + + i = c.create_text(10, 20, text='Hello', fill='red', angle=45, + font='TkFixedFont') + self.assertEqual(str(c.itemcget(i, 'fill')), 'red') + self.assertEqual(float(c.itemcget(i, 'angle')), 45.0) + self.assertEqual(str(c.itemcget(i, 'font')), 'TkFixedFont') + self.assertRaises(TclError, c.create_text, 10, 20, angle='spam') + + def test_create_window(self): + c = self.create() + button = tkinter.Button(c, text='ok') + i = c.create_window(10, 20, window=button) + self.assertEqual(c.coords(i), [10.0, 20.0]) + self.assertEqual(c.itemcget(i, 'window'), str(button)) + self.assertEqual(c.itemcget(i, 'anchor'), 'center') + + for anchor in 'n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw', 'center': + i = c.create_window(10, 20, window=tkinter.Button(c), anchor=anchor) + self.assertEqual(c.itemcget(i, 'anchor'), anchor) + self.assertRaises(TclError, c.create_window, 10, 20, + window=button, anchor='spam') + + i = c.create_window(10, 20, window=tkinter.Button(c), + width=30, height=40) + self.assertEqual(int(c.itemcget(i, 'width')), 30) + self.assertEqual(int(c.itemcget(i, 'height')), 40) + self.assertRaises(TclError, c.create_window, 10, 20, + window=button, width='spam') + def test_coords(self): c = self.create() i = c.create_line(20, 30, 40, 50, 60, 10, tags='x') @@ -1038,6 +1154,391 @@ def test_moveto(self): self.assertEqual(x2_2 - x1_2, x2_3 - x1_3) self.assertEqual(y2_2 - y1_2, y2_3 - y1_3) + def test_create_items(self): + c = self.create() + image = tkinter.PhotoImage(master=self.root, width=10, height=10) + button = tkinter.Button(c, text='ok') + items = { + 'arc': c.create_arc(10, 20, 30, 40), + 'bitmap': c.create_bitmap(10, 20, bitmap='gray50'), + 'image': c.create_image(10, 20, image=image), + 'line': c.create_line(10, 20, 30, 40), + 'oval': c.create_oval(10, 20, 30, 40), + 'polygon': c.create_polygon(10, 20, 30, 40, 50, 20), + 'rectangle': c.create_rectangle(10, 20, 30, 40), + 'text': c.create_text(10, 20, text='hello'), + 'window': c.create_window(10, 20, window=button), + } + for itemtype, item in items.items(): + self.assertIsInstance(item, int) + self.assertEqual(c.type(item), itemtype) + # All items are reported by find_all in creation (stacking) order. + self.assertEqual(c.find_all(), tuple(sorted(items.values()))) + + # No coordinates at all is an IndexError; a bad number is a TclError. + self.assertRaises(IndexError, c.create_arc) + self.assertRaises(TclError, c.create_arc, 1, 2, 3) + self.assertRaises(TclError, c.create_oval, 1, 2) + + def test_type(self): + c = self.create() + rect = c.create_rectangle(10, 20, 30, 40) + self.assertEqual(c.type(rect), 'rectangle') + # An unmatched tag or id is not an error. + self.assertIsNone(c.type('nonexistent')) + self.assertIsNone(c.type(9999)) + self.assertRaises(TypeError, c.type) + self.assertRaises(TypeError, c.type, rect, 'extra') + + def test_bbox(self): + c = self.create() + rect = c.create_rectangle(10, 10, 30, 30) + bbox = c.bbox(rect) + self.assertIsInstance(bbox, tuple) + self.assertEqual(len(bbox), 4) + for v in bbox: + self.assertIsInstance(v, int) + # The bounding box encloses the item (with a small margin). + self.assertEqual(bbox, (9, 9, 31, 31)) + # bbox over several items is their union. + rect2 = c.create_rectangle(50, 50, 70, 70) + self.assertEqual(c.bbox(rect, rect2), (9, 9, 71, 71)) + # An unmatched tag has no bounding box. + self.assertIsNone(c.bbox('nonexistent')) + # At least one tag or id is required. + self.assertRaises(TclError, c.bbox) + + def test_canvasx_canvasy(self): + c = self.create(borderwidth=0, highlightthickness=0) + self.assertEqual(c.canvasx(0), 0.0) + self.assertEqual(c.canvasx(10), 10.0) + self.assertIsInstance(c.canvasx(10), float) + # gridspacing rounds to the nearest multiple. + self.assertEqual(c.canvasx(13, 5), 15.0) + self.assertEqual(c.canvasy(0), 0.0) + self.assertEqual(c.canvasy(10), 10.0) + self.assertRaises(TypeError, c.canvasx) + self.assertRaises(TypeError, c.canvasx, 0, 5, 1) + self.assertRaises(TypeError, c.canvasy) + self.assertRaises(TypeError, c.canvasy, 0, 5, 1) + self.assertRaises(TclError, c.canvasx, 'spam') + self.assertRaises(TclError, c.canvasy, 'spam') + + def test_move(self): + c = self.create() + rect = c.create_rectangle(10, 10, 30, 30) + c.move(rect, 5, 7) + self.assertEqual(c.coords(rect), [15.0, 17.0, 35.0, 37.0]) + c.move(rect, -5, -7) + self.assertEqual(c.coords(rect), [10.0, 10.0, 30.0, 30.0]) + # move() takes variable arguments; bad or missing values reach Tcl. + self.assertRaises(TclError, c.move, rect, 'spam', 0) + self.assertRaises(TclError, c.move, rect) + + def test_scale(self): + c = self.create() + rect = c.create_rectangle(10, 10, 30, 30) + c.scale(rect, 0, 0, 2, 2) + self.assertEqual(c.coords(rect), [20.0, 20.0, 60.0, 60.0]) + c.scale(rect, 0, 0, 0.5, 0.5) + self.assertEqual(c.coords(rect), [10.0, 10.0, 30.0, 30.0]) + self.assertRaises(TclError, c.scale, rect, 0, 0, 'spam', 2) + self.assertRaises(TclError, c.scale, rect, 0, 0) # missing factors + + def test_delete(self): + c = self.create() + r1 = c.create_rectangle(10, 10, 30, 30) + r2 = c.create_rectangle(50, 50, 70, 70) + r3 = c.create_rectangle(90, 90, 110, 110) + self.assertEqual(c.find_all(), (r1, r2, r3)) + c.delete(r2) + self.assertEqual(c.find_all(), (r1, r3)) + # Deleting a non-existent item is not an error. + c.delete(9999) + c.delete('all') + self.assertEqual(c.find_all(), ()) + + def test_find(self): + c = self.create() + r1 = c.create_rectangle(10, 10, 30, 30) + r2 = c.create_rectangle(50, 50, 70, 70) + r3 = c.create_rectangle(100, 100, 120, 120) + + self.assertEqual(c.find_all(), (r1, r2, r3)) + # find_above/find_below return the single adjacent item. + self.assertEqual(c.find_above(r1), (r2,)) + self.assertEqual(c.find_below(r3), (r2,)) + self.assertEqual(c.find_above(r3), ()) # nothing above the top item + self.assertEqual(c.find_withtag(r2), (r2,)) + self.assertEqual(c.find_closest(60, 60), (r2,)) + self.assertEqual(c.find_enclosed(0, 0, 80, 80), (r1, r2)) + self.assertEqual(c.find_overlapping(0, 0, 20, 20), (r1,)) + # An unmatched query returns an empty tuple. + self.assertEqual(c.find_withtag('nonexistent'), ()) + for result in (c.find_all(), c.find_withtag(r1)): + self.assertIsInstance(result, tuple) + + self.assertRaises(TclError, c.find_closest, 'spam', 0) + self.assertRaises(TclError, c.find_enclosed, 0, 0, 'spam', 0) + self.assertRaises(TclError, c.find_overlapping, 0, 0, 'spam', 0) + self.assertRaises(TypeError, c.find_withtag) + self.assertRaises(TypeError, c.find_withtag, r1, 'extra') + self.assertRaises(TypeError, c.find_above) + self.assertRaises(TypeError, c.find_above, r1, 'extra') + self.assertRaises(TypeError, c.find_below) + self.assertRaises(TypeError, c.find_closest) + self.assertRaises(TypeError, c.find_closest, 0, 0, 1, 2, 3) + self.assertRaises(TypeError, c.find_enclosed, 0, 0, 1) + self.assertRaises(TypeError, c.find_enclosed, 0, 0, 1, 2, 3) + + def test_addtag_gettags_dtag(self): + c = self.create() + r1 = c.create_rectangle(10, 10, 30, 30) + r2 = c.create_rectangle(50, 50, 70, 70) + + self.assertEqual(c.gettags(r1), ()) + c.addtag_withtag('spam', r1) + self.assertEqual(c.gettags(r1), ('spam',)) + self.assertEqual(c.find_withtag('spam'), (r1,)) + + c.addtag_all('all') + self.assertIn('all', c.gettags(r1)) + self.assertIn('all', c.gettags(r2)) + + c.addtag_above('above1', r1) + self.assertIn('above1', c.gettags(r2)) + c.addtag_below('below2', r2) + self.assertIn('below2', c.gettags(r1)) + + c.addtag_enclosed('enc', 0, 0, 40, 40) + self.assertEqual(c.find_withtag('enc'), (r1,)) + c.addtag_overlapping('ov', 0, 0, 20, 20) + self.assertEqual(c.find_withtag('ov'), (r1,)) + c.addtag_closest('close', 60, 60) + self.assertEqual(c.find_withtag('close'), (r2,)) + + # gettags of an unmatched tag is empty. + self.assertEqual(c.gettags('nonexistent'), ()) + + # dtag removes a tag from an item. + c.dtag(r1, 'spam') + self.assertNotIn('spam', c.gettags(r1)) + + self.assertRaises(TypeError, c.addtag_withtag, 'tag') + self.assertRaises(TypeError, c.addtag_withtag, 'tag', r1, 'extra') + self.assertRaises(TypeError, c.addtag_all) + self.assertRaises(TypeError, c.addtag_enclosed, 'tag', 0, 0, 1) + self.assertRaises(TypeError, c.addtag_enclosed, 'tag', 0, 0, 1, 2, 3) + self.assertRaises(TclError, c.addtag_closest, 'tag', 'spam', 0) + self.assertRaises(TclError, c.addtag_enclosed, 'tag', 0, 0, 'spam', 0) + self.assertRaises(TclError, c.gettags) # needs an item + + def test_itemconfigure(self): + c = self.create() + rect = c.create_rectangle(10, 10, 30, 30) + c.itemconfigure(rect, fill='red', width=3) + self.assertEqual(str(c.itemcget(rect, 'fill')), 'red') + self.assertEqual(float(c.itemcget(rect, 'width')), 3.0) + + # Querying all options returns a dict; a single one returns its spec. + cnf = c.itemconfigure(rect) + self.assertIsInstance(cnf, dict) + self.assertIn('fill', cnf) + self.assertEqual(c.itemconfigure(rect, 'fill')[-1], 'red') + + # itemconfig is an alias of itemconfigure. + self.assertEqual(c.itemconfig, c.itemconfigure) + + self.assertRaises(TclError, c.itemcget, rect, 'badoption') + self.assertRaises(TclError, c.itemconfigure, rect, badoption='x') + self.assertRaises(TypeError, c.itemcget, rect) + self.assertRaises(TypeError, c.itemcget, rect, 'fill', 'extra') + + def test_tag_raise_lower(self): + c = self.create() + r1 = c.create_rectangle(10, 10, 30, 30) + r2 = c.create_rectangle(50, 50, 70, 70) + r3 = c.create_rectangle(90, 90, 110, 110) + self.assertEqual(c.find_all(), (r1, r2, r3)) + + c.tag_raise(r1) + self.assertEqual(c.find_all(), (r2, r3, r1)) + c.tag_lower(r1) + self.assertEqual(c.find_all(), (r1, r2, r3)) + # Raise above / lower below a specific item. + c.tag_raise(r1, r2) + self.assertEqual(c.find_all(), (r2, r1, r3)) + c.tag_lower(r3, r2) + self.assertEqual(c.find_all(), (r3, r2, r1)) + + # lower/lift are aliases of tag_lower/tag_raise. + self.assertEqual(c.lower, c.tag_lower) + self.assertEqual(c.lift, c.tag_raise) + + # raise/lower need at least an item; an unmatched tag is not an error. + self.assertRaises(TclError, c.tag_raise) + self.assertRaises(TclError, c.tag_lower) + self.assertIsNone(c.tag_raise('nonexistent')) + + def test_text_item(self): + c = self.create() + item = c.create_text(10, 10, text='Hello') + self.assertEqual(c.index(item, 'end'), 5) + self.assertIsInstance(c.index(item, 'end'), int) + + c.insert(item, 'end', ' world') + self.assertEqual(c.itemcget(item, 'text'), 'Hello world') + self.assertEqual(c.index(item, 'end'), 11) + c.insert(item, 0, '>> ') + self.assertEqual(c.itemcget(item, 'text'), '>> Hello world') + + c.dchars(item, 0, 2) + self.assertEqual(c.itemcget(item, 'text'), 'Hello world') + c.icursor(item, 3) + + # index requires an indexable (text) item and a valid index. + self.assertRaises(TclError, c.index, item, 'badspec') + self.assertRaises(TclError, c.index, item) # missing index + self.assertRaises(TclError, c.dchars, item, 'badspec', 'end') + rect = c.create_rectangle(10, 10, 30, 30) + self.assertRaises(TclError, c.index, rect, 'end') + + def test_select(self): + c = self.create() + item = c.create_text(10, 10, text='Hello world') + self.assertIsNone(c.select_item()) + + c.select_from(item, 0) + c.select_to(item, 4) + self.assertEqual(int(c.select_item()), item) + c.select_adjust(item, 6) + + c.select_clear() + self.assertIsNone(c.select_item()) + self.assertRaises(TypeError, c.select_from, item) + self.assertRaises(TypeError, c.select_from, item, 0, 'extra') + # A bad index reaches Tcl; selection applies only to text items. + self.assertRaises(TclError, c.select_from, item, 'badspec') + rect = c.create_rectangle(10, 10, 30, 30) + self.assertRaises(TclError, c.select_from, rect, 0) + + def test_focus(self): + c = self.create() + item = c.create_text(10, 10, text='Hello') + # Only text items can take the focus. + c.focus(item) + self.assertEqual(int(c.focus()), item) + c.focus('') + self.assertIn(c.focus(), ('', None)) + + def test_scan(self): + c = self.create() + c.create_rectangle(10, 10, 300, 300) + c.scan_mark(0, 0) + c.scan_dragto(5, 5) # default gain=10 + c.scan_dragto(5, 5, 1) + self.assertRaises(TypeError, c.scan_mark) + self.assertRaises(TypeError, c.scan_mark, 0, 0, 0) + self.assertRaises(TclError, c.scan_mark, 'spam', 0) + + def test_postscript(self): + c = self.create() + c.create_rectangle(10, 10, 30, 30, fill='black') + ps = c.postscript() + self.assertIsInstance(ps, str) + self.assertStartsWith(ps, '%!PS-Adobe') + self.assertRaises(TclError, c.postscript, badoption='spam') + + def assertCommandExist(self, widget, funcid): + self.assertEqual( + widget.tk.splitlist(widget.tk.call('info', 'commands', funcid)), + (funcid,)) + + def assertCommandNotExist(self, widget, funcid): + self.assertEqual( + widget.tk.splitlist(widget.tk.call('info', 'commands', funcid)), + ()) + + def test_tag_bind(self): + c = self.create() + c.pack() + item = c.create_rectangle(20, 20, 100, 100, fill='red') + self.assertEqual(c.tag_bind(item), ()) + self.assertEqual(c.tag_bind(item, '<Button-1>'), '') + + events = [] + def test1(e): events.append('a') + def test2(e): events.append('b') + + funcid = c.tag_bind(item, '<Button-1>', test1) + self.assertEqual(c.tag_bind(item), ('<Button-1>',)) + script = c.tag_bind(item, '<Button-1>') + self.assertIn(funcid, script) + self.assertCommandExist(c, funcid) + + funcid2 = c.tag_bind(item, '<Button-1>', test2, add=True) + script = c.tag_bind(item, '<Button-1>') + self.assertIn(funcid, script) + self.assertIn(funcid2, script) + self.assertCommandExist(c, funcid) + self.assertCommandExist(c, funcid2) + + c.wait_visibility() + c.focus_force() + c.update() + c.event_generate('<Button-1>', x=50, y=50) + c.update() + self.assertEqual(events, ['a', 'b']) + + # Binding to a tag applies to all items carrying it. + c.addtag_withtag('spam', item) + events.clear() + c.tag_bind('spam', '<Button-3>', test1) + c.event_generate('<Button-3>', x=50, y=50) + c.update() + self.assertEqual(events, ['a']) + + def test_tag_unbind(self): + c = self.create() + c.pack() + item = c.create_rectangle(20, 20, 100, 100, fill='red') + + events = [] + def test1(e): events.append('a') + def test2(e): events.append('b') + + funcid = c.tag_bind(item, '<Button-1>', test1) + funcid2 = c.tag_bind(item, '<Button-1>', test2, add=True) + c.wait_visibility() + c.focus_force() + c.update() + c.event_generate('<Button-1>', x=50, y=50) + c.update() + self.assertEqual(events, ['a', 'b']) + + # Removing one function leaves the other in place. + c.tag_unbind(item, '<Button-1>', funcid) + script = c.tag_bind(item, '<Button-1>') + self.assertNotIn(funcid, script) + self.assertIn(funcid2, script) + self.assertCommandNotExist(c, funcid) + self.assertCommandExist(c, funcid2) + events.clear() + c.event_generate('<Button-1>', x=50, y=50) + c.update() + self.assertEqual(events, ['b']) + + # Without a funcid all bindings for the sequence are removed. + c.tag_unbind(item, '<Button-1>') + self.assertEqual(c.tag_bind(item, '<Button-1>'), '') + self.assertEqual(c.tag_bind(item), ()) + events.clear() + c.event_generate('<Button-1>', x=50, y=50) + c.update() + self.assertEqual(events, []) + + self.assertRaises(TypeError, c.tag_unbind, item) + @add_configure_tests(IntegerSizeTests, StandardOptionsTests) class ListboxTest(AbstractWidgetTest, unittest.TestCase): From 13529d43c93fad5bb394be348a805b2f94fbb9cf Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 19 Jun 2026 13:52:05 +0200 Subject: [PATCH 372/818] [3.15] gh-151678: Add tests for the remaining tkinter widgets (GH-151687) (GH-151725) Cover previously-untested methods of several widgets: * Button, Checkbutton and Radiobutton: invoke, flash and toggle; * Entry: delete, icursor and the select_* aliases; * Spinbox: invoke, identify and scan; * Scale and Scrollbar: identify, and Scrollbar fraction and delta; * PanedWindow: panes, remove/forget, sash and proxy positioning, identify, and adding panes with configuration options. Also test that invoke does nothing for a disabled button and the errors raised for invalid indices, coordinates, option names and values. (cherry picked from commit 93b9e7666f4337e3cacfed6993568e4bec575e9b) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --- Lib/test/test_tkinter/test_widgets.py | 250 ++++++++++++++++++++++++++ 1 file changed, 250 insertions(+) diff --git a/Lib/test/test_tkinter/test_widgets.py b/Lib/test/test_tkinter/test_widgets.py index ea53382bfa2ab9..8ce71bc37ca2e4 100644 --- a/Lib/test/test_tkinter/test_widgets.py +++ b/Lib/test/test_tkinter/test_widgets.py @@ -208,6 +208,23 @@ def test_configure_default(self): widget = self.create() self.checkEnumParam(widget, 'default', 'active', 'disabled', 'normal') + def test_invoke(self): + success = [] + widget = self.create(command=lambda: success.append(1)) + widget.pack() + widget.invoke() + self.assertEqual(success, [1]) + # invoke does nothing for a disabled button. + widget.configure(state='disabled') + widget.invoke() + self.assertEqual(success, [1]) + + def test_flash(self): + widget = self.create() + widget.pack() + widget.update_idletasks() + widget.flash() # No exception. + @add_configure_tests(StandardOptionsTests) class CheckbuttonTest(AbstractLabelTest, unittest.TestCase): @@ -263,6 +280,39 @@ def test_same_name(self): b2.deselect() self.assertEqual(v.get(), 0) + def test_invoke(self): + success = [] + v = tkinter.IntVar(self.root) + widget = self.create(variable=v, onvalue=1, offvalue=0, + command=lambda: success.append(v.get())) + widget.pack() + widget.invoke() + self.assertEqual(v.get(), 1) + self.assertEqual(success, [1]) + widget.invoke() + self.assertEqual(v.get(), 0) + self.assertEqual(success, [1, 0]) + # A disabled checkbutton is not toggled and its command is not called. + widget.configure(state='disabled') + widget.invoke() + self.assertEqual(v.get(), 0) + self.assertEqual(success, [1, 0]) + + def test_toggle(self): + v = tkinter.IntVar(self.root) + widget = self.create(variable=v, onvalue=1, offvalue=0) + self.assertEqual(v.get(), 0) + widget.toggle() + self.assertEqual(v.get(), 1) + widget.toggle() + self.assertEqual(v.get(), 0) + + def test_flash(self): + widget = self.create() + widget.pack() + widget.update_idletasks() + widget.flash() # No exception. + @add_configure_tests(StandardOptionsTests) class RadiobuttonTest(AbstractLabelTest, unittest.TestCase): OPTIONS = ( @@ -285,6 +335,28 @@ def test_configure_value(self): widget = self.create() self.checkParams(widget, 'value', 1, 2.3, '', 'any string') + def test_invoke(self): + success = [] + v = tkinter.StringVar(self.root) + widget = self.create(variable=v, value='on', + command=lambda: success.append(v.get())) + widget.pack() + widget.invoke() + self.assertEqual(v.get(), 'on') + self.assertEqual(success, ['on']) + # invoke does nothing for a disabled radiobutton. + v.set('') + widget.configure(state='disabled') + widget.invoke() + self.assertEqual(v.get(), '') + self.assertEqual(success, ['on']) + + def test_flash(self): + widget = self.create() + widget.pack() + widget.update_idletasks() + widget.flash() # No exception. + @add_configure_tests(StandardOptionsTests) class MenubuttonTest(AbstractLabelTest, unittest.TestCase): @@ -476,6 +548,47 @@ def test_selection_methods(self): self.assertEqual(widget.selection_get(), '12345') widget.selection_adjust(0) + def test_delete(self): + widget = self.create() + widget.insert(0, 'abcdef') + widget.delete(1, 3) + self.assertEqual(widget.get(), 'adef') + widget.delete(1) + self.assertEqual(widget.get(), 'aef') + widget.delete(0, 'end') + self.assertEqual(widget.get(), '') + self.assertRaisesRegex(TclError, r'bad (entry|spinbox) index "xyz"', + widget.delete, 'xyz') + self.assertRaises(TypeError, widget.delete) + + def test_icursor(self): + widget = self.create() + widget.insert(0, 'abcdef') + widget.icursor(3) + widget.insert('insert', 'XYZ') + self.assertEqual(widget.get(), 'abcXYZdef') + self.assertRaisesRegex(TclError, r'bad (entry|spinbox) index "xyz"', + widget.icursor, 'xyz') + self.assertRaises(TypeError, widget.icursor) + + def test_select_aliases(self): + # The select_* methods are aliases of the selection_* methods. + widget = self.create() + widget.insert(0, '12345') + self.assertFalse(widget.select_present()) + widget.select_range(0, 'end') + self.assertTrue(widget.select_present()) + self.assertEqual(widget.selection_get(), '12345') + widget.select_from(1) + widget.select_to(3) + self.assertEqual(widget.selection_get(), '23') + widget.select_adjust(4) + self.assertEqual(widget.selection_get(), '234') + widget.select_clear() + self.assertFalse(widget.select_present()) + self.assertRaisesRegex(TclError, 'bad entry index "xyz"', + widget.select_range, 'xyz', 'end') + @add_configure_tests(StandardOptionsTests) class SpinboxTest(EntryTest, unittest.TestCase): @@ -624,6 +737,38 @@ def test_selection_element(self): widget.selection_element("buttondown") self.assertEqual(widget.selection_element(), "buttondown") + # Spinbox has no select_* aliases, unlike Entry. + test_select_aliases = None + + def test_invoke(self): + widget = self.create(from_=0, to=10) + widget.delete(0, 'end') + widget.insert(0, '5') + widget.invoke('buttonup') + self.assertEqual(widget.get(), '6') + widget.invoke('buttondown') + self.assertEqual(widget.get(), '5') + self.assertRaisesRegex(TclError, 'bad element "spam"', + widget.invoke, 'spam') + + def test_identify(self): + widget = self.create() + widget.pack() + widget.update_idletasks() + # The empty string is returned for a point over no element. + self.assertIn(widget.identify(5, 5), + ('entry', 'buttonup', 'buttondown', 'none', '')) + self.assertRaises(TclError, widget.identify, 'a', 'b') + + def test_scan(self): + widget = self.create() + widget.insert(0, 'a' * 100) + widget.pack() + widget.update_idletasks() + self.assertEqual(widget.scan_mark(10), ()) + self.assertEqual(widget.scan_dragto(0), ()) + self.assertRaises(TypeError, widget.scan_mark) + @add_configure_tests(StandardOptionsTests) class TextTest(AbstractWidgetTest, unittest.TestCase): @@ -1850,6 +1995,14 @@ def test_configure_to(self): self.checkFloatParam(widget, 'to', 300, 14.9, 15.1, -10, conv=float_round) + def test_identify(self): + widget = self.create() + widget.pack() + widget.update_idletasks() + self.assertIn(widget.identify(5, 5), + ('slider', 'trough1', 'trough2', '')) + self.assertRaises(TclError, widget.identify, 'a', 'b') + @add_configure_tests(PixelSizeTests, StandardOptionsTests) class ScrollbarTest(AbstractWidgetTest, unittest.TestCase): @@ -1903,6 +2056,34 @@ def test_set(self): self.assertRaises(TypeError, sb.set, 0.6) self.assertRaises(TypeError, sb.set, 0.6, 0.7, 0.8) + def test_fraction(self): + sb = self.create() + sb.pack(fill='y', expand=True) + sb.update_idletasks() + self.assertIsInstance(sb.fraction(0, 0), float) + f = sb.fraction(0, 1000) + self.assertIsInstance(f, float) + self.assertGreaterEqual(f, 0.0) + self.assertLessEqual(f, 1.0) + self.assertRaises(TclError, sb.fraction, 'a', 'b') + self.assertRaises(TypeError, sb.fraction, 0) + + def test_delta(self): + sb = self.create() + sb.pack(fill='y', expand=True) + sb.update_idletasks() + self.assertIsInstance(sb.delta(0, 10), float) + self.assertRaises(TclError, sb.delta, 'a', 'b') + self.assertRaises(TypeError, sb.delta, 0) + + def test_identify(self): + sb = self.create() + sb.pack(fill='y', expand=True) + sb.update_idletasks() + self.assertIn(sb.identify(5, 5), + ('arrow1', 'arrow2', 'slider', 'trough1', 'trough2', '')) + self.assertRaises(TclError, sb.identify, 'a', 'b') + @add_configure_tests(PixelSizeTests, StandardOptionsTests) class PanedWindowTest(AbstractWidgetTest, unittest.TestCase): @@ -1980,6 +2161,75 @@ def create2(self): p.add(c) return p, b, c + def test_panes(self): + p, b, c = self.create2() + self.assertEqual([str(x) for x in p.panes()], [str(b), str(c)]) + + def test_remove(self): + p, b, c = self.create2() + p.remove(b) + self.assertEqual([str(x) for x in p.panes()], [str(c)]) + p.forget(c) # forget is an alias of remove. + self.assertEqual(p.panes(), ()) + + def test_sash(self): + p, b, c = self.create2() + p.configure(width=200, height=50) + p.pack() + p.update() + x, y = p.sash_coord(0) + self.assertIsInstance(x, int) + self.assertIsInstance(y, int) + p.sash_place(0, 120, 0) + p.update() + self.assertEqual(p.sash_coord(0)[0], 120) + p.sash_mark(0) # No exception. + self.assertRaises(TclError, p.sash_coord, 5) + + def test_proxy(self): + p, b, c = self.create2() + p.configure(width=200, height=50) + p.pack() + p.update() + p.proxy_place(100, 10) + p.update() + self.assertEqual(p.proxy_coord()[0], 100) + p.proxy_forget() + p.update() + + def test_identify(self): + p, b, c = self.create2() + p.configure(width=200, height=50) + p.pack() + p.update() + x, y = p.sash_coord(0) + # A point over the sash reports the sash. + self.assertIn('sash', p.identify(x + 1, y + 5)) + # A point over a pane reports nothing. + self.assertFalse(p.identify(2, 2)) + self.assertRaises(TclError, p.identify, 'a', 'b') + + def test_add_options(self): + p = self.create() + b = tkinter.Button(p) + p.add(b, minsize=40, padx=3, sticky='ns') + self.assertEqual(p.panecget(b, 'minsize'), + 40 if self.wantobjects else '40') + self.assertEqual(p.panecget(b, 'padx'), + 3 if self.wantobjects else '3') + self.assertEqual(p.panecget(b, 'sticky'), 'ns') + self.assertRaisesRegex(TclError, 'unknown option "-spam"', + p.add, tkinter.Button(p), spam='x') + self.assertRaisesRegex(TclError, 'bad window path name "spam"', + p.add, 'spam') + + def test_paneconfigure_errors(self): + p, b, c = self.create2() + self.assertRaisesRegex(TclError, 'unknown option "-spam"', + p.paneconfigure, b, spam='x') + self.assertRaises(TclError, p.panecget, b, 'spam') + self.assertRaises(TclError, p.paneconfigure, 'spam') + def test_paneconfigure(self): p, b, c = self.create2() self.assertRaises(TypeError, p.paneconfigure) From d81cc8634190e8f48442c73502e124c730a605ca Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 19 Jun 2026 14:01:54 +0200 Subject: [PATCH 373/818] [3.15] gh-151693: Add curses tests for panels, textpad, and window behavior (GH-151694) (GH-151719) Add curses tests for panels, textpad, and window behavior Extend test_curses with behavior-verifying tests that go beyond the existing smoke tests: * curses.panel stacking: new_panel/top/bottom/above/below ordering, hide/show/hidden, move, replace and userptr round-trip. * Real-window curses.textpad.Textbox: gather(), edit(), stripspaces, insert mode and the Emacs-like editing commands (previously only exercised through a MagicMock). * Window output: addstr cursor advance and addnstr truncation, insstr/insnstr shifting without cursor movement, and pad behavior (instr, subpad cell sharing, the required 6-argument refresh()). * Error handling: out-of-range coordinates raising curses.error and bad character/string argument types. (cherry picked from commit b4cfb992ed3a28b8cd626f70e3550ac8dbec1758) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --- Lib/test/test_curses.py | 278 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 277 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_curses.py b/Lib/test/test_curses.py index d5ca7f2ca1ae65..647959146a792c 100644 --- a/Lib/test/test_curses.py +++ b/Lib/test/test_curses.py @@ -334,6 +334,63 @@ def test_output_string_embedded_null_chars(self): self.assertRaises(ValueError, stdscr.insstr, arg) self.assertRaises(ValueError, stdscr.insnstr, arg, 1) + def test_add_string_behavior(self): + # addstr() advances the cursor past the written text; addnstr() + # writes at most n characters. + win = curses.newwin(1, 10, 0, 0) + win.addstr(0, 0, 'abc') + self.assertEqual(win.getyx(), (0, 3)) + win.erase() + win.addnstr(0, 0, 'abcdef', 3) + self.assertEqual(win.instr(0, 0), b'abc ') + + def test_insert_string_behavior(self): + # insstr()/insnstr() insert at the cursor, shift the rest of the + # line right (losing characters off the edge), and leave the cursor + # where it was. + win = curses.newwin(1, 10, 0, 0) + win.addstr(0, 0, 'abcde') + win.move(0, 1) + win.insstr('XY') + self.assertEqual(win.getyx(), (0, 1)) # cursor did not advance + self.assertEqual(win.instr(0, 0), b'aXYbcde ') + + win.erase() + win.addstr(0, 0, 'ZZZZZ') + win.move(0, 0) + win.insnstr('abcdef', 3) # at most 3 characters + self.assertEqual(win.instr(0, 0), b'abcZZZZZ ') + + def test_insch(self): + # insch() inserts a single character at the cursor (or at y, x), + # shifting the rest of the line right. + win = curses.newwin(2, 10, 0, 0) + win.addstr(0, 0, 'abc') + win.move(0, 1) + win.insch(ord('X')) + self.assertEqual(win.instr(0, 0), b'aXbc ') + win.insch(1, 0, 'Y', curses.A_BOLD) + self.assertEqual(win.inch(1, 0), b'Y'[0] | curses.A_BOLD) + + def test_pad(self): + pad = curses.newpad(10, 20) + pad.addstr(0, 0, 'PADTEXT') + self.assertEqual(pad.instr(0, 0, 7), b'PADTEXT') + + # subpad() shares the parent pad's character cells. + sub = pad.subpad(3, 5, 0, 0) + self.assertEqual(sub.getmaxyx(), (3, 5)) + self.assertEqual(sub.instr(0, 0, 5), b'PADTE') + + # A pad is refreshed onto an explicit screen rectangle; the + # 6-argument form is required (and rejected for ordinary windows). + pad.refresh(0, 0, 0, 0, 4, 10) + pad.noutrefresh(0, 0, 0, 0, 4, 10) + curses.doupdate() + self.assertRaises(TypeError, pad.refresh) + win = curses.newwin(5, 5, 0, 0) + self.assertRaises(TypeError, win.refresh, 0, 0, 0, 0, 4, 4) + def test_read_from_window(self): stdscr = self.stdscr stdscr.addstr(0, 1, 'ABCD', curses.A_BOLD) @@ -350,6 +407,26 @@ def test_read_from_window(self): self.assertRaises(ValueError, stdscr.instr, -2) self.assertRaises(ValueError, stdscr.instr, 0, 2, -2) + def test_coordinate_errors(self): + # Addressing a cell outside the window raises curses.error. + win = curses.newwin(5, 10, 0, 0) + self.assertRaises(curses.error, win.move, 100, 100) + self.assertRaises(curses.error, win.move, -1, -1) + self.assertRaises(curses.error, win.addch, 100, 100, ord('x')) + self.assertRaises(curses.error, win.inch, 100, 100) + self.assertRaises(curses.error, win.chgat, 100, 0, curses.A_BOLD) + + def test_argument_errors(self): + win = curses.newwin(5, 10, 0, 0) + # A character argument must be an int, a byte or a one-element string. + self.assertRaises(TypeError, win.addch, []) + self.assertRaises(OverflowError, win.addch, 2**64) + # A string method rejects a non-string, non-bytes argument. + self.assertRaises(TypeError, win.addstr, 5) + self.assertRaises(TypeError, win.addstr) + # Wrong number of positional arguments. + self.assertRaises(TypeError, win.instr, 0, 0, 0, 0) + def test_getch(self): win = curses.newwin(5, 12, 5, 2) @@ -819,6 +896,10 @@ def test_prog_mode(self): self.skipTest('requires terminal') curses.def_prog_mode() curses.reset_prog_mode() + # def_shell_mode()/reset_shell_mode() are intentionally not exercised + # here: they capture and restore curses' "shell mode" terminal state, + # which is only meaningful before initscr(). Calling them mid-suite + # corrupts the modes that endwin() restores and breaks later tests. def test_beep(self): if (curses.tigetstr("bel") is not None @@ -1031,7 +1112,8 @@ def test_keyname(self): @requires_curses_func('has_key') def test_has_key(self): - curses.has_key(13) + self.assertIsInstance(curses.has_key(13), bool) + self.assertIsInstance(curses.has_key(curses.KEY_LEFT), bool) @requires_curses_func('getmouse') def test_getmouse(self): @@ -1083,6 +1165,200 @@ def test_disallow_instantiation(self): panel = curses.panel.new_panel(w) check_disallow_instantiation(self, type(panel)) + @requires_curses_func('panel') + def test_panel_stack(self): + panel = curses.panel + # new_panel() puts the panel on top of the stack, so the three + # panels end up ordered bottom -> top as p1, p2, p3. + p1 = panel.new_panel(curses.newwin(3, 6, 0, 0)) + p2 = panel.new_panel(curses.newwin(3, 6, 1, 1)) + p3 = panel.new_panel(curses.newwin(3, 6, 2, 2)) + self.addCleanup(self._delete_panels, p1, p2, p3) + + # The most recently created panel is on top. + self.assertIs(panel.top_panel(), p3) + # window() returns the wrapped window. + self.assertEqual(p2.window().getbegyx(), (1, 1)) + + # above()/below() walk the stack one step at a time. + self.assertIs(p1.above(), p2) + self.assertIs(p2.above(), p3) + self.assertIsNone(p3.above()) # nothing above the top panel + self.assertIs(p3.below(), p2) + self.assertIs(p2.below(), p1) + + # top() raises a panel to the top, bottom() lowers it to the bottom. + p1.top() + self.assertIs(panel.top_panel(), p1) + self.assertIsNone(p1.above()) + p1.bottom() + self.assertIs(panel.bottom_panel(), p1) + self.assertIsNone(p1.below()) + + # update_panels() refreshes the virtual screen from the stack. + panel.update_panels() + + @requires_curses_func('panel') + def test_panel_hide_show(self): + p = curses.panel.new_panel(curses.newwin(3, 6, 0, 0)) + self.addCleanup(self._delete_panels, p) + self.assertIs(p.hidden(), False) + p.hide() + self.assertIs(p.hidden(), True) + p.show() + self.assertIs(p.hidden(), False) + + @requires_curses_func('panel') + def test_panel_move(self): + win = curses.newwin(3, 6, 1, 2) + p = curses.panel.new_panel(win) + self.addCleanup(self._delete_panels, p) + self.assertEqual(win.getbegyx(), (1, 2)) + p.move(4, 5) + self.assertEqual(win.getbegyx(), (4, 5)) + + @requires_curses_func('panel') + def test_panel_replace(self): + win1 = curses.newwin(3, 6, 0, 0) + win2 = curses.newwin(4, 8, 1, 1) + p = curses.panel.new_panel(win1) + self.addCleanup(self._delete_panels, p) + self.assertIs(p.window(), win1) + p.replace(win2) + self.assertIs(p.window(), win2) + + @requires_curses_func('panel') + def test_panel_userptr(self): + p = curses.panel.new_panel(curses.newwin(3, 6, 0, 0)) + self.addCleanup(self._delete_panels, p) + obj = ['userptr'] + p.set_userptr(obj) + self.assertIs(p.userptr(), obj) + + def _delete_panels(self, *panels): + # Drop the panels from the global stack so they do not leak into + # later tests that inspect top_panel()/bottom_panel(). + for p in panels: + try: + p.bottom() + except curses.panel.error: + pass + del panels + gc_collect() + + def _make_textbox(self, nlines, ncols, *, insert_mode=False, stripspaces=1): + win = curses.newwin(nlines, ncols, 0, 0) + box = curses.textpad.Textbox(win, insert_mode=insert_mode) + box.stripspaces = stripspaces + return box, win + + def _type(self, box, text): + for ch in text: + box.do_command(ch if isinstance(ch, int) else ord(ch)) + + def test_textbox_gather(self): + # Typed text is read back by gather(). With stripspaces on (the + # default) gather() keeps a single trailing blank on a line and + # drops trailing empty lines. + box, win = self._make_textbox(3, 10) + self._type(box, 'Hello') + self.assertEqual(box.gather(), 'Hello \n') + + def test_textbox_gather_multiline(self): + box, win = self._make_textbox(3, 10) + self._type(box, 'ab') + box.do_command(curses.ascii.NL) # ^j -> start of next line + self._type(box, 'cd') + self.assertEqual(box.gather(), 'ab \ncd \n') + + def test_textbox_stripspaces(self): + box, win = self._make_textbox(1, 8, stripspaces=1) + self._type(box, 'hi') + self.assertEqual(box.gather(), 'hi ') + + box, win = self._make_textbox(1, 8, stripspaces=0) + self._type(box, 'hi') + self.assertEqual(box.gather(), 'hi ') + + def test_textbox_insert_mode(self): + # In insert mode a typed character shifts the rest of the line right. + box, win = self._make_textbox(1, 10, insert_mode=True) + self._type(box, 'aXc') + win.move(0, 1) + self._type(box, 'b') + self.assertEqual(box.gather(), 'abXc ') + + def test_textbox_movement(self): + box, win = self._make_textbox(3, 10) + self._type(box, 'abc') + box.do_command(curses.ascii.SOH) # ^a -> left edge + self.assertEqual(win.getyx(), (0, 0)) + box.do_command(curses.ascii.ENQ) # ^e -> end of line + self.assertEqual(win.getyx(), (0, 3)) + + def test_textbox_kill_to_eol(self): + box, win = self._make_textbox(1, 10) + self._type(box, 'abcdef') + win.move(0, 3) + box.do_command(curses.ascii.VT) # ^k -> clear to end of line + self.assertEqual(box.gather(), 'abc ') + + def test_textbox_backspace(self): + box, win = self._make_textbox(1, 10) + self._type(box, 'abc') + box.do_command(curses.ascii.BS) # ^h -> delete backward + self.assertEqual(box.gather(), 'ab ') + + def test_textbox_edit(self): + # edit() reads characters until Ctrl-G and returns the contents. + box, win = self._make_textbox(1, 10) + for ch in reversed('Hi' + chr(curses.ascii.BEL)): + curses.ungetch(ch) + self.assertEqual(box.edit(), 'Hi ') + + def test_textbox_edit_validate(self): + # The validate hook can rewrite an incoming keystroke. + box, win = self._make_textbox(1, 10) + for ch in reversed('abc' + chr(curses.ascii.BEL)): + curses.ungetch(ch) + box.edit(lambda ch: ord('X') if ch == ord('b') else ch) + self.assertEqual(box.gather(), 'aXc ') + + def test_textpad_rectangle(self): + # rectangle() draws a box with ACS line/corner characters. + win = curses.newwin(6, 12, 0, 0) + curses.textpad.rectangle(win, 0, 0, 4, 8) + chartext = curses.A_CHARTEXT + self.assertEqual(win.inch(0, 0) & chartext, + curses.ACS_ULCORNER & chartext) + self.assertEqual(win.inch(0, 8) & chartext, + curses.ACS_URCORNER & chartext) + self.assertEqual(win.inch(4, 0) & chartext, + curses.ACS_LLCORNER & chartext) + self.assertEqual(win.inch(4, 8) & chartext, + curses.ACS_LRCORNER & chartext) + self.assertEqual(win.inch(0, 1) & chartext, + curses.ACS_HLINE & chartext) + self.assertEqual(win.inch(1, 0) & chartext, + curses.ACS_VLINE & chartext) + + def test_wrapper(self): + # wrapper() sets up curses, passes the screen to the callable along + # with extra arguments, returns its result and restores the terminal. + if not self.isatty: + self.skipTest('requires terminal') + + def body(stdscr, a, b): + self.assertIsInstance(stdscr, type(self.stdscr)) + self.assertIs(curses.isendwin(), False) + return a + b + + self.assertEqual(curses.wrapper(body, 2, 3), 5) + self.assertIs(curses.isendwin(), True) + # wrapper() left the screen ended; revive it so the per-test + # endwin() cleanup does not fail with ERR. + curses.doupdate() + @requires_curses_func('is_term_resized') def test_is_term_resized(self): lines, cols = curses.LINES, curses.COLS From b010116e26bda41acbe6de54225266f5d02a3c1e Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 19 Jun 2026 14:37:43 +0200 Subject: [PATCH 374/818] [3.15] gh-151693: Make the curses tests portable to other curses implementations (GH-151729) (GH-151733) Make the curses tests portable to other curses implementations Guard the chgat() check (chgat() needs wchgat()) and stop assuming a subpad shares the parent pad's cells (implementation-defined in X/Open). (cherry picked from commit 64fab74bd7288bfa67cd7727452febdaafed4270) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --- Lib/test/test_curses.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_curses.py b/Lib/test/test_curses.py index 647959146a792c..c6a762c04e0525 100644 --- a/Lib/test/test_curses.py +++ b/Lib/test/test_curses.py @@ -377,10 +377,12 @@ def test_pad(self): pad.addstr(0, 0, 'PADTEXT') self.assertEqual(pad.instr(0, 0, 7), b'PADTEXT') - # subpad() shares the parent pad's character cells. + # subpad() creates a pad within the parent pad. Cell sharing with + # the parent is implementation-defined, so write to the subpad itself. sub = pad.subpad(3, 5, 0, 0) self.assertEqual(sub.getmaxyx(), (3, 5)) - self.assertEqual(sub.instr(0, 0, 5), b'PADTE') + sub.addstr(1, 0, 'sub') + self.assertEqual(sub.instr(1, 0, 3), b'sub') # A pad is refreshed onto an explicit screen rectangle; the # 6-argument form is required (and rejected for ordinary windows). @@ -414,7 +416,8 @@ def test_coordinate_errors(self): self.assertRaises(curses.error, win.move, -1, -1) self.assertRaises(curses.error, win.addch, 100, 100, ord('x')) self.assertRaises(curses.error, win.inch, 100, 100) - self.assertRaises(curses.error, win.chgat, 100, 0, curses.A_BOLD) + if hasattr(win, 'chgat'): # chgat() requires wchgat() + self.assertRaises(curses.error, win.chgat, 100, 0, curses.A_BOLD) def test_argument_errors(self): win = curses.newwin(5, 10, 0, 0) From 80d7626c74c1e455a9a2e0d34a06bf29b9970487 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 19 Jun 2026 15:52:07 +0200 Subject: [PATCH 375/818] [3.15] gh-150902: Optimize PyCriticalSection2 to skip locking the same locks held by the current CS2 (gh-151554) This mimics an optimization already present for the single-mutex critical section. (cherry picked from commit c2ca7724af94df6e078a4b2e86d1be8c410d9940) Co-authored-by: Daniele Parmeggiani <8658291+dpdani@users.noreply.github.com> --- Include/internal/pycore_critical_section.h | 7 +++---- ...026-06-08-13-14-42.gh-issue-150902.-CWZ66.rst | 1 + Python/critical_section.c | 16 ++++++++++++++++ 3 files changed, 20 insertions(+), 4 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-08-13-14-42.gh-issue-150902.-CWZ66.rst diff --git a/Include/internal/pycore_critical_section.h b/Include/internal/pycore_critical_section.h index 2a2846b1296b90..51d99d74ca159f 100644 --- a/Include/internal/pycore_critical_section.h +++ b/Include/internal/pycore_critical_section.h @@ -196,10 +196,9 @@ _PyCriticalSection2_Begin(PyThreadState *tstate, PyCriticalSection2 *c, PyObject static inline void _PyCriticalSection2_End(PyThreadState *tstate, PyCriticalSection2 *c) { - // if mutex1 is NULL, we used the fast path in - // _PyCriticalSection_BeginSlow for mutexes that are already held, - // which should only happen when mutex1 and mutex2 were the same mutex, - // and mutex2 should also be NULL. + // if mutex1 is NULL, we used the fast path in either + // _PyCriticalSection_BeginSlow or _PyCriticalSection2_BeginSlow for mutexes + // that are already held, and mutex2 should also be NULL. if (c->_cs_base._cs_mutex == NULL) { assert(c->_cs_mutex2 == NULL); return; diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-08-13-14-42.gh-issue-150902.-CWZ66.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-08-13-14-42.gh-issue-150902.-CWZ66.rst new file mode 100644 index 00000000000000..e3b7cd387b439f --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-08-13-14-42.gh-issue-150902.-CWZ66.rst @@ -0,0 +1 @@ +Apply an existing optimization of PyCriticalSection (single mutex) to PyCriticalSection2: avoid acquiring the same locks that the current CS has already acquired. diff --git a/Python/critical_section.c b/Python/critical_section.c index 98e23eda7cdd77..dbee6f236a73be 100644 --- a/Python/critical_section.c +++ b/Python/critical_section.c @@ -72,6 +72,22 @@ _PyCriticalSection2_BeginSlow(PyThreadState *tstate, PyCriticalSection2 *c, PyMu c->_cs_base._cs_prev = 0; return; } + // Same optimization as in _PyCriticalSection_BeginSlow: skip locking when + // recursively acquiring the same locks. + if (tstate->critical_section && + tstate->critical_section & _Py_CRITICAL_SECTION_TWO_MUTEXES) { + PyCriticalSection2 *prev2 = (PyCriticalSection2 *) + untag_critical_section(tstate->critical_section); + assert((uintptr_t)m1 < (uintptr_t)m2); + assert((uintptr_t)prev2->_cs_base._cs_mutex < + (uintptr_t)prev2->_cs_mutex2); + if (prev2->_cs_base._cs_mutex == m1 && prev2->_cs_mutex2 == m2) { + c->_cs_base._cs_mutex = NULL; + c->_cs_mutex2 = NULL; + c->_cs_base._cs_prev = 0; + return; + } + } c->_cs_base._cs_mutex = NULL; c->_cs_mutex2 = NULL; c->_cs_base._cs_prev = tstate->critical_section; From 81ceb566290f5824523414fa6b468c643aa55c8f Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 19 Jun 2026 17:06:42 +0200 Subject: [PATCH 376/818] [3.15] gh-151678: Add tests for tkinter Misc, Wm and geometry manager methods (GH-151732) (GH-151737) Cover previously-untested methods of the Misc, Wm, Pack, Place and Grid classes: * a new WinfoTest class for the winfo_* query methods (class, name, parent, children, toplevel, visual and screen information, atoms, pointer and screen coordinates, fpixels, containing, interps, viewable), including the pre-existing winfo_rgb and winfo_pathname; * in MiscTest: getint, getdouble, getvar, register, deletecommand, option_add/get/clear, nametowidget, the focus_*, grab_* and selection_own* methods, event_add/delete/info, and bell; * in WmTest: title, geometry, minsize/maxsize, resizable, aspect, grid, positionfrom/sizefrom, focusmodel, iconname, client/command, overrideredirect, state (with withdraw and deiconify), frame, group, protocol and transient; * the short-named aliases of the grid_*, pack_* and place_* geometry manager methods. (cherry picked from commit 23793ac211371415eaf9491fef031f121969dfb3) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --- .../test_tkinter/test_geometry_managers.py | 55 +++ Lib/test/test_tkinter/test_misc.py | 389 ++++++++++++++++-- 2 files changed, 407 insertions(+), 37 deletions(-) diff --git a/Lib/test/test_tkinter/test_geometry_managers.py b/Lib/test/test_tkinter/test_geometry_managers.py index 3dcdadd1aacf10..7fb0abff0049b5 100644 --- a/Lib/test/test_tkinter/test_geometry_managers.py +++ b/Lib/test/test_tkinter/test_geometry_managers.py @@ -289,6 +289,25 @@ def test_pack_slaves(self): b.pack_configure() self.assertEqual(pack.pack_slaves(), [a, b]) + def test_pack_short_aliases(self): + # slaves, content and propagate are aliases of the pack_* methods + # (Misc precedes Pack, Place and Grid in the method resolution order). + pack, a, b, c, d = self.create2() + self.assertEqual(pack.slaves, pack.pack_slaves) + self.assertEqual(pack.content, pack.pack_content) + self.assertEqual(pack.propagate, pack.pack_propagate) + + self.assertEqual(pack.slaves(), []) + a.pack_configure() + self.assertEqual(pack.slaves(), [a]) + self.assertEqual(pack.content(), [a]) + + pack.configure(width=300, height=200) + pack.propagate(False) + self.root.update() + self.assertEqual(pack.winfo_reqwidth(), 300) + self.assertEqual(pack.winfo_reqheight(), 200) + class PlaceTest(AbstractWidgetTest, unittest.TestCase): @@ -503,6 +522,18 @@ def test_place_slaves(self): with self.assertRaises(TypeError): foo.place_slaves(0) + def test_place_method_aliases(self): + # The Place manager defines configure, info, forget, slaves and + # content as aliases of its place_* methods. On a real widget the + # short names are provided by Misc and Pack (earlier in the method + # resolution order), so the aliases are checked on the class itself. + self.assertIs(tkinter.Place.configure, tkinter.Place.place_configure) + self.assertIs(tkinter.Place.config, tkinter.Place.place_configure) + self.assertIs(tkinter.Place.info, tkinter.Place.place_info) + self.assertIs(tkinter.Place.forget, tkinter.Place.place_forget) + self.assertIs(tkinter.Place.slaves, tkinter.Misc.place_slaves) + self.assertIs(tkinter.Place.content, tkinter.Misc.place_content) + class GridTest(AbstractWidgetTest, unittest.TestCase): @@ -938,6 +969,30 @@ def test_grid_slaves(self): self.assertEqual(self.root.grid_slaves(column=1), [d, c, a]) self.assertEqual(self.root.grid_slaves(row=1, column=1), [d, c]) + def test_grid_short_aliases(self): + # columnconfigure, rowconfigure, size, anchor and bbox are aliases of + # the corresponding grid_* methods (Misc precedes Pack, Place and Grid + # in the method resolution order). + root = self.root + self.assertEqual(root.columnconfigure, root.grid_columnconfigure) + self.assertEqual(root.rowconfigure, root.grid_rowconfigure) + self.assertEqual(root.size, root.grid_size) + self.assertEqual(root.anchor, root.grid_anchor) + self.assertEqual(root.bbox, root.grid_bbox) + + self.assertEqual(root.size(), (0, 0)) + b = tkinter.Button(root) + b.grid_configure(column=2, row=3) + self.assertEqual(root.size(), (3, 4)) + + root.columnconfigure(0, weight=2) + self.assertEqual(root.grid_columnconfigure(0, 'weight'), 2) + root.rowconfigure(0, weight=3) + self.assertEqual(root.grid_rowconfigure(0, 'weight'), 3) + + root.anchor('se') + self.assertEqual(root.tk.call('grid', 'anchor', root), 'se') + if __name__ == '__main__': unittest.main() diff --git a/Lib/test/test_tkinter/test_misc.py b/Lib/test/test_tkinter/test_misc.py index f017e94a8b3c22..2dbe1cb31fef62 100644 --- a/Lib/test/test_tkinter/test_misc.py +++ b/Lib/test/test_tkinter/test_misc.py @@ -319,44 +319,101 @@ def test_clipboard_astral(self): with self.assertRaises(tkinter.TclError): root.clipboard_get() - def test_winfo_rgb(self): - - def assertApprox(col1, col2): - # A small amount of flexibility is required (bpo-45496) - # 33 is ~0.05% of 65535, which is a reasonable margin - for col1_channel, col2_channel in zip(col1, col2): - self.assertAlmostEqual(col1_channel, col2_channel, delta=33) - - root = self.root - rgb = root.winfo_rgb - - # Color name. - self.assertEqual(rgb('red'), (65535, 0, 0)) - self.assertEqual(rgb('dark slate blue'), (18504, 15677, 35723)) - # #RGB - extends each 4-bit hex value to be 16-bit. - self.assertEqual(rgb('#F0F'), (0xFFFF, 0x0000, 0xFFFF)) - # #RRGGBB - extends each 8-bit hex value to be 16-bit. - assertApprox(rgb('#4a3c8c'), (0x4a4a, 0x3c3c, 0x8c8c)) - # #RRRRGGGGBBBB - assertApprox(rgb('#dede14143939'), (0xdede, 0x1414, 0x3939)) - # Invalid string. - with self.assertRaises(tkinter.TclError): - rgb('#123456789a') - # RGB triplet is invalid input. - with self.assertRaises(tkinter.TclError): - rgb((111, 78, 55)) + def test_getint(self): + self.assertEqual(self.root.getint('42'), 42) + self.assertEqual(self.root.getint(42), 42) + self.assertEqual(self.root.getint('-5'), -5) + self.assertRaises(ValueError, self.root.getint, 'spam') + + def test_getdouble(self): + self.assertEqual(self.root.getdouble('3.5'), 3.5) + self.assertEqual(self.root.getdouble(3), 3.0) + self.assertRaises(ValueError, self.root.getdouble, 'spam') + + def test_getvar(self): + self.root.setvar('test_var', 'hello') + self.assertEqual(self.root.getvar('test_var'), 'hello') + + def test_register(self): + result = [] + def callback(): + result.append(1) + return 'spam' + name = self.root.register(callback) + self.assertIsInstance(name, str) + self.assertEqual(self.root.tk.call(name), 'spam') + self.assertEqual(result, [1]) + self.root.deletecommand(name) + self.assertRaises(TclError, self.root.tk.call, name) + + def test_option(self): + self.addCleanup(self.root.option_clear) + self.root.option_add('*Button.background', 'red') + b = tkinter.Button(self.root) + self.assertEqual(b.option_get('background', 'Background'), 'red') + self.assertEqual(b.option_get('foreground', 'Foreground'), '') + self.root.option_clear() + self.assertEqual(b.option_get('background', 'Background'), '') + + def test_nametowidget(self): + b = tkinter.Button(self.root, name='btn') + self.assertIs(self.root.nametowidget('btn'), b) + self.assertIs(self.root.nametowidget(str(b)), b) + self.assertRaises(KeyError, self.root.nametowidget, '.nonexistent') + + def test_focus_methods(self): + f = tkinter.Frame(self.root, width=150, height=100) + f.pack() + self.root.wait_visibility() # needed on Windows + self.root.update_idletasks() + f.focus_force() + self.root.update() + self.assertIs(self.root.focus_get(), f) + self.assertIs(self.root.focus_displayof(), f) + self.assertIs(f.focus_lastfor(), f) + b = tkinter.Button(f) + b.pack() + self.root.update() + b.focus_set() + self.root.update() + self.assertIs(self.root.focus_get(), b) - def test_winfo_pathname(self): - t = tkinter.Toplevel(self.root) - w = tkinter.Button(t) - wid = w.winfo_id() - self.assertIsInstance(wid, int) - self.assertEqual(self.root.winfo_pathname(hex(wid)), str(w)) - self.assertEqual(self.root.winfo_pathname(hex(wid), displayof=None), str(w)) - self.assertEqual(self.root.winfo_pathname(hex(wid), displayof=t), str(w)) - self.assertEqual(self.root.winfo_pathname(wid), str(w)) - self.assertEqual(self.root.winfo_pathname(wid, displayof=None), str(w)) - self.assertEqual(self.root.winfo_pathname(wid, displayof=t), str(w)) + def test_grab(self): + f = tkinter.Frame(self.root) + f.pack() + self.root.wait_visibility() + self.assertIsNone(self.root.grab_current()) + self.assertIsNone(f.grab_status()) + f.grab_set() + self.assertEqual(f.grab_status(), 'local') + self.assertIs(self.root.grab_current(), f) + f.grab_release() + self.assertIsNone(f.grab_status()) + self.assertIsNone(self.root.grab_current()) + + def test_selection_own(self): + self.root.selection_own() + self.assertIs(self.root.selection_own_get(), self.root) + f = tkinter.Frame(self.root) + f.selection_own() + self.assertIs(self.root.selection_own_get(), f) + + def test_event_add_delete_info(self): + self.addCleanup(self.root.event_delete, '<<TestEvent>>') + self.root.event_add('<<TestEvent>>', '<Control-z>', '<Control-y>') + self.assertEqual(self.root.event_info('<<TestEvent>>'), + ('<Control-Key-z>', '<Control-Key-y>')) + self.assertIn('<<TestEvent>>', self.root.event_info()) + self.root.event_delete('<<TestEvent>>', '<Control-y>') + self.assertEqual(self.root.event_info('<<TestEvent>>'), + ('<Control-Key-z>',)) + self.root.event_delete('<<TestEvent>>') + self.assertEqual(self.root.event_info('<<TestEvent>>'), ()) + self.assertRaises(TypeError, self.root.event_delete) + + def test_bell(self): + self.root.bell() # No exception. + self.root.bell(displayof=self.root) def test_event_repr_defaults(self): e = tkinter.Event() @@ -522,6 +579,150 @@ def test_iterable_protocol(self): widget in widget +class WinfoTest(AbstractTkTest, unittest.TestCase): + + def test_winfo_rgb(self): + + def assertApprox(col1, col2): + # A small amount of flexibility is required (bpo-45496) + # 33 is ~0.05% of 65535, which is a reasonable margin + for col1_channel, col2_channel in zip(col1, col2): + self.assertAlmostEqual(col1_channel, col2_channel, delta=33) + + root = self.root + rgb = root.winfo_rgb + + # Color name. + self.assertEqual(rgb('red'), (65535, 0, 0)) + self.assertEqual(rgb('dark slate blue'), (18504, 15677, 35723)) + # #RGB - extends each 4-bit hex value to be 16-bit. + self.assertEqual(rgb('#F0F'), (0xFFFF, 0x0000, 0xFFFF)) + # #RRGGBB - extends each 8-bit hex value to be 16-bit. + assertApprox(rgb('#4a3c8c'), (0x4a4a, 0x3c3c, 0x8c8c)) + # #RRRRGGGGBBBB + assertApprox(rgb('#dede14143939'), (0xdede, 0x1414, 0x3939)) + # Invalid string. + with self.assertRaises(tkinter.TclError): + rgb('#123456789a') + # RGB triplet is invalid input. + with self.assertRaises(tkinter.TclError): + rgb((111, 78, 55)) + + def test_winfo_pathname(self): + t = tkinter.Toplevel(self.root) + w = tkinter.Button(t) + wid = w.winfo_id() + self.assertIsInstance(wid, int) + self.assertEqual(self.root.winfo_pathname(hex(wid)), str(w)) + self.assertEqual(self.root.winfo_pathname(hex(wid), displayof=None), str(w)) + self.assertEqual(self.root.winfo_pathname(hex(wid), displayof=t), str(w)) + self.assertEqual(self.root.winfo_pathname(wid), str(w)) + self.assertEqual(self.root.winfo_pathname(wid, displayof=None), str(w)) + self.assertEqual(self.root.winfo_pathname(wid, displayof=t), str(w)) + + def test_winfo_class_name_parent(self): + f = tkinter.Frame(self.root) + b = tkinter.Button(f) + self.assertEqual(f.winfo_class(), 'Frame') + self.assertEqual(b.winfo_class(), 'Button') + self.assertEqual(b.winfo_name(), str(b).rsplit('.', 1)[-1]) + self.assertEqual(b.winfo_parent(), str(f)) + self.assertEqual(f.winfo_parent(), str(self.root)) + self.assertIs(f.winfo_toplevel(), self.root) + t = tkinter.Toplevel(self.root) + self.assertIs(tkinter.Button(t).winfo_toplevel(), t) + self.assertEqual(self.root.nametowidget(b.winfo_parent()), f) + + def test_winfo_children(self): + self.assertEqual(self.root.winfo_children(), []) + f = tkinter.Frame(self.root) + b = tkinter.Button(f) + self.assertEqual(self.root.winfo_children(), [f]) + self.assertEqual(f.winfo_children(), [b]) + + def test_winfo_visual_info(self): + f = tkinter.Frame(self.root) + self.assertIsInstance(f.winfo_depth(), int) + self.assertIsInstance(f.winfo_cells(), int) + self.assertIsInstance(f.winfo_visual(), str) + self.assertIsInstance(f.winfo_visualid(), str) + self.assertIsInstance(f.winfo_colormapfull(), bool) + visuals = self.root.winfo_visualsavailable() + self.assertIsInstance(visuals, list) + for name, depth in visuals: + self.assertIsInstance(name, str) + self.assertIsInstance(depth, int) + + def test_winfo_viewable(self): + f = tkinter.Frame(self.root) + self.assertFalse(f.winfo_viewable()) + f.pack() + f.wait_visibility() + self.root.update() + self.assertTrue(f.winfo_viewable()) + + def test_winfo_atom(self): + atom = self.root.winfo_atom('PRIMARY') + self.assertIsInstance(atom, int) + self.assertEqual(self.root.winfo_atomname(atom), 'PRIMARY') + self.assertEqual( + self.root.winfo_atomname(atom, displayof=self.root), 'PRIMARY') + self.assertEqual( + self.root.winfo_atom('PRIMARY', displayof=self.root), atom) + self.assertRaisesRegex(TclError, 'no atom exists', + self.root.winfo_atomname, 10 ** 9) + + def test_winfo_pointer(self): + self.assertIsInstance(self.root.winfo_pointerx(), int) + self.assertIsInstance(self.root.winfo_pointery(), int) + xy = self.root.winfo_pointerxy() + self.assertIsInstance(xy, tuple) + self.assertEqual(len(xy), 2) + self.assertTrue(all(isinstance(v, int) for v in xy)) + + def test_winfo_containing(self): + self.root.update() + # No window contains a point far off the screen. + self.assertIsNone(self.root.winfo_containing(-10000, -10000)) + self.assertIsNone( + self.root.winfo_containing(-10000, -10000, displayof=self.root)) + + def test_winfo_fpixels(self): + self.assertIsInstance(self.root.winfo_fpixels('1i'), float) + self.assertAlmostEqual(self.root.winfo_fpixels('1i'), + self.root.winfo_fpixels('72p')) + # Tk < 9 reports 'bad screen distance "spam"', Tk 9 reports + # 'expected screen distance ... but got "spam"'. + self.assertRaisesRegex(TclError, + r'(bad|expected) screen distance.*"spam"', + self.root.winfo_fpixels, 'spam') + + def test_winfo_screen(self): + for name in ('winfo_screenwidth', 'winfo_screenheight', + 'winfo_screenmmwidth', 'winfo_screenmmheight', + 'winfo_screencells', 'winfo_screendepth'): + value = getattr(self.root, name)() + self.assertIsInstance(value, int) + self.assertGreater(value, 0) + self.assertIsInstance(self.root.winfo_screenvisual(), str) + self.assertIsInstance(self.root.winfo_screen(), str) + self.assertIsInstance(self.root.winfo_server(), str) + + def test_winfo_vroot(self): + for name in ('winfo_vrootwidth', 'winfo_vrootheight', + 'winfo_vrootx', 'winfo_vrooty'): + self.assertIsInstance(getattr(self.root, name)(), int) + + def test_winfo_interps(self): + interps = self.root.winfo_interps() + self.assertIsInstance(interps, tuple) + # The registry of interpreters is only populated where "send" is + # supported (i.e. X11), so do not require this interpreter's name. + if self.root._windowingsystem == 'x11': + self.assertIn(self.root.tk.call('tk', 'appname'), interps) + self.assertEqual(self.root.winfo_interps(displayof=self.root), interps) + + class WmTest(AbstractTkTest, unittest.TestCase): def test_wm_attribute(self): @@ -601,6 +802,120 @@ def test_wm_iconbitmap(self): t.destroy() + def test_wm_title(self): + t = tkinter.Toplevel(self.root) + t.title('Hello') + self.assertEqual(t.title(), 'Hello') + self.assertEqual(t.wm_title(), 'Hello') + t.wm_title('Spam') + self.assertEqual(t.title(), 'Spam') + + def test_wm_geometry(self): + t = tkinter.Toplevel(self.root) + t.geometry('200x100+10+20') + t.update() + self.assertRegex(t.geometry(), r'^200x100\+-?\d+\+-?\d+$') + self.assertEqual(t.wm_geometry(), t.geometry()) + + def test_wm_minsize_maxsize(self): + t = tkinter.Toplevel(self.root) + # Use a width above the minimum enforced by some platforms (72 on Aqua). + t.minsize(150, 100) + self.assertEqual(t.minsize(), (150, 100)) + t.maxsize(500, 600) + self.assertEqual(t.maxsize(), (500, 600)) + + def test_wm_resizable(self): + t = tkinter.Toplevel(self.root) + t.resizable(False, True) + self.assertEqual(t.resizable(), (0, 1)) + self.assertRaisesRegex(TclError, 'expected boolean value', + t.resizable, 'spam', True) + + def test_wm_aspect(self): + t = tkinter.Toplevel(self.root) + self.assertEqual(t.aspect(), None) + t.aspect(1, 2, 3, 4) + self.assertEqual(t.aspect(), (1, 2, 3, 4)) + + def test_wm_grid(self): + t = tkinter.Toplevel(self.root) + t.wm_grid(10, 10, 5, 5) + self.assertEqual(t.wm_grid(), (10, 10, 5, 5)) + + def test_wm_positionfrom_sizefrom(self): + # These set X11 size hints and may be no-ops on other platforms. + t = tkinter.Toplevel(self.root) + t.positionfrom('user') + self.assertIn(t.positionfrom(), ('user', '')) + t.sizefrom('program') + self.assertIn(t.sizefrom(), ('program', '')) + + def test_wm_focusmodel(self): + t = tkinter.Toplevel(self.root) + self.assertEqual(t.focusmodel(), 'passive') + t.focusmodel('active') + self.assertEqual(t.focusmodel(), 'active') + self.assertRaises(TclError, t.focusmodel, 'spam') + + def test_wm_iconname(self): + # WM_ICON_NAME is an X11 property and may be a no-op elsewhere. + t = tkinter.Toplevel(self.root) + t.iconname('Icon') + self.assertIn(t.iconname(), ('Icon', '')) + + def test_wm_client_command(self): + t = tkinter.Toplevel(self.root) + t.client('myhost') + t.wm_command('myapp -x') + # WM_CLIENT_MACHINE and WM_COMMAND are X11 properties; elsewhere the + # setters may be no-ops and wm_command may return a split list. + if t._windowingsystem == 'x11': + self.assertEqual(t.client(), 'myhost') + self.assertEqual(t.wm_command(), 'myapp -x') + + def test_wm_overrideredirect(self): + t = tkinter.Toplevel(self.root) + self.assertFalse(t.overrideredirect()) + t.overrideredirect(True) + self.assertTrue(t.overrideredirect()) + + def test_wm_state(self): + t = tkinter.Toplevel(self.root) + t.update() + self.assertEqual(t.state(), 'normal') + t.withdraw() + self.assertEqual(t.state(), 'withdrawn') + t.deiconify() + t.update() + self.assertEqual(t.state(), 'normal') + self.assertRaises(TclError, t.state, 'spam') + + def test_wm_frame(self): + t = tkinter.Toplevel(self.root) + t.update() + self.assertIsInstance(t.frame(), str) + + def test_wm_group(self): + # The window group is an X11 concept and may be a no-op elsewhere. + t = tkinter.Toplevel(self.root) + t.group(self.root) + self.assertIn(t.group(), (str(self.root), '')) + + def test_wm_protocol(self): + t = tkinter.Toplevel(self.root) + self.assertIsInstance(t.protocol(), tuple) + t.protocol('WM_SAVE_YOURSELF', lambda: None) + self.assertIn('WM_SAVE_YOURSELF', t.protocol()) + # Querying a single protocol returns the bound command name. + self.assertTrue(t.protocol('WM_SAVE_YOURSELF')) + + def test_wm_transient(self): + t = tkinter.Toplevel(self.root) + self.assertEqual(t.transient(), '') + t.transient(self.root) + self.assertEqual(str(t.transient()), str(self.root)) + class EventTest(AbstractTkTest, unittest.TestCase): From ba0cae13cea9a42158818977dba605a0d66e55bc Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 19 Jun 2026 18:12:13 +0200 Subject: [PATCH 377/818] [3.15] gh-151678: Add tests for tkinter.ttk methods (GH-151736) (GH-151741) Cover previously-untested ttk methods: * Progressbar.step, start and stop; * Treeview.parent, next, prev, see and identify_element; * Style.theme_settings; * OptionMenu.set_menu. (cherry picked from commit 7d4a0aad7be3cfb367b8977a03a64e754577d5f0) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --- Lib/test/test_ttk/test_extensions.py | 18 ++++++++ Lib/test/test_ttk/test_style.py | 16 +++++++ Lib/test/test_ttk/test_widgets.py | 65 ++++++++++++++++++++++++++++ 3 files changed, 99 insertions(+) diff --git a/Lib/test/test_ttk/test_extensions.py b/Lib/test/test_ttk/test_extensions.py index 669a3e184eb771..2765b226e271f9 100644 --- a/Lib/test/test_ttk/test_extensions.py +++ b/Lib/test/test_ttk/test_extensions.py @@ -281,6 +281,24 @@ def cb_test(item): optmenu.destroy() + def test_set_menu(self): + optmenu = ttk.OptionMenu(self.root, self.textvar, 'a', 'a', 'b', 'c') + menu = optmenu['menu'] + self.assertEqual(menu.index('end'), 2) + + # set_menu rebuilds the menu with new values and an optional default. + optmenu.set_menu('y', 'x', 'y', 'z') + self.assertEqual(self.textvar.get(), 'y') + self.assertEqual([menu.entrycget(i, 'label') for i in range(3)], + ['x', 'y', 'z']) + + # Without a default the variable is left unchanged. + optmenu.set_menu(None, 'p', 'q') + self.assertEqual(self.textvar.get(), 'y') + self.assertEqual([menu.entrycget(i, 'label') for i in range(2)], + ['p', 'q']) + optmenu.destroy() + def test_unique_radiobuttons(self): # check that radiobuttons are unique across instances (bpo25684) items = ('a', 'b', 'c') diff --git a/Lib/test/test_ttk/test_style.py b/Lib/test/test_ttk/test_style.py index fdbaae1b644e4d..f85f76eb499278 100644 --- a/Lib/test/test_ttk/test_style.py +++ b/Lib/test/test_ttk/test_style.py @@ -124,6 +124,22 @@ def test_theme_use(self): self.style.theme_use(curr_theme) + def test_theme_settings(self): + style = self.style + theme = style.theme_use() + style.theme_settings(theme, { + 'Test.TLabel': { + 'configure': {'foreground': 'red', 'background': 'blue'}, + 'map': {'foreground': [('active', 'green')]}, + }, + }) + self.assertEqual(style.lookup('Test.TLabel', 'foreground'), 'red') + self.assertEqual(style.lookup('Test.TLabel', 'background'), 'blue') + self.assertEqual(style.map('Test.TLabel', 'foreground'), + [('active', 'green')]) + self.assertRaises(tkinter.TclError, style.theme_settings, + 'nonexistingname', {}) + def test_configure_custom_copy(self): style = self.style diff --git a/Lib/test/test_ttk/test_widgets.py b/Lib/test/test_ttk/test_widgets.py index 8cce9aed9d514f..adcd736cd40b19 100644 --- a/Lib/test/test_ttk/test_widgets.py +++ b/Lib/test/test_ttk/test_widgets.py @@ -973,6 +973,27 @@ def test_configure_value(self): test_configure_wraplength = requires_tk(8, 7)(StandardOptionsTests.test_configure_wraplength) + def test_step(self): + widget = self.create(maximum=100, mode='determinate') + self.assertEqual(float(widget['value']), 0.0) + widget.step() # The default increment is 1.0. + self.assertEqual(float(widget['value']), 1.0) + widget.step(5) + self.assertEqual(float(widget['value']), 6.0) + widget.step(-2) + self.assertEqual(float(widget['value']), 4.0) + + def test_start_stop(self): + widget = self.create(maximum=100, mode='determinate') + widget.pack() + widget.start() # Schedule autoincrement; no exception. + widget.update() + widget.stop() # Cancel it. + # After stopping, the value no longer changes. + value = float(widget['value']) + widget.update() + self.assertEqual(float(widget['value']), value) + @unittest.skipIf(sys.platform == 'darwin', 'ttk.Scrollbar is special on MacOSX') @@ -1639,6 +1660,50 @@ def test_exists(self): # in the tcl interpreter since tk requires an item. self.assertRaises(tkinter.TclError, self.tv.exists, None) + def test_parent(self): + a = self.tv.insert('', 'end') + b = self.tv.insert(a, 'end') + self.assertEqual(self.tv.parent(b), a) + self.assertEqual(self.tv.parent(a), '') + self.assertRaises(tkinter.TclError, self.tv.parent, 'nonexistent') + + def test_next_prev(self): + a = self.tv.insert('', 'end') + b = self.tv.insert('', 'end') + c = self.tv.insert('', 'end') + self.assertEqual(self.tv.next(a), b) + self.assertEqual(self.tv.next(b), c) + self.assertEqual(self.tv.next(c), '') + self.assertEqual(self.tv.prev(c), b) + self.assertEqual(self.tv.prev(b), a) + self.assertEqual(self.tv.prev(a), '') + self.assertRaises(tkinter.TclError, self.tv.next, 'nonexistent') + self.assertRaises(tkinter.TclError, self.tv.prev, 'nonexistent') + + def test_see(self): + a = self.tv.insert('', 'end') + b = self.tv.insert(a, 'end') + # see() opens all of the item's ancestors. + self.assertFalse(self.tv.tk.getboolean(self.tv.item(a, 'open'))) + self.tv.see(b) + self.assertTrue(self.tv.tk.getboolean(self.tv.item(a, 'open'))) + self.assertRaises(tkinter.TclError, self.tv.see, 'nonexistent') + + def test_identify_element(self): + self.tv.pack() + self.tv.wait_visibility() + parent = self.tv.insert('', 'end', text='parent') + self.tv.insert(parent, 'end', text='child') + self.tv.update() + x, y, w, h = self.tv.bbox(parent) + # The Treeitem.indicator element is packed at the left of the row in + # the Item layout on every platform and theme. + element = self.tv.identify_element(x + 8, y + h // 2) + self.assertRegex(element, r'.*indicator\z') + # The empty string is returned outside the widget. + self.assertEqual(self.tv.identify_element(-1, -1), '') + self.assertRaises(tkinter.TclError, self.tv.identify_element, None, 5) + def test_focus(self): # nothing is focused right now self.assertEqual(self.tv.focus(), '') From a30acf2495e37c666bb7b3893c5da6ab7363a5e7 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 20 Jun 2026 01:12:25 +0200 Subject: [PATCH 378/818] [3.15] gh-151678: Add tests for tkinter font, image, variable, Misc and Wm methods (GH-151751) (GH-151754) * font: copy(), the config alias, the displayof argument of measure and metrics, and the errors raised for invalid options and a wrong number of arguments; * image: the cget method and the config alias, and the errors raised by transparency_get and transparency_set; * variable: that initialize is an alias of set and the deprecated trace is an alias of trace_variable; * Misc: tk_focusNext, tk_focusPrev, tk_strictMotif, tk_bisque and option_readfile; * Wm: wm_iconphoto. (cherry picked from commit 66cc04855100c3865bd01adfe92a3a02dbc3a914) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --- Lib/test/test_tkinter/test_font.py | 33 +++++++++++++++ Lib/test/test_tkinter/test_images.py | 13 ++++++ Lib/test/test_tkinter/test_misc.py | 53 +++++++++++++++++++++++++ Lib/test/test_tkinter/test_variables.py | 3 ++ 4 files changed, 102 insertions(+) diff --git a/Lib/test/test_tkinter/test_font.py b/Lib/test/test_tkinter/test_font.py index ee147710fbfc85..8adc9e1151db4e 100644 --- a/Lib/test/test_tkinter/test_font.py +++ b/Lib/test/test_tkinter/test_font.py @@ -21,6 +21,7 @@ def setUpClass(cls): cls.font = font.Font(root=cls.root, name=fontname, exists=False) def test_configure(self): + self.assertEqual(self.font.config, self.font.configure) options = self.font.configure() self.assertGreaterEqual(set(options), {'family', 'size', 'weight', 'slant', 'underline', 'overstrike'}) @@ -36,6 +37,26 @@ def test_configure(self): self.assertIsInstance(options[key], sizetype) self.assertIsInstance(self.font.cget(key), sizetype) self.assertIsInstance(self.font[key], sizetype) + self.assertRaisesRegex(tkinter.TclError, 'bad option "-spam"', + self.font.cget, 'spam') + self.assertRaisesRegex(tkinter.TclError, 'bad option "-spam"', + self.font.configure, spam='x') + self.assertRaises(TypeError, self.font.cget) + self.assertRaises(TypeError, self.font.cget, 'size', 'weight') + + def test_copy(self): + f = font.Font(root=self.root, family='Times', size=10, weight='bold') + copied = f.copy() + self.assertIsInstance(copied, font.Font) + self.assertIsNot(copied, f) + self.assertNotEqual(copied.name, f.name) + self.assertEqual(copied.actual(), f.actual()) + # The copy is independent of the original. + sizetype = int if self.wantobjects else str + copied.configure(size=20) + self.assertEqual(f.cget('size'), sizetype(10)) + self.assertEqual(copied.cget('size'), sizetype(20)) + self.assertRaises(TypeError, f.copy, 'x') def test_unicode_family(self): family = 'MS \u30b4\u30b7\u30c3\u30af' @@ -60,6 +81,9 @@ def test_actual(self): for key in 'size', 'underline', 'overstrike': self.assertIsInstance(options[key], sizetype) self.assertIsInstance(self.font.actual(key), sizetype) + self.assertRaisesRegex(tkinter.TclError, 'bad option "-spam"', + self.font.actual, 'spam') + self.assertRaises(TypeError, self.font.actual, 'size', 'weight', 'slant') def test_name(self): self.assertEqual(self.font.name, fontname) @@ -83,6 +107,11 @@ def test_equality(self): def test_measure(self): self.assertIsInstance(self.font.measure('abc'), int) + self.assertEqual(self.font.measure(''), 0) + self.assertIsInstance( + self.font.measure('abc', displayof=self.root), int) + self.assertRaises(TypeError, self.font.measure) + self.assertRaises(TypeError, self.font.measure, 'a', 'b', 'c') def test_metrics(self): metrics = self.font.metrics() @@ -90,8 +119,12 @@ def test_metrics(self): {'ascent', 'descent', 'linespace', 'fixed'}) for key in metrics: self.assertEqual(self.font.metrics(key), metrics[key]) + self.assertEqual(self.font.metrics(key, displayof=self.root), + metrics[key]) self.assertIsInstance(metrics[key], int) self.assertIsInstance(self.font.metrics(key), int) + self.assertRaisesRegex(tkinter.TclError, 'bad metric "-spam"', + self.font.metrics, 'spam') def test_families(self): families = font.families(self.root) diff --git a/Lib/test/test_tkinter/test_images.py b/Lib/test/test_tkinter/test_images.py index 3aca9515a33b24..f9b314da9e8a91 100644 --- a/Lib/test/test_tkinter/test_images.py +++ b/Lib/test/test_tkinter/test_images.py @@ -288,6 +288,11 @@ def test_configure_width_height(self): image.configure(height=10) self.assertEqual(image['width'], '20') self.assertEqual(image['height'], '10') + self.assertEqual(image.cget('width'), image['width']) + self.assertEqual(image.cget('height'), image['height']) + self.assertRaises(TypeError, image.cget) + self.assertRaises(TypeError, image.cget, 'width', 'height') + self.assertEqual(image.config, image.configure) self.assertEqual(image.width(), 20) self.assertEqual(image.height(), 10) @@ -656,6 +661,14 @@ def test_transparency(self): self.assertEqual(image.transparency_get(4, 6), True) image.transparency_set(4, 6, False) self.assertEqual(image.transparency_get(4, 6), False) + self.assertRaises(tkinter.TclError, image.transparency_get, -1, 0) + self.assertRaises(tkinter.TclError, image.transparency_get, 16, 0) + self.assertRaises(tkinter.TclError, image.transparency_set, -1, 0, True) + self.assertRaises(tkinter.TclError, image.transparency_set, 16, 0, True) + self.assertRaises(TypeError, image.transparency_get, 0) + self.assertRaises(TypeError, image.transparency_get, 0, 0, 0) + self.assertRaises(TypeError, image.transparency_set, 0, 0) + self.assertRaises(TypeError, image.transparency_set, 0, 0, True, 0) if __name__ == "__main__": diff --git a/Lib/test/test_tkinter/test_misc.py b/Lib/test/test_tkinter/test_misc.py index 2dbe1cb31fef62..0a13b9dc75162a 100644 --- a/Lib/test/test_tkinter/test_misc.py +++ b/Lib/test/test_tkinter/test_misc.py @@ -5,6 +5,7 @@ from tkinter import TclError import enum from test import support +from test.support import os_helper from test.test_tkinter.support import setUpModule # noqa: F401 from test.test_tkinter.support import (AbstractTkTest, AbstractDefaultRootTest, requires_tk, get_tk_patchlevel) @@ -355,6 +356,19 @@ def test_option(self): self.root.option_clear() self.assertEqual(b.option_get('background', 'Background'), '') + def test_option_readfile(self): + self.addCleanup(self.root.option_clear) + self.addCleanup(os_helper.unlink, os_helper.TESTFN) + with open(os_helper.TESTFN, 'w') as f: + f.write('*Button.background: red\n') + self.root.option_readfile(os_helper.TESTFN) + b = tkinter.Button(self.root) + self.assertEqual(b.option_get('background', 'Background'), 'red') + self.assertRaises(TclError, self.root.option_readfile, + os_helper.TESTFN + '.nonexistent') + self.assertRaises(TypeError, self.root.option_readfile) + self.assertRaises(TypeError, self.root.option_readfile, 'a', 'b', 'c') + def test_nametowidget(self): b = tkinter.Button(self.root, name='btn') self.assertIs(self.root.nametowidget('btn'), b) @@ -415,6 +429,38 @@ def test_bell(self): self.root.bell() # No exception. self.root.bell(displayof=self.root) + def test_tk_focusNext_focusPrev(self): + f = tkinter.Frame(self.root) + f.pack() + entries = [tkinter.Entry(f) for _ in range(3)] + for entry in entries: + entry.pack() + # tk_focusNext skips widgets that are not viewable. + entries[-1].wait_visibility() + self.assertIs(entries[0].tk_focusNext(), entries[1]) + self.assertIs(entries[1].tk_focusNext(), entries[2]) + self.assertIs(entries[2].tk_focusPrev(), entries[1]) + self.assertIs(entries[1].tk_focusPrev(), entries[0]) + self.assertRaises(TypeError, entries[0].tk_focusNext, 'x') + self.assertRaises(TypeError, entries[0].tk_focusPrev, 'x') + + def test_tk_strictMotif(self): + self.addCleanup(self.root.tk_strictMotif, False) + self.assertIs(self.root.tk_strictMotif(), False) + self.assertIs(self.root.tk_strictMotif(True), True) + self.assertIs(self.root.tk_strictMotif(), True) + self.assertIs(self.root.tk_strictMotif(False), False) + self.assertRaises(TypeError, self.root.tk_strictMotif, 1, 2) + + def test_tk_bisque(self): + # tk_bisque resets the color palette; use a separate root so that + # the shared one is not affected. + root = tkinter.Tk() + self.addCleanup(root.destroy) + root.tk_bisque() + self.assertEqual(root['background'], '#ffe4c4') + self.assertRaises(TypeError, root.tk_bisque, 'x') + def test_event_repr_defaults(self): e = tkinter.Event() e.serial = 12345 @@ -802,6 +848,13 @@ def test_wm_iconbitmap(self): t.destroy() + def test_wm_iconphoto(self): + t = tkinter.Toplevel(self.root) + img = tkinter.PhotoImage(master=t, width=16, height=16) + t.wm_iconphoto(False, img) # No exception. + t.wm_iconphoto(True, img) + self.assertRaises(tkinter.TclError, t.wm_iconphoto, False, 'spam') + def test_wm_title(self): t = tkinter.Toplevel(self.root) t.title('Hello') diff --git a/Lib/test/test_tkinter/test_variables.py b/Lib/test/test_tkinter/test_variables.py index 8733095ffb65f4..5ee4e9467dd0cb 100644 --- a/Lib/test/test_tkinter/test_variables.py +++ b/Lib/test/test_tkinter/test_variables.py @@ -111,6 +111,7 @@ def test_initialize(self): self.assertFalse(v.side_effect) v.set("value") self.assertTrue(v.side_effect) + self.assertEqual(Variable.initialize, Variable.set) def test_trace_old(self): if tcl_version >= (9, 0): @@ -118,6 +119,7 @@ def test_trace_old(self): # Old interface v = Variable(self.root) vname = str(v) + self.assertEqual(v.trace, v.trace_variable) trace = [] def read_tracer(*args): trace.append(('read',) + args) @@ -328,6 +330,7 @@ def test_set(self): self.assertEqual(self.root.globalgetvar("name"), false) v.set("on") self.assertEqual(self.root.globalgetvar("name"), true) + self.assertEqual(BooleanVar.initialize, BooleanVar.set) def test_invalid_value_domain(self): false = 0 if self.root.wantobjects() else "0" From b83a217558ee30c48a3aa08f0cb7c869f9c75e96 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 20 Jun 2026 01:31:12 +0200 Subject: [PATCH 379/818] [3.15] gh-150836: Mount embedded Tk ZIP in _tkinter on Windows (GH-151735) Tcl/Tk 9 may embed the Tk script library in the Tk DLL on Windows. This embedded library is not found by Tcl by default. Mount the loaded Tk DLL as a zipfs archive before calling Tk_Init(), so Tk can find its embedded tk_library using its existing library discovery logic. Preserve Tk_Init()'s normal path if the library is not embedded. (cherry picked from commit c4eb3adbb42d781e2ad35bee5621f1c621c6767b) Co-authored-by: Jonathan J. Helmus <jjhelmus@gmail.com> --- ...-06-04-18-53-18.gh-issue-150836.Wci7bZ.rst | 1 + Modules/_tkinter.c | 59 ++++++++++++++++++- Modules/tkappinit.c | 2 +- Modules/tkinter.h | 2 + 4 files changed, 61 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Windows/2026-06-04-18-53-18.gh-issue-150836.Wci7bZ.rst diff --git a/Misc/NEWS.d/next/Windows/2026-06-04-18-53-18.gh-issue-150836.Wci7bZ.rst b/Misc/NEWS.d/next/Windows/2026-06-04-18-53-18.gh-issue-150836.Wci7bZ.rst new file mode 100644 index 00000000000000..6497b7927db7da --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2026-06-04-18-53-18.gh-issue-150836.Wci7bZ.rst @@ -0,0 +1 @@ +Make installed tkinter work with Tcl/Tk 9 builds that embed the Tk script library in the Tk DLL on Windows. diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c index 6eca98a3c8033f..1deff4ed44684c 100644 --- a/Modules/_tkinter.c +++ b/Modules/_tkinter.c @@ -53,6 +53,10 @@ Copyright (C) 1994 Steen Lumholt. # include <tk.h> #endif +#if defined(MS_WINDOWS) && TK_MAJOR_VERSION >= 9 +# include <tkPlatDecls.h> +#endif + #include "tkinter.h" #if TK_HEX_VERSION < 0x0805020c @@ -175,6 +179,57 @@ _get_tcl_lib_path(void) } #endif /* MS_WINDOWS */ +#if defined(MS_WINDOWS) && TK_MAJOR_VERSION >= 9 +static void +mount_tk_dll_zip(void) +{ + HINSTANCE tk_module = Tk_GetHINSTANCE(); + wchar_t *tk_path = NULL; + DWORD path_len = 0; + for (DWORD buffer_len = 256; + tk_path == NULL && buffer_len < (1024 * 1024); + buffer_len *= 2) + { + tk_path = (wchar_t *)PyMem_RawMalloc( + buffer_len * sizeof(*tk_path)); + if (tk_path != NULL) { + path_len = GetModuleFileNameW(tk_module, tk_path, buffer_len); + if (path_len == buffer_len) { + PyMem_RawFree(tk_path); + tk_path = NULL; + } + } + } + + if (tk_path == NULL || path_len == 0) { + PyMem_RawFree(tk_path); + return; + } + + Tcl_DString utf8_path; + + Tcl_DStringInit(&utf8_path); + Tcl_WCharToUtfDString(tk_path, path_len, &utf8_path); + /* Failure is harmless if the DLL has no embedded ZIP or if another + interpreter has already mounted it. */ + (void) TclZipfs_Mount(NULL, Tcl_DStringValue(&utf8_path), + "//zipfs:/lib/tk", NULL); + Tcl_DStringFree(&utf8_path); + PyMem_RawFree(tk_path); +} +#endif + +int +Tkinter_TkInit(Tcl_Interp *interp) +{ +#if defined(MS_WINDOWS) && TK_MAJOR_VERSION >= 9 + /* Tcl/Tk 9 may embed the tk_library in the Tk DLL which tcl_findLibrary + does not search. Mount the DLL using Zipfs if possible. */ + mount_tk_dll_zip(); +#endif + return Tk_Init(interp); +} + /* The threading situation is complicated. Tcl is not thread-safe, except when configured with --enable-threads. @@ -544,7 +599,7 @@ Tcl_AppInit(Tcl_Interp *interp) return TCL_OK; } - if (Tk_Init(interp) == TCL_ERROR) { + if (Tkinter_TkInit(interp) == TCL_ERROR) { PySys_WriteStderr("Tk_Init error: %s\n", Tcl_GetStringResult(interp)); return TCL_ERROR; } @@ -2988,7 +3043,7 @@ _tkinter_tkapp_loadtk_impl(TkappObject *self) return NULL; } if (_tk_exists == NULL || strcmp(_tk_exists, "1") != 0) { - if (Tk_Init(interp) == TCL_ERROR) { + if (Tkinter_TkInit(interp) == TCL_ERROR) { Tkinter_Error(self); return NULL; } diff --git a/Modules/tkappinit.c b/Modules/tkappinit.c index 4c4081e43a8e3d..1075ccf24d4487 100644 --- a/Modules/tkappinit.c +++ b/Modules/tkappinit.c @@ -37,7 +37,7 @@ Tcl_AppInit(Tcl_Interp *interp) return TCL_OK; } - if (Tk_Init(interp) == TCL_ERROR) { + if (Tkinter_TkInit(interp) == TCL_ERROR) { return TCL_ERROR; } diff --git a/Modules/tkinter.h b/Modules/tkinter.h index 40281c21760331..b73e99b28a4021 100644 --- a/Modules/tkinter.h +++ b/Modules/tkinter.h @@ -16,4 +16,6 @@ (TK_RELEASE_LEVEL << 8) | \ (TK_RELEASE_SERIAL << 0)) +int Tkinter_TkInit(Tcl_Interp *interp); + #endif /* !TKINTER_H */ From 88f79419a81e8756d004c1b49dc389d4a1611379 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 20 Jun 2026 08:17:52 +0200 Subject: [PATCH 380/818] [3.15] gh-151678: Add tests for tkinter.scrolledtext (GH-151753) (GH-151759) Add a test for the ScrolledText widget, which had no tests: that it is a Text widget held in a Frame with a Scrollbar, that Text methods work, that the geometry manager methods are redirected to the frame while configure is not, and that the scrollbar tracks the text view. (cherry picked from commit a9db5cb52fefffc8fcdddc8e1c5f23222970825a) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --- Lib/test/test_tkinter/test_scrolledtext.py | 65 ++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 Lib/test/test_tkinter/test_scrolledtext.py diff --git a/Lib/test/test_tkinter/test_scrolledtext.py b/Lib/test/test_tkinter/test_scrolledtext.py new file mode 100644 index 00000000000000..913e7d8aab6c46 --- /dev/null +++ b/Lib/test/test_tkinter/test_scrolledtext.py @@ -0,0 +1,65 @@ +import unittest +import tkinter +from tkinter.scrolledtext import ScrolledText +from test.support import requires +from test.test_tkinter.support import setUpModule # noqa: F401 +from test.test_tkinter.support import AbstractTkTest + +requires('gui') + + +class ScrolledTextTest(AbstractTkTest, unittest.TestCase): + + def create(self, **kwargs): + st = ScrolledText(self.root, **kwargs) + self.addCleanup(st.destroy) + return st + + def test_create(self): + st = self.create(background='red', height=5) + # It is a Text widget held in a Frame together with a Scrollbar. + self.assertIsInstance(st, tkinter.Text) + self.assertIsInstance(st.frame, tkinter.Frame) + self.assertIsInstance(st.vbar, tkinter.Scrollbar) + self.assertEqual(st.winfo_parent(), str(st.frame)) + # str() returns the frame, so that geometry managers manage it. + self.assertEqual(str(st), str(st.frame)) + # Keyword options configure the Text. + self.assertEqual(str(st['background']), 'red') + self.assertEqual(st['height'], 5 if self.wantobjects else '5') + + def test_text_methods(self): + st = self.create() + st.insert('1.0', 'hello\nworld') + self.assertEqual(st.get('1.0', 'end-1c'), 'hello\nworld') + self.assertEqual(st.index('end-1c'), '2.5') + st.delete('1.0', 'end') + self.assertEqual(st.get('1.0', 'end-1c'), '') + + def test_geometry_methods(self): + st = self.create() + # configure is not redirected; it configures the Text. + st.configure(height=8) + self.assertEqual(st['height'], 8 if self.wantobjects else '8') + # Pack, Grid and Place methods are redirected to the frame. + st.pack() + self.root.update() + self.assertEqual(st.frame.winfo_manager(), 'pack') + self.assertEqual(st.pack_info(), st.frame.pack_info()) + st.pack_forget() + self.assertEqual(st.frame.winfo_manager(), '') + + def test_scrollbar(self): + st = self.create(height=5) + st.pack() + st.insert('1.0', '\n'.join(map(str, range(100)))) + self.root.update() + # The scrollbar tracks the text view. + self.assertEqual(st.vbar.get(), st.yview()) + st.yview_moveto(1.0) + self.root.update() + self.assertEqual(st.vbar.get()[1], 1.0) + + +if __name__ == "__main__": + unittest.main() From 3618730de3b51423d54642603c9e7490d2a769d1 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 20 Jun 2026 15:37:55 +0200 Subject: [PATCH 381/818] [3.15] gh-151678: Add tests for tkinter.dnd (GH-151780) (GH-151790) Drive the drag-and-drop protocol (dnd_start and the DndHandler enter/ motion/commit, leave/cancel and end callbacks). (cherry picked from commit 2a126a534b0253cf65fb6d06da0cce72eb2eaa23) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --- Lib/test/test_tkinter/test_dnd.py | 98 +++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 Lib/test/test_tkinter/test_dnd.py diff --git a/Lib/test/test_tkinter/test_dnd.py b/Lib/test/test_tkinter/test_dnd.py new file mode 100644 index 00000000000000..501b0d7f78586c --- /dev/null +++ b/Lib/test/test_tkinter/test_dnd.py @@ -0,0 +1,98 @@ +import unittest +import tkinter +from tkinter import dnd +from test.support import requires +from test.test_tkinter.support import setUpModule # noqa: F401 +from test.test_tkinter.support import AbstractTkTest + +requires('gui') + + +class Target: + def __init__(self, widget, log): + self.widget = widget + self.log = log + widget.dnd_accept = self.dnd_accept + + def dnd_accept(self, source, event): + self.log.append('accept') + return self + + def dnd_enter(self, source, event): + self.log.append('enter') + + def dnd_motion(self, source, event): + self.log.append('motion') + + def dnd_leave(self, source, event): + self.log.append('leave') + + def dnd_commit(self, source, event): + self.log.append('commit') + + +class Source: + def __init__(self, log): + self.log = log + + def dnd_end(self, target, event): + self.log.append('end') + + +class FakeEvent: + def __init__(self, widget, num=1): + self.num = num + self.widget = widget + self.x = self.y = self.x_root = self.y_root = 0 + + +class DndTest(AbstractTkTest, unittest.TestCase): + + def setUp(self): + super().setUp() + self.canvas = tkinter.Canvas(self.root) + self.canvas.pack() + # on_motion() locates the target with winfo_containing(). Bypass that + # real screen lookup, which depends on the window being visible and + # unobscured, so the test does not hinge on the window manager. + self.canvas.winfo_containing = lambda x, y: self.canvas + self.log = [] + self.source = Source(self.log) + self.target = Target(self.canvas, self.log) + + def test_drag_and_drop(self): + handler = dnd.dnd_start(self.source, FakeEvent(self.canvas)) + self.assertIsNotNone(handler) + handler.on_motion(FakeEvent(self.canvas)) # Enter the target. + handler.on_motion(FakeEvent(self.canvas)) # Move within the target. + handler.on_release(FakeEvent(self.canvas)) # Drop on the target. + self.assertEqual(self.log, + ['accept', 'enter', 'accept', 'motion', 'commit', 'end']) + + def test_cancel(self): + handler = dnd.dnd_start(self.source, FakeEvent(self.canvas)) + handler.on_motion(FakeEvent(self.canvas)) # Enter the target. + handler.cancel() # Leaves the target without committing. + self.assertEqual(self.log, ['accept', 'enter', 'leave', 'end']) + + def test_no_target(self): + # Nothing under the pointer accepts the drag. + self.canvas.winfo_containing = lambda x, y: None + handler = dnd.dnd_start(self.source, FakeEvent(self.canvas)) + handler.on_motion(FakeEvent(self.canvas)) + handler.on_release(FakeEvent(self.canvas)) + self.assertEqual(self.log, ['end']) + + def test_no_recursive_start(self): + handler = dnd.dnd_start(self.source, FakeEvent(self.canvas)) + self.assertIsNotNone(handler) + # A drag is already in progress, so a second start is ignored. + self.assertIsNone(dnd.dnd_start(self.source, FakeEvent(self.canvas))) + handler.cancel() + + def test_high_button_number_ignored(self): + self.assertIsNone(dnd.dnd_start(self.source, FakeEvent(self.canvas, num=6))) + + +if __name__ == "__main__": + unittest.main() From 70d495aab0f878c43b02af4298d5882b61c17391 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 20 Jun 2026 15:49:16 +0200 Subject: [PATCH 382/818] [3.15] gh-151678: Add tests for tkinter.filedialog (GH-151781) (GH-151795) Exercise the native dialogs (Open, SaveAs and Directory) through the _test_callback seam without opening them, and test the pure-Python FileDialog selection, filter and ok/cancel logic without entering its modal loop. (cherry picked from commit 58fd9ec3cfe0d588db97eb98c0dc7fdb0256be76) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --- Lib/test/test_tkinter/test_filedialog.py | 73 ++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 Lib/test/test_tkinter/test_filedialog.py diff --git a/Lib/test/test_tkinter/test_filedialog.py b/Lib/test/test_tkinter/test_filedialog.py new file mode 100644 index 00000000000000..054e719a0f883d --- /dev/null +++ b/Lib/test/test_tkinter/test_filedialog.py @@ -0,0 +1,73 @@ +import os +import unittest +from tkinter import filedialog +from tkinter.commondialog import Dialog +from test.support import requires, swap_attr +from test.test_tkinter.support import setUpModule # noqa: F401 +from test.test_tkinter.support import AbstractTkTest + +requires('gui') + + +class NativeDialogTest(AbstractTkTest, unittest.TestCase): + # Open, SaveAs and Directory wrap modal native dialogs. The _test_callback + # seam is called by show() just before the dialog would open; replacing it + # with a function that raises exercises show() without blocking on the + # dialog. + + def check(self, dialog_class, command): + self.assertEqual(dialog_class.command, command) + master = None + def test_callback(dialog, parent): + nonlocal master + master = parent + raise ZeroDivisionError + with swap_attr(Dialog, '_test_callback', test_callback): + d = dialog_class(self.root, title='Test') + self.assertRaises(ZeroDivisionError, d.show) + self.assertIs(master, self.root) + + def test_open(self): + self.check(filedialog.Open, 'tk_getOpenFile') + + def test_saveas(self): + self.check(filedialog.SaveAs, 'tk_getSaveFile') + + def test_directory(self): + self.check(filedialog.Directory, 'tk_chooseDirectory') + + +class FileDialogTest(AbstractTkTest, unittest.TestCase): + # The pure-Python FileDialog runs its own modal loop in go(); its logic is + # exercised here without entering the loop. + + def test_selection(self): + d = filedialog.FileDialog(self.root) + d.directory = os.path.abspath(os.sep) + d.set_selection('spam.txt') + self.assertEqual(os.path.basename(d.get_selection()), 'spam.txt') + + def test_filter(self): + d = filedialog.FileDialog(self.root) + d.set_filter(os.getcwd(), '*.py') + self.assertEqual(d.get_filter(), (os.getcwd(), '*.py')) + + def test_ok_cancel(self): + d = filedialog.FileDialog(self.root) + d.directory = os.getcwd() + d.set_selection('spam.txt') + d.ok_command() # Accepts the current selection. + self.assertEqual(os.path.basename(d.how), 'spam.txt') + d.cancel_command() # Returns no selection. + self.assertIsNone(d.how) + + def test_subclasses(self): + for cls in filedialog.LoadFileDialog, filedialog.SaveFileDialog: + with self.subTest(cls=cls.__name__): + d = cls(self.root) + self.assertIsInstance(d, filedialog.FileDialog) + self.assertEqual(d.top.title(), cls.title) + + +if __name__ == "__main__": + unittest.main() From 86cdbd8e44ebb70ab20f82c5d9b19af25998ac21 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 20 Jun 2026 16:12:08 +0200 Subject: [PATCH 383/818] [3.15] gh-151678: Add tests for the remaining tkinter Misc, Wm and Text methods (GH-151782) (GH-151799) Cover Misc.wait_variable and wait_window, tk_focusFollowsMouse, selection_handle, the error paths of grab_set_global, send, the X11-specific Wm methods iconposition, iconmask, iconwindow, colormapwindows and manage/forget, and the Text.window_config alias and deprecated yview_pickplace. (cherry picked from commit aa71eb287f6d812e5270109acb9119c2ad0baef9) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --- Lib/test/test_tkinter/test_misc.py | 71 ++++++++++++++++++++++++++++++ Lib/test/test_tkinter/test_text.py | 6 +++ 2 files changed, 77 insertions(+) diff --git a/Lib/test/test_tkinter/test_misc.py b/Lib/test/test_tkinter/test_misc.py index 0a13b9dc75162a..96cc7fb85929d0 100644 --- a/Lib/test/test_tkinter/test_misc.py +++ b/Lib/test/test_tkinter/test_misc.py @@ -461,6 +461,48 @@ def test_tk_bisque(self): self.assertEqual(root['background'], '#ffe4c4') self.assertRaises(TypeError, root.tk_bisque, 'x') + def test_wait_variable(self): + var = tkinter.StringVar(self.root) + self.assertEqual(self.root.waitvar, self.root.wait_variable) + self.root.after(1, var.set, 'done') + self.root.wait_variable(var) # Returns once the variable is set. + self.assertEqual(var.get(), 'done') + + def test_wait_window(self): + top = tkinter.Toplevel(self.root) + self.root.after(1, top.destroy) + self.root.wait_window(top) # Returns once the window is destroyed. + self.assertFalse(top.winfo_exists()) + + def test_tk_focusFollowsMouse(self): + self.root.tk_focusFollowsMouse() # No exception. + + def test_selection_handle(self): + f = tkinter.Frame(self.root) + def handler(offset, length): + return 'PAYLOAD'[int(offset):int(offset) + int(length)] + f.selection_handle(handler) + f.selection_own() + self.assertEqual(f.selection_get(), 'PAYLOAD') + + def test_grab_set_global(self): + # A successful global grab directs all events on the display to this + # application, so only the error paths are tested here. + self.assertRaises(TypeError, self.root.grab_set_global, 'extra') + with self.subTest('non-viewable window'): + if self.root._windowingsystem != 'x11': + # Grabbing a non-viewable window fails only on X11; elsewhere + # it would actually grab the whole display. + self.skipTest('only X11 fails the grab') + f = tkinter.Frame(self.root) # not yet viewable + self.assertRaisesRegex(TclError, 'grab failed', f.grab_set_global) + + def test_send(self): + if self.root._windowingsystem != 'x11': + self.skipTest('send is only supported on X11') + self.assertRaisesRegex(TclError, 'no application named', + self.root.send, 'no_such_interp_xyzzy', 'set x 1') + def test_event_repr_defaults(self): e = tkinter.Event() e.serial = 12345 @@ -917,6 +959,35 @@ def test_wm_iconname(self): t.iconname('Icon') self.assertIn(t.iconname(), ('Icon', '')) + def test_wm_iconposition(self): + t = tkinter.Toplevel(self.root) + t.wm_iconposition(3, 4) # An X11 hint; may be a no-op elsewhere. + if t._windowingsystem == 'x11': + self.assertEqual(t.wm_iconposition(), (3, 4)) + + def test_wm_iconmask_iconwindow(self): + if self.root._windowingsystem != 'x11': + self.skipTest('iconmask and iconwindow are X11-specific') + t = tkinter.Toplevel(self.root) + t.wm_iconmask('gray50') # No exception. + icon = tkinter.Toplevel(self.root) + t.wm_iconwindow(icon) + self.assertEqual(str(t.wm_iconwindow()), str(icon)) + + def test_wm_colormapwindows(self): + if self.root._windowingsystem != 'x11': + self.skipTest('colormapwindows is X11-specific') + t = tkinter.Toplevel(self.root) + self.assertEqual(t.wm_colormapwindows(), []) + f = tkinter.Frame(t) + t.wm_colormapwindows(f) + self.assertEqual([str(w) for w in t.wm_colormapwindows()], [str(f)]) + + def test_wm_manage_forget(self): + f = tkinter.Frame(self.root) + self.root.wm_manage(f) # Make the frame a top-level window. + self.root.wm_forget(f) # Revert it; no exception either way. + def test_wm_client_command(self): t = tkinter.Toplevel(self.root) t.client('myhost') diff --git a/Lib/test/test_tkinter/test_text.py b/Lib/test/test_tkinter/test_text.py index 0303c2ac1ed1da..3d15e7f4909e83 100644 --- a/Lib/test/test_tkinter/test_text.py +++ b/Lib/test/test_tkinter/test_text.py @@ -505,6 +505,7 @@ def test_window_configure(self): self.assertIsInstance(cnf, dict) self.assertIn('stretch', cnf) self.assertRaises(TclError, text.window_cget, '1.1', 'spam') + self.assertEqual(text.window_config, text.window_configure) button.destroy() def test_peer(self): @@ -562,6 +563,11 @@ def test_see(self): self.assertRaises(TypeError, text.see) self.assertRaises(TypeError, text.see, '1.0', '2.0') + # yview_pickplace is a deprecated way to make an index visible. + text.yview_pickplace('1.0') + text.update() + self.assertIsNotNone(text.bbox('1.0')) + def test_search(self): text = self.text From ba8548ca82773803dff5d426bbf4a8a40375c924 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 20 Jun 2026 17:00:38 +0200 Subject: [PATCH 384/818] [3.15] gh-151678: Add tests for tkinter widget virtual events (GH-151793) (GH-151805) Verify the virtual events that widgets emit in response to user interaction, driven by generated events: <<ListboxSelect>> (Listbox), <<Increment>> and <<Decrement>> (ttk Spinbox), and <<TreeviewSelect>>, <<TreeviewOpen>> and <<TreeviewClose>> (ttk Treeview). (cherry picked from commit e51b616efff845ea2a7d312aa43d5f5100064d88) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --- Lib/test/test_tkinter/test_widgets.py | 17 +++++++++++ Lib/test/test_ttk/test_widgets.py | 44 +++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) diff --git a/Lib/test/test_tkinter/test_widgets.py b/Lib/test/test_tkinter/test_widgets.py index 8ce71bc37ca2e4..4b51d219d87e5b 100644 --- a/Lib/test/test_tkinter/test_widgets.py +++ b/Lib/test/test_tkinter/test_widgets.py @@ -1926,6 +1926,23 @@ def test_selection(self): self.assertRaisesRegex(TclError, 'bad listbox index "spam"', lb.selection_includes, 'spam') + def test_selection_event(self): + # Keyboard navigation changes the selection and fires the + # <<ListboxSelect>> virtual event. + lb = self.create(selectmode='browse', exportselection=False) + lb.insert(0, *('el%d' % i for i in range(5))) + lb.pack() + lb.update() + events = [] + lb.bind('<<ListboxSelect>>', lambda e: events.append(lb.curselection())) + lb.focus_force() + lb.activate(0) + lb.event_generate('<Down>') + lb.event_generate('<Down>') + lb.update() + self.assertEqual(events, [(1,), (2,)]) + self.assertEqual(lb.curselection(), (2,)) + @add_configure_tests(PixelSizeTests, StandardOptionsTests) class ScaleTest(AbstractWidgetTest, unittest.TestCase): diff --git a/Lib/test/test_ttk/test_widgets.py b/Lib/test/test_ttk/test_widgets.py index adcd736cd40b19..a3b3c88b46edd2 100644 --- a/Lib/test/test_ttk/test_widgets.py +++ b/Lib/test/test_ttk/test_widgets.py @@ -1307,6 +1307,19 @@ def test_configure_command(self): self.spin.update() self.assertEqual(len(success), 2) + def test_increment_decrement_events(self): + # Clicking the arrows fires the <<Increment>> and <<Decrement>> + # virtual events. + events = [] + self.spin.bind('<<Increment>>', lambda e: events.append('increment')) + self.spin.bind('<<Decrement>>', lambda e: events.append('decrement')) + self.spin.update() + self._click_increment_arrow() + self.spin.update() + self._click_decrement_arrow() + self.spin.update() + self.assertEqual(events, ['increment', 'decrement']) + def test_configure_to(self): self.spin['from'] = 0 self.spin['to'] = 5 @@ -1945,6 +1958,37 @@ def test_selection(self): self.tv.selection_toggle((c1, c3)) self.assertEqual(self.tv.selection(), (c3, item2)) + def test_virtual_events(self): + # Keyboard navigation fires the <<TreeviewSelect>>, <<TreeviewOpen>> + # and <<TreeviewClose>> virtual events. + parent = self.tv.insert('', 'end') + self.tv.insert(parent, 'end') + item2 = self.tv.insert('', 'end') + self.tv.pack() + self.tv.update() + selects, opens, closes = [], [], [] + self.tv.bind('<<TreeviewSelect>>', + lambda e: selects.append(self.tv.selection())) + self.tv.bind('<<TreeviewOpen>>', lambda e: opens.append(self.tv.focus())) + self.tv.bind('<<TreeviewClose>>', lambda e: closes.append(self.tv.focus())) + self.tv.focus_force() + self.tv.focus(parent) + self.tv.selection_set(parent) + self.tv.update() + + self.tv.event_generate('<Right>') # Open the focused parent. + self.tv.update() + self.assertEqual(opens, [parent]) + + self.tv.event_generate('<Left>') # Close it again. + self.tv.update() + self.assertEqual(closes, [parent]) + + self.tv.event_generate('<Down>') # Move the selection. + self.tv.update() + self.assertEqual(self.tv.selection(), (item2,)) + self.assertIn((item2,), selects) + def test_set(self): self.tv['columns'] = ['A', 'B'] item = self.tv.insert('', 'end', values=['a', 'b']) From 45a0043971a0f4d1ec586e4fe18cbd6e9a2e2268 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 20 Jun 2026 19:01:40 +0200 Subject: [PATCH 385/818] [3.15] gh-151770: Fix `datetime.fromisoformat()` on an out-of-range month w/ a 24:00 time (GH-151771) (#151809) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (cherry picked from commit 1fb874cc076e771c39a7bbc650dce386e3c5b7a0) Co-authored-by: tonghuaroot (童话) <tonghuaroot@gmail.com> Co-authored-by: Stan Ulbrych <stan@python.org> --- Lib/_pydatetime.py | 4 ++-- Lib/test/datetimetester.py | 1 + .../Library/2026-06-20-15-00-00.gh-issue-151770.dtiso0.rst | 3 +++ Modules/_datetimemodule.c | 2 +- 4 files changed, 7 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-06-20-15-00-00.gh-issue-151770.dtiso0.rst diff --git a/Lib/_pydatetime.py b/Lib/_pydatetime.py index b6d68f2372850a..c1448374402de4 100644 --- a/Lib/_pydatetime.py +++ b/Lib/_pydatetime.py @@ -55,7 +55,7 @@ def _days_before_year(year): def _days_in_month(year, month): "year, month -> number of days in that month in that year." - assert 1 <= month <= 12, month + assert 1 <= month <= 12, f"month must be in 1..12, not {month}" if month == 2 and _is_leap(year): return 29 return _DAYS_IN_MONTH[month] @@ -1987,7 +1987,7 @@ def fromisoformat(cls, date_string): if became_next_day: year, month, day = date_components # Only wrap day/month when it was previously valid - if month <= 12 and day <= (days_in_month := _days_in_month(year, month)): + if 1 <= month <= 12 and day <= (days_in_month := _days_in_month(year, month)): # Calculate midnight of the next day day += 1 if day > days_in_month: diff --git a/Lib/test/datetimetester.py b/Lib/test/datetimetester.py index d26e41982deb81..1cbe78c1ecbfdc 100644 --- a/Lib/test/datetimetester.py +++ b/Lib/test/datetimetester.py @@ -3773,6 +3773,7 @@ def test_fromisoformat_fails_datetime_valueerror(self): "2009-04-01T12:30:90", # Second out of range "2009-04-01T12:90:45", # Minute out of range "2009-04-01T25:30:45", # Hour out of range + "2009-00-01T24:00:00", # Month below range "2009-13-01T24:00:00", # Month out of range "9999-12-31T24:00:00", # Year out of range ] diff --git a/Misc/NEWS.d/next/Library/2026-06-20-15-00-00.gh-issue-151770.dtiso0.rst b/Misc/NEWS.d/next/Library/2026-06-20-15-00-00.gh-issue-151770.dtiso0.rst new file mode 100644 index 00000000000000..10b3db8efa42b0 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-20-15-00-00.gh-issue-151770.dtiso0.rst @@ -0,0 +1,3 @@ +Fix :meth:`datetime.datetime.fromisoformat` raising :exc:`AssertionError` +instead of :exc:`ValueError` for an out-of-range month combined with a +``24:00`` time. diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index 789e9a8b1488b9..21bb911d0fb03f 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -6144,7 +6144,7 @@ datetime_datetime_fromisoformat_impl(PyTypeObject *type, PyObject *string) goto error; } - if ((hour == 24) && (month <= 12)) { + if ((hour == 24) && (month >= 1 && month <= 12)) { int d_in_month = days_in_month(year, month); if (day <= d_in_month) { if (minute == 0 && second == 0 && microsecond == 0) { From 37aa97330de0190e0d7dff9208ad61435a230d40 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 21 Jun 2026 13:35:52 +0200 Subject: [PATCH 386/818] [3.15] gh-150831: docs: clarify generator, generator function, and generator iterator in glossary (GH-150905) (#151840) gh-150831: docs: clarify generator, generator function, and generator iterator in glossary (GH-150905) (cherry picked from commit 1de86e1492af92f4b18aad94390bcd4336e579ab) Co-authored-by: Aniket <148300120+Aniketsy@users.noreply.github.com> --- Doc/glossary.rst | 55 ++++++++++++++++++++++++++++++------------------ 1 file changed, 34 insertions(+), 21 deletions(-) diff --git a/Doc/glossary.rst b/Doc/glossary.rst index 56bc799d945e7b..7b74651fda1fe5 100644 --- a/Doc/glossary.rst +++ b/Doc/glossary.rst @@ -96,21 +96,24 @@ Glossary :meth:`~object.__aexit__` methods. Introduced by :pep:`492`. asynchronous generator - A function which returns an :term:`asynchronous generator iterator`. It - looks like a coroutine function defined with :keyword:`async def` except - that it contains :keyword:`yield` expressions for producing a series of - values usable in an :keyword:`async for` loop. - - Usually refers to an asynchronous generator function, but may refer to an - *asynchronous generator iterator* in some contexts. In cases where the - intended meaning isn't clear, using the full terms avoids ambiguity. + Informally used to mean either an :term:`asynchronous generator + function` or an :term:`asynchronous generator iterator`, depending on + context. The formal terms :term:`asynchronous generator function` and + :term:`asynchronous generator iterator` are uncommon in practice; + "asynchronous generator" alone is almost always sufficient. + + asynchronous generator function + A function which returns an :term:`asynchronous generator iterator`. + It looks like a coroutine function defined with :keyword:`async def` + except that it contains :keyword:`yield` expressions for producing a + series of values usable in an :keyword:`async for` loop. See :pep:`525`. An asynchronous generator function may contain :keyword:`await` expressions as well as :keyword:`async for`, and :keyword:`async with` statements. asynchronous generator iterator - An object created by an :term:`asynchronous generator` function. + An object created by an :term:`asynchronous generator function`. This is an :term:`asynchronous iterator` which when called using the :meth:`~object.__anext__` method returns an awaitable object which will execute @@ -641,23 +644,33 @@ Glossary .. index:: single: generator generator - A function which returns a :term:`generator iterator`. It looks like a - normal function except that it contains :keyword:`yield` expressions - for producing a series of values usable in a for-loop or that can be - retrieved one at a time with the :func:`next` function. + Informally used to mean either a :term:`generator function` or a + :term:`generator iterator`, depending on context. The formal terms + :term:`generator function` and :term:`generator iterator` are uncommon + in practice; "generator" alone is almost always sufficient. - Usually refers to a generator function, but may refer to a - *generator iterator* in some contexts. In cases where the intended - meaning isn't clear, using the full terms avoids ambiguity. + .. index:: single: generator function + + generator function + A function which returns a :term:`generator` object. It looks like a + normal function except that it contains :keyword:`yield` expressions + for producing a series of values usable in a :keyword:`for`\-loop or + that can be retrieved one at a time with the :func:`next` function. + See :ref:`yieldexpr`. generator iterator - An object created by a :term:`generator` function. + An object created by a :term:`generator function` or a + :term:`generator expression`. Each :keyword:`yield` temporarily suspends processing, remembering the - execution state (including local variables and pending - try-statements). When the *generator iterator* resumes, it picks up where - it left off (in contrast to functions which start fresh on every - invocation). + execution state (including local variables and pending try-statements). + When the *generator iterator* resumes, it picks up where it left off + (in contrast to functions which start fresh on every invocation). + + Generator iterators also implement the :meth:`~generator.send` method + to send a value into the suspended generator, and the + :meth:`~generator.throw` method to raise an exception at the point + where the generator was paused. See :ref:`generator-methods`. .. index:: single: generator expression From aa83ca3ec884d37a03910e76242d80ae045c80e3 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 21 Jun 2026 17:10:43 +0200 Subject: [PATCH 387/818] [3.15] gh-86726: Document tkinter.simpledialog query options and Dialog.result (GH-151851) (GH-151852) (cherry picked from commit 8270ae560c632f2ee88ab6c6b33562227d0deaae) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> --- Doc/library/dialog.rst | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/Doc/library/dialog.rst b/Doc/library/dialog.rst index 952fd1f0783671..402cfcfe75369f 100644 --- a/Doc/library/dialog.rst +++ b/Doc/library/dialog.rst @@ -15,16 +15,31 @@ The :mod:`!tkinter.simpledialog` module contains convenience classes and functions for creating simple modal dialogs to get a value from the user. -.. function:: askfloat(title, prompt, **kw) - askinteger(title, prompt, **kw) - askstring(title, prompt, **kw) +.. function:: askfloat(title, prompt, *, initialvalue=None, minvalue=None, maxvalue=None, parent=None) + askinteger(title, prompt, *, initialvalue=None, minvalue=None, maxvalue=None, parent=None) + askstring(title, prompt, *, initialvalue=None, show=None, parent=None) - The above three functions provide dialogs that prompt the user to enter a value - of the desired type. + Prompt the user to enter a value of the desired type and return it, or + ``None`` if the dialog is cancelled. + + *title* is the dialog title and *prompt* the message shown above the entry. + *initialvalue* is the value initially placed in the entry. + *parent* is the window over which the dialog is shown. + :func:`askinteger` and :func:`askfloat` also accept *minvalue* and + *maxvalue*, which bound the accepted value. + :func:`askstring` also accepts *show*, a character used to mask the entered + text, for example ``'*'`` to hide a password. .. class:: Dialog(parent, title=None) The base class for custom dialogs. + Instantiating it shows the dialog modally and returns once the user closes + it; the entered value is then available in the :attr:`!result` attribute. + + .. attribute:: result + + The value produced by :meth:`apply`, or ``None`` if the dialog was + cancelled. .. method:: body(master) @@ -46,7 +61,8 @@ functions for creating simple modal dialogs to get a value from the user. .. method:: apply() - Process the data entered by the user. + Process the data entered by the user, for example by storing it in the + :attr:`!result` attribute. Called after :meth:`validate` succeeds and just before the dialog is destroyed. The default implementation does nothing; override it to act on or store From f43f4384cce232003099fb6a1303f476f9e641c4 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 21 Jun 2026 18:54:36 +0200 Subject: [PATCH 388/818] [3.15] gh-151678: Add interactive tests for tkinter.simpledialog (GH-151794) (GH-151802) Drive the modal query dialogs with generated events to exercise the <Return> and <Escape> key bindings and the value validation: accepting an integer, float or string, cancelling, rejecting a non-numeric value and rejecting a value outside the allowed range. (cherry picked from commit 706238e764169dd36f918a0541adf9687cc3f296) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --- Lib/test/test_tkinter/test_simpledialog.py | 66 +++++++++++++++++++++- 1 file changed, 64 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_tkinter/test_simpledialog.py b/Lib/test/test_tkinter/test_simpledialog.py index 313ad82e0a2c0d..6cf57fde8d4c56 100644 --- a/Lib/test/test_tkinter/test_simpledialog.py +++ b/Lib/test/test_tkinter/test_simpledialog.py @@ -1,9 +1,11 @@ import unittest import tkinter +from tkinter import messagebox from test.support import requires, swap_attr from test.test_tkinter.support import setUpModule # noqa: F401 -from test.test_tkinter.support import AbstractDefaultRootTest -from tkinter.simpledialog import Dialog, askinteger +from test.test_tkinter.support import AbstractDefaultRootTest, AbstractTkTest +from tkinter.simpledialog import (Dialog, askinteger, + _QueryInteger, _QueryFloat, _QueryString) requires('gui') @@ -32,5 +34,65 @@ def mock_wait_window(w): self.assertRaises(RuntimeError, askinteger, "Go To Line", "Line number") +class QueryDialogTest(AbstractTkTest, unittest.TestCase): + # The query dialogs are modal: their __init__ blocks in wait_window(). + # Mock that out so the dialog stays alive and can be driven with generated + # events, exercising the <Return>/<Escape> bindings and the validation. + + def open(self, query, **kw): + with swap_attr(Dialog, 'wait_window', staticmethod(lambda w: None)): + d = query("Title", "Prompt", parent=self.root, **kw) + self.addCleanup(lambda: d.winfo_exists() and d.destroy()) + d.focus_force() + d.update() + return d + + def enter(self, d, value, key='<Return>'): + d.entry.delete(0, 'end') + d.entry.insert(0, value) + d.event_generate(key) + d.update() + + def test_return_accepts(self): + for query, value, expected in [ + (_QueryInteger, '42', 42), + (_QueryFloat, '1.5', 1.5), + (_QueryString, 'spam', 'spam'), + ]: + with self.subTest(query=query.__name__): + d = self.open(query) + self.enter(d, value) + self.assertEqual(d.result, expected) + self.assertFalse(d.winfo_exists()) # The dialog closed. + + def test_escape_cancels(self): + d = self.open(_QueryString) + self.enter(d, 'spam', '<Escape>') + self.assertIsNone(d.result) + self.assertFalse(d.winfo_exists()) + + def test_invalid_value(self): + warnings = [] + d = self.open(_QueryInteger) + with swap_attr(messagebox, 'showwarning', + lambda *a, **k: warnings.append(a)): + self.enter(d, 'not a number') + self.assertIsNone(d.result) + self.assertTrue(d.winfo_exists()) # The dialog stays open. + self.assertTrue(warnings) + + def test_out_of_range(self): + warnings = [] + d = self.open(_QueryInteger, minvalue=10, maxvalue=20) + with swap_attr(messagebox, 'showwarning', + lambda *a, **k: warnings.append(a)): + self.enter(d, '5') # Below the minimum. + self.assertIsNone(d.result) + self.enter(d, '25') # Above the maximum. + self.assertIsNone(d.result) + self.assertTrue(d.winfo_exists()) + self.assertEqual(len(warnings), 2) + + if __name__ == "__main__": unittest.main() From f5119a536a6ca97f282fb0e8d3f700369f907bb6 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 21 Jun 2026 19:43:01 +0200 Subject: [PATCH 389/818] [3.15] gh-151845: Fix formatfloat() return-value contract in unicode_format.c (GH-151846) (#151865) gh-151845: Fix formatfloat() return-value contract in unicode_format.c (GH-151846) Fix formatfloat() return-value contract in unicode_format.c (cherry picked from commit c2661e6189ab2833bf32fa723cc427e64c026839) Co-authored-by: AN Long <aisk@users.noreply.github.com> --- Objects/unicode_format.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Objects/unicode_format.c b/Objects/unicode_format.c index e2790c8c1d4343..1d6f3f7d9a6f6a 100644 --- a/Objects/unicode_format.c +++ b/Objects/unicode_format.c @@ -159,8 +159,13 @@ formatfloat(PyObject *v, return -1; } } - else + else { *p_output = _PyUnicode_FromASCII(p, len); + if (*p_output == NULL) { + PyMem_Free(p); + return -1; + } + } PyMem_Free(p); return 0; } From a2d2ee8e9e3b3ca57d25fbe8ccf6eec2cd7dbefa Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 21 Jun 2026 20:14:04 +0200 Subject: [PATCH 390/818] [3.15] RTD Previews: Get correct base branch for backports (GH-150690) (#151867) Co-authored-by: Stan Ulbrych <stan@python.org> --- .readthedocs.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.readthedocs.yml b/.readthedocs.yml index 3b8a30c0251873..038417e4bb3438 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -11,19 +11,21 @@ build: os: ubuntu-24.04 tools: python: "3" + apt_packages: + - jq jobs: - post_checkout: + post_system_dependencies: # https://docs.readthedocs.com/platform/stable/guides/build/skip-build.html#skip-builds-based-on-conditions # - # Cancel building pull requests when there aren't changes in the Doc + # Cancel building pull requests when there are no changes in the Doc # directory or RTD configuration, or if we can't cleanly merge the base # branch. - | set -eEux; if [ "$READTHEDOCS_VERSION_TYPE" = "external" ]; then - base_branch=main; + base_branch=$(wget -qO- "https://api.github.com/repos/python/cpython/pulls/$READTHEDOCS_VERSION" | jq -er ".base.ref"); git fetch --depth=50 origin $base_branch:origin-$base_branch; for attempt in $(seq 10); do From 2e4dddfa17e91edf8756117977b2b9e337c79913 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 21 Jun 2026 20:59:26 +0200 Subject: [PATCH 391/818] [3.15] gh-151678: Add tests for tkinter.simpledialog (GH-151856) (GH-151869) (cherry picked from commit f28ef858f5515d200319e9675d66f8f13afa5a0d) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --- Lib/test/test_tkinter/test_simpledialog.py | 177 ++++++++++++++++++++- 1 file changed, 176 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_tkinter/test_simpledialog.py b/Lib/test/test_tkinter/test_simpledialog.py index 6cf57fde8d4c56..942b7ebf7120b3 100644 --- a/Lib/test/test_tkinter/test_simpledialog.py +++ b/Lib/test/test_tkinter/test_simpledialog.py @@ -4,12 +4,143 @@ from test.support import requires, swap_attr from test.test_tkinter.support import setUpModule # noqa: F401 from test.test_tkinter.support import AbstractDefaultRootTest, AbstractTkTest -from tkinter.simpledialog import (Dialog, askinteger, +from tkinter.simpledialog import (Dialog, SimpleDialog, + askinteger, askfloat, askstring, _QueryInteger, _QueryFloat, _QueryString) requires('gui') +class SimpleDialogTest(AbstractTkTest, unittest.TestCase): + # SimpleDialog's modal loop is in go(); its bindings are exercised here by + # generating events on the constructed dialog, without entering the loop. + + def create(self, **kw): + kw.setdefault('text', 'Question?') + kw.setdefault('buttons', ['Yes', 'No']) + kw.setdefault('default', 0) + kw.setdefault('cancel', 1) + d = SimpleDialog(self.root, **kw) + self.addCleanup(lambda: d.root.winfo_exists() and d.root.destroy()) + return d + + def test_message(self): + # The text is shown in a message widget. + d = self.create(text='Hello?') + self.assertEqual(d.message.winfo_class(), 'Message') + self.assertEqual(str(d.message.cget('text')), 'Hello?') + + def test_class_name(self): + # class_ sets the Tk class of the dialog window. + d = self.create(class_='MyDialog') + self.assertEqual(d.root.winfo_class(), 'MyDialog') + + def test_button(self): + # Pressing a button records its index. + d = self.create(buttons=['Yes', 'No']) + d.frame.winfo_children()[1].invoke() # "No" + self.assertEqual(d.num, 1) + + def test_default_button(self): + # The default button is drawn with a raised border. + d = self.create(buttons=['Yes', 'No'], default=0) + self.assertEqual(str(d.frame.winfo_children()[0].cget('relief')), 'ridge') + + def test_return_activates_default(self): + # <Return> invokes the default button. + d = self.create() # default 0 + d.root.focus_force() + d.root.update() + d.root.event_generate('<Return>') + d.root.update() + self.assertEqual(d.num, 0) + + def test_return_no_default(self): + # With no default button, <Return> rings the bell and leaves the dialog + # open instead of activating a button. + d = self.create(default=None) + d.root.focus_force() + d.root.update() + bells = [] + with swap_attr(d.root, 'bell', lambda *a, **k: bells.append(True)): + d.root.event_generate('<Return>') + d.root.update() + self.assertTrue(bells) # rang the bell + self.assertIsNone(d.num) + self.assertTrue(d.root.winfo_exists()) + + def test_wm_delete_cancels(self): + # Closing the window through the window manager records the cancel index. + d = self.create() # cancel 1 + d.wm_delete_window() + self.assertEqual(d.num, 1) + + def test_wm_delete_no_cancel(self): + # With no cancel index, closing the window through the window manager + # rings the bell and leaves the dialog open instead of recording an + # index. + d = self.create(default=None, cancel=None) + d.root.update() + bells = [] + with swap_attr(d.root, 'bell', lambda *a, **k: bells.append(True)): + d.wm_delete_window() + d.root.update() + self.assertTrue(bells) # rang the bell + self.assertIsNone(d.num) + self.assertTrue(d.root.winfo_exists()) + + def test_go(self): + # go() runs the modal loop and returns the chosen button's index. + d = self.create() + d.root.after(1, lambda: d.done(0)) + self.assertEqual(d.go(), 0) + + +class DialogTest(AbstractTkTest, unittest.TestCase): + # Dialog is a base class for custom dialogs; exercise it via _QueryInteger. + + def open(self, **kw): + with swap_attr(Dialog, 'wait_window', staticmethod(lambda w: None)): + d = _QueryInteger('Title', 'Prompt', parent=self.root, **kw) + self.addCleanup(lambda: d.winfo_exists() and d.destroy()) + return d + + def buttons(self, d): + # Map the button box's buttons by their label. + return {str(b.cget('text')): b + for frame in d.winfo_children() + for b in frame.winfo_children() + if b.winfo_class() == 'Button'} + + def test_background(self): + # The classic dialog keeps the default Toplevel background. + d = self.open() + ref = tkinter.Toplevel(self.root) + self.addCleanup(ref.destroy) + self.assertEqual(str(d.cget('background')), str(ref.cget('background'))) + + def test_buttons(self): + # The button box has OK (the default) and Cancel buttons. + buttons = self.buttons(self.open()) + self.assertEqual(set(buttons), {'OK', 'Cancel'}) + self.assertEqual(str(buttons['OK'].cget('default')), 'active') + + def test_ok(self): + # The OK button validates the entry and stores the result. + d = self.open() + d.entry.insert(0, '42') + self.buttons(d)['OK'].invoke() + self.assertEqual(d.result, 42) + self.assertFalse(d.winfo_exists()) # The dialog closed. + + def test_cancel(self): + # The Cancel button closes the dialog without a result. + d = self.open() + self.buttons(d)['Cancel'].invoke() + self.assertIsNone(d.result) + self.assertFalse(d.winfo_exists()) + + class DefaultRootTest(AbstractDefaultRootTest, unittest.TestCase): def test_askinteger(self): @@ -53,6 +184,19 @@ def enter(self, d, value, key='<Return>'): d.event_generate(key) d.update() + def test_initialvalue(self): + # The entry is pre-filled with the initial value, which is accepted. + d = self.open(_QueryInteger, initialvalue=42) + self.assertEqual(d.entry.get(), '42') + d.event_generate('<Return>') + d.update() + self.assertEqual(d.result, 42) + + def test_show(self): + # _QueryString hides the entered text when show is given. + d = self.open(_QueryString, show='*') + self.assertEqual(str(d.entry.cget('show')), '*') + def test_return_accepts(self): for query, value, expected in [ (_QueryInteger, '42', 42), @@ -93,6 +237,37 @@ def test_out_of_range(self): self.assertTrue(d.winfo_exists()) self.assertEqual(len(warnings), 2) + def test_boundary_values_accepted(self): + # The min/max checks are inclusive: a value equal to a bound passes. + d = self.open(_QueryInteger, minvalue=10, maxvalue=20) + self.enter(d, '10') # Exactly the minimum. + self.assertEqual(d.result, 10) + self.assertFalse(d.winfo_exists()) + + d = self.open(_QueryInteger, minvalue=10, maxvalue=20) + self.enter(d, '20') # Exactly the maximum. + self.assertEqual(d.result, 20) + self.assertFalse(d.winfo_exists()) + + def run_ask(self, ask, value, **kw): + # Drive a modal ask* function: enter a value and accept it. + def accept(d): + d.entry.delete(0, 'end') + d.entry.insert(0, value) + d.ok() + with swap_attr(Dialog, 'wait_window', staticmethod(accept)): + return ask('Title', 'Prompt', parent=self.root, **kw) + + def test_ask_functions(self): + self.assertEqual(self.run_ask(askinteger, '42'), 42) + self.assertEqual(self.run_ask(askfloat, '1.5'), 1.5) + self.assertEqual(self.run_ask(askstring, 'spam'), 'spam') + + def test_ask_cancelled(self): + # A cancelled ask* returns None. + with swap_attr(Dialog, 'wait_window', staticmethod(lambda d: d.cancel())): + self.assertIsNone(askstring('Title', 'Prompt', parent=self.root)) + if __name__ == "__main__": unittest.main() From 453714a2dc0d16e6e6b8cff70801dfc1284bf74d Mon Sep 17 00:00:00 2001 From: Timofei <128279579+deadlovelll@users.noreply.github.com> Date: Mon, 22 Jun 2026 01:08:37 +0300 Subject: [PATCH 392/818] [3.15] gh-151665: Fix inspect.signature() on type alias and type parameter evaluators (#151787) --- Lib/inspect.py | 4 +++ Lib/test/test_type_params.py | 25 +++++++++++++++++++ ...-06-20-14-47-55.gh-issue-151665.82fmzx.rst | 2 ++ 3 files changed, 31 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2026-06-20-14-47-55.gh-issue-151665.82fmzx.rst diff --git a/Lib/inspect.py b/Lib/inspect.py index dc5a6e3be883bb..0dbd596db16023 100644 --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -2720,6 +2720,10 @@ def __init__(self, name, kind, *, default=_empty, annotation=_empty): raise ValueError(msg) self._kind = _POSITIONAL_ONLY name = 'implicit{}'.format(name[1:]) + elif name == '.format': + # gh-151665: Hidden parameter of compiler-generated annotation and type + # alias/typevar evaluators. Show it as "format". + name = 'format' # It's possible for C functions to have a positional-only parameter # where the name is a keyword, so for compatibility we'll allow it. diff --git a/Lib/test/test_type_params.py b/Lib/test/test_type_params.py index 84c1b954136736..27660379ec43a3 100644 --- a/Lib/test/test_type_params.py +++ b/Lib/test/test_type_params.py @@ -1,4 +1,5 @@ import annotationlib +import inspect import textwrap import types import unittest @@ -1446,6 +1447,30 @@ def f[T: int = int, **P = int, *Ts = int](): pass self.assertIs(annotationlib.call_evaluate_function(case, annotationlib.Format.FORWARDREF), int) self.assertEqual(annotationlib.call_evaluate_function(case, annotationlib.Format.STRING), 'int') + def test_signature(self): + # gh-151665: the ".format" parameter of compiler-generated evaluators + # used to break inspect.signature(). It should show up as "format". + type Alias = int + def f[T: int = int, **P = int, *Ts = int](): pass + T, P, Ts = f.__type_params__ + def g[T: (int, str)](): pass + T3, = g.__type_params__ + cases = [ + Alias.evaluate_value, + T.evaluate_bound, + T.evaluate_default, + P.evaluate_default, + Ts.evaluate_default, + T3.evaluate_constraints, + ] + for case in cases: + with self.subTest(case=case): + sig = inspect.signature(case) + self.assertEqual(str(sig), '(format=1, /)') + param, = sig.parameters.values() + self.assertEqual(param.name, 'format') + self.assertIs(param.kind, inspect.Parameter.POSITIONAL_ONLY) + def test_constraints(self): def f[T: (int, str)](): pass T, = f.__type_params__ diff --git a/Misc/NEWS.d/next/Library/2026-06-20-14-47-55.gh-issue-151665.82fmzx.rst b/Misc/NEWS.d/next/Library/2026-06-20-14-47-55.gh-issue-151665.82fmzx.rst new file mode 100644 index 00000000000000..d08a1220cbe5ef --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-20-14-47-55.gh-issue-151665.82fmzx.rst @@ -0,0 +1,2 @@ +:func:`inspect.signature` now works on the lazy evaluators of type aliases +and type parameters instead of raising :exc:`ValueError`. From a940f933af981a90efbd81912091def59c8c2018 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 22 Jun 2026 02:29:07 +0200 Subject: [PATCH 393/818] [3.15] gh-142387: Revert Android testbed to API level 35 (GH-151816) (#151883) Revert Android testbed to API level 35 (cherry picked from commit 24828e57e17621fff166c7c81c8cf70fd5cf4540) Co-authored-by: Malcolm Smith <smith@chaquo.com> --- Platforms/Android/testbed/app/build.gradle.kts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Platforms/Android/testbed/app/build.gradle.kts b/Platforms/Android/testbed/app/build.gradle.kts index e51398fce81e26..a56714406803cb 100644 --- a/Platforms/Android/testbed/app/build.gradle.kts +++ b/Platforms/Android/testbed/app/build.gradle.kts @@ -105,12 +105,13 @@ android { // This controls the API level of the maxVersion managed emulator, which is used // by CI and cibuildwheel. + // * 32 has intermittent failures accessing the internet (#142387). // * 33 has excessive buffering in the logcat client // (https://cs.android.com/android/_/android/platform/system/logging/+/d340721894f223327339010df59b0ac514308826). - // * 34 consumes too much disk space on GitHub Actions (#142289). - // * 35 has issues connecting to the internet (#142387). + // * 34 consumes too much disk space on GitHub Actions (#142289), though switching to the + // "default" image may be a workaround. // * 36 and later are not available as aosp_atd images yet. - targetSdk = 32 + targetSdk = 35 versionCode = 1 versionName = "1.0" From 21f96ea8079edc49b9e2fa0bb279cb0c90fe6dbf Mon Sep 17 00:00:00 2001 From: Stan Ulbrych <stan@python.org> Date: Mon, 22 Jun 2026 09:43:29 +0100 Subject: [PATCH 394/818] [3.15] Remove 3.15 pending-removals from deprecations index (#151873) --- Doc/deprecations/index.rst | 2 -- 1 file changed, 2 deletions(-) diff --git a/Doc/deprecations/index.rst b/Doc/deprecations/index.rst index eedcd2e9c9dd42..cc983ee8a26127 100644 --- a/Doc/deprecations/index.rst +++ b/Doc/deprecations/index.rst @@ -1,8 +1,6 @@ Deprecations ============ -.. include:: pending-removal-in-3.15.rst - .. include:: pending-removal-in-3.16.rst .. include:: pending-removal-in-3.17.rst From ef171b603d8f8e7f885e85d3387cdb523ced4b97 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 22 Jun 2026 14:02:32 +0200 Subject: [PATCH 395/818] [3.15] gh-144133: Add a warning to the `encodings.punycode` documentation (GH-151812) (#151922) (cherry picked from commit 7ec70e1df33098de24d4b2cb181586d04cdde441) Co-authored-by: Stan Ulbrych <stan@python.org> --- Doc/library/codecs.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Doc/library/codecs.rst b/Doc/library/codecs.rst index 059ed2c03acfa3..99fcf35aa893e4 100644 --- a/Doc/library/codecs.rst +++ b/Doc/library/codecs.rst @@ -1399,6 +1399,14 @@ encodings. | punycode | | Implement :rfc:`3492`. | | | | Stateful codecs are not | | | | supported. | +| | | | +| | | .. warning:: | +| | | | +| | | The decoding and | +| | | encoding algorithms | +| | | scale poorly, so | +| | | limit the length of | +| | | untrusted input. | +--------------------+---------+---------------------------+ | raw_unicode_escape | | Latin-1 encoding with | | | | :samp:`\\u{XXXX}` and | From 59706a6d9a409dde530a86eeea6164f3ef1ff54d Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 22 Jun 2026 14:42:45 +0200 Subject: [PATCH 396/818] [3.15] gh-86726: Document tkinter method-name conflicts (GH-151917) (GH-151926) Document where widget methods shadow inherited Misc, geometry-manager and Wm methods, correct the inaccurate "size/bbox is an alias of grid_size/grid_bbox" claims, and add "# overrides X" comments at the definitions. Also document the geometry-manager ambiguity: the short names forget, info, slaves, content and propagate are defined by Pack, Place and Grid but resolve to the pack variant. Cross-reference the window-manager methods grid, forget and state with the same-named grid geometry manager, Pack.forget and ttk.Widget.state. (cherry picked from commit 4de5683f213a862c23cf8d46e3d797986e663025) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --- Doc/library/tkinter.rst | 137 +++++++++++++++++++++++++++++++----- Doc/library/tkinter.ttk.rst | 21 ++++++ Lib/tkinter/__init__.py | 26 +++---- Lib/tkinter/ttk.py | 8 +-- 4 files changed, 159 insertions(+), 33 deletions(-) diff --git a/Doc/library/tkinter.rst b/Doc/library/tkinter.rst index b0421721bf8d7e..86075baadc6ad0 100644 --- a/Doc/library/tkinter.rst +++ b/Doc/library/tkinter.rst @@ -1266,11 +1266,19 @@ Base and mixin classes If *belowThis* is given, the widget is moved to be just below it in the stacking order instead. + :meth:`tkraise`/:meth:`lift` and :meth:`lower` are overridden by the + :class:`Canvas` widget, + where they restack canvas items instead. + .. method:: image_names() Return the names of all images that currently exist in the Tcl interpreter. + This is overridden by the :class:`Text` widget, + where :meth:`!image_names` returns the names of its embedded images + instead. + .. method:: image_types() Return the available image types, such as ``'photo'`` and ``'bitmap'``. @@ -1303,7 +1311,11 @@ Base and mixin classes column 0 to that cell; if *col2* and *row2* are also given, it spans from the cell (*column*, *row*) to the cell (*col2*, *row2*). - :meth:`bbox` is an alias of :meth:`!grid_bbox`. + :meth:`bbox` is an alias of :meth:`!grid_bbox`, + except on :class:`Canvas`, :class:`Listbox`, :class:`Spinbox`, + :class:`Text`, :class:`ttk.Entry <tkinter.ttk.Entry>` and + :class:`ttk.Treeview <tkinter.ttk.Treeview>`, + which provide their own :meth:`!bbox` method. .. method:: columnconfigure(index, cnf={}, **kw) :no-typesetting: @@ -1378,7 +1390,9 @@ Base and mixin classes Return the size of the grid managed by this container as a ``(columns, rows)`` tuple. - :meth:`size` is an alias of :meth:`!grid_size`. + :meth:`size` is an alias of :meth:`!grid_size`, + except on the :class:`Listbox` widget, + which provides its own :meth:`!size` method. .. method:: grid_slaves(row=None, column=None) @@ -1681,7 +1695,10 @@ Base and mixin classes widget's display, the widget is remembered as the focus window for its top level, and the focus will be redirected to it the next time the window manager gives the focus to the top level. - :meth:`focus` is an alias of :meth:`!focus_set`. + :meth:`focus` is an alias of :meth:`!focus_set`, + except on the :class:`Canvas` and + :class:`ttk.Treeview <tkinter.ttk.Treeview>` widgets, + which provide their own :meth:`!focus` method. .. method:: focus_force() @@ -1783,6 +1800,10 @@ Base and mixin classes The *displayof* keyword argument names a widget that determines the display on which to operate, and defaults to this widget. + This is overridden by the :class:`Entry`, :class:`Listbox` and + :class:`Spinbox` widgets, + where :meth:`!selection_clear` clears the widget's own selection instead. + .. method:: selection_get(**kw) Return the contents of the current X selection. @@ -1860,7 +1881,7 @@ Base and mixin classes first and ``STRING`` is used as a fallback. The *displayof* keyword argument names a widget that determines the display, and defaults to the root window of the application. - This is equivalent to ``selection_get(selection= 'CLIPBOARD')``. + This is equivalent to ``selection_get(selection='CLIPBOARD')``. .. method:: option_add(pattern, value, priority=None) @@ -2546,6 +2567,8 @@ Base and mixin classes widget is managed again. :meth:`wm_forget` is an alias of :meth:`!forget`. + Not to be confused with :meth:`Pack.forget`. + .. versionadded:: 3.3 .. method:: wm_frame() @@ -2591,6 +2614,8 @@ Base and mixin classes string if the window is not gridded. :meth:`wm_grid` is an alias of :meth:`!grid`. + Not to be confused with the grid geometry manager :meth:`Grid.grid`. + .. method:: wm_group(pathName=None) :no-typesetting: @@ -2828,6 +2853,9 @@ Base and mixin classes :meth:`iconwindow`); the ``'icon'`` state cannot be set. :meth:`wm_state` is an alias of :meth:`!state`. + Not to be confused with :meth:`ttk.Widget.state + <tkinter.ttk.Widget.state>`. + .. method:: wm_title(string=None) :no-typesetting: @@ -2879,6 +2907,21 @@ Base and mixin classes *pack* geometry manager. See also :ref:`pack-the-packer`. + .. note:: + + :class:`Pack`, :class:`Place` and :class:`Grid` all define the short + method names :meth:`!forget`, :meth:`!info`, :meth:`!slaves`, + :meth:`!content` and :meth:`!propagate`. + On a widget the bare names resolve to the *pack* manager's versions, + since :class:`Pack` and :class:`Misc` precede :class:`Place` and + :class:`Grid` in the method resolution order, + whatever manager actually manages the widget; + and :meth:`!configure`/:meth:`!config` configure the widget's options, + not its geometry. + Use the explicit ``pack_*``, ``grid_*`` and ``place_*`` methods + (and ``pack``, ``grid``, ``place`` for geometry configuration) + to act on a specific geometry manager. + .. method:: configure(cnf={}, **kw) :no-typesetting: @@ -2941,7 +2984,13 @@ Base and mixin classes Unmap the widget and remove it from the packing order, forgetting its packing options. It can be packed again later with :meth:`pack_configure`. - :meth:`forget` is an alias of :meth:`!pack_forget`. + :meth:`forget` is an alias of :meth:`!pack_forget`, + except on :class:`PanedWindow`, + :class:`ttk.Notebook <tkinter.ttk.Notebook>` and + :class:`ttk.PanedWindow <tkinter.ttk.PanedWindow>`, + which provide their own :meth:`!forget` method. + + Not to be confused with :meth:`Wm.forget`. .. method:: info() :no-typesetting: @@ -3048,7 +3097,6 @@ Base and mixin classes Unmap the widget and remove it from the placement, forgetting its place options. - :meth:`forget` is an alias of :meth:`!place_forget`. .. method:: info() :no-typesetting: @@ -3056,7 +3104,6 @@ Base and mixin classes .. method:: place_info() Return a dictionary of the widget's current place options. - :meth:`info` is an alias of :meth:`!place_info`. .. method:: slaves() :no-typesetting: @@ -3065,7 +3112,6 @@ Base and mixin classes Same as :meth:`Misc.place_slaves`: return the list of widgets placed in this widget. - :meth:`slaves` is an alias of :meth:`!place_slaves`. .. method:: content() :no-typesetting: @@ -3073,7 +3119,6 @@ Base and mixin classes .. method:: place_content() Same as :meth:`Misc.place_content`. - :meth:`content` is an alias of :meth:`!place_content`. .. versionadded:: 3.15 @@ -3095,6 +3140,9 @@ Base and mixin classes grid(cnf={}, **kw) Position the widget in a cell of its container's grid. + + Not to be confused with :meth:`Wm.grid`. + The supported options are: *row*, *column* @@ -3139,7 +3187,6 @@ Base and mixin classes Unmap the widget and remove it from the grid, forgetting its grid options. - :meth:`forget` is an alias of :meth:`!grid_forget`. .. method:: grid_remove() @@ -3152,7 +3199,6 @@ Base and mixin classes .. method:: grid_info() Return a dictionary of the widget's current grid options. - :meth:`info` is an alias of :meth:`!grid_info`. .. method:: bbox(column=None, row=None, col2=None, row2=None) :no-typesetting: @@ -3160,7 +3206,11 @@ Base and mixin classes .. method:: grid_bbox(column=None, row=None, col2=None, row2=None) Same as :meth:`Misc.grid_bbox`. - :meth:`bbox` is an alias of :meth:`!grid_bbox`. + :meth:`bbox` is an alias of :meth:`!grid_bbox`, + except on :class:`Canvas`, :class:`Listbox`, :class:`Spinbox`, + :class:`Text`, :class:`ttk.Entry <tkinter.ttk.Entry>` and + :class:`ttk.Treeview <tkinter.ttk.Treeview>`, + which provide their own :meth:`!bbox` method. .. method:: columnconfigure(index, cnf={}, **kw) :no-typesetting: @@ -3196,7 +3246,9 @@ Base and mixin classes Same as :meth:`Misc.grid_size`: return a ``(columns, rows)`` tuple giving the size of the grid. - :meth:`size` is an alias of :meth:`!grid_size`. + :meth:`size` is an alias of :meth:`!grid_size`, + except on the :class:`Listbox` widget, + which provides its own :meth:`!size` method. .. method:: propagate() propagate(flag) @@ -3206,7 +3258,6 @@ Base and mixin classes grid_propagate(flag) Same as :meth:`Misc.grid_propagate`. - :meth:`propagate` is an alias of :meth:`!grid_propagate`. .. method:: slaves(row=None, column=None) :no-typesetting: @@ -3215,7 +3266,6 @@ Base and mixin classes Same as :meth:`Misc.grid_slaves`: return the widgets managed in the grid, optionally restricted to a *row* and/or *column*. - :meth:`slaves` is an alias of :meth:`!grid_slaves`. .. method:: content(row=None, column=None) :no-typesetting: @@ -3223,7 +3273,6 @@ Base and mixin classes .. method:: grid_content(row=None, column=None) Same as :meth:`Misc.grid_content`. - :meth:`content` is an alias of :meth:`!grid_content`. .. versionadded:: 3.15 @@ -3825,6 +3874,14 @@ Widget classes This has no effect on embedded window items. :meth:`lower` is an alias of :meth:`!tag_lower`. + .. note:: + + On a :class:`Canvas`, :meth:`tkraise`/:meth:`lift` and :meth:`lower` + restack canvas items, + shadowing the inherited :meth:`Misc.tkraise`/:meth:`Misc.lift` and + :meth:`Misc.lower` methods that restack the widget itself, + which are therefore not available. + .. method:: tag_bind(tagOrId, sequence=None, func=None, add=None) Bind the callback *func* to the event *sequence* for all items given by @@ -3860,6 +3917,9 @@ Widget classes Return ``None`` if no item matches or the matching items have nothing to display. + This shadows the inherited :meth:`!Misc.bbox`; + use :meth:`~Misc.grid_bbox` for the grid bounding box. + .. method:: canvasx(screenx, gridspacing=None) Given a window x-coordinate *screenx*, return the canvas x-coordinate @@ -3886,6 +3946,9 @@ Widget classes An item only displays the insertion cursor when both it is the focus item and its canvas has the input focus. + This shadows the inherited :meth:`!Misc.focus`; + use :meth:`~Misc.focus_set` to focus the widget itself. + .. method:: icursor(tagOrId, index, /) Set the insertion cursor of the items given by *tagOrId* to just before @@ -4083,6 +4146,12 @@ Widget classes If the selection is not in this widget the method has no effect. :meth:`select_clear` is an alias of :meth:`!selection_clear`. + .. note:: + + This shadows the inherited :meth:`Misc.selection_clear`, + which clears the X selection; + that method is not available on an :class:`Entry`. + .. method:: select_from(index) :no-typesetting: @@ -4222,6 +4291,9 @@ Widget classes Return the total number of items in the listbox. + This shadows the inherited :meth:`!Misc.size`; + use :meth:`~Misc.grid_size` for the grid size. + .. method:: index(index) Return the integer index value corresponding to *index*, or ``None`` if @@ -4238,6 +4310,9 @@ Widget classes visible, the result still gives the full area of the item, including the parts that are not visible. + This shadows the inherited :meth:`!Misc.bbox`; + use :meth:`~Misc.grid_bbox` for the grid bounding box. + .. method:: nearest(y) Given a y-coordinate within the listbox window, return the index of the @@ -4286,6 +4361,12 @@ Widget classes The selection state of items outside this range is not changed. :meth:`select_clear` is an alias of :meth:`!selection_clear`. + .. note:: + + This shadows the inherited :meth:`Misc.selection_clear`, + which clears the X selection; + that method is not available on a :class:`Listbox`. + .. method:: select_includes(index) :no-typesetting: @@ -4670,6 +4751,9 @@ Widget classes Remove the pane containing *child* from the panedwindow. All geometry management options for *child* are forgotten. :meth:`forget` is an alias of :meth:`!remove`. + This shadows the inherited geometry-manager :meth:`!forget`; + use :meth:`~Pack.pack_forget`, :meth:`~Grid.grid_forget` or + :meth:`~Place.place_forget` to remove the widget itself from its manager. .. method:: panes() @@ -4961,6 +5045,9 @@ Widget classes The bounding box may refer to a region outside the visible area of the window. + This shadows the inherited :meth:`!Misc.bbox`; + use :meth:`~Misc.grid_bbox` for the grid bounding box. + .. method:: identify(x, y) Return the name of the window element at the pixel coordinates *x*, *y*: @@ -5022,6 +5109,12 @@ Widget classes Clear the selection if it is currently in this widget. If the selection is not in this widget, the method has no effect. + .. note:: + + This shadows the inherited :meth:`Misc.selection_clear`, + which clears the X selection; + that method is not available on a :class:`Spinbox`. + .. method:: selection_element(element=None) Set or get the currently selected element. @@ -5179,6 +5272,9 @@ Widget classes pixels, of the visible part of the character at *index*, or ``None`` if that character is not visible on the screen. + This shadows the inherited :meth:`!Misc.bbox`; + use :meth:`~Misc.grid_bbox` for the grid bounding box. + .. method:: dlineinfo(index) Return a tuple ``(x, y, width, height, baseline)`` describing the display @@ -5433,6 +5529,12 @@ Widget classes Return a tuple of the names of all images embedded in the widget. + .. note:: + + This shadows the inherited :meth:`Misc.image_names`, + which returns the names of all images in the Tcl interpreter; + that method is not available on a :class:`Text`. + .. method:: window_create(index, cnf={}, **kw) Embed a window (any widget) at *index*. @@ -5641,6 +5743,7 @@ Variable classes .. method:: set(value) Set the variable to *value*. + :meth:`initialize` is an alias of :meth:`!set`. .. versionadded:: 3.3 The *initialize* spelling. @@ -5687,6 +5790,7 @@ Variable classes *mode* is one of the strings ``'r'``, ``'w'`` or ``'u'``, for read, write or unset. Return the internal name of the registered callback. + :meth:`trace` is an alias of :meth:`!trace_variable`. .. deprecated:: 3.6 Use :meth:`trace_add` instead. This method wraps a Tcl feature that @@ -5758,6 +5862,7 @@ Variable classes .. method:: set(value) Set the variable to *value*, converting it to a boolean. + :meth:`initialize` is an alias of :meth:`!set`. .. versionadded:: 3.3 The *initialize* spelling. diff --git a/Doc/library/tkinter.ttk.rst b/Doc/library/tkinter.ttk.rst index 9d90770a5840ee..0f5a8da1445784 100644 --- a/Doc/library/tkinter.ttk.rst +++ b/Doc/library/tkinter.ttk.rst @@ -289,6 +289,8 @@ the methods :meth:`tkinter.Widget.cget <tkinter.Misc.cget>` and which flags were changed. If *statespec* is not specified, returns the currently enabled state flags. + Not to be confused with :meth:`Wm.state <tkinter.Wm.state>`. + *statespec* will usually be a list or a tuple. @@ -590,6 +592,11 @@ ttk.Notebook Removes the tab specified by *tab_id*, unmaps and unmanages the associated window. + This shadows the inherited geometry-manager :meth:`!forget`; + use :meth:`~tkinter.Pack.pack_forget`, :meth:`~tkinter.Grid.grid_forget` + or :meth:`~tkinter.Place.place_forget` to remove the widget itself from + its manager. + .. method:: hide(tab_id) @@ -988,6 +995,9 @@ ttk.Treeview *item* is not visible (that is, if it is a descendant of a closed item or is scrolled offscreen), returns an empty string. + This shadows the inherited :meth:`!Misc.bbox`; + use :meth:`~tkinter.Misc.grid_bbox` for the grid bounding box. + .. method:: get_children(item=None) @@ -1061,6 +1071,9 @@ ttk.Treeview If *item* is specified, sets the focus item to *item*. Otherwise, returns the current focus item, or '' if there is none. + This shadows the inherited :meth:`!Misc.focus`; + use :meth:`~tkinter.Misc.focus_set` to focus the widget itself. + .. method:: heading(column, option=None, **kw) @@ -1681,6 +1694,9 @@ and inherits the common methods of :class:`Widget`. Return a tuple ``(x, y, width, height)`` giving the bounding box of the character at the given *index*. + This shadows the inherited :meth:`!Misc.bbox`; + use :meth:`~tkinter.Misc.grid_bbox` for the grid bounding box. + .. method:: identify(x, y) Return the name of the element under the point given by *x* and *y*, or @@ -1774,6 +1790,11 @@ and inherits the common methods of :class:`Widget`. Remove *child*, which may be either an integer index or the name of a managed subwindow, from the panes. + This shadows the inherited geometry-manager :meth:`!forget`; + use :meth:`~tkinter.Pack.pack_forget`, :meth:`~tkinter.Grid.grid_forget` + or :meth:`~tkinter.Place.place_forget` to remove the widget itself from + its manager. + .. method:: pane(pane, option=None, **kw) Query or modify the options of the specified *pane*, where *pane* is diff --git a/Lib/tkinter/__init__.py b/Lib/tkinter/__init__.py index ba8365f56c37a7..b0152778cb5485 100644 --- a/Lib/tkinter/__init__.py +++ b/Lib/tkinter/__init__.py @@ -3011,7 +3011,7 @@ def addtag_withtag(self, newtag, tagOrId): """Add tag NEWTAG to all items with TAGORID.""" self.addtag(newtag, 'withtag', tagOrId) - def bbox(self, *args): + def bbox(self, *args): # overrides Misc.bbox """Return a tuple of X1,Y1,X2,Y2 coordinates for a rectangle which encloses all items with tags specified as arguments.""" return self._getints( @@ -3150,7 +3150,7 @@ def find_withtag(self, tagOrId): """Return all items with TAGORID.""" return self.find('withtag', tagOrId) - def focus(self, *args): + def focus(self, *args): # overrides Misc.focus """Set focus to the first item specified in ARGS.""" return self.tk.call((self._w, 'focus') + args) @@ -3196,7 +3196,7 @@ def tag_lower(self, *args): (optional below another item).""" self.tk.call((self._w, 'lower') + args) - lower = tag_lower + lower = tag_lower # overrides Misc.lower def move(self, *args): """Move an item TAGORID given in ARGS.""" @@ -3224,7 +3224,7 @@ def tag_raise(self, *args): (optional above another item).""" self.tk.call((self._w, 'raise') + args) - lift = tkraise = tag_raise + lift = tkraise = tag_raise # overrides Misc.tkraise def scale(self, *args): """Scale item TAGORID with XORIGIN, YORIGIN, XSCALE, YSCALE.""" @@ -3369,7 +3369,7 @@ def selection_adjust(self, index): select_adjust = selection_adjust - def selection_clear(self): + def selection_clear(self): # overrides Misc.selection_clear """Clear the selection if it is in this widget.""" self.tk.call(self._w, 'selection', 'clear') @@ -3463,7 +3463,7 @@ def activate(self, index): """Activate item identified by INDEX.""" self.tk.call(self._w, 'activate', index) - def bbox(self, index): + def bbox(self, index): # overrides Misc.bbox """Return a tuple of X1,Y1,X2,Y2 coordinates for a rectangle which encloses the item identified by the given index.""" return self._getints(self.tk.call(self._w, 'bbox', index)) or None @@ -3519,7 +3519,7 @@ def selection_anchor(self, index): select_anchor = selection_anchor - def selection_clear(self, first, last=None): + def selection_clear(self, first, last=None): # overrides Misc.selection_clear """Clear the selection from FIRST to LAST (included).""" self.tk.call(self._w, 'selection', 'clear', first, last) @@ -3540,7 +3540,7 @@ def selection_set(self, first, last=None): select_set = selection_set - def size(self): + def size(self): # overrides Misc.size """Return the number of elements in the listbox.""" return self.tk.getint(self.tk.call(self._w, 'size')) @@ -3856,7 +3856,7 @@ def __init__(self, master=None, cnf={}, **kw): """ Widget.__init__(self, master, 'text', cnf, kw) - def bbox(self, index): + def bbox(self, index): # overrides Misc.bbox """Return a tuple of (x,y,width,height) which gives the bounding box of the visible part of the character at the given index.""" return self._getints( @@ -4041,7 +4041,7 @@ def image_create(self, index, cnf={}, **kw): self._w, "image", "create", index, *self._options(cnf, kw)) - def image_names(self): + def image_names(self): # overrides Misc.image_names """Return all names of embedded images in this widget.""" return self.tk.call(self._w, "image", "names") @@ -4716,7 +4716,7 @@ def __init__(self, master=None, cnf={}, **kw): """ Widget.__init__(self, master, 'spinbox', cnf, kw) - def bbox(self, index): + def bbox(self, index): # overrides Misc.bbox """Return a tuple of X1,Y1,X2,Y2 coordinates for a rectangle which encloses the character given by index. @@ -4825,7 +4825,7 @@ def selection_adjust(self, index): """ return self.selection("adjust", index) - def selection_clear(self): + def selection_clear(self): # overrides Misc.selection_clear """Clear the selection If the selection isn't in this widget then the @@ -4922,7 +4922,7 @@ def remove(self, child): """ self.tk.call(self._w, 'forget', child) - forget = remove + forget = remove # overrides Pack.forget def identify(self, x, y): """Identify the panedwindow component at point x, y diff --git a/Lib/tkinter/ttk.py b/Lib/tkinter/ttk.py index 5c5ef11ae05ba6..cb66420d1cd129 100644 --- a/Lib/tkinter/ttk.py +++ b/Lib/tkinter/ttk.py @@ -646,7 +646,7 @@ def __init__(self, master=None, widget=None, **kw): Widget.__init__(self, master, widget or "ttk::entry", kw) - def bbox(self, index): + def bbox(self, index): # overrides Misc.bbox """Return a tuple of (x, y, width, height) which describes the bounding box of the character given by index.""" return self._getints(self.tk.call(self._w, "bbox", index)) @@ -824,7 +824,7 @@ def add(self, child, **kw): self.tk.call(self._w, "add", child, *(_format_optdict(kw))) - def forget(self, tab_id): + def forget(self, tab_id): # overrides Pack.forget """Removes the tab specified by tab_id, unmaps and unmanages the associated window.""" self.tk.call(self._w, "forget", tab_id) @@ -1187,7 +1187,7 @@ def __init__(self, master=None, **kw): Widget.__init__(self, master, "ttk::treeview", kw) - def bbox(self, item, column=None): + def bbox(self, item, column=None): # overrides Misc.bbox """Returns the bounding box (relative to the treeview widget's window) of the specified item in the form x y width height. @@ -1246,7 +1246,7 @@ def exists(self, item): return self.tk.getboolean(self.tk.call(self._w, "exists", item)) - def focus(self, item=None): + def focus(self, item=None): # overrides Misc.focus """If item is specified, sets the focus item to item. Otherwise, returns the current focus item, or '' if there is none.""" return self.tk.call(self._w, "focus", item) From e187964a907cc8fbebe0df51ee64ba91d4fa6dc7 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 22 Jun 2026 22:09:28 +0200 Subject: [PATCH 397/818] [3.15] gh-62480: De-personalize docs on using the C API (GH-151784) (#151936) (cherry picked from commit 1c5a11018ad605072b2efac67f3ca87b41b622c6) Co-authored-by: Rafael Weingartner-Ortner <38643099+RafaelWO@users.noreply.github.com> Co-authored-by: Stan Ulbrych <stan@python.org> --- Doc/extending/extending.rst | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/Doc/extending/extending.rst b/Doc/extending/extending.rst index d33cbd2813d637..110dfea8cb98ab 100644 --- a/Doc/extending/extending.rst +++ b/Doc/extending/extending.rst @@ -231,10 +231,8 @@ calling the Python callback functions from a C callback. Other uses are also imaginable. Fortunately, the Python interpreter is easily called recursively, and there is a -standard interface to call a Python function. (I won't dwell on how to call the -Python parser with a particular string as input --- if you're interested, have a -look at the implementation of the :option:`-c` command line option in -:file:`Modules/main.c` from the Python source code.) +standard interface to call a Python function. (If you're interested in how to call the +Python parser with a particular string as input, see :ref:`veryhigh`.) Calling a Python function is easy. First, the Python program must somehow pass you the Python function object. You should provide a function (or some other @@ -641,7 +639,7 @@ and the object is freed. An alternative strategy is called :dfn:`automatic garbage collection`. (Sometimes, reference counting is also referred to as a garbage collection -strategy, hence my use of "automatic" to distinguish the two.) The big +strategy, hence the use of "automatic" to distinguish the two.) The big advantage of automatic garbage collection is that the user doesn't need to call :c:func:`free` explicitly. (Another claimed advantage is an improvement in speed or memory usage --- this is no hard fact however.) The disadvantage is that for From 2957ff721bf13ab3c14f7cdb63607a81be6a8232 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 23 Jun 2026 02:13:20 +0200 Subject: [PATCH 398/818] [3.15] gh-151722: Defer GC tracking of frozendict to end of construction (gh-151740) (gh-151954) gh-151722: Defer GC tracking of frozendict to end of construction (gh-151740) (cherry picked from commit 6920036f287480f7d39d6a4005803aeac27aff3f) Co-authored-by: Donghee Na <donghee.na@python.org> --- ...-06-20-00-30-47.gh-issue-151722.RPMPIY.rst | 2 + Objects/dictobject.c | 53 +++++++++++++------ 2 files changed, 40 insertions(+), 15 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-20-00-30-47.gh-issue-151722.RPMPIY.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-20-00-30-47.gh-issue-151722.RPMPIY.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-20-00-30-47.gh-issue-151722.RPMPIY.rst new file mode 100644 index 00000000000000..57b5dee7458ede --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-20-00-30-47.gh-issue-151722.RPMPIY.rst @@ -0,0 +1,2 @@ +Defer GC tracking of :class:`frozendict` to end of construction. Patch by +Donghee Na. diff --git a/Objects/dictobject.c b/Objects/dictobject.c index 25dc81f726f59c..0782b4022f3a81 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -138,6 +138,7 @@ As a consequence of this, split keys have a maximum size of 16. // Forward declarations static PyObject* frozendict_new(PyTypeObject *type, PyObject *args, PyObject *kwds); +static PyObject* frozendict_new_untracked(PyTypeObject *type); static PyObject* dict_new(PyTypeObject *type, PyObject *args, PyObject *kwds); static int dict_merge(PyObject *a, PyObject *b, int override, PyObject **dupkey); static int dict_contains(PyObject *op, PyObject *key); @@ -4119,12 +4120,9 @@ dict_dict_merge(PyDictObject *mp, PyDictObject *other, int override, PyObject ** set_keys(mp, keys); STORE_USED(mp, other->ma_used); ASSERT_CONSISTENT(mp); - - if (_PyObject_GC_IS_TRACKED(other) && !_PyObject_GC_IS_TRACKED(mp)) { - /* Maintain tracking. */ - _PyObject_GC_TRACK(mp); + if (PyDict_Check(mp)) { + assert(_PyObject_GC_IS_TRACKED(mp)); } - return 0; } } @@ -5215,14 +5213,13 @@ static PyNumberMethods dict_as_number = { }; static PyObject * -dict_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +dict_new_untracked(PyTypeObject *type) { assert(type != NULL); - assert(type->tp_alloc != NULL); // dict subclasses must implement the GC protocol assert(_PyType_IS_GC(type)); - PyObject *self = type->tp_alloc(type, 0); + PyObject *self = _PyType_AllocNoTrack(type, 0); if (self == NULL) { return NULL; } @@ -5235,9 +5232,19 @@ dict_new(PyTypeObject *type, PyObject *args, PyObject *kwds) d->ma_keys = Py_EMPTY_KEYS; d->ma_values = NULL; ASSERT_CONSISTENT(d); - if (!_PyObject_GC_IS_TRACKED(d)) { - _PyObject_GC_TRACK(d); + return self; +} + +static PyObject * +dict_new(PyTypeObject *type, PyObject *Py_UNUSED(args), PyObject *Py_UNUSED(kwds)) +{ + /* tp_new ignores args/kwds; args/kwds are consumed by dict_init (tp_init). */ + PyObject *self = dict_new_untracked(type); + if (self == NULL) { + return NULL; } + assert(!_PyObject_GC_IS_TRACKED(self)); + _PyObject_GC_TRACK(self); return self; } @@ -5296,7 +5303,9 @@ frozendict_vectorcall(PyObject *type, PyObject * const*args, return Py_NewRef(args[0]); } - PyObject *self = frozendict_new(_PyType_CAST(type), NULL, NULL); + /* gh-151722: Keep the frozendict untracked until it is fully built, + so a half-built object is never reachable from another thread (using the gc module). */ + PyObject *self = frozendict_new_untracked(_PyType_CAST(type)); if (self == NULL) { return NULL; } @@ -5316,6 +5325,8 @@ frozendict_vectorcall(PyObject *type, PyObject * const*args, } } } + assert(!_PyObject_GC_IS_TRACKED(self)); + _PyObject_GC_TRACK(self); return self; } @@ -8307,17 +8318,27 @@ frozendict_hash(PyObject *op) } +/* Allocate an empty, GC-untracked frozendict; the constructor tracks it once + fully built. */ static PyObject * -frozendict_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +frozendict_new_untracked(PyTypeObject *type) { - PyObject *d = dict_new(type, args, kwds); + PyObject *d = dict_new_untracked(type); if (d == NULL) { return NULL; } assert(can_modify_dict(_PyAnyDict_CAST(d))); + _PyFrozenDictObject_CAST(d)->ma_hash = -1; + return d; +} - PyFrozenDictObject *self = _PyFrozenDictObject_CAST(d); - self->ma_hash = -1; +static PyObject * +frozendict_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PyObject *d = frozendict_new_untracked(type); + if (d == NULL) { + return NULL; + } if (args != NULL) { if (dict_update_common(d, args, kwds, "frozendict") < 0) { @@ -8329,6 +8350,8 @@ frozendict_new(PyTypeObject *type, PyObject *args, PyObject *kwds) assert(kwds == NULL); } + assert(!_PyObject_GC_IS_TRACKED(d)); + _PyObject_GC_TRACK(d); return d; } From 752e23ec9061640b57efb4fbad6859e4448e42de Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 23 Jun 2026 06:26:53 +0200 Subject: [PATCH 399/818] [3.15] gh-75666: Fix a reference leak in tkinter event bindings (GH-151808) (GH-151958) The Tcl commands created for event callbacks are now deleted when a binding is replaced or unbound, instead of being leaked. (cherry picked from commit 3f09a175ad022ca7ccdbb8583a0c137d493533ef) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> --- Lib/idlelib/idle_test/test_iomenu.py | 3 +-- Lib/test/test_tkinter/test_misc.py | 18 +++++++------- Lib/tkinter/__init__.py | 24 +++++++++++++++---- ...6-06-20-15-00-00.gh-issue-75666.Kt9xQ2.rst | 2 ++ 4 files changed, 32 insertions(+), 15 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-06-20-15-00-00.gh-issue-75666.Kt9xQ2.rst diff --git a/Lib/idlelib/idle_test/test_iomenu.py b/Lib/idlelib/idle_test/test_iomenu.py index e0642cf0cabef0..80f72bdfe5ff0e 100644 --- a/Lib/idlelib/idle_test/test_iomenu.py +++ b/Lib/idlelib/idle_test/test_iomenu.py @@ -23,11 +23,10 @@ def setUpClass(cls): cls.root = Tk() cls.root.withdraw() cls.editwin = EditorWindow(root=cls.root) - cls.io = iomenu.IOBinding(cls.editwin) + cls.io = cls.editwin.io @classmethod def tearDownClass(cls): - cls.io.close() cls.editwin._close() del cls.editwin cls.root.update_idletasks() diff --git a/Lib/test/test_tkinter/test_misc.py b/Lib/test/test_tkinter/test_misc.py index 96cc7fb85929d0..fba528764415ab 100644 --- a/Lib/test/test_tkinter/test_misc.py +++ b/Lib/test/test_tkinter/test_misc.py @@ -1469,6 +1469,8 @@ def test3(e): pass self.assertNotIn(funcid, script) self.assertNotIn(funcid2, script) self.assertIn(funcid3, script) + self.assertCommandNotExist(funcid) + self.assertCommandNotExist(funcid2) self.assertCommandExist(funcid3) def test_bind_class(self): @@ -1513,8 +1515,8 @@ def test2(e): pass unbind_class('Test', event) self.assertEqual(bind_class('Test', event), '') self.assertEqual(bind_class('Test'), ()) - self.assertCommandExist(funcid) - self.assertCommandExist(funcid2) + self.assertCommandNotExist(funcid) + self.assertCommandNotExist(funcid2) unbind_class('Test', event) # idempotent @@ -1542,8 +1544,8 @@ def test3(e): pass self.assertNotIn(funcid, script) self.assertNotIn(funcid2, script) self.assertIn(funcid3, script) - self.assertCommandExist(funcid) - self.assertCommandExist(funcid2) + self.assertCommandNotExist(funcid) + self.assertCommandNotExist(funcid2) self.assertCommandExist(funcid3) def test_bind_all(self): @@ -1585,8 +1587,8 @@ def test2(e): pass unbind_all(event) self.assertEqual(bind_all(event), '') self.assertNotIn(event, bind_all()) - self.assertCommandExist(funcid) - self.assertCommandExist(funcid2) + self.assertCommandNotExist(funcid) + self.assertCommandNotExist(funcid2) unbind_all(event) # idempotent @@ -1614,8 +1616,8 @@ def test3(e): pass self.assertNotIn(funcid, script) self.assertNotIn(funcid2, script) self.assertIn(funcid3, script) - self.assertCommandExist(funcid) - self.assertCommandExist(funcid2) + self.assertCommandNotExist(funcid) + self.assertCommandNotExist(funcid2) self.assertCommandExist(funcid3) def _test_tag_bind(self, w): diff --git a/Lib/tkinter/__init__.py b/Lib/tkinter/__init__.py index b0152778cb5485..6875deaf5a5cca 100644 --- a/Lib/tkinter/__init__.py +++ b/Lib/tkinter/__init__.py @@ -1503,13 +1503,26 @@ def bindtags(self, tagList=None): else: self.tk.call('bindtags', self._w, tagList) - def _bind(self, what, sequence, func, add, needcleanup=1): + def _delete_bind_commands(self, *what): + lines = self.tk.call(what).split('\n') + p = re.compile(r'if \{"\[([^ ]+) .*\]" == "break"\} break') + for line in lines: + m = p.fullmatch(line) + if m: + funcid = m[1] + try: + self.deletecommand(funcid) + except TclError: + pass + + def _bind(self, what, sequence, func, add): """Internal function.""" if isinstance(func, str): self.tk.call(what + (sequence, func)) elif func: - funcid = self._register(func, self._substitute, - needcleanup) + if not add: + self._delete_bind_commands(*what, sequence) + funcid = self._register(func, self._substitute, needcleanup=True) cmd = ('%sif {"[%s %s]" == "break"} break\n' % (add and '+' or '', @@ -1575,6 +1588,7 @@ def unbind(self, sequence, funcid=None): def _unbind(self, what, funcid=None): if funcid is None: + self._delete_bind_commands(*what) self.tk.call(*what, '') else: lines = self.tk.call(what).split('\n') @@ -1591,7 +1605,7 @@ def bind_all(self, sequence=None, func=None, add=None): An additional boolean parameter ADD specifies whether FUNC will be called additionally to the other bound function or whether it will replace the previous function. See bind for the return value.""" - return self._root()._bind(('bind', 'all'), sequence, func, add, True) + return self._root()._bind(('bind', 'all'), sequence, func, add) def unbind_all(self, sequence): """Unbind for all widgets for event SEQUENCE all functions.""" @@ -1605,7 +1619,7 @@ def bind_class(self, className, sequence=None, func=None, add=None): whether it will replace the previous function. See bind for the return value.""" - return self._root()._bind(('bind', className), sequence, func, add, True) + return self._root()._bind(('bind', className), sequence, func, add) def unbind_class(self, className, sequence): """Unbind for all widgets with bindtag CLASSNAME for event SEQUENCE diff --git a/Misc/NEWS.d/next/Library/2026-06-20-15-00-00.gh-issue-75666.Kt9xQ2.rst b/Misc/NEWS.d/next/Library/2026-06-20-15-00-00.gh-issue-75666.Kt9xQ2.rst new file mode 100644 index 00000000000000..d2b2b066837bb1 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-20-15-00-00.gh-issue-75666.Kt9xQ2.rst @@ -0,0 +1,2 @@ +Fix a reference leak in :mod:`tkinter`: the Tcl commands created for event +callbacks are now deleted when a binding is replaced or unbound. From fe5dc86f1f8a3e2baad924cf0c01e1a4c81858da Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 23 Jun 2026 08:28:59 +0200 Subject: [PATCH 400/818] [3.15] gh-151905: fix memory error handling in PyFrame_GetBack (GH-151906) (#151919) Co-authored-by: Prakash Sellathurai <prakashsellathurai@gmail.com> --- .../2026-06-22-06-26-34.gh-issue-151905.FOLMYg.rst | 1 + Objects/frameobject.c | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-22-06-26-34.gh-issue-151905.FOLMYg.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-22-06-26-34.gh-issue-151905.FOLMYg.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-22-06-26-34.gh-issue-151905.FOLMYg.rst new file mode 100644 index 00000000000000..c71122df6b8580 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-22-06-26-34.gh-issue-151905.FOLMYg.rst @@ -0,0 +1 @@ +Fix OOM error handling in :c:func:`PyFrame_GetBack` to propagate exceptions instead of masking them as None. diff --git a/Objects/frameobject.c b/Objects/frameobject.c index f60cdb2dd1bf20..3e70a71953709e 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -1117,7 +1117,7 @@ frame_back_get_impl(PyFrameObject *self) /*[clinic end generated code: output=3a84c22a55a63c79 input=9e528570d0e1f44a]*/ { PyObject *res = (PyObject *)PyFrame_GetBack(self); - if (res == NULL) { + if (res == NULL && !PyErr_Occurred()) { Py_RETURN_NONE; } return res; @@ -2405,6 +2405,9 @@ PyFrame_GetBack(PyFrameObject *frame) prev = _PyFrame_GetFirstComplete(prev); if (prev) { back = _PyFrame_GetFrameObject(prev); + if (back == NULL) { + return NULL; + } } } return (PyFrameObject*)Py_XNewRef(back); From cf16a33fad15d1058ed71b92573d0bed57f85457 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> Date: Tue, 23 Jun 2026 12:35:40 +0300 Subject: [PATCH 401/818] Python 3.15.0b3 --- Doc/c-api/init_config.rst | 2 +- Include/patchlevel.h | 4 +- Lib/pydoc_data/module_docs.py | 3 +- Lib/pydoc_data/topics.py | 67 +- Misc/NEWS.d/3.15.0b3.rst | 785 ++++++++++++++++++ ...-06-09-11-54-13.gh-issue-151163.vFAtjv.rst | 1 - ...-06-04-14-26-17.gh-issue-150907.CA91_B.rst | 2 - ...-06-10-15-22-44.gh-issue-149044.O7KEcs.rst | 3 - ...-06-10-16-43-37.gh-issue-123619.dV82r6.rst | 3 - ...-06-18-18-24-11.gh-issue-141510.-EOHJ1.rst | 1 - ...-issue-149321.remove-lazy-imports-none.rst | 1 - ...-05-13-21-26-26.gh-issue-149805.IG6cza.rst | 2 - ...-05-22-21-52-38.gh-issue-150207.l2BUtI.rst | 1 - ...-05-24-22-46-49.gh-issue-148613.PLpmyd.rst | 2 - ...-05-30-20-19-35.gh-issue-150633.XkNul0.rst | 3 - ...-06-01-19-00-00.gh-issue-150700.W8CzVR.rst | 3 - ...-06-01-19-21-01.gh-issue-150723.Hb3JDG.rst | 4 - ...-06-01-19-24-12.gh-issue-150723.WlcL_-.rst | 4 - ...-06-05-22-52-41.gh-issue-150988.fDKfMJ.rst | 2 - ...-06-08-05-31-22.gh-issue-151065._o_31F.rst | 1 - ...-06-08-13-14-42.gh-issue-150902.-CWZ66.rst | 1 - ...-06-09-10-28-30.gh-issue-151126.DKa6Sl.rst | 5 - ...-06-09-12-24-35.gh-issue-151112.4RKCkD.rst | 1 - ...-06-10-15-19-58.gh-issue-151238.C9Wu4x.rst | 2 - ...-06-10-15-42-46.gh-issue-151253.7MMQ8P.rst | 3 - ...-06-11-16-03-23.gh-issue-151297.NGPkUM.rst | 1 - ...-06-12-15-30-25.gh-issue-151218.5M_nv8.rst | 3 - ...-06-14-05-05-15.gh-issue-151461.5q0s88.rst | 3 - ...-06-16-00-45-42.gh-issue-151510.HJ-kGn.rst | 2 - ...-06-16-17-23-37.gh-issue-151546.LhiaZz.rst | 3 - ...-06-20-00-30-47.gh-issue-151722.RPMPIY.rst | 2 - ...-06-22-06-26-34.gh-issue-151905.FOLMYg.rst | 1 - ...-09-16-23-42-27.gh-issue-109503.mZ-kdU.rst | 3 - ...-05-23-17-27-41.gh-issue-150319.ol9tWK.rst | 2 - ...6-06-17-12-00-00.gh-issue-86726.__bOgH.rst | 4 - .../2019-12-12-03-18-02.bpo-6699.1CqJFG.rst | 1 - ...-01-23-21-23-50.gh-issue-101267._f-cFH.rst | 7 - ...3-02-26-14-07-18.gh-issue-91099._QPbEL.rst | 2 - ...-06-18-04-08-37.gh-issue-120665.x7T1hV.rst | 1 - ...-01-18-06-42-47.gh-issue-143988.MtLtCP.rst | 2 - ...2026-04-24-19-54-00.gh-issue-148954.v1.rst | 1 - ...-05-13-12-16-54.gh-issue-149473.nOQZqn.rst | 2 - ...-05-15-19-52-41.gh-issue-149891.BJUIGB.rst | 1 - ...6-05-17-12-37-59.gh-issue-53144.c5tr1p.rst | 2 - ...-05-18-22-45-54.gh-issue-149816.T68vc_.rst | 1 - ...-05-27-23-47-31.gh-issue-148932.Y1xmvA.rst | 1 - ...-06-02-14-21-46.gh-issue-150750.SVS2o0.rst | 1 - ...-06-03-13-51-29.gh-issue-150662.ELT8Vg.rst | 4 - ...-06-04-18-22-56.gh-issue-143008.z5tw-J.rst | 1 - ...06-04-21-49-18.gh-issue-150913.EmptyBl.rst | 3 - ...6-06-04-23-10-31.gh-issue-62825.BtG_yQ.rst | 2 - ...-06-06-15-20-54.gh-issue-151021.J4qk2A.rst | 3 - ...-06-07-17-29-33.gh-issue-151039.AZ0qBn.rst | 1 - ...-06-09-12-00-00.gh-issue-150771.K7mNx2.rst | 4 - ...-06-10-00-00-02.gh-issue-109940.Cx1099.rst | 2 - ...-06-11-00-00-00.gh-issue-151295.NQYUzW.rst | 4 - ...-06-11-11-52-23.gh-issue-149671.6Rpr5r.rst | 3 - ...-06-11-16-25-38.gh-issue-151126.bh_Usy.rst | 2 - ...-06-11-21-43-24.gh-issue-151337.JSVV18.rst | 1 - ...-06-12-00-04-34.gh-issue-151126.aHaBYq.rst | 2 - ...6-12-07-20-08.gh-issue-151390.CmYN9EeJ.rst | 1 - ...-06-12-22-46-31.gh-issue-151403.DalZWh.rst | 3 - ...-06-13-04-11-00.gh-issue-151426.f2V67e.rst | 4 - ...-06-13-11-57-48.gh-issue-151436.UEDowO.rst | 4 - ...-06-19-07-26-20.gh-issue-151695.IBDlkN.rst | 4 - ...-06-20-14-47-55.gh-issue-151665.82fmzx.rst | 2 - ...-06-20-15-00-00.gh-issue-151770.dtiso0.rst | 3 - ...6-06-20-15-00-00.gh-issue-75666.Kt9xQ2.rst | 2 - ...-05-18-17-46-00.gh-issue-149835.EebFlk.rst | 3 - ...-05-30-09-36-20.gh-issue-150599.nlHqU-.rst | 3 - ...-06-09-10-23-57.gh-issue-151159.91GpWQ.rst | 1 - ...-06-09-23-38-08.gh-issue-151159.ds-9f8.rst | 1 - ...-06-16-14-58-02.gh-issue-151544._bexVy.rst | 4 - ...-04-24-01-38-56.gh-issue-148853._uM4_Q.rst | 2 - ...-06-06-16-22-00.gh-issue-150966.7N9x5Q.rst | 2 - ...-06-09-11-52-52.gh-issue-151130.1vslPH.rst | 1 - ...-06-04-18-53-18.gh-issue-150836.Wci7bZ.rst | 1 - ...-06-09-11-40-48.gh-issue-151159.JKVfme.rst | 1 - ...-06-09-11-55-41.gh-issue-151163.oizZYV.rst | 1 - ...-06-09-11-52-35.gh-issue-151163.RlPXHq.rst | 1 - README.rst | 2 +- 81 files changed, 834 insertions(+), 196 deletions(-) create mode 100644 Misc/NEWS.d/3.15.0b3.rst delete mode 100644 Misc/NEWS.d/next/Build/2026-06-09-11-54-13.gh-issue-151163.vFAtjv.rst delete mode 100644 Misc/NEWS.d/next/C_API/2026-06-04-14-26-17.gh-issue-150907.CA91_B.rst delete mode 100644 Misc/NEWS.d/next/C_API/2026-06-10-15-22-44.gh-issue-149044.O7KEcs.rst delete mode 100644 Misc/NEWS.d/next/C_API/2026-06-10-16-43-37.gh-issue-123619.dV82r6.rst delete mode 100644 Misc/NEWS.d/next/C_API/2026-06-18-18-24-11.gh-issue-141510.-EOHJ1.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-05-05-12-00-00.gh-issue-149321.remove-lazy-imports-none.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-05-13-21-26-26.gh-issue-149805.IG6cza.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-05-22-21-52-38.gh-issue-150207.l2BUtI.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-05-24-22-46-49.gh-issue-148613.PLpmyd.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-05-30-20-19-35.gh-issue-150633.XkNul0.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-01-19-00-00.gh-issue-150700.W8CzVR.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-01-19-21-01.gh-issue-150723.Hb3JDG.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-01-19-24-12.gh-issue-150723.WlcL_-.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-05-22-52-41.gh-issue-150988.fDKfMJ.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-08-05-31-22.gh-issue-151065._o_31F.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-08-13-14-42.gh-issue-150902.-CWZ66.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-09-10-28-30.gh-issue-151126.DKa6Sl.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-09-12-24-35.gh-issue-151112.4RKCkD.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-10-15-19-58.gh-issue-151238.C9Wu4x.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-10-15-42-46.gh-issue-151253.7MMQ8P.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-11-16-03-23.gh-issue-151297.NGPkUM.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-12-15-30-25.gh-issue-151218.5M_nv8.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-14-05-05-15.gh-issue-151461.5q0s88.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-16-00-45-42.gh-issue-151510.HJ-kGn.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-16-17-23-37.gh-issue-151546.LhiaZz.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-20-00-30-47.gh-issue-151722.RPMPIY.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-22-06-26-34.gh-issue-151905.FOLMYg.rst delete mode 100644 Misc/NEWS.d/next/Documentation/2023-09-16-23-42-27.gh-issue-109503.mZ-kdU.rst delete mode 100644 Misc/NEWS.d/next/Documentation/2026-05-23-17-27-41.gh-issue-150319.ol9tWK.rst delete mode 100644 Misc/NEWS.d/next/Documentation/2026-06-17-12-00-00.gh-issue-86726.__bOgH.rst delete mode 100644 Misc/NEWS.d/next/IDLE/2019-12-12-03-18-02.bpo-6699.1CqJFG.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-01-23-21-23-50.gh-issue-101267._f-cFH.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-02-26-14-07-18.gh-issue-91099._QPbEL.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-06-18-04-08-37.gh-issue-120665.x7T1hV.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-01-18-06-42-47.gh-issue-143988.MtLtCP.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-04-24-19-54-00.gh-issue-148954.v1.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-05-13-12-16-54.gh-issue-149473.nOQZqn.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-05-15-19-52-41.gh-issue-149891.BJUIGB.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-05-17-12-37-59.gh-issue-53144.c5tr1p.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-05-18-22-45-54.gh-issue-149816.T68vc_.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-05-27-23-47-31.gh-issue-148932.Y1xmvA.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-06-02-14-21-46.gh-issue-150750.SVS2o0.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-06-03-13-51-29.gh-issue-150662.ELT8Vg.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-06-04-18-22-56.gh-issue-143008.z5tw-J.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-06-04-21-49-18.gh-issue-150913.EmptyBl.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-06-04-23-10-31.gh-issue-62825.BtG_yQ.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-06-06-15-20-54.gh-issue-151021.J4qk2A.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-06-07-17-29-33.gh-issue-151039.AZ0qBn.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-06-09-12-00-00.gh-issue-150771.K7mNx2.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-06-10-00-00-02.gh-issue-109940.Cx1099.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-06-11-00-00-00.gh-issue-151295.NQYUzW.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-06-11-11-52-23.gh-issue-149671.6Rpr5r.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-06-11-16-25-38.gh-issue-151126.bh_Usy.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-06-11-21-43-24.gh-issue-151337.JSVV18.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-06-12-00-04-34.gh-issue-151126.aHaBYq.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-06-12-07-20-08.gh-issue-151390.CmYN9EeJ.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-06-12-22-46-31.gh-issue-151403.DalZWh.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-06-13-04-11-00.gh-issue-151426.f2V67e.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-06-13-11-57-48.gh-issue-151436.UEDowO.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-06-19-07-26-20.gh-issue-151695.IBDlkN.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-06-20-14-47-55.gh-issue-151665.82fmzx.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-06-20-15-00-00.gh-issue-151770.dtiso0.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-06-20-15-00-00.gh-issue-75666.Kt9xQ2.rst delete mode 100644 Misc/NEWS.d/next/Security/2026-05-18-17-46-00.gh-issue-149835.EebFlk.rst delete mode 100644 Misc/NEWS.d/next/Security/2026-05-30-09-36-20.gh-issue-150599.nlHqU-.rst delete mode 100644 Misc/NEWS.d/next/Security/2026-06-09-10-23-57.gh-issue-151159.91GpWQ.rst delete mode 100644 Misc/NEWS.d/next/Security/2026-06-09-23-38-08.gh-issue-151159.ds-9f8.rst delete mode 100644 Misc/NEWS.d/next/Security/2026-06-16-14-58-02.gh-issue-151544._bexVy.rst delete mode 100644 Misc/NEWS.d/next/Tests/2026-04-24-01-38-56.gh-issue-148853._uM4_Q.rst delete mode 100644 Misc/NEWS.d/next/Tests/2026-06-06-16-22-00.gh-issue-150966.7N9x5Q.rst delete mode 100644 Misc/NEWS.d/next/Tests/2026-06-09-11-52-52.gh-issue-151130.1vslPH.rst delete mode 100644 Misc/NEWS.d/next/Windows/2026-06-04-18-53-18.gh-issue-150836.Wci7bZ.rst delete mode 100644 Misc/NEWS.d/next/Windows/2026-06-09-11-40-48.gh-issue-151159.JKVfme.rst delete mode 100644 Misc/NEWS.d/next/Windows/2026-06-09-11-55-41.gh-issue-151163.oizZYV.rst delete mode 100644 Misc/NEWS.d/next/macOS/2026-06-09-11-52-35.gh-issue-151163.RlPXHq.rst diff --git a/Doc/c-api/init_config.rst b/Doc/c-api/init_config.rst index d6b9837987a399..c72955dbad9033 100644 --- a/Doc/c-api/init_config.rst +++ b/Doc/c-api/init_config.rst @@ -623,7 +623,7 @@ Some options are read from the :mod:`sys` attributes. For example, the option .. versionadded:: 3.14 - .. versionchanged:: next + .. versionchanged:: 3.15 The function now replaces :data:`sys.flags` (create a new object), instead of modifying :data:`sys.flags` in-place. diff --git a/Include/patchlevel.h b/Include/patchlevel.h index e474c56e101e1b..60664cf6862527 100644 --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -24,10 +24,10 @@ #define PY_MINOR_VERSION 15 #define PY_MICRO_VERSION 0 #define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_BETA -#define PY_RELEASE_SERIAL 2 +#define PY_RELEASE_SERIAL 3 /* Version as a string */ -#define PY_VERSION "3.15.0b2+dev" +#define PY_VERSION "3.15.0b3" /*--end constants--*/ diff --git a/Lib/pydoc_data/module_docs.py b/Lib/pydoc_data/module_docs.py index 0505210b0bfe0d..8611b1e7c47dd1 100644 --- a/Lib/pydoc_data/module_docs.py +++ b/Lib/pydoc_data/module_docs.py @@ -1,4 +1,4 @@ -# Autogenerated by Sphinx on Tue Jun 2 18:28:34 2026 +# Autogenerated by Sphinx on Tue Jun 23 12:35:44 2026 # as part of the release process. module_docs = { @@ -254,6 +254,7 @@ 'tkinter': 'tkinter#module-tkinter', 'tkinter.colorchooser': 'tkinter.colorchooser#module-tkinter.colorchooser', 'tkinter.commondialog': 'dialog#module-tkinter.commondialog', + 'tkinter.dialog': 'dialog#module-tkinter.dialog', 'tkinter.dnd': 'tkinter.dnd#module-tkinter.dnd', 'tkinter.filedialog': 'dialog#module-tkinter.filedialog', 'tkinter.font': 'tkinter.font#module-tkinter.font', diff --git a/Lib/pydoc_data/topics.py b/Lib/pydoc_data/topics.py index 3ab289ebed6a6f..7016734651125d 100644 --- a/Lib/pydoc_data/topics.py +++ b/Lib/pydoc_data/topics.py @@ -1,4 +1,4 @@ -# Autogenerated by Sphinx on Tue Jun 2 18:28:34 2026 +# Autogenerated by Sphinx on Tue Jun 23 12:35:44 2026 # as part of the release process. topics = { @@ -2896,6 +2896,8 @@ def foo(): * "float" + * "frozendict" + * "frozenset" * "int" @@ -4045,11 +4047,11 @@ def f() -> annotation: ... object.__hash__(self) Called by built-in function "hash()" and for operations on members - of hashed collections including "set", "frozenset", and "dict". - The "__hash__()" method should return an integer. The only required - property is that objects which compare equal have the same hash - value; it is advised to mix together the hash values of the - components of the object that also play a part in comparison of + of hashed collections including "set", "frozenset", "dict", and + "frozendict". The "__hash__()" method should return an integer. The + only required property is that objects which compare equal have the + same hash value; it is advised to mix together the hash values of + the components of the object that also play a part in comparison of objects by packing them into a tuple and hashing the tuple. Example: @@ -7028,10 +7030,6 @@ def whats_on_the_telly(penguin=None): Imports inside functions, class bodies, or "try"/"except"/"finally" blocks are always eager, regardless of "__lazy_modules__". -Setting "-X lazy_imports=none" (or the "PYTHON_LAZY_IMPORTS" -environment variable to "none") overrides "__lazy_modules__" and -forces all imports to be eager. - Added in version 3.15. @@ -7317,10 +7315,6 @@ def <lambda>(parameters): Imports inside functions, class bodies, or "try"/"except"/"finally" blocks are always eager, regardless of "__lazy_modules__". -Setting "-X lazy_imports=none" (or the "PYTHON_LAZY_IMPORTS" -environment variable to "none") overrides "__lazy_modules__" and -forces all imports to be eager. - Added in version 3.15. ''', 'lists': r'''List displays @@ -8880,11 +8874,11 @@ class C: pass # a class with no methods (yet) object.__hash__(self) Called by built-in function "hash()" and for operations on members - of hashed collections including "set", "frozenset", and "dict". - The "__hash__()" method should return an integer. The only required - property is that objects which compare equal have the same hash - value; it is advised to mix together the hash values of the - components of the object that also play a part in comparison of + of hashed collections including "set", "frozenset", "dict", and + "frozendict". The "__hash__()" method should return an integer. The + only required property is that objects which compare equal have the + same hash value; it is advised to mix together the hash values of + the components of the object that also play a part in comparison of objects by packing them into a tuple and hashing the tuple. Example: @@ -10634,9 +10628,22 @@ class is used in a class pattern with positional arguments, each decimal characters and digits that need special handling, such as the compatibility superscript digits. This covers digits which cannot be used to form numbers in base 10, like the Kharosthi - numbers. Formally, a digit is a character that has the property + numbers. Formally, a digit is a character that has the property value Numeric_Type=Digit or Numeric_Type=Decimal. + For example: + + >>> '0123456789'.isdigit() + True + >>> '٠١٢٣٤٥٦٧٨٩'.isdigit() # Arabic-Indic digits zero to nine + True + >>> '⅕'.isdigit() # Vulgar fraction one fifth + False + >>> '²'.isdecimal(), '²'.isdigit(), '²'.isnumeric() + (False, True, True) + + See also "isdecimal()" and "isnumeric()". + str.isidentifier() Return "True" if the string is a valid identifier according to the @@ -10672,15 +10679,14 @@ class is used in a class pattern with positional arguments, each >>> '0123456789'.isnumeric() True - >>> '٠١٢٣٤٥٦٧٨٩'.isnumeric() # Arabic-indic digit zero to nine + >>> '٠١٢٣٤٥٦٧٨٩'.isnumeric() # Arabic-Indic digits zero to nine True >>> '⅕'.isnumeric() # Vulgar fraction one fifth True >>> '²'.isdecimal(), '²'.isdigit(), '²'.isnumeric() (False, True, True) - See also "isdecimal()" and "isdigit()". Numeric characters are a - superset of decimal numbers. + See also "isdecimal()" and "isdigit()". str.isprintable() @@ -11064,7 +11070,7 @@ class is used in a class pattern with positional arguments, each >>> " foo ".split(maxsplit=0) ['foo '] - See also "join()". + See also "join()" and "rsplit()". str.splitlines(keepends=False) @@ -13763,6 +13769,9 @@ class dict(iterable, /, **kwargs) insertion order. This behavior was an implementation detail of CPython from 3.6. + Dictionaries are generic over two types, signifying (respectively) + the types of the dictionary’s keys and values. + These are the operations that dictionaries support (and therefore, custom mapping types should support too): @@ -14104,6 +14113,10 @@ class frozendict(iterable, /, **kwargs) "frozendict" is not a "dict" subclass but inherits directly from "object". + Like dictionaries, frozendicts are generic over two types, + signifying (respectively) the types of the frozendict’s keys and + values. + Added in version 3.15. ''', 'typesmethods': r'''Methods @@ -14508,6 +14521,8 @@ class list(iterable=(), /) Many other operations also produce lists, including the "sorted()" built-in. + Lists are generic over the types of their items. + Lists implement all of the common and mutable sequence operations. Lists also provide the following additional method: @@ -14598,6 +14613,10 @@ class tuple(iterable=(), /) Tuples implement all of the common sequence operations. + Tuples are generic over the types of their contents. For more + information, refer to the typing documentation on annotating + tuples. + For heterogeneous collections of data where access by name is clearer than access by index, "collections.namedtuple()" may be a more appropriate choice than a simple tuple object. diff --git a/Misc/NEWS.d/3.15.0b3.rst b/Misc/NEWS.d/3.15.0b3.rst new file mode 100644 index 00000000000000..6e9191898cf5fe --- /dev/null +++ b/Misc/NEWS.d/3.15.0b3.rst @@ -0,0 +1,785 @@ +.. date: 2026-06-16-14-58-02 +.. gh-issue: 151544 +.. nonce: _bexVy +.. release date: 2026-06-23 +.. section: Security + +:file:`Modules/Setup.local` is no longer used as a landmark to discover +whether Python is running in a source tree, as it could potentially affect +actual installs. The :file:`pybuilddir.txt` file is now the sole indicator +of running in a source tree. + +.. + +.. date: 2026-06-09-23-38-08 +.. gh-issue: 151159 +.. nonce: ds-9f8 +.. section: Security + +Update macOS installer to use OpenSSL 3.5.7. + +.. + +.. date: 2026-06-09-10-23-57 +.. gh-issue: 151159 +.. nonce: 91GpWQ +.. section: Security + +Update Android and iOS installers to use OpenSSL 3.5.7. + +.. + +.. date: 2026-05-30-09-36-20 +.. gh-issue: 150599 +.. nonce: nlHqU- +.. section: Security + +Fix a possible stack buffer overflow in :mod:`bz2` when a +:class:`bz2.BZ2Decompressor` is reused after a decompression error. The +decompressor now becomes unusable after libbz2 reports an error. + +.. + +.. date: 2026-05-18-17-46-00 +.. gh-issue: 149835 +.. nonce: EebFlk +.. section: Security + +:func:`shutil.move` now resolves symlinks via :func:`os.path.realpath` when +checking whether the destination is inside the source directory, preventing +a symlink-based bypass of that guard. + +.. + +.. date: 2026-06-22-06-26-34 +.. gh-issue: 151905 +.. nonce: FOLMYg +.. section: Core and Builtins + +Fix OOM error handling in :c:func:`PyFrame_GetBack` to propagate exceptions +instead of masking them as None. + +.. + +.. date: 2026-06-20-00-30-47 +.. gh-issue: 151722 +.. nonce: RPMPIY +.. section: Core and Builtins + +Defer GC tracking of :class:`frozendict` to end of construction. Patch by +Donghee Na. + +.. + +.. date: 2026-06-16-17-23-37 +.. gh-issue: 151546 +.. nonce: LhiaZz +.. section: Core and Builtins + +Fix the stack limit check if Python is linked to musl (ex: Alpine Linux). +Use the stack size set by the linker to compute the stack limits. Patch by +Victor Stinner. + +.. + +.. date: 2026-06-16-00-45-42 +.. gh-issue: 151510 +.. nonce: HJ-kGn +.. section: Core and Builtins + +Fix a crash in :func:`!__lazy_import__` when called without an explicit +``globals`` argument and without a current Python frame. + +.. + +.. date: 2026-06-14-05-05-15 +.. gh-issue: 151461 +.. nonce: 5q0s88 +.. section: Core and Builtins + +Fix direct execution of files with invalid source encodings to report the +underlying codec lookup or decoding error instead of the generic +``SyntaxError: encoding problem`` message. Patch by Bartosz Sławecki. + +.. + +.. date: 2026-06-12-15-30-25 +.. gh-issue: 151218 +.. nonce: 5M_nv8 +.. section: Core and Builtins + +:c:func:`PyConfig_Set` and :func:`sys.set_int_max_str_digits` now replace +:data:`sys.flags` (create a new object), instead of modifying +:data:`sys.flags` in-place. Patch by Victor Stinner. + +.. + +.. date: 2026-06-11-16-03-23 +.. gh-issue: 151297 +.. nonce: NGPkUM +.. section: Core and Builtins + +Fix an invalid pointer dereference that could occur when calling +:c:func:`PyObject_Realloc` with a NULL pointer in :term:`free-threaded +builds <free-threaded build>` or with :envvar:`PYTHONMALLOC` set to +``mimalloc``. + +.. + +.. date: 2026-06-10-15-42-46 +.. gh-issue: 151253 +.. nonce: 7MMQ8P +.. section: Core and Builtins + +If ``import encodings`` (first import) fails at Python startup, dump the +Python path configuration to help users debugging their configuration. Patch +by Victor Stinner. + +.. + +.. date: 2026-06-10-15-19-58 +.. gh-issue: 151238 +.. nonce: C9Wu4x +.. section: Core and Builtins + +Fix a crash when compiling a concatenated f-string or t-string if an error +occurs when processing one of it's parts. + +.. + +.. date: 2026-06-09-12-24-35 +.. gh-issue: 151112 +.. nonce: 4RKCkD +.. section: Core and Builtins + +Fix a crash in the compiler that could occur when running out of memory. + +.. + +.. date: 2026-06-09-10-28-30 +.. gh-issue: 151126 +.. nonce: DKa6Sl +.. section: Core and Builtins + +Fix a crash, when there's no memory left on a device, which happened in: +code compilation, :mod:`!_interpchannels` module, +:func:`!_winapi.CreateProcess` function. + +Now these places raise proper :exc:`MemoryError` errors. + +.. + +.. date: 2026-06-08-13-14-42 +.. gh-issue: 150902 +.. nonce: -CWZ66 +.. section: Core and Builtins + +Apply an existing optimization of PyCriticalSection (single mutex) to +PyCriticalSection2: avoid acquiring the same locks that the current CS has +already acquired. + +.. + +.. date: 2026-06-08-05-31-22 +.. gh-issue: 151065 +.. nonce: _o_31F +.. section: Core and Builtins + +Fix memory leak when using the :ref:`mimalloc memory allocator <mimalloc>`. + +.. + +.. date: 2026-06-05-22-52-41 +.. gh-issue: 150988 +.. nonce: fDKfMJ +.. section: Core and Builtins + +Fix a reference leak in :exc:`OSError` when attributes are set before +``super().__init__()``. + +.. + +.. date: 2026-06-01-19-24-12 +.. gh-issue: 150723 +.. nonce: WlcL_- +.. section: Core and Builtins + +Fix perf jitdump timestamps on macOS. Events were stamped using +``CLOCK_MONOTONIC``, but macOS profilers timestamp their samples with +``mach_absolute_time()``. The mismatch prevented the JIT code mappings from +lining up with the samples, so no Python frame could be resolved. + +.. + +.. date: 2026-06-01-19-21-01 +.. gh-issue: 150723 +.. nonce: Hb3JDG +.. section: Core and Builtins + +Fix malformed perf jitdump thread ids on macOS. The ``thread_id`` field of +the ``JR_CODE_LOAD`` record was written as a 64-bit value instead of the +32-bit value required by the jitdump format, which shifted every following +field and prevented profilers from resolving Python frames. + +.. + +.. date: 2026-06-01-19-00-00 +.. gh-issue: 150700 +.. nonce: W8CzVR +.. section: Core and Builtins + +Fix a :exc:`SystemError` when compiling a class-scope comprehension +containing a ``lambda`` that references ``__class__``, ``__classdict__``, or +``__conditional_annotations__``. Patch by Bartosz Sławecki. + +.. + +.. date: 2026-05-30-20-19-35 +.. gh-issue: 150633 +.. nonce: XkNul0 +.. section: Core and Builtins + +Fix the frozen importer accepting module names with embedded null bytes, +which caused it to bypass the :data:`sys.modules` cache and create duplicate +module objects. + +.. + +.. date: 2026-05-24-22-46-49 +.. gh-issue: 148613 +.. nonce: PLpmyd +.. section: Core and Builtins + +Fix a data race in the free-threaded build between :func:`gc.set_threshold` +and garbage collection scheduling during object allocation. + +.. + +.. date: 2026-05-22-21-52-38 +.. gh-issue: 150207 +.. nonce: l2BUtI +.. section: Core and Builtins + +Fix a crash when a memory allocation fails during tokenizer initialization. +A proper :exc:`MemoryError` is now raised instead. + +.. + +.. date: 2026-05-13-21-26-26 +.. gh-issue: 149805 +.. nonce: IG6cza +.. section: Core and Builtins + +Fix a :exc:`SystemError` when compiling a compiling ``__classdict__`` class +annotation. Found by OSS-Fuzz in :oss-fuzz:`512907042`. + +.. + +.. date: 2026-05-05-12-00-00 +.. gh-issue: 149321 +.. nonce: remove-lazy-imports-none +.. section: Core and Builtins + +Do not support ``none`` as a lazy imports mode. + +.. + +.. date: 2026-06-20-15-00-00 +.. gh-issue: 75666 +.. nonce: Kt9xQ2 +.. section: Library + +Fix a reference leak in :mod:`tkinter`: the Tcl commands created for event +callbacks are now deleted when a binding is replaced or unbound. + +.. + +.. date: 2026-06-20-15-00-00 +.. gh-issue: 151770 +.. nonce: dtiso0 +.. section: Library + +Fix :meth:`datetime.datetime.fromisoformat` raising :exc:`AssertionError` +instead of :exc:`ValueError` for an out-of-range month combined with a +``24:00`` time. + +.. + +.. date: 2026-06-20-14-47-55 +.. gh-issue: 151665 +.. nonce: 82fmzx +.. section: Library + +:func:`inspect.signature` now works on the lazy evaluators of type aliases +and type parameters instead of raising :exc:`ValueError`. + +.. + +.. date: 2026-06-19-07-26-20 +.. gh-issue: 151695 +.. nonce: IBDlkN +.. section: Library + +Fix a use-after-free in the :mod:`curses` module. The encoding of the +initial screen, used by :func:`curses.unctrl` and :func:`curses.ungetch` to +encode non-ASCII characters, is now kept as a private copy instead of a +borrowed pointer to a window object that may be deallocated. + +.. + +.. date: 2026-06-13-11-57-48 +.. gh-issue: 151436 +.. nonce: UEDowO +.. section: Library + +Fix skewed stack trackes in the Tachyon profiler when caching is enabled and +when generators and coroutines are profiled, by updating +``tstate->last_profiled_frame`` at every frame-removal site. The issue +resulted in total erasure of some callers. Patch by Maurycy +Pawłowski-Wieroński. + +.. + +.. date: 2026-06-13-04-11-00 +.. gh-issue: 151426 +.. nonce: f2V67e +.. section: Library + +Fix impossible stack traces (callers and callees cross called, orphans and +incorrect lines) in the Tachyon profiler when caching frames, by +snapshotting the stack chunks before walking the frame chain on a cache +miss. Patch by Maurycy Pawłowski-Wieroński. + +.. + +.. date: 2026-06-12-22-46-31 +.. gh-issue: 151403 +.. nonce: DalZWh +.. section: Library + +Fixed a crash in :class:`subprocess.Popen` (and +``_posixsubprocess.fork_exec``) when an ``argv`` item's +:meth:`~os.PathLike.__fspath__` concurrently mutates the ``args`` sequence +being converted. + +.. + +.. date: 2026-06-12-07-20-08 +.. gh-issue: 151390 +.. nonce: CmYN9EeJ +.. section: Library + +Colorize ``match`` in the :term:`REPL` when followed by a unary ``+`` or +``-`` operator. Patch by Bartosz Sławecki. + +.. + +.. date: 2026-06-12-00-04-34 +.. gh-issue: 151126 +.. nonce: aHaBYq +.. section: Library + +Fix crash on unset :exc:`MemoryError` on allocation failure in +:func:`ctypes.get_errno`. + +.. + +.. date: 2026-06-11-21-43-24 +.. gh-issue: 151337 +.. nonce: JSVV18 +.. section: Library + +Avoid possible memory leak in ``tkinter.c`` on Windows. + +.. + +.. date: 2026-06-11-16-25-38 +.. gh-issue: 151126 +.. nonce: bh_Usy +.. section: Library + +Fix a crash when :exc:`MemoryError` in :func:`!os._path_splitroot` was not +set properly. + +.. + +.. date: 2026-06-11-11-52-23 +.. gh-issue: 149671 +.. nonce: 6Rpr5r +.. section: Library + +Restore compatibility with setuptools ``-nspkg.pth`` files in the +:mod:`site` module. Inject ``sitedir`` variable in the frame which executes +pth code. Patch by Victor Stinner. + +.. + +.. date: 2026-06-11-00-00-00 +.. gh-issue: 151295 +.. nonce: NQYUzW +.. section: Library + +Fixed a crash (use-after-free) in :meth:`bytes.join` and +:meth:`bytearray.join` that could occur if an item's +:meth:`~object.__buffer__` concurrently mutates the sequence being joined. +The mutation is now reported as a :exc:`RuntimeError` instead. + +.. + +.. date: 2026-06-10-00-00-02 +.. gh-issue: 109940 +.. nonce: Cx1099 +.. section: Library + +Fix Windows :mod:`venv` activation in ``cmd.exe`` to respect +``VIRTUAL_ENV_DISABLE_PROMPT``. + +.. + +.. date: 2026-06-09-12-00-00 +.. gh-issue: 150771 +.. nonce: K7mNx2 +.. section: Library + +Fix :mod:`email` messages created with ``shift_jis`` or ``euc-jp`` charsets. +``set_content()`` now stores the payload using the output charset +(``iso-2022-jp``) so printing the message no longer raises +:exc:`UnicodeEncodeError`. + +.. + +.. date: 2026-06-07-17-29-33 +.. gh-issue: 151039 +.. nonce: AZ0qBn +.. section: Library + +Fix a crash when static :mod:`datetime` types outlive the ``_datetime`` +module. + +.. + +.. date: 2026-06-06-15-20-54 +.. gh-issue: 151021 +.. nonce: J4qk2A +.. section: Library + +Fix :meth:`mmap.mmap.find` and :meth:`~mmap.mmap.rfind` to return ``-1`` +when searching for an empty subsequence with a start position past the end +of the mapping. + +.. + +.. date: 2026-06-04-23-10-31 +.. gh-issue: 62825 +.. nonce: BtG_yQ +.. section: Library + +Encodings "KS_C_5601-1987", "KS X 1001", etc are now aliases of "CP949" +instead of "EUC-KR". + +.. + +.. date: 2026-06-04-21-49-18 +.. gh-issue: 150913 +.. nonce: EmptyBl +.. section: Library + +Fix :class:`sqlite3.Blob` slice assignment to raise :exc:`TypeError` and +:exc:`IndexError` for type and size mismatches respectively, even when the +target slice is empty. + +.. + +.. date: 2026-06-04-18-22-56 +.. gh-issue: 143008 +.. nonce: z5tw-J +.. section: Library + +Fix race conditions when re-initializing a :class:`io.TextIOWrapper` object. + +.. + +.. date: 2026-06-03-13-51-29 +.. gh-issue: 150662 +.. nonce: ELT8Vg +.. section: Library + +Fix the ``--gecko`` collector in :mod:`profiling.sampling` that kept every +sample in memory. It now writes sample and marker data to temporary files +and reads them back, ultimately building the output file at the end. Patch +by Pablo Galindo and Maurycy Pawłowski-Wieroński. + +.. + +.. date: 2026-06-02-14-21-46 +.. gh-issue: 150750 +.. nonce: SVS2o0 +.. section: Library + +Fix a race condition in :meth:`collections.deque.index` with free-threading. + +.. + +.. date: 2026-05-27-23-47-31 +.. gh-issue: 148932 +.. nonce: Y1xmvA +.. section: Library + +Fix ``profiling.sampling`` on Windows virtual environments to resolve the +actual Python PID from a virtual environment shim. + +.. + +.. date: 2026-05-18-22-45-54 +.. gh-issue: 149816 +.. nonce: T68vc_ +.. section: Library + +Fix race condition in :attr:`ssl.SSLContext.sni_callback` + +.. + +.. date: 2026-05-17-12-37-59 +.. gh-issue: 53144 +.. nonce: c5tr1p +.. section: Library + +The :mod:`email` package now supports all aliases of Python codecs and uses +MIME/IANA names for all IANA registered charsets. + +.. + +.. date: 2026-05-15-19-52-41 +.. gh-issue: 149891 +.. nonce: BJUIGB +.. section: Library + +Add support for more encoding aliases `officially registered in IANA +<https://www.iana.org/assignments/character-sets/character-sets.xhtml>`__. + +.. + +.. date: 2026-05-13-12-16-54 +.. gh-issue: 149473 +.. nonce: nOQZqn +.. section: Library + +Calling ``os.environ.clear()`` now emits ``os._clearenv`` auditing event. +Patch by Victor Stinner. + +.. + +.. date: 2026-04-24-19-54-00 +.. gh-issue: 148954 +.. nonce: v1 +.. section: Library + +Fix XML injection vulnerability in :func:`xmlrpc.client.dumps` where the +``methodname`` was not being escaped before interpolation into the XML body. + +.. + +.. date: 2026-01-18-06-42-47 +.. gh-issue: 143988 +.. nonce: MtLtCP +.. section: Library + +Fixed crashes in :meth:`socket.socket.sendmsg` and +:meth:`socket.socket.recvmsg_into` that could occur if buffer sequences are +concurrently mutated. + +.. + +.. date: 2024-06-18-04-08-37 +.. gh-issue: 120665 +.. nonce: x7T1hV +.. section: Library + +Fixed an issue where ``unittest`` loaders would load and instantiate +:class:`unittest.TestCase`-derived subclasses that are also abstract base +classes, which can't be instantiated. + +.. + +.. date: 2023-02-26-14-07-18 +.. gh-issue: 91099 +.. nonce: _QPbEL +.. section: Library + +:meth:`imaplib.IMAP4.login` now raises exceptions with :class:`str` instead +of :class:`bytes`. Patch by Florian Best. + +.. + +.. date: 2023-01-23-21-23-50 +.. gh-issue: 101267 +.. nonce: _f-cFH +.. section: Library + +When a worker process terminates unexpectedly, +:class:`concurrent.futures.ProcessPoolExecutor` now sets a separate +:exc:`~concurrent.futures.process.BrokenProcessPool` exception on each +pending future instead of sharing a single instance among them all. Sharing +one exception produced malformed tracebacks: each :meth:`Future.result() +<concurrent.futures.Future.result>` call re-raised the same object, +appending another copy of the traceback to it. + +.. + +.. date: 2026-06-17-12-00-00 +.. gh-issue: 86726 +.. nonce: __bOgH +.. section: Documentation + +Greatly expand the :mod:`tkinter` documentation to cover the full public API +of the package and its submodules. The descriptions are oriented towards +Python rather than Tcl/Tk, with corrected return types and +``versionadded``/``versionchanged`` information. + +.. + +.. date: 2026-05-23-17-27-41 +.. gh-issue: 150319 +.. nonce: ol9tWK +.. section: Documentation + +Generic builtin and standard library types now document the meaning of their +type parameters. + +.. + +.. date: 2023-09-16-23-42-27 +.. gh-issue: 109503 +.. nonce: mZ-kdU +.. section: Documentation + +Fix documentation for :func:`shutil.move` on usage of :func:`os.rename` +since nonatomic move might be used even if the files are on the same +filesystem. Patch by Fang Li + +.. + +.. date: 2026-06-09-11-52-52 +.. gh-issue: 151130 +.. nonce: 1vslPH +.. section: Tests + +Add more tests for ``PyWeakref_*`` C API. + +.. + +.. date: 2026-06-06-16-22-00 +.. gh-issue: 150966 +.. nonce: 7N9x5Q +.. section: Tests + +Avoid prematurely terminating failing live sampling profiler test targets, +which made stderr assertions flaky on ASAN buildbots. + +.. + +.. date: 2026-04-24-01-38-56 +.. gh-issue: 148853 +.. nonce: _uM4_Q +.. section: Tests + +Fix tests failing on FreeBSD in test.support's +in_systemd_nspawn_sync_suppressed() due to unreadable /run directory. + +.. + +.. date: 2026-06-09-11-54-13 +.. gh-issue: 151163 +.. nonce: vFAtjv +.. section: Build + +Updated Android build to include SQLite version 3.53.2. + +.. + +.. date: 2026-06-09-11-55-41 +.. gh-issue: 151163 +.. nonce: oizZYV +.. section: Windows + +Updated Windows builds to include SQLite version 3.53.2. + +.. + +.. date: 2026-06-09-11-40-48 +.. gh-issue: 151159 +.. nonce: JKVfme +.. section: Windows + +Updated bundled version of OpenSSL to 3.5.7. + +.. + +.. date: 2026-06-04-18-53-18 +.. gh-issue: 150836 +.. nonce: Wci7bZ +.. section: Windows + +Make installed tkinter work with Tcl/Tk 9 builds that embed the Tk script +library in the Tk DLL on Windows. + +.. + +.. date: 2026-06-09-11-52-35 +.. gh-issue: 151163 +.. nonce: RlPXHq +.. section: macOS + +Updated macOS installer to include SQLite version 3.53.2. + +.. + +.. bpo: 6699 +.. date: 2019-12-12-03-18-02 +.. nonce: 1CqJFG +.. section: IDLE + +Warn the user if a file will be overwritten when saving. + +.. + +.. date: 2026-06-18-18-24-11 +.. gh-issue: 141510 +.. nonce: -EOHJ1 +.. section: C API + +Add :class:`frozendict` to the fast paths of +:c:func:`PyMapping_GetOptionalItem`, :c:func:`PyMapping_Keys`, +:c:func:`PyMapping_Values`, and :c:func:`PyMapping_Items`. + +.. + +.. date: 2026-06-10-16-43-37 +.. gh-issue: 123619 +.. nonce: dV82r6 +.. section: C API + +:c:func:`PyUnstable_Object_EnableDeferredRefcount` now returns ``0`` if the +object is not tracked by the garbage collector: if :func:`gc.is_tracked` is +false. Patch by Victor Stinner. + +.. + +.. date: 2026-06-10-15-22-44 +.. gh-issue: 149044 +.. nonce: O7KEcs +.. section: C API + +Improved error message when specifying non-type base classes in +:c:macro:`Py_tp_bases`, :c:macro:`Py_tp_base`, and *bases* argument to +:c:func:`PyType_FromMetaclass` and other ``PyType_From*`` functions. + +.. + +.. date: 2026-06-04-14-26-17 +.. gh-issue: 150907 +.. nonce: CA91_B +.. section: C API + +Fix ``dynamic_annotations.h`` header file when built with C++ and Valgrind: +add ``extern "C++" scope`` for the C++ template. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Build/2026-06-09-11-54-13.gh-issue-151163.vFAtjv.rst b/Misc/NEWS.d/next/Build/2026-06-09-11-54-13.gh-issue-151163.vFAtjv.rst deleted file mode 100644 index e4f3a044c81c6f..00000000000000 --- a/Misc/NEWS.d/next/Build/2026-06-09-11-54-13.gh-issue-151163.vFAtjv.rst +++ /dev/null @@ -1 +0,0 @@ -Updated Android build to include SQLite version 3.53.2. diff --git a/Misc/NEWS.d/next/C_API/2026-06-04-14-26-17.gh-issue-150907.CA91_B.rst b/Misc/NEWS.d/next/C_API/2026-06-04-14-26-17.gh-issue-150907.CA91_B.rst deleted file mode 100644 index f58b248f3a0b98..00000000000000 --- a/Misc/NEWS.d/next/C_API/2026-06-04-14-26-17.gh-issue-150907.CA91_B.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix ``dynamic_annotations.h`` header file when built with C++ and Valgrind: -add ``extern "C++" scope`` for the C++ template. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/C_API/2026-06-10-15-22-44.gh-issue-149044.O7KEcs.rst b/Misc/NEWS.d/next/C_API/2026-06-10-15-22-44.gh-issue-149044.O7KEcs.rst deleted file mode 100644 index fe0730b1bf87c4..00000000000000 --- a/Misc/NEWS.d/next/C_API/2026-06-10-15-22-44.gh-issue-149044.O7KEcs.rst +++ /dev/null @@ -1,3 +0,0 @@ -Improved error message when specifying non-type base classes in -:c:macro:`Py_tp_bases`, :c:macro:`Py_tp_base`, and *bases* argument to -:c:func:`PyType_FromMetaclass` and other ``PyType_From*`` functions. diff --git a/Misc/NEWS.d/next/C_API/2026-06-10-16-43-37.gh-issue-123619.dV82r6.rst b/Misc/NEWS.d/next/C_API/2026-06-10-16-43-37.gh-issue-123619.dV82r6.rst deleted file mode 100644 index 4d4c94563330c0..00000000000000 --- a/Misc/NEWS.d/next/C_API/2026-06-10-16-43-37.gh-issue-123619.dV82r6.rst +++ /dev/null @@ -1,3 +0,0 @@ -:c:func:`PyUnstable_Object_EnableDeferredRefcount` now returns ``0`` if the -object is not tracked by the garbage collector: if :func:`gc.is_tracked` is -false. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/C_API/2026-06-18-18-24-11.gh-issue-141510.-EOHJ1.rst b/Misc/NEWS.d/next/C_API/2026-06-18-18-24-11.gh-issue-141510.-EOHJ1.rst deleted file mode 100644 index c77b462e97bdd1..00000000000000 --- a/Misc/NEWS.d/next/C_API/2026-06-18-18-24-11.gh-issue-141510.-EOHJ1.rst +++ /dev/null @@ -1 +0,0 @@ -Add :class:`frozendict` to the fast paths of :c:func:`PyMapping_GetOptionalItem`, :c:func:`PyMapping_Keys`, :c:func:`PyMapping_Values`, and :c:func:`PyMapping_Items`. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-05-12-00-00.gh-issue-149321.remove-lazy-imports-none.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-05-12-00-00.gh-issue-149321.remove-lazy-imports-none.rst deleted file mode 100644 index 44e96ce7be0bfb..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-05-12-00-00.gh-issue-149321.remove-lazy-imports-none.rst +++ /dev/null @@ -1 +0,0 @@ -Do not support ``none`` as a lazy imports mode. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-13-21-26-26.gh-issue-149805.IG6cza.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-13-21-26-26.gh-issue-149805.IG6cza.rst deleted file mode 100644 index 02d050840ee1f9..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-13-21-26-26.gh-issue-149805.IG6cza.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix a :exc:`SystemError` when compiling a compiling ``__classdict__`` class -annotation. Found by OSS-Fuzz in :oss-fuzz:`512907042`. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-22-21-52-38.gh-issue-150207.l2BUtI.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-22-21-52-38.gh-issue-150207.l2BUtI.rst deleted file mode 100644 index 12fbffcd170684..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-22-21-52-38.gh-issue-150207.l2BUtI.rst +++ /dev/null @@ -1 +0,0 @@ -Fix a crash when a memory allocation fails during tokenizer initialization. A proper :exc:`MemoryError` is now raised instead. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-24-22-46-49.gh-issue-148613.PLpmyd.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-24-22-46-49.gh-issue-148613.PLpmyd.rst deleted file mode 100644 index 71a701bf3eb355..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-24-22-46-49.gh-issue-148613.PLpmyd.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix a data race in the free-threaded build between :func:`gc.set_threshold` -and garbage collection scheduling during object allocation. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-30-20-19-35.gh-issue-150633.XkNul0.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-30-20-19-35.gh-issue-150633.XkNul0.rst deleted file mode 100644 index c397ad61f086c1..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-30-20-19-35.gh-issue-150633.XkNul0.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix the frozen importer accepting module names with embedded null bytes, which -caused it to bypass the :data:`sys.modules` cache and create duplicate module -objects. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-01-19-00-00.gh-issue-150700.W8CzVR.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-01-19-00-00.gh-issue-150700.W8CzVR.rst deleted file mode 100644 index e7734034ff5c81..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-01-19-00-00.gh-issue-150700.W8CzVR.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix a :exc:`SystemError` when compiling a class-scope comprehension containing -a ``lambda`` that references ``__class__``, ``__classdict__``, or -``__conditional_annotations__``. Patch by Bartosz Sławecki. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-01-19-21-01.gh-issue-150723.Hb3JDG.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-01-19-21-01.gh-issue-150723.Hb3JDG.rst deleted file mode 100644 index 1920c8cdfce4f4..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-01-19-21-01.gh-issue-150723.Hb3JDG.rst +++ /dev/null @@ -1,4 +0,0 @@ -Fix malformed perf jitdump thread ids on macOS. The ``thread_id`` field of the -``JR_CODE_LOAD`` record was written as a 64-bit value instead of the 32-bit -value required by the jitdump format, which shifted every following field and -prevented profilers from resolving Python frames. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-01-19-24-12.gh-issue-150723.WlcL_-.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-01-19-24-12.gh-issue-150723.WlcL_-.rst deleted file mode 100644 index 78c896b669c239..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-01-19-24-12.gh-issue-150723.WlcL_-.rst +++ /dev/null @@ -1,4 +0,0 @@ -Fix perf jitdump timestamps on macOS. Events were stamped using -``CLOCK_MONOTONIC``, but macOS profilers timestamp their samples with -``mach_absolute_time()``. The mismatch prevented the JIT code mappings from -lining up with the samples, so no Python frame could be resolved. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-05-22-52-41.gh-issue-150988.fDKfMJ.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-05-22-52-41.gh-issue-150988.fDKfMJ.rst deleted file mode 100644 index 6fb70a1ce2685c..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-05-22-52-41.gh-issue-150988.fDKfMJ.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix a reference leak in :exc:`OSError` when attributes are set before -``super().__init__()``. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-08-05-31-22.gh-issue-151065._o_31F.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-08-05-31-22.gh-issue-151065._o_31F.rst deleted file mode 100644 index e46c96ef784cc9..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-08-05-31-22.gh-issue-151065._o_31F.rst +++ /dev/null @@ -1 +0,0 @@ -Fix memory leak when using the :ref:`mimalloc memory allocator <mimalloc>`. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-08-13-14-42.gh-issue-150902.-CWZ66.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-08-13-14-42.gh-issue-150902.-CWZ66.rst deleted file mode 100644 index e3b7cd387b439f..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-08-13-14-42.gh-issue-150902.-CWZ66.rst +++ /dev/null @@ -1 +0,0 @@ -Apply an existing optimization of PyCriticalSection (single mutex) to PyCriticalSection2: avoid acquiring the same locks that the current CS has already acquired. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-09-10-28-30.gh-issue-151126.DKa6Sl.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-09-10-28-30.gh-issue-151126.DKa6Sl.rst deleted file mode 100644 index 67e2ce4044431f..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-09-10-28-30.gh-issue-151126.DKa6Sl.rst +++ /dev/null @@ -1,5 +0,0 @@ -Fix a crash, when there's no memory left on a device, -which happened in: code compilation, :mod:`!_interpchannels` module, -:func:`!_winapi.CreateProcess` function. - -Now these places raise proper :exc:`MemoryError` errors. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-09-12-24-35.gh-issue-151112.4RKCkD.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-09-12-24-35.gh-issue-151112.4RKCkD.rst deleted file mode 100644 index 93ee5c8cf1914b..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-09-12-24-35.gh-issue-151112.4RKCkD.rst +++ /dev/null @@ -1 +0,0 @@ -Fix a crash in the compiler that could occur when running out of memory. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-10-15-19-58.gh-issue-151238.C9Wu4x.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-10-15-19-58.gh-issue-151238.C9Wu4x.rst deleted file mode 100644 index fe7519fb487895..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-10-15-19-58.gh-issue-151238.C9Wu4x.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix a crash when compiling a concatenated f-string or t-string if an error -occurs when processing one of it's parts. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-10-15-42-46.gh-issue-151253.7MMQ8P.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-10-15-42-46.gh-issue-151253.7MMQ8P.rst deleted file mode 100644 index 56d2f3b2633bb0..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-10-15-42-46.gh-issue-151253.7MMQ8P.rst +++ /dev/null @@ -1,3 +0,0 @@ -If ``import encodings`` (first import) fails at Python startup, dump the -Python path configuration to help users debugging their configuration. Patch -by Victor Stinner. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-11-16-03-23.gh-issue-151297.NGPkUM.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-11-16-03-23.gh-issue-151297.NGPkUM.rst deleted file mode 100644 index 288d726e0f1004..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-11-16-03-23.gh-issue-151297.NGPkUM.rst +++ /dev/null @@ -1 +0,0 @@ -Fix an invalid pointer dereference that could occur when calling :c:func:`PyObject_Realloc` with a NULL pointer in :term:`free-threaded builds <free-threaded build>` or with :envvar:`PYTHONMALLOC` set to ``mimalloc``. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-12-15-30-25.gh-issue-151218.5M_nv8.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-12-15-30-25.gh-issue-151218.5M_nv8.rst deleted file mode 100644 index 46539efc373eb0..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-12-15-30-25.gh-issue-151218.5M_nv8.rst +++ /dev/null @@ -1,3 +0,0 @@ -:c:func:`PyConfig_Set` and :func:`sys.set_int_max_str_digits` now replace -:data:`sys.flags` (create a new object), instead of modifying :data:`sys.flags` -in-place. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-14-05-05-15.gh-issue-151461.5q0s88.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-14-05-05-15.gh-issue-151461.5q0s88.rst deleted file mode 100644 index d76a9bc95278bc..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-14-05-05-15.gh-issue-151461.5q0s88.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix direct execution of files with invalid source encodings to report the -underlying codec lookup or decoding error instead of the generic -``SyntaxError: encoding problem`` message. Patch by Bartosz Sławecki. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-16-00-45-42.gh-issue-151510.HJ-kGn.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-16-00-45-42.gh-issue-151510.HJ-kGn.rst deleted file mode 100644 index cfa5ee8d3839c1..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-16-00-45-42.gh-issue-151510.HJ-kGn.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix a crash in :func:`!__lazy_import__` when called without an explicit -``globals`` argument and without a current Python frame. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-16-17-23-37.gh-issue-151546.LhiaZz.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-16-17-23-37.gh-issue-151546.LhiaZz.rst deleted file mode 100644 index af1c23bd50355f..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-16-17-23-37.gh-issue-151546.LhiaZz.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix the stack limit check if Python is linked to musl (ex: Alpine Linux). -Use the stack size set by the linker to compute the stack limits. Patch by -Victor Stinner. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-20-00-30-47.gh-issue-151722.RPMPIY.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-20-00-30-47.gh-issue-151722.RPMPIY.rst deleted file mode 100644 index 57b5dee7458ede..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-20-00-30-47.gh-issue-151722.RPMPIY.rst +++ /dev/null @@ -1,2 +0,0 @@ -Defer GC tracking of :class:`frozendict` to end of construction. Patch by -Donghee Na. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-22-06-26-34.gh-issue-151905.FOLMYg.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-22-06-26-34.gh-issue-151905.FOLMYg.rst deleted file mode 100644 index c71122df6b8580..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-22-06-26-34.gh-issue-151905.FOLMYg.rst +++ /dev/null @@ -1 +0,0 @@ -Fix OOM error handling in :c:func:`PyFrame_GetBack` to propagate exceptions instead of masking them as None. diff --git a/Misc/NEWS.d/next/Documentation/2023-09-16-23-42-27.gh-issue-109503.mZ-kdU.rst b/Misc/NEWS.d/next/Documentation/2023-09-16-23-42-27.gh-issue-109503.mZ-kdU.rst deleted file mode 100644 index c3c6c57569c2ea..00000000000000 --- a/Misc/NEWS.d/next/Documentation/2023-09-16-23-42-27.gh-issue-109503.mZ-kdU.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix documentation for :func:`shutil.move` on usage of -:func:`os.rename` since nonatomic move might be used even if the files are -on the same filesystem. Patch by Fang Li diff --git a/Misc/NEWS.d/next/Documentation/2026-05-23-17-27-41.gh-issue-150319.ol9tWK.rst b/Misc/NEWS.d/next/Documentation/2026-05-23-17-27-41.gh-issue-150319.ol9tWK.rst deleted file mode 100644 index d56ccbce2fa325..00000000000000 --- a/Misc/NEWS.d/next/Documentation/2026-05-23-17-27-41.gh-issue-150319.ol9tWK.rst +++ /dev/null @@ -1,2 +0,0 @@ -Generic builtin and standard library types now document the meaning of their -type parameters. diff --git a/Misc/NEWS.d/next/Documentation/2026-06-17-12-00-00.gh-issue-86726.__bOgH.rst b/Misc/NEWS.d/next/Documentation/2026-06-17-12-00-00.gh-issue-86726.__bOgH.rst deleted file mode 100644 index 787b95dbf23627..00000000000000 --- a/Misc/NEWS.d/next/Documentation/2026-06-17-12-00-00.gh-issue-86726.__bOgH.rst +++ /dev/null @@ -1,4 +0,0 @@ -Greatly expand the :mod:`tkinter` documentation to cover the full public API -of the package and its submodules. The descriptions are oriented towards -Python rather than Tcl/Tk, with corrected return types and -``versionadded``/``versionchanged`` information. diff --git a/Misc/NEWS.d/next/IDLE/2019-12-12-03-18-02.bpo-6699.1CqJFG.rst b/Misc/NEWS.d/next/IDLE/2019-12-12-03-18-02.bpo-6699.1CqJFG.rst deleted file mode 100644 index e7fb9bf1b3bdf6..00000000000000 --- a/Misc/NEWS.d/next/IDLE/2019-12-12-03-18-02.bpo-6699.1CqJFG.rst +++ /dev/null @@ -1 +0,0 @@ -Warn the user if a file will be overwritten when saving. diff --git a/Misc/NEWS.d/next/Library/2023-01-23-21-23-50.gh-issue-101267._f-cFH.rst b/Misc/NEWS.d/next/Library/2023-01-23-21-23-50.gh-issue-101267._f-cFH.rst deleted file mode 100644 index 901a3fb60ab5b9..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-01-23-21-23-50.gh-issue-101267._f-cFH.rst +++ /dev/null @@ -1,7 +0,0 @@ -When a worker process terminates unexpectedly, -:class:`concurrent.futures.ProcessPoolExecutor` now sets a separate -:exc:`~concurrent.futures.process.BrokenProcessPool` exception on each pending -future instead of sharing a single instance among them all. Sharing one -exception produced malformed tracebacks: each -:meth:`Future.result() <concurrent.futures.Future.result>` call re-raised the -same object, appending another copy of the traceback to it. diff --git a/Misc/NEWS.d/next/Library/2023-02-26-14-07-18.gh-issue-91099._QPbEL.rst b/Misc/NEWS.d/next/Library/2023-02-26-14-07-18.gh-issue-91099._QPbEL.rst deleted file mode 100644 index d886e8ac6032a4..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-02-26-14-07-18.gh-issue-91099._QPbEL.rst +++ /dev/null @@ -1,2 +0,0 @@ -:meth:`imaplib.IMAP4.login` now raises exceptions with :class:`str` instead of -:class:`bytes`. Patch by Florian Best. diff --git a/Misc/NEWS.d/next/Library/2024-06-18-04-08-37.gh-issue-120665.x7T1hV.rst b/Misc/NEWS.d/next/Library/2024-06-18-04-08-37.gh-issue-120665.x7T1hV.rst deleted file mode 100644 index 27e93988ed11ef..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-06-18-04-08-37.gh-issue-120665.x7T1hV.rst +++ /dev/null @@ -1 +0,0 @@ -Fixed an issue where ``unittest`` loaders would load and instantiate :class:`unittest.TestCase`-derived subclasses that are also abstract base classes, which can't be instantiated. diff --git a/Misc/NEWS.d/next/Library/2026-01-18-06-42-47.gh-issue-143988.MtLtCP.rst b/Misc/NEWS.d/next/Library/2026-01-18-06-42-47.gh-issue-143988.MtLtCP.rst deleted file mode 100644 index fcc0cb54934b90..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-01-18-06-42-47.gh-issue-143988.MtLtCP.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fixed crashes in :meth:`socket.socket.sendmsg` and :meth:`socket.socket.recvmsg_into` -that could occur if buffer sequences are concurrently mutated. diff --git a/Misc/NEWS.d/next/Library/2026-04-24-19-54-00.gh-issue-148954.v1.rst b/Misc/NEWS.d/next/Library/2026-04-24-19-54-00.gh-issue-148954.v1.rst deleted file mode 100644 index 6245af7e362e92..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-04-24-19-54-00.gh-issue-148954.v1.rst +++ /dev/null @@ -1 +0,0 @@ -Fix XML injection vulnerability in :func:`xmlrpc.client.dumps` where the ``methodname`` was not being escaped before interpolation into the XML body. diff --git a/Misc/NEWS.d/next/Library/2026-05-13-12-16-54.gh-issue-149473.nOQZqn.rst b/Misc/NEWS.d/next/Library/2026-05-13-12-16-54.gh-issue-149473.nOQZqn.rst deleted file mode 100644 index db624aba31a9de..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-05-13-12-16-54.gh-issue-149473.nOQZqn.rst +++ /dev/null @@ -1,2 +0,0 @@ -Calling ``os.environ.clear()`` now emits ``os._clearenv`` auditing event. -Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Library/2026-05-15-19-52-41.gh-issue-149891.BJUIGB.rst b/Misc/NEWS.d/next/Library/2026-05-15-19-52-41.gh-issue-149891.BJUIGB.rst deleted file mode 100644 index f8bc28659533af..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-05-15-19-52-41.gh-issue-149891.BJUIGB.rst +++ /dev/null @@ -1 +0,0 @@ -Add support for more encoding aliases `officially registered in IANA <https://www.iana.org/assignments/character-sets/character-sets.xhtml>`__. diff --git a/Misc/NEWS.d/next/Library/2026-05-17-12-37-59.gh-issue-53144.c5tr1p.rst b/Misc/NEWS.d/next/Library/2026-05-17-12-37-59.gh-issue-53144.c5tr1p.rst deleted file mode 100644 index 283a5ba44d1f19..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-05-17-12-37-59.gh-issue-53144.c5tr1p.rst +++ /dev/null @@ -1,2 +0,0 @@ -The :mod:`email` package now supports all aliases of Python codecs and uses -MIME/IANA names for all IANA registered charsets. diff --git a/Misc/NEWS.d/next/Library/2026-05-18-22-45-54.gh-issue-149816.T68vc_.rst b/Misc/NEWS.d/next/Library/2026-05-18-22-45-54.gh-issue-149816.T68vc_.rst deleted file mode 100644 index 9996cc7ec0e866..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-05-18-22-45-54.gh-issue-149816.T68vc_.rst +++ /dev/null @@ -1 +0,0 @@ -Fix race condition in :attr:`ssl.SSLContext.sni_callback` diff --git a/Misc/NEWS.d/next/Library/2026-05-27-23-47-31.gh-issue-148932.Y1xmvA.rst b/Misc/NEWS.d/next/Library/2026-05-27-23-47-31.gh-issue-148932.Y1xmvA.rst deleted file mode 100644 index a0b7a9740cd518..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-05-27-23-47-31.gh-issue-148932.Y1xmvA.rst +++ /dev/null @@ -1 +0,0 @@ -Fix ``profiling.sampling`` on Windows virtual environments to resolve the actual Python PID from a virtual environment shim. diff --git a/Misc/NEWS.d/next/Library/2026-06-02-14-21-46.gh-issue-150750.SVS2o0.rst b/Misc/NEWS.d/next/Library/2026-06-02-14-21-46.gh-issue-150750.SVS2o0.rst deleted file mode 100644 index bda500383e7cda..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-06-02-14-21-46.gh-issue-150750.SVS2o0.rst +++ /dev/null @@ -1 +0,0 @@ -Fix a race condition in :meth:`collections.deque.index` with free-threading. diff --git a/Misc/NEWS.d/next/Library/2026-06-03-13-51-29.gh-issue-150662.ELT8Vg.rst b/Misc/NEWS.d/next/Library/2026-06-03-13-51-29.gh-issue-150662.ELT8Vg.rst deleted file mode 100644 index 42ed6ad7cd3c65..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-06-03-13-51-29.gh-issue-150662.ELT8Vg.rst +++ /dev/null @@ -1,4 +0,0 @@ -Fix the ``--gecko`` collector in :mod:`profiling.sampling` that kept every -sample in memory. It now writes sample and marker data to temporary files -and reads them back, ultimately building the output file at the end. Patch -by Pablo Galindo and Maurycy Pawłowski-Wieroński. diff --git a/Misc/NEWS.d/next/Library/2026-06-04-18-22-56.gh-issue-143008.z5tw-J.rst b/Misc/NEWS.d/next/Library/2026-06-04-18-22-56.gh-issue-143008.z5tw-J.rst deleted file mode 100644 index e99bc39c45f9b8..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-06-04-18-22-56.gh-issue-143008.z5tw-J.rst +++ /dev/null @@ -1 +0,0 @@ -Fix race conditions when re-initializing a :class:`io.TextIOWrapper` object. diff --git a/Misc/NEWS.d/next/Library/2026-06-04-21-49-18.gh-issue-150913.EmptyBl.rst b/Misc/NEWS.d/next/Library/2026-06-04-21-49-18.gh-issue-150913.EmptyBl.rst deleted file mode 100644 index f95a6ee6ee15bf..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-06-04-21-49-18.gh-issue-150913.EmptyBl.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix :class:`sqlite3.Blob` slice assignment to raise -:exc:`TypeError` and :exc:`IndexError` for type and size mismatches -respectively, even when the target slice is empty. diff --git a/Misc/NEWS.d/next/Library/2026-06-04-23-10-31.gh-issue-62825.BtG_yQ.rst b/Misc/NEWS.d/next/Library/2026-06-04-23-10-31.gh-issue-62825.BtG_yQ.rst deleted file mode 100644 index 95a4fb1c61d4c3..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-06-04-23-10-31.gh-issue-62825.BtG_yQ.rst +++ /dev/null @@ -1,2 +0,0 @@ -Encodings "KS_C_5601-1987", "KS X 1001", etc are now aliases of "CP949" -instead of "EUC-KR". diff --git a/Misc/NEWS.d/next/Library/2026-06-06-15-20-54.gh-issue-151021.J4qk2A.rst b/Misc/NEWS.d/next/Library/2026-06-06-15-20-54.gh-issue-151021.J4qk2A.rst deleted file mode 100644 index 0617fa068c844d..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-06-06-15-20-54.gh-issue-151021.J4qk2A.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix :meth:`mmap.mmap.find` and :meth:`~mmap.mmap.rfind` to return ``-1`` -when searching for an empty subsequence with a start position past the end -of the mapping. diff --git a/Misc/NEWS.d/next/Library/2026-06-07-17-29-33.gh-issue-151039.AZ0qBn.rst b/Misc/NEWS.d/next/Library/2026-06-07-17-29-33.gh-issue-151039.AZ0qBn.rst deleted file mode 100644 index 1e99567f555057..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-06-07-17-29-33.gh-issue-151039.AZ0qBn.rst +++ /dev/null @@ -1 +0,0 @@ -Fix a crash when static :mod:`datetime` types outlive the ``_datetime`` module. diff --git a/Misc/NEWS.d/next/Library/2026-06-09-12-00-00.gh-issue-150771.K7mNx2.rst b/Misc/NEWS.d/next/Library/2026-06-09-12-00-00.gh-issue-150771.K7mNx2.rst deleted file mode 100644 index 6535e5c48bf036..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-06-09-12-00-00.gh-issue-150771.K7mNx2.rst +++ /dev/null @@ -1,4 +0,0 @@ -Fix :mod:`email` messages created with ``shift_jis`` or ``euc-jp`` charsets. -``set_content()`` now stores the payload using the output charset -(``iso-2022-jp``) so printing the message no longer raises -:exc:`UnicodeEncodeError`. diff --git a/Misc/NEWS.d/next/Library/2026-06-10-00-00-02.gh-issue-109940.Cx1099.rst b/Misc/NEWS.d/next/Library/2026-06-10-00-00-02.gh-issue-109940.Cx1099.rst deleted file mode 100644 index 130dc780b61286..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-06-10-00-00-02.gh-issue-109940.Cx1099.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix Windows :mod:`venv` activation in ``cmd.exe`` to respect -``VIRTUAL_ENV_DISABLE_PROMPT``. diff --git a/Misc/NEWS.d/next/Library/2026-06-11-00-00-00.gh-issue-151295.NQYUzW.rst b/Misc/NEWS.d/next/Library/2026-06-11-00-00-00.gh-issue-151295.NQYUzW.rst deleted file mode 100644 index e9012f023ff7f7..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-06-11-00-00-00.gh-issue-151295.NQYUzW.rst +++ /dev/null @@ -1,4 +0,0 @@ -Fixed a crash (use-after-free) in :meth:`bytes.join` and -:meth:`bytearray.join` that could occur if an item's -:meth:`~object.__buffer__` concurrently mutates the sequence being joined. -The mutation is now reported as a :exc:`RuntimeError` instead. diff --git a/Misc/NEWS.d/next/Library/2026-06-11-11-52-23.gh-issue-149671.6Rpr5r.rst b/Misc/NEWS.d/next/Library/2026-06-11-11-52-23.gh-issue-149671.6Rpr5r.rst deleted file mode 100644 index 5c08828e5fd77e..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-06-11-11-52-23.gh-issue-149671.6Rpr5r.rst +++ /dev/null @@ -1,3 +0,0 @@ -Restore compatibility with setuptools ``-nspkg.pth`` files in the :mod:`site` -module. Inject ``sitedir`` variable in the frame which executes pth code. -Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Library/2026-06-11-16-25-38.gh-issue-151126.bh_Usy.rst b/Misc/NEWS.d/next/Library/2026-06-11-16-25-38.gh-issue-151126.bh_Usy.rst deleted file mode 100644 index 25149057aa7d09..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-06-11-16-25-38.gh-issue-151126.bh_Usy.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix a crash when :exc:`MemoryError` in :func:`!os._path_splitroot` -was not set properly. diff --git a/Misc/NEWS.d/next/Library/2026-06-11-21-43-24.gh-issue-151337.JSVV18.rst b/Misc/NEWS.d/next/Library/2026-06-11-21-43-24.gh-issue-151337.JSVV18.rst deleted file mode 100644 index 0344eee9471d29..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-06-11-21-43-24.gh-issue-151337.JSVV18.rst +++ /dev/null @@ -1 +0,0 @@ -Avoid possible memory leak in ``tkinter.c`` on Windows. diff --git a/Misc/NEWS.d/next/Library/2026-06-12-00-04-34.gh-issue-151126.aHaBYq.rst b/Misc/NEWS.d/next/Library/2026-06-12-00-04-34.gh-issue-151126.aHaBYq.rst deleted file mode 100644 index 20ef69d5de5ac5..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-06-12-00-04-34.gh-issue-151126.aHaBYq.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix crash on unset :exc:`MemoryError` on allocation failure in -:func:`ctypes.get_errno`. diff --git a/Misc/NEWS.d/next/Library/2026-06-12-07-20-08.gh-issue-151390.CmYN9EeJ.rst b/Misc/NEWS.d/next/Library/2026-06-12-07-20-08.gh-issue-151390.CmYN9EeJ.rst deleted file mode 100644 index ff8de30599c6ad..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-06-12-07-20-08.gh-issue-151390.CmYN9EeJ.rst +++ /dev/null @@ -1 +0,0 @@ -Colorize ``match`` in the :term:`REPL` when followed by a unary ``+`` or ``-`` operator. Patch by Bartosz Sławecki. diff --git a/Misc/NEWS.d/next/Library/2026-06-12-22-46-31.gh-issue-151403.DalZWh.rst b/Misc/NEWS.d/next/Library/2026-06-12-22-46-31.gh-issue-151403.DalZWh.rst deleted file mode 100644 index ca779ed684e761..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-06-12-22-46-31.gh-issue-151403.DalZWh.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fixed a crash in :class:`subprocess.Popen` (and ``_posixsubprocess.fork_exec``) -when an ``argv`` item's :meth:`~os.PathLike.__fspath__` concurrently mutates the -``args`` sequence being converted. diff --git a/Misc/NEWS.d/next/Library/2026-06-13-04-11-00.gh-issue-151426.f2V67e.rst b/Misc/NEWS.d/next/Library/2026-06-13-04-11-00.gh-issue-151426.f2V67e.rst deleted file mode 100644 index 428302e5f847f3..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-06-13-04-11-00.gh-issue-151426.f2V67e.rst +++ /dev/null @@ -1,4 +0,0 @@ -Fix impossible stack traces (callers and callees cross called, orphans and -incorrect lines) in the Tachyon profiler when caching frames, by snapshotting -the stack chunks before walking the frame chain on a cache miss. Patch by -Maurycy Pawłowski-Wieroński. diff --git a/Misc/NEWS.d/next/Library/2026-06-13-11-57-48.gh-issue-151436.UEDowO.rst b/Misc/NEWS.d/next/Library/2026-06-13-11-57-48.gh-issue-151436.UEDowO.rst deleted file mode 100644 index 1d1aadbf57be48..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-06-13-11-57-48.gh-issue-151436.UEDowO.rst +++ /dev/null @@ -1,4 +0,0 @@ -Fix skewed stack trackes in the Tachyon profiler when caching is enabled and -when generators and coroutines are profiled, by updating -``tstate->last_profiled_frame`` at every frame-removal site. The issue resulted -in total erasure of some callers. Patch by Maurycy Pawłowski-Wieroński. diff --git a/Misc/NEWS.d/next/Library/2026-06-19-07-26-20.gh-issue-151695.IBDlkN.rst b/Misc/NEWS.d/next/Library/2026-06-19-07-26-20.gh-issue-151695.IBDlkN.rst deleted file mode 100644 index f44cb6b9307165..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-06-19-07-26-20.gh-issue-151695.IBDlkN.rst +++ /dev/null @@ -1,4 +0,0 @@ -Fix a use-after-free in the :mod:`curses` module. The encoding of the initial -screen, used by :func:`curses.unctrl` and :func:`curses.ungetch` to encode -non-ASCII characters, is now kept as a private copy instead of a borrowed -pointer to a window object that may be deallocated. diff --git a/Misc/NEWS.d/next/Library/2026-06-20-14-47-55.gh-issue-151665.82fmzx.rst b/Misc/NEWS.d/next/Library/2026-06-20-14-47-55.gh-issue-151665.82fmzx.rst deleted file mode 100644 index d08a1220cbe5ef..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-06-20-14-47-55.gh-issue-151665.82fmzx.rst +++ /dev/null @@ -1,2 +0,0 @@ -:func:`inspect.signature` now works on the lazy evaluators of type aliases -and type parameters instead of raising :exc:`ValueError`. diff --git a/Misc/NEWS.d/next/Library/2026-06-20-15-00-00.gh-issue-151770.dtiso0.rst b/Misc/NEWS.d/next/Library/2026-06-20-15-00-00.gh-issue-151770.dtiso0.rst deleted file mode 100644 index 10b3db8efa42b0..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-06-20-15-00-00.gh-issue-151770.dtiso0.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix :meth:`datetime.datetime.fromisoformat` raising :exc:`AssertionError` -instead of :exc:`ValueError` for an out-of-range month combined with a -``24:00`` time. diff --git a/Misc/NEWS.d/next/Library/2026-06-20-15-00-00.gh-issue-75666.Kt9xQ2.rst b/Misc/NEWS.d/next/Library/2026-06-20-15-00-00.gh-issue-75666.Kt9xQ2.rst deleted file mode 100644 index d2b2b066837bb1..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-06-20-15-00-00.gh-issue-75666.Kt9xQ2.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix a reference leak in :mod:`tkinter`: the Tcl commands created for event -callbacks are now deleted when a binding is replaced or unbound. diff --git a/Misc/NEWS.d/next/Security/2026-05-18-17-46-00.gh-issue-149835.EebFlk.rst b/Misc/NEWS.d/next/Security/2026-05-18-17-46-00.gh-issue-149835.EebFlk.rst deleted file mode 100644 index 20cab736552486..00000000000000 --- a/Misc/NEWS.d/next/Security/2026-05-18-17-46-00.gh-issue-149835.EebFlk.rst +++ /dev/null @@ -1,3 +0,0 @@ -:func:`shutil.move` now resolves symlinks via :func:`os.path.realpath` -when checking whether the destination is inside the source directory, -preventing a symlink-based bypass of that guard. diff --git a/Misc/NEWS.d/next/Security/2026-05-30-09-36-20.gh-issue-150599.nlHqU-.rst b/Misc/NEWS.d/next/Security/2026-05-30-09-36-20.gh-issue-150599.nlHqU-.rst deleted file mode 100644 index a37d86cf423f82..00000000000000 --- a/Misc/NEWS.d/next/Security/2026-05-30-09-36-20.gh-issue-150599.nlHqU-.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix a possible stack buffer overflow in :mod:`bz2` when a -:class:`bz2.BZ2Decompressor` is reused after a decompression error. -The decompressor now becomes unusable after libbz2 reports an error. diff --git a/Misc/NEWS.d/next/Security/2026-06-09-10-23-57.gh-issue-151159.91GpWQ.rst b/Misc/NEWS.d/next/Security/2026-06-09-10-23-57.gh-issue-151159.91GpWQ.rst deleted file mode 100644 index 735164c1a65ec3..00000000000000 --- a/Misc/NEWS.d/next/Security/2026-06-09-10-23-57.gh-issue-151159.91GpWQ.rst +++ /dev/null @@ -1 +0,0 @@ -Update Android and iOS installers to use OpenSSL 3.5.7. diff --git a/Misc/NEWS.d/next/Security/2026-06-09-23-38-08.gh-issue-151159.ds-9f8.rst b/Misc/NEWS.d/next/Security/2026-06-09-23-38-08.gh-issue-151159.ds-9f8.rst deleted file mode 100644 index d9251a93b40b2c..00000000000000 --- a/Misc/NEWS.d/next/Security/2026-06-09-23-38-08.gh-issue-151159.ds-9f8.rst +++ /dev/null @@ -1 +0,0 @@ -Update macOS installer to use OpenSSL 3.5.7. diff --git a/Misc/NEWS.d/next/Security/2026-06-16-14-58-02.gh-issue-151544._bexVy.rst b/Misc/NEWS.d/next/Security/2026-06-16-14-58-02.gh-issue-151544._bexVy.rst deleted file mode 100644 index 418e3b4b967794..00000000000000 --- a/Misc/NEWS.d/next/Security/2026-06-16-14-58-02.gh-issue-151544._bexVy.rst +++ /dev/null @@ -1,4 +0,0 @@ -:file:`Modules/Setup.local` is no longer used as a landmark to discover -whether Python is running in a source tree, as it could potentially affect -actual installs. The :file:`pybuilddir.txt` file is now the sole indicator -of running in a source tree. diff --git a/Misc/NEWS.d/next/Tests/2026-04-24-01-38-56.gh-issue-148853._uM4_Q.rst b/Misc/NEWS.d/next/Tests/2026-04-24-01-38-56.gh-issue-148853._uM4_Q.rst deleted file mode 100644 index 9d3fbc2590dc7a..00000000000000 --- a/Misc/NEWS.d/next/Tests/2026-04-24-01-38-56.gh-issue-148853._uM4_Q.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix tests failing on FreeBSD in test.support's -in_systemd_nspawn_sync_suppressed() due to unreadable /run directory. diff --git a/Misc/NEWS.d/next/Tests/2026-06-06-16-22-00.gh-issue-150966.7N9x5Q.rst b/Misc/NEWS.d/next/Tests/2026-06-06-16-22-00.gh-issue-150966.7N9x5Q.rst deleted file mode 100644 index 3bbb471163d64e..00000000000000 --- a/Misc/NEWS.d/next/Tests/2026-06-06-16-22-00.gh-issue-150966.7N9x5Q.rst +++ /dev/null @@ -1,2 +0,0 @@ -Avoid prematurely terminating failing live sampling profiler test targets, -which made stderr assertions flaky on ASAN buildbots. diff --git a/Misc/NEWS.d/next/Tests/2026-06-09-11-52-52.gh-issue-151130.1vslPH.rst b/Misc/NEWS.d/next/Tests/2026-06-09-11-52-52.gh-issue-151130.1vslPH.rst deleted file mode 100644 index 0333e66446ce16..00000000000000 --- a/Misc/NEWS.d/next/Tests/2026-06-09-11-52-52.gh-issue-151130.1vslPH.rst +++ /dev/null @@ -1 +0,0 @@ -Add more tests for ``PyWeakref_*`` C API. diff --git a/Misc/NEWS.d/next/Windows/2026-06-04-18-53-18.gh-issue-150836.Wci7bZ.rst b/Misc/NEWS.d/next/Windows/2026-06-04-18-53-18.gh-issue-150836.Wci7bZ.rst deleted file mode 100644 index 6497b7927db7da..00000000000000 --- a/Misc/NEWS.d/next/Windows/2026-06-04-18-53-18.gh-issue-150836.Wci7bZ.rst +++ /dev/null @@ -1 +0,0 @@ -Make installed tkinter work with Tcl/Tk 9 builds that embed the Tk script library in the Tk DLL on Windows. diff --git a/Misc/NEWS.d/next/Windows/2026-06-09-11-40-48.gh-issue-151159.JKVfme.rst b/Misc/NEWS.d/next/Windows/2026-06-09-11-40-48.gh-issue-151159.JKVfme.rst deleted file mode 100644 index ad1be115db5ce8..00000000000000 --- a/Misc/NEWS.d/next/Windows/2026-06-09-11-40-48.gh-issue-151159.JKVfme.rst +++ /dev/null @@ -1 +0,0 @@ -Updated bundled version of OpenSSL to 3.5.7. diff --git a/Misc/NEWS.d/next/Windows/2026-06-09-11-55-41.gh-issue-151163.oizZYV.rst b/Misc/NEWS.d/next/Windows/2026-06-09-11-55-41.gh-issue-151163.oizZYV.rst deleted file mode 100644 index 580a87400862c5..00000000000000 --- a/Misc/NEWS.d/next/Windows/2026-06-09-11-55-41.gh-issue-151163.oizZYV.rst +++ /dev/null @@ -1 +0,0 @@ -Updated Windows builds to include SQLite version 3.53.2. diff --git a/Misc/NEWS.d/next/macOS/2026-06-09-11-52-35.gh-issue-151163.RlPXHq.rst b/Misc/NEWS.d/next/macOS/2026-06-09-11-52-35.gh-issue-151163.RlPXHq.rst deleted file mode 100644 index 7e9bf6f4587974..00000000000000 --- a/Misc/NEWS.d/next/macOS/2026-06-09-11-52-35.gh-issue-151163.RlPXHq.rst +++ /dev/null @@ -1 +0,0 @@ -Updated macOS installer to include SQLite version 3.53.2. diff --git a/README.rst b/README.rst index ac84a8a7d054bd..56f6a71ffb24db 100644 --- a/README.rst +++ b/README.rst @@ -1,4 +1,4 @@ -This is Python version 3.15.0 beta 2 +This is Python version 3.15.0 beta 3 ==================================== .. image:: https://github.com/python/cpython/actions/workflows/build.yml/badge.svg?branch=main&event=push From b34a86f282608582b2abb61a47b37c7832ec2117 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 23 Jun 2026 14:09:29 +0200 Subject: [PATCH 402/818] [3.15] gh-151556: Show example CSV file content in the `csv` module docs (GH-151563) (cherry picked from commit 7915c4a8dd5b047b1e48b127690fb6a202a6e4ca) Co-authored-by: Lucas <lucasefernandes333@gmail.com> Co-authored-by: Stan Ulbrych <stan@python.org> --- Doc/library/csv.rst | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/Doc/library/csv.rst b/Doc/library/csv.rst index 21ecdbcc08f348..87c2d4702e7408 100644 --- a/Doc/library/csv.rst +++ b/Doc/library/csv.rst @@ -81,6 +81,13 @@ The :mod:`!csv` module defines the following functions: Spam, Spam, Spam, Spam, Spam, Baked Beans Spam, Lovely Spam, Wonderful Spam + where :file:`eggs.csv` contains: + + .. code-block:: text + + Spam Spam Spam Spam Spam |Baked Beans| + Spam |Lovely Spam| |Wonderful Spam| + .. function:: writer(csvfile, /, dialect='excel', **fmtparams) @@ -110,6 +117,13 @@ The :mod:`!csv` module defines the following functions: spamwriter.writerow(['Spam'] * 5 + ['Baked Beans']) spamwriter.writerow(['Spam', 'Lovely Spam', 'Wonderful Spam']) + which writes :file:`eggs.csv` containing: + + .. code-block:: text + + Spam Spam Spam Spam Spam |Baked Beans| + Spam |Lovely Spam| |Wonderful Spam| + .. function:: register_dialect(name, /, dialect='excel', **fmtparams) @@ -191,6 +205,14 @@ The :mod:`!csv` module defines the following classes: >>> print(row) {'first_name': 'John', 'last_name': 'Cleese'} + where :file:`names.csv` contains: + + .. code-block:: text + + first_name,last_name + Eric,Idle + John,Cleese + .. class:: DictWriter(f, fieldnames, restval='', extrasaction='raise', \ dialect='excel', *args, **kwds) @@ -228,6 +250,15 @@ The :mod:`!csv` module defines the following classes: writer.writerow({'first_name': 'Lovely', 'last_name': 'Spam'}) writer.writerow({'first_name': 'Wonderful', 'last_name': 'Spam'}) + which writes :file:`names.csv` containing: + + .. code-block:: text + + first_name,last_name + Baked,Beans + Lovely,Spam + Wonderful,Spam + .. class:: Dialect From 2b414580b6ab87a00c35fb29341f9b1640da0279 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> Date: Tue, 23 Jun 2026 16:25:59 +0300 Subject: [PATCH 403/818] Post 3.15.0b3 --- Include/patchlevel.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Include/patchlevel.h b/Include/patchlevel.h index 60664cf6862527..f597c49cfd398d 100644 --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -27,7 +27,7 @@ #define PY_RELEASE_SERIAL 3 /* Version as a string */ -#define PY_VERSION "3.15.0b3" +#define PY_VERSION "3.15.0b3+dev" /*--end constants--*/ From 4ce6bf7c8aa7725828a38981c306f214c1f29365 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 23 Jun 2026 15:46:28 +0200 Subject: [PATCH 404/818] [3.15] gh-151981: Make `tarfile._Stream.seek` break at EOF (GH-151982) (#151991) (cherry picked from commit f50bf13566189c8d0ce5a814f33eff3d89951896) Co-authored-by: Petr Viktorin <encukou@gmail.com> Co-authored-by: Stan Ulbrych <stan@python.org> --- Lib/tarfile.py | 4 +++- Lib/test/test_tarfile.py | 16 ++++++++++++++++ ...026-06-23-13-28-16.gh-issue-151981.xBHEcU.rst | 2 ++ 3 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Security/2026-06-23-13-28-16.gh-issue-151981.xBHEcU.rst diff --git a/Lib/tarfile.py b/Lib/tarfile.py index 55e4a4e0c9a29c..7660c1dbc44ba4 100644 --- a/Lib/tarfile.py +++ b/Lib/tarfile.py @@ -520,7 +520,9 @@ def seek(self, pos=0): if pos - self.pos >= 0: blocks, remainder = divmod(pos - self.pos, self.bufsize) for i in range(blocks): - self.read(self.bufsize) + data = self.read(self.bufsize) + if not data: + break self.read(remainder) else: raise StreamError("seeking backwards is not allowed") diff --git a/Lib/test/test_tarfile.py b/Lib/test/test_tarfile.py index 4be207e8cbf4e6..04c4e990a69d73 100644 --- a/Lib/test/test_tarfile.py +++ b/Lib/test/test_tarfile.py @@ -4802,6 +4802,22 @@ def valueerror_filter(tarinfo, path): with self.check_context(arc.open(errorlevel='boo!'), filtererror_filter): self.expect_exception(TypeError) # errorlevel is not int + @support.subTests('format', [tarfile.GNU_FORMAT, tarfile.PAX_FORMAT]) + def test_getmembers_big_size(self, format): + # gh-151981: A loop in seek() for streaming files tried to read the + # declared number of blocks even at EOF + tinfo = tarfile.TarInfo("huge-file") + tinfo.size = 1 << 64 + bio = io.BytesIO() + # Write header without data + bio.write(tinfo.tobuf(format)) + + # Reset & try to get contents + bio.seek(0) + with tarfile.open(fileobj=bio, mode="r|") as tar: + with self.assertRaises(tarfile.ReadError): + tar.getmembers() + class OverwriteTests(archiver_tests.OverwriteTests, unittest.TestCase): testdir = os.path.join(TEMPDIR, "testoverwrite") diff --git a/Misc/NEWS.d/next/Security/2026-06-23-13-28-16.gh-issue-151981.xBHEcU.rst b/Misc/NEWS.d/next/Security/2026-06-23-13-28-16.gh-issue-151981.xBHEcU.rst new file mode 100644 index 00000000000000..2123ab8e081b1d --- /dev/null +++ b/Misc/NEWS.d/next/Security/2026-06-23-13-28-16.gh-issue-151981.xBHEcU.rst @@ -0,0 +1,2 @@ +In :mod:`tarfile`, seeking a stream now stops when end of the stream is +reached. From 672825e2f36a57e173959b0d9d409d4560dab8df Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 23 Jun 2026 15:58:57 +0200 Subject: [PATCH 405/818] [3.15] gh-151558: Fix symlink escape via `tarfile` hardlink-extraction fallback (GH-151559) (#151997) (cherry picked from commit 27dd970bf6b17ebca7c8ed486a40ab043ed7af8f) Co-authored-by: Stan Ulbrych <stan@python.org> --- Lib/tarfile.py | 3 +++ Lib/test/test_tarfile.py | 24 +++++++++++++++++++ ...-06-10-13-08-19.gh-issue-151558.mL74i2.rst | 3 +++ 3 files changed, 30 insertions(+) create mode 100644 Misc/NEWS.d/next/Security/2026-06-10-13-08-19.gh-issue-151558.mL74i2.rst diff --git a/Lib/tarfile.py b/Lib/tarfile.py index 7660c1dbc44ba4..43d3db728cb76c 100644 --- a/Lib/tarfile.py +++ b/Lib/tarfile.py @@ -2806,6 +2806,9 @@ def makelink_with_filter(self, tarinfo, targetpath, "makelink_with_filter: if filter_function is not None, " + "extraction_root must also not be None") try: + filter_function( + unfiltered.replace(name=tarinfo.name, deep=False), + extraction_root) filtered = filter_function(unfiltered, extraction_root) except _FILTER_ERRORS as cause: raise LinkFallbackError(tarinfo, unfiltered.name) from cause diff --git a/Lib/test/test_tarfile.py b/Lib/test/test_tarfile.py index 04c4e990a69d73..447ccee6f6a519 100644 --- a/Lib/test/test_tarfile.py +++ b/Lib/test/test_tarfile.py @@ -4384,6 +4384,30 @@ def test_sneaky_hardlink_fallback(self): self.expect_file("boom", symlink_to='../../link_here') self.expect_file("c", symlink_to='b') + @symlink_test + def test_sneaky_hardlink_fallback_deep(self): + # (CVE-2026-11940) + with ArchiveMaker() as arc: + arc.add("a/b/s", symlink_to=os.path.join("..", "escape")) + arc.add("s", hardlink_to=os.path.join("a", "b", "s")) + + with self.check_context(arc.open(), 'data'): + e = self.expect_exception( + tarfile.LinkFallbackError, + "link 's' would be extracted as a copy of " + + "'a/b/s', which was rejected") + self.assertIsInstance(e.__cause__, + tarfile.LinkOutsideDestinationError) + + for filter in 'tar', 'fully_trusted': + with self.subTest(filter), self.check_context(arc.open(), filter): + if not os_helper.can_symlink(): + self.expect_file("a/") + self.expect_file("a/b/") + else: + self.expect_file("a/b/s", symlink_to=os.path.join('..', 'escape')) + self.expect_file("s", symlink_to=os.path.join('..', 'escape')) + @symlink_test def test_exfiltration_via_symlink(self): # (CVE-2025-4138) diff --git a/Misc/NEWS.d/next/Security/2026-06-10-13-08-19.gh-issue-151558.mL74i2.rst b/Misc/NEWS.d/next/Security/2026-06-10-13-08-19.gh-issue-151558.mL74i2.rst new file mode 100644 index 00000000000000..74459d5680e21a --- /dev/null +++ b/Misc/NEWS.d/next/Security/2026-06-10-13-08-19.gh-issue-151558.mL74i2.rst @@ -0,0 +1,3 @@ +Fixed an vulnerability in the :mod:`tarfile` ``data`` and ``tar`` extraction +filters where crafted archives could create a symlink pointing outside the +destination directory. This was a bypass of :cve:`2025-4330`. From 7b765a47b83d9f5155c8fc7a6e54ab86e5e61600 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 23 Jun 2026 16:46:05 +0200 Subject: [PATCH 406/818] [3.15] gh-151773: Fix NULL dereference in `PyContextVar_Set` (GH-151836) (#152009) gh-151773: Fix NULL dereference in `PyContextVar_Set` (GH-151836) (cherry picked from commit d35b1719a58c8682a22ef698e070e97661af8d14) Co-authored-by: dev <b.chouksey27@gmail.com> --- .../2026-06-21-16-00-00.gh-issue-151773.mN4kRt.rst | 2 ++ Python/context.c | 3 +++ 2 files changed, 5 insertions(+) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-21-16-00-00.gh-issue-151773.mN4kRt.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-21-16-00-00.gh-issue-151773.mN4kRt.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-21-16-00-00.gh-issue-151773.mN4kRt.rst new file mode 100644 index 00000000000000..b4193c5e15ffef --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-21-16-00-00.gh-issue-151773.mN4kRt.rst @@ -0,0 +1,2 @@ +Fix a crash in :func:`contextvars.ContextVar.set` when memory allocation +fails. diff --git a/Python/context.c b/Python/context.c index 593e6ef90037cf..4678054ff3ad74 100644 --- a/Python/context.c +++ b/Python/context.c @@ -362,6 +362,9 @@ PyContextVar_Set(PyObject *ovar, PyObject *val) Py_XINCREF(old_val); PyContextToken *tok = token_new(ctx, var, old_val); Py_XDECREF(old_val); + if (tok == NULL) { + return NULL; + } if (contextvar_set(var, val)) { Py_DECREF(tok); From 2ff445be4ea6a74b105606118ed50ab4505ee6a1 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 23 Jun 2026 17:15:00 +0200 Subject: [PATCH 407/818] [3.15] gh-151126: Add missing `PyErr_NoMemory()` in `type_from_slots_or_spec` (GH-151582) (#152016) (cherry picked from commit 7928a8b730b0334c9f97c2144ab00fe0d88f1e97) Co-authored-by: Ivy Xu <fakeshadow1337@gmail.com> Co-authored-by: Stan Ulbrych <stan@python.org> --- Misc/ACKS | 1 + Objects/typeobject.c | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Misc/ACKS b/Misc/ACKS index 38817b1698c09a..5b5df7ae11f2df 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -2144,6 +2144,7 @@ Xiang Zhang Robert Xiao Florent Xicluna Yanbo, Xie +Ivy Xu Kaisheng Xu Xinhang Xu Arnon Yaari diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 12821b134d9709..969ae450013a31 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -5488,6 +5488,7 @@ type_from_slots_or_spec( Py_ssize_t name_buf_len = strlen(it.name) + 1; _ht_tpname = PyMem_Malloc(name_buf_len); if (_ht_tpname == NULL) { + PyErr_NoMemory(); goto finally; } memcpy(_ht_tpname, it.name, name_buf_len); @@ -5774,7 +5775,7 @@ type_from_slots_or_spec( ((PyObject*)type)->ob_flags |= _Py_TYPE_REVEALED_FLAG; #endif - finally: +finally: if (PyErr_Occurred()) { Py_CLEAR(res); } From bd39eea0dbb9dc9ec04144f34498eb4e8cc61b32 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 23 Jun 2026 18:41:17 +0200 Subject: [PATCH 408/818] [3.15] gh-151596: Add missing argument 'size' to pure-Python implementation of `TextIOBase.readline` (GH-151679) (GH-151870) (cherry picked from commit 30aeeb375b8f6c1f0eec95f7af60d3d4afa37f33) Co-authored-by: saber-bit <bryanventura0324@gmail.com> --- Lib/_pyio.py | 2 +- .../next/Library/2026-06-18-23-59-46.gh-issue-151596.5ma144.rst | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2026-06-18-23-59-46.gh-issue-151596.5ma144.rst diff --git a/Lib/_pyio.py b/Lib/_pyio.py index 9739b6d37fb21b..342a50724d49fb 100644 --- a/Lib/_pyio.py +++ b/Lib/_pyio.py @@ -1928,7 +1928,7 @@ def truncate(self, pos=None): """Truncate size to pos, where pos is an int.""" self._unsupported("truncate") - def readline(self): + def readline(self, size=-1, /): """Read until newline or EOF. Returns an empty string if EOF is hit immediately. diff --git a/Misc/NEWS.d/next/Library/2026-06-18-23-59-46.gh-issue-151596.5ma144.rst b/Misc/NEWS.d/next/Library/2026-06-18-23-59-46.gh-issue-151596.5ma144.rst new file mode 100644 index 00000000000000..17ec1341142e93 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-18-23-59-46.gh-issue-151596.5ma144.rst @@ -0,0 +1 @@ +Add missing ``size`` positional argument to the pure-Python implementation of :meth:`io.TextIOBase.readline`. From 415e218ed5ff1d541803aa46ea1e69ddcda03062 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 23 Jun 2026 22:58:10 +0200 Subject: [PATCH 409/818] [3.15] gh-151842: Fix crash upon OOM in `_interpreters.capture_exception` (GH-151843) (GH-152031) (cherry picked from commit 5e0747db2f5a063657a117e88b58a20624c848d1) Co-authored-by: Amrutha <amruthamodela06@gmail.com> --- .../Library/2026-06-30-13-00-00.gh-issue-151842.OOM31g.rst | 2 ++ Modules/_interpretersmodule.c | 4 +++- Python/crossinterp.c | 2 ++ 3 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2026-06-30-13-00-00.gh-issue-151842.OOM31g.rst diff --git a/Misc/NEWS.d/next/Library/2026-06-30-13-00-00.gh-issue-151842.OOM31g.rst b/Misc/NEWS.d/next/Library/2026-06-30-13-00-00.gh-issue-151842.OOM31g.rst new file mode 100644 index 00000000000000..8a2ecf3c40032f --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-30-13-00-00.gh-issue-151842.OOM31g.rst @@ -0,0 +1,2 @@ +Fix a crash in :func:`!_interpreters.capture_exception` when +:exc:`MemoryError` happens. Patch by Amrutha Modela. diff --git a/Modules/_interpretersmodule.c b/Modules/_interpretersmodule.c index e7a91ced48f176..d024dee906ded3 100644 --- a/Modules/_interpretersmodule.c +++ b/Modules/_interpretersmodule.c @@ -1541,7 +1541,9 @@ _interpreters_capture_exception_impl(PyObject *module, PyObject *exc_arg) } finally: - _PyXI_FreeExcInfo(info); + if (info != NULL) { + _PyXI_FreeExcInfo(info); + } if (exc != exc_arg) { if (PyErr_Occurred()) { PyErr_SetRaisedException(exc); diff --git a/Python/crossinterp.c b/Python/crossinterp.c index 6b489bf03f86ec..ed77c1be646e27 100644 --- a/Python/crossinterp.c +++ b/Python/crossinterp.c @@ -1689,6 +1689,7 @@ _PyXI_NewExcInfo(PyObject *exc) } _PyXI_excinfo *info = PyMem_RawCalloc(1, sizeof(_PyXI_excinfo)); if (info == NULL) { + PyErr_NoMemory(); return NULL; } const char *failure; @@ -1709,6 +1710,7 @@ _PyXI_NewExcInfo(PyObject *exc) void _PyXI_FreeExcInfo(_PyXI_excinfo *info) { + assert(info != NULL); _PyXI_excinfo_clear(info); PyMem_RawFree(info); } From 4677e25714bae597149a6fdfd50083548b8fb400 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 24 Jun 2026 05:27:00 +0200 Subject: [PATCH 410/818] [3.15] gh-150994: _colorize: modernize typing imports (GH-151018) (#152041) gh-150994: _colorize: modernize typing imports (GH-151018) (cherry picked from commit fcda96fbf399d069d11f7e874352ad03273cf0b7) Co-authored-by: Jelle Zijlstra <jelle.zijlstra@gmail.com> --- Lib/_colorize.py | 10 ++++------ Lib/test/test__colorize.py | 2 +- .../2026-06-06-06-29-17.gh-issue-150994.I2119M.rst | 1 + .../2026-06-11-06-56-31.gh-issue-150994.gd1wVw.rst | 1 + 4 files changed, 7 insertions(+), 7 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-06-06-06-29-17.gh-issue-150994.I2119M.rst create mode 100644 Misc/NEWS.d/next/Library/2026-06-11-06-56-31.gh-issue-150994.gd1wVw.rst diff --git a/Lib/_colorize.py b/Lib/_colorize.py index 5e0c0124e597b8..27eb7f13baca97 100644 --- a/Lib/_colorize.py +++ b/Lib/_colorize.py @@ -4,14 +4,12 @@ from collections.abc import Callable, Iterator, Mapping from dataclasses import dataclass, field, Field +lazy from typing import IO, Literal, Self, ClassVar COLORIZE = True - -# types -if False: - from typing import IO, Literal, Self, ClassVar - _theme: Theme +_theme: Theme +type BackgroundStyle = Literal["dark", "light"] class ANSIColors: @@ -319,7 +317,7 @@ class LiveProfiler(ThemeSection): medal_bronze_fg: int = CursesColors.GREEN # Background style: 'dark' or 'light' - background_style: Literal["dark", "light"] = "dark" + background_style: BackgroundStyle = "dark" LiveProfilerLight = LiveProfiler( diff --git a/Lib/test/test__colorize.py b/Lib/test/test__colorize.py index 48fa52bfd5672c..c7bc6914ac1bc4 100644 --- a/Lib/test/test__colorize.py +++ b/Lib/test/test__colorize.py @@ -28,7 +28,7 @@ class TestImportTime(unittest.TestCase): @cpython_only def test_lazy_import(self): import_helper.ensure_lazy_imports( - "_colorize", {"copy", "re", "inspect"} + "_colorize", {"copy", "re", "inspect", "typing"} ) diff --git a/Misc/NEWS.d/next/Library/2026-06-06-06-29-17.gh-issue-150994.I2119M.rst b/Misc/NEWS.d/next/Library/2026-06-06-06-29-17.gh-issue-150994.I2119M.rst new file mode 100644 index 00000000000000..c4a610c24806b0 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-06-06-29-17.gh-issue-150994.I2119M.rst @@ -0,0 +1 @@ +Make the type annotations in the private ``_colorize`` module resolvable. diff --git a/Misc/NEWS.d/next/Library/2026-06-11-06-56-31.gh-issue-150994.gd1wVw.rst b/Misc/NEWS.d/next/Library/2026-06-11-06-56-31.gh-issue-150994.gd1wVw.rst new file mode 100644 index 00000000000000..005a1d99b766dc --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-11-06-56-31.gh-issue-150994.gd1wVw.rst @@ -0,0 +1 @@ +Make type annotations in the private ``_colorize`` module resolvable. From dbc9b686e02abb9af57f16184666ba9a344f8004 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 24 Jun 2026 08:32:05 +0200 Subject: [PATCH 411/818] [3.15] gh-126219: Fix crash in tkinter.Tk with non-BMP className on Tcl/Tk 8.x (GH-151980) (GH-152045) Tcl 8.x crashes when title-casing a non-BMP character during Tk initialization, so such a className is now rejected with a ValueError. (cherry picked from commit 124c7cd91be8cff76d1eec0adef65991c23c4419) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --- Lib/test/test_tkinter/test_misc.py | 27 ++++++++++++++++++- ...-06-23-13-27-14.gh-issue-126219.kOfv2g.rst | 3 +++ Modules/_tkinter.c | 14 ++++++++++ 3 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2026-06-23-13-27-14.gh-issue-126219.kOfv2g.rst diff --git a/Lib/test/test_tkinter/test_misc.py b/Lib/test/test_tkinter/test_misc.py index fba528764415ab..4a95f5550878d3 100644 --- a/Lib/test/test_tkinter/test_misc.py +++ b/Lib/test/test_tkinter/test_misc.py @@ -8,7 +8,8 @@ from test.support import os_helper from test.test_tkinter.support import setUpModule # noqa: F401 from test.test_tkinter.support import (AbstractTkTest, AbstractDefaultRootTest, - requires_tk, get_tk_patchlevel) + requires_tk, get_tk_patchlevel, + tcl_version) support.requires('gui') @@ -667,6 +668,30 @@ def test_iterable_protocol(self): widget in widget +class TkTest(AbstractTkTest, unittest.TestCase): + + def test_className(self): + # The className argument sets the class of the root window. Tk + # title-cases it: the first letter is upper-cased, the rest lower-cased. + cases = [ + ('fooBAR', 'Foobar'), + ('éÉ', 'Éé'), # small and capital E WITH ACUTE + ] + if tcl_version >= (9, 0): + # small and capital DESERET LETTER LONG I (a non-BMP script) + cases.append(('\U00010428\U00010400', '\U00010400\U00010428')) + for className, klass in cases: + root = tkinter.Tk(className=className) + try: + self.assertEqual(root.winfo_class(), klass) + finally: + root.destroy() + if tcl_version < (9, 0): + # gh-126219: title-casing a non-BMP first letter crashed Tcl 8.x; + # such a class name is now rejected. + self.assertRaises(ValueError, tkinter.Tk, className='\U00010428') + + class WinfoTest(AbstractTkTest, unittest.TestCase): def test_winfo_rgb(self): diff --git a/Misc/NEWS.d/next/Library/2026-06-23-13-27-14.gh-issue-126219.kOfv2g.rst b/Misc/NEWS.d/next/Library/2026-06-23-13-27-14.gh-issue-126219.kOfv2g.rst new file mode 100644 index 00000000000000..8cc8c64c719471 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-23-13-27-14.gh-issue-126219.kOfv2g.rst @@ -0,0 +1,3 @@ +Fixed a crash in :class:`tkinter.Tk` when *className* contains a non-BMP +character and tkinter is built against Tcl/Tk 8.x. Such a name is now +rejected with a :exc:`ValueError`. diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c index 1deff4ed44684c..466e275c5cecf0 100644 --- a/Modules/_tkinter.c +++ b/Modules/_tkinter.c @@ -3272,6 +3272,20 @@ _tkinter_create_impl(PyObject *module, const char *screenName, CHECK_STRING_LENGTH(className); CHECK_STRING_LENGTH(use); +#if TCL_MAJOR_VERSION < 9 + /* className is title-cased during Tk initialization. Tcl 8.x does not + * support non-BMP characters (encoded as 4-byte UTF-8 sequences) there + * and crashes in Tcl_UtfToTitle (see gh-126219). Reject them up front. */ + for (const unsigned char *p = (const unsigned char *)className; *p; p++) { + if (*p >= 0xF0) { + PyErr_SetString(PyExc_ValueError, + "className must not contain non-BMP characters " + "with this version of Tcl/Tk"); + return NULL; + } + } +#endif + return (PyObject *) Tkapp_New(screenName, className, interactive, wantobjects, wantTk, sync, use); From 9bd0199e5b20c9516c2d66b24b6168874f7d98d7 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 24 Jun 2026 08:38:52 +0200 Subject: [PATCH 412/818] [3.15] gh-84008: Document that the LC_NUMERIC locale affects tkinter numeric widgets (GH-152008) (GH-152049) Spinbox, Scale and ttk.Spinbox format floating-point values according to the LC_NUMERIC locale, but such values are always parsed with a period, so a comma-decimal locale breaks DoubleVar.get(). (cherry picked from commit ee78d4323c174d0281fef5e04e965cda4c46eeb7) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --- Doc/library/tkinter.rst | 18 ++++++++++++++++++ Doc/library/tkinter.ttk.rst | 3 +++ 2 files changed, 21 insertions(+) diff --git a/Doc/library/tkinter.rst b/Doc/library/tkinter.rst index 86075baadc6ad0..317bfea9babc8b 100644 --- a/Doc/library/tkinter.rst +++ b/Doc/library/tkinter.rst @@ -4903,6 +4903,9 @@ Widget classes dropped; *from* is spelled ``from_`` because :keyword:`from` is a Python keyword. + With a non-integer *resolution*, see :ref:`numeric values and the locale + <tkinter-numeric-locale>`. + .. method:: get() Return the current value of the scale. @@ -5001,6 +5004,9 @@ Widget classes text. Inherits from :class:`Widget` and :class:`XView`. + With a non-integer *increment*, see :ref:`numeric values and the locale + <tkinter-numeric-locale>`. + Many of the methods take an *index* argument identifying a character in the spinbox's string. As described in the Tk ``spinbox`` manual page, *index* may be a numeric @@ -5844,6 +5850,18 @@ Variable classes Return the value of the variable as a :class:`float`. + .. _tkinter-numeric-locale: + + .. note:: + + A floating-point value is always parsed with a period (``.``) as the + decimal separator, but :class:`Spinbox`, :class:`Scale` and + :class:`ttk.Spinbox <tkinter.ttk.Spinbox>` format it according to the + ``LC_NUMERIC`` locale. Under a locale that uses a comma they produce a + value that :meth:`get` cannot read, raising :exc:`TclError`. Set + ``LC_NUMERIC`` to a locale that uses a period (such as ``'C'``) to avoid + this. + .. class:: BooleanVar(master=None, value=None, name=None) diff --git a/Doc/library/tkinter.ttk.rst b/Doc/library/tkinter.ttk.rst index 0f5a8da1445784..70abe7bb846543 100644 --- a/Doc/library/tkinter.ttk.rst +++ b/Doc/library/tkinter.ttk.rst @@ -463,6 +463,9 @@ ttk.Spinbox .. class:: Spinbox + With a non-integer increment, see :ref:`numeric values and the locale + <tkinter-numeric-locale>`. + .. versionadded:: 3.8 .. method:: get() From f84299087fcdee0ca962db49a7a4a91461d54f18 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 24 Jun 2026 09:19:09 +0200 Subject: [PATCH 413/818] [3.15] gh-87904: Document curses classes (GH-151643) (GH-152048) Add docstrings for the curses.window, curses.error, curses.panel.panel and curses.panel.error classes. Document the panel class and its error exception in curses.panel.rst, using the real lowercase panel name. (cherry picked from commit 560ff8e2021d818555884622f6865f4a0d60756f) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --- Doc/library/curses.panel.rst | 60 ++++++++++++++++++++++++++---------- Modules/_curses_panel.c | 12 ++++++-- Modules/_cursesmodule.c | 12 +++++++- 3 files changed, 64 insertions(+), 20 deletions(-) diff --git a/Doc/library/curses.panel.rst b/Doc/library/curses.panel.rst index 2cfd522f34879a..dd345bff428ad6 100644 --- a/Doc/library/curses.panel.rst +++ b/Doc/library/curses.panel.rst @@ -16,6 +16,14 @@ displayed. Panels can be added, moved up or down in the stack, and removed. Functions --------- +The module :mod:`!curses.panel` defines the following exception: + + +.. exception:: error + + Exception raised when a curses panel library function returns an error. + + The module :mod:`!curses.panel` defines the following functions: @@ -48,73 +56,91 @@ The module :mod:`!curses.panel` defines the following functions: Panel objects ------------- -Panel objects, as returned by :func:`new_panel` above, are windows with a -stacking order. There's always a window associated with a panel which determines -the content, while the panel methods are responsible for the window's depth in -the panel stack. +.. raw:: html + + <!-- Keep the old URL fragments working (see gh-89554) --> + <span id='curses.panel.Panel.above'></span> + <span id='curses.panel.Panel.below'></span> + <span id='curses.panel.Panel.bottom'></span> + <span id='curses.panel.Panel.hidden'></span> + <span id='curses.panel.Panel.hide'></span> + <span id='curses.panel.Panel.move'></span> + <span id='curses.panel.Panel.replace'></span> + <span id='curses.panel.Panel.set_userptr'></span> + <span id='curses.panel.Panel.show'></span> + <span id='curses.panel.Panel.top'></span> + <span id='curses.panel.Panel.userptr'></span> + <span id='curses.panel.Panel.window'></span> + +.. class:: panel + + Panel objects, as returned by :func:`new_panel` above, are windows with a + stacking order. There's always a window associated with a panel which + determines the content, while the panel methods are responsible for the + window's depth in the panel stack. -Panel objects have the following methods: + Panel objects have the following methods: -.. method:: Panel.above() +.. method:: panel.above() Returns the panel above the current panel. -.. method:: Panel.below() +.. method:: panel.below() Returns the panel below the current panel. -.. method:: Panel.bottom() +.. method:: panel.bottom() Push the panel to the bottom of the stack. -.. method:: Panel.hidden() +.. method:: panel.hidden() Returns ``True`` if the panel is hidden (not visible), ``False`` otherwise. -.. method:: Panel.hide() +.. method:: panel.hide() Hide the panel. This does not delete the object, it just makes the window on screen invisible. -.. method:: Panel.move(y, x) +.. method:: panel.move(y, x) Move the panel to the screen coordinates ``(y, x)``. -.. method:: Panel.replace(win) +.. method:: panel.replace(win) Change the window associated with the panel to the window *win*. -.. method:: Panel.set_userptr(obj) +.. method:: panel.set_userptr(obj) Set the panel's user pointer to *obj*. This is used to associate an arbitrary piece of data with the panel, and can be any Python object. -.. method:: Panel.show() +.. method:: panel.show() Display the panel (which might have been hidden), placing it on top of the panel stack. -.. method:: Panel.top() +.. method:: panel.top() Push panel to the top of the stack. -.. method:: Panel.userptr() +.. method:: panel.userptr() Returns the user pointer for the panel. This might be any Python object. -.. method:: Panel.window() +.. method:: panel.window() Returns the window object associated with the panel. diff --git a/Modules/_curses_panel.c b/Modules/_curses_panel.c index 411e8187e5b447..c192ce5f05452f 100644 --- a/Modules/_curses_panel.c +++ b/Modules/_curses_panel.c @@ -672,7 +672,13 @@ static PyMethodDef PyCursesPanel_Methods[] = { /* -------------------------------------------------------*/ +PyDoc_STRVAR(PyCursesPanel_Type_doc, +"A curses panel.\n" +"\n" +"Panel objects are returned by new_panel()."); + static PyType_Slot PyCursesPanel_Type_slots[] = { + {Py_tp_doc, (void *)PyCursesPanel_Type_doc}, {Py_tp_clear, PyCursesPanel_Clear}, {Py_tp_dealloc, PyCursesPanel_Dealloc}, {Py_tp_traverse, PyCursesPanel_Traverse}, @@ -821,8 +827,10 @@ _curses_panel_exec(PyObject *mod) } /* For exception _curses_panel.error */ - state->error = PyErr_NewException( - "_curses_panel.error", NULL, NULL); + state->error = PyErr_NewExceptionWithDoc( + "_curses_panel.error", + "Exception raised when a curses panel library function returns an error.", + NULL, NULL); if (PyModule_AddObjectRef(mod, "error", state->error) < 0) { return -1; diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index 02a8e2c1b1bc10..b7195264c7f090 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -3099,7 +3099,14 @@ static PyGetSetDef PyCursesWindow_getsets[] = { {NULL, NULL, NULL, NULL } /* sentinel */ }; +PyDoc_STRVAR(PyCursesWindow_Type_doc, +"A curses window.\n" +"\n" +"Window objects are returned by initscr() and newwin(), and by the\n" +"methods that create subwindows and pads."); + static PyType_Slot PyCursesWindow_Type_slots[] = { + {Py_tp_doc, (void *)PyCursesWindow_Type_doc}, {Py_tp_methods, PyCursesWindow_methods}, {Py_tp_getset, PyCursesWindow_getsets}, {Py_tp_dealloc, PyCursesWindow_dealloc}, @@ -5560,7 +5567,10 @@ cursesmodule_exec(PyObject *module) } /* For exception curses.error */ - state->error = PyErr_NewException("_curses.error", NULL, NULL); + state->error = PyErr_NewExceptionWithDoc( + "_curses.error", + "Exception raised when a curses library function returns an error.", + NULL, NULL); if (state->error == NULL) { return -1; } From 72554b378e58955740ebce9861a4699ba8761eb8 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 24 Jun 2026 11:21:41 +0200 Subject: [PATCH 414/818] [3.15] gh-151497: Avoid huge pre-allocation for oversized tarfile extended headers (GH-151498) (GH-151977) gh-151497: Avoid huge pre-allocation for oversized tarfile extended headers (GH-151498) tarfile reads a member's extended header (a GNU long name/link or a pax header) with a single read sized by the header's size field: buf = tarfile.fileobj.read(self._block(self.size)) The size is taken from the archive and is not validated, so a ~512-byte crafted file can claim several gigabytes (or, via base-256 encoding, far more) and make read() pre-allocate that much memory -- on open/iterate, before any extraction filter runs. Read the extended-header data in bounded chunks instead, so an oversized or truncated header can no longer force a huge allocation. The bytes returned for valid archives are unchanged. (cherry picked from commit da99711d37dba3413af05207ea8b12cb06041c0f) Co-authored-by: Shardul Deshpande <iamsharduld@users.noreply.github.com> --- Lib/tarfile.py | 30 +++++++++++- Lib/test/test_tarfile.py | 47 +++++++++++++++++++ ...-06-15-15-32-36.gh-issue-151497.1cfmSV.rst | 4 ++ 3 files changed, 79 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-06-15-15-32-36.gh-issue-151497.1cfmSV.rst diff --git a/Lib/tarfile.py b/Lib/tarfile.py index 43d3db728cb76c..e4b4b24ba9b640 100644 --- a/Lib/tarfile.py +++ b/Lib/tarfile.py @@ -256,6 +256,32 @@ def copyfileobj(src, dst, length=None, exception=OSError, bufsize=None): dst.write(buf) return +# Maximum number of bytes read in a single call when reading a member's +# extended header (a GNU long name/link or a pax header). The size of such +# a header is taken from the archive and is not trustworthy, so it is read in +# bounded chunks to avoid a huge up-front allocation when a crafted or +# truncated archive claims far more data than the file actually contains +# (gh-151497). +_EXTHEADER_READ_CHUNK = 1024 * 1024 # 1 MiB + +def _safe_read(fileobj, size): + """Read up to *size* bytes from *fileobj* in bounded chunks. + + Returns the same bytes as ``fileobj.read(size)`` would (including a short + result at end of file), but limits pre-allocation, so an + oversized size field in a crafted header cannot force a huge allocation. + """ + if size <= _EXTHEADER_READ_CHUNK: + return fileobj.read(size) + chunks = [] + while size > 0: + chunk = fileobj.read(min(size, _EXTHEADER_READ_CHUNK)) + if not chunk: + break + chunks.append(chunk) + size -= len(chunk) + return b"".join(chunks) + def _safe_print(s): encoding = getattr(sys.stdout, 'encoding', None) if encoding is not None: @@ -1445,7 +1471,7 @@ def _proc_gnulong(self, tarfile): """Process the blocks that hold a GNU longname or longlink member. """ - buf = tarfile.fileobj.read(self._block(self.size)) + buf = _safe_read(tarfile.fileobj, self._block(self.size)) # Fetch the next header and process it. try: @@ -1501,7 +1527,7 @@ def _proc_pax(self, tarfile): POSIX.1-2008. """ # Read the header information. - buf = tarfile.fileobj.read(self._block(self.size)) + buf = _safe_read(tarfile.fileobj, self._block(self.size)) # A pax header stores supplemental information for either # the following file (extended) or all following files diff --git a/Lib/test/test_tarfile.py b/Lib/test/test_tarfile.py index 447ccee6f6a519..585365353069ea 100644 --- a/Lib/test/test_tarfile.py +++ b/Lib/test/test_tarfile.py @@ -550,6 +550,53 @@ def test_extractfile_attrs(self): self.assertIs(fobj.seekable(), True) +class ReadSizeRecorder(io.BytesIO): + # Records the largest size ever passed to read(), so a test can check + # that tarfile does not request far more data than the archive holds + # (which on a real file would pre-allocate it). + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.max_read_size = 0 + + def read(self, size=-1): + if size is not None and size >= 0: + self.max_read_size = max(self.max_read_size, size) + return super().read(size) + + +@support.cpython_only +class ExtendedHeaderMemoryTest(unittest.TestCase): + # gh-151497: the size of a GNU long name/link or a pax extended header is + # read from the archive and is untrusted. A crafted header can claim a + # size far larger than the file actually contains; opening such an archive + # must not try to read (and so pre-allocate) the claimed size in one go. + + def crafted_archive(self, hdrtype): + tarinfo = tarfile.TarInfo("A") + tarinfo.type = hdrtype + tarinfo.size = 0xFFFFFFFF # ~4 GiB claimed in a 512-byte header + return tarinfo.tobuf(format=tarfile.GNU_FORMAT) + + def check(self, hdrtype): + fobj = ReadSizeRecorder(self.crafted_archive(hdrtype)) + try: + with tarfile.open(fileobj=fobj, mode="r:") as tar: + tar.getmembers() + except tarfile.ReadError: + pass # a truncated header is fine; we only check the allocation + # The bogus ~4 GiB size must never reach a single read() call. + self.assertLessEqual(fobj.max_read_size, tarfile._EXTHEADER_READ_CHUNK) + + def test_gnu_longname_oversized_size(self): + self.check(tarfile.GNUTYPE_LONGNAME) + + def test_gnu_longlink_oversized_size(self): + self.check(tarfile.GNUTYPE_LONGLINK) + + def test_pax_header_oversized_size(self): + self.check(tarfile.XHDTYPE) + + class MiscReadTestBase(CommonReadTest): is_stream = False diff --git a/Misc/NEWS.d/next/Library/2026-06-15-15-32-36.gh-issue-151497.1cfmSV.rst b/Misc/NEWS.d/next/Library/2026-06-15-15-32-36.gh-issue-151497.1cfmSV.rst new file mode 100644 index 00000000000000..a4c03c9d71d761 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-15-15-32-36.gh-issue-151497.1cfmSV.rst @@ -0,0 +1,4 @@ +Opening a :mod:`tarfile` archive no longer attempts to pre-allocate a huge +buffer when a crafted or truncated member claims an oversized extended header +(a GNU long name/link or a pax header). The extended header is now read in +bounded chunks, so its size field can no longer trigger memory exhaustion. From 1ba0d6ef4c5a9c3da846e71a0b922eb86fd2b84e Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 24 Jun 2026 11:22:39 +0200 Subject: [PATCH 415/818] [3.15] GH-150605: use windows-2025 in GitHub Actions (GH-150606) (#151939) Co-authored-by: Chris Eibl <138194463+chris-eibl@users.noreply.github.com> --- .github/workflows/jit.yml | 4 ++-- .github/workflows/reusable-windows-msi.yml | 2 +- .github/workflows/reusable-windows.yml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/jit.yml b/.github/workflows/jit.yml index 66bff36fe5e90c..025ff7ecbeeaff 100644 --- a/.github/workflows/jit.yml +++ b/.github/workflows/jit.yml @@ -64,10 +64,10 @@ jobs: include: - target: i686-pc-windows-msvc/msvc architecture: Win32 - runner: windows-2025-vs2026 + runner: windows-2025 - target: x86_64-pc-windows-msvc/msvc architecture: x64 - runner: windows-2025-vs2026 + runner: windows-2025 - target: aarch64-pc-windows-msvc/msvc architecture: ARM64 runner: windows-11-arm diff --git a/.github/workflows/reusable-windows-msi.yml b/.github/workflows/reusable-windows-msi.yml index a74724323ec15f..d07b4f7f29e487 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: ${{ inputs.arch == 'arm64' && 'windows-11-arm' || 'windows-2025-vs2026' }} + runs-on: ${{ inputs.arch == 'arm64' && 'windows-11-arm' || 'windows-2025' }} timeout-minutes: 60 env: ARCH: ${{ inputs.arch }} diff --git a/.github/workflows/reusable-windows.yml b/.github/workflows/reusable-windows.yml index c6e8128884e90c..dbb192fb8819a4 100644 --- a/.github/workflows/reusable-windows.yml +++ b/.github/workflows/reusable-windows.yml @@ -26,7 +26,7 @@ env: jobs: build: name: Build and test (${{ inputs.arch }}, ${{ inputs.interpreter }}) - runs-on: ${{ inputs.arch == 'arm64' && 'windows-11-arm' || 'windows-2025-vs2026' }} + runs-on: ${{ inputs.arch == 'arm64' && 'windows-11-arm' || 'windows-2025' }} timeout-minutes: 60 env: ARCH: ${{ inputs.arch }} From 0adb386f6e68eb2e73d32e19f235d012df009528 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 24 Jun 2026 11:35:18 +0200 Subject: [PATCH 416/818] [3.15] gh-143927: Normalize all line endings (CR, CRLF, and LF) in configparser (GH-143929) (GH-152002) gh-143927: Normalize all line endings (CR, CRLF, and LF) in configparser (GH-143929) (cherry picked from commit 5858e42c539dac8394636a6e9b30472b8994851f) Co-authored-by: Seth Larson <seth@python.org> --- Lib/configparser.py | 4 +++- Lib/test/test_configparser.py | 11 +++++++++++ .../2026-01-16-11-58-19.gh-issue-143927.aviFeG.rst | 2 ++ 3 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Security/2026-01-16-11-58-19.gh-issue-143927.aviFeG.rst diff --git a/Lib/configparser.py b/Lib/configparser.py index a53ac87276445a..3c452afe8ade48 100644 --- a/Lib/configparser.py +++ b/Lib/configparser.py @@ -992,7 +992,9 @@ def _write_section(self, fp, section_name, section_items, delimiter, unnamed=Fal value = self._interpolation.before_write(self, section_name, key, value) if value is not None or not self._allow_no_value: - value = delimiter + str(value).replace('\n', '\n\t') + # Convert all possible line-endings into '\n\t' + value = (delimiter + str(value).replace('\r\n', '\n') + .replace('\r', '\n').replace('\n', '\n\t')) else: value = "" fp.write("{}{}\n".format(key, value)) diff --git a/Lib/test/test_configparser.py b/Lib/test/test_configparser.py index 8d8dd2a2bf27fb..4783943f71a109 100644 --- a/Lib/test/test_configparser.py +++ b/Lib/test/test_configparser.py @@ -526,6 +526,17 @@ def test_default_case_sensitivity(self): cf.get(self.default_section, "Foo"), "Bar", "could not locate option, expecting case-insensitive defaults") + def test_crlf_normalization(self): + cf = self.newconfig({"key1": "a\nb","key2": "a\rb", "key3": "a\r\nb", "key4": "a\r\nb"}) + buf = io.StringIO() + cf.write(buf) + cf_str = buf.getvalue() + self.assertNotIn("\r", cf_str) + self.assertNotIn("\r\n", cf_str) + self.assertEqual(cf_str.count("\n"), 10) + self.assertEqual(cf_str.count("\n\t"), 4) + self.assertTrue(cf_str.endswith("\n\n")) + def test_parse_errors(self): cf = self.newconfig() self.parse_error(cf, configparser.ParsingError, diff --git a/Misc/NEWS.d/next/Security/2026-01-16-11-58-19.gh-issue-143927.aviFeG.rst b/Misc/NEWS.d/next/Security/2026-01-16-11-58-19.gh-issue-143927.aviFeG.rst new file mode 100644 index 00000000000000..ca554997e5c396 --- /dev/null +++ b/Misc/NEWS.d/next/Security/2026-01-16-11-58-19.gh-issue-143927.aviFeG.rst @@ -0,0 +1,2 @@ +Normalize all line endings (CR, CRLF, and LF) to LF+TAB when writing +multi-line configparser values. From dcbcf09fe9543fdaba1ba9b7cfffff2e8b280e94 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 24 Jun 2026 12:35:55 +0200 Subject: [PATCH 417/818] [3.15] Capitalize first word in `unittest.mock.assert_*` docs and docstrings (GH-151951) (#152059) (cherry picked from commit a46db4f8ba4aa84e0fc5b6986c2388cae2e873ae) Co-authored-by: Hans Yu <github@shauny.anonaddy.me> --- Doc/library/unittest.mock.rst | 4 ++-- Lib/unittest/mock.py | 14 +++++++------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Doc/library/unittest.mock.rst b/Doc/library/unittest.mock.rst index 5e28a8ada595ef..cce8f2833ac5a0 100644 --- a/Doc/library/unittest.mock.rst +++ b/Doc/library/unittest.mock.rst @@ -345,7 +345,7 @@ the *new_callable* argument to :func:`patch`. .. method:: assert_any_call(*args, **kwargs) - assert the mock has been called with the specified arguments. + Assert the mock has been called with the specified arguments. The assert passes if the mock has *ever* been called, unlike :meth:`assert_called_with` and :meth:`assert_called_once_with` that @@ -360,7 +360,7 @@ the *new_callable* argument to :func:`patch`. .. method:: assert_has_calls(calls, any_order=False) - assert the mock has been called with the specified calls. + Assert the mock has been called with the specified calls. The :attr:`mock_calls` list is checked for the calls. If *any_order* is false then the calls must be diff --git a/Lib/unittest/mock.py b/Lib/unittest/mock.py index 2f6f03c7a11ae6..8cf1e5411e91f7 100644 --- a/Lib/unittest/mock.py +++ b/Lib/unittest/mock.py @@ -937,7 +937,7 @@ def _call_matcher(self, _call): return _call def assert_not_called(self): - """assert that the mock was never called. + """Assert that the mock was never called. """ if self.call_count != 0: msg = ("Expected '%s' to not have been called. Called %s times.%s" @@ -947,7 +947,7 @@ def assert_not_called(self): raise AssertionError(msg) def assert_called(self): - """assert that the mock was called at least once + """Assert that the mock was called at least once. """ if self.call_count == 0: msg = ("Expected '%s' to have been called." % @@ -955,7 +955,7 @@ def assert_called(self): raise AssertionError(msg) def assert_called_once(self): - """assert that the mock was called only once. + """Assert that the mock was called only once. """ if not self.call_count == 1: msg = ("Expected '%s' to have been called once. Called %s times.%s" @@ -965,7 +965,7 @@ def assert_called_once(self): raise AssertionError(msg) def assert_called_with(self, /, *args, **kwargs): - """assert that the last call was made with the specified arguments. + """Assert that the last call was made with the specified arguments. Raises an AssertionError if the args and keyword args passed in are different to the last call to the mock.""" @@ -987,7 +987,7 @@ def _error_message(): def assert_called_once_with(self, /, *args, **kwargs): - """assert that the mock was called exactly once and that call was + """Assert that the mock was called exactly once and that call was with the specified arguments.""" if not self.call_count == 1: msg = ("Expected '%s' to be called once. Called %s times.%s" @@ -999,7 +999,7 @@ def assert_called_once_with(self, /, *args, **kwargs): def assert_has_calls(self, calls, any_order=False): - """assert the mock has been called with the specified calls. + """Assert the mock has been called with the specified calls. The `mock_calls` list is checked for the calls. If `any_order` is False (the default) then the calls must be @@ -1044,7 +1044,7 @@ def assert_has_calls(self, calls, any_order=False): def assert_any_call(self, /, *args, **kwargs): - """assert the mock has been called with the specified arguments. + """Assert the mock has been called with the specified arguments. The assert passes if the mock has *ever* been called, unlike `assert_called_with` and `assert_called_once_with` that only pass if From bc52a01e71dfd3427928498e81615ca6078b2ee4 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 24 Jun 2026 14:00:28 +0200 Subject: [PATCH 418/818] [3.15] gh-140550: Docs additions & fixups for PEP 793 (GH-151661) (GH-152064) gh-140550: Docs additions & fixups for PEP 793 (GH-151661) (cherry picked from commit 763cc2209d69bd0bf41cbb9bded5a48ee23ca6de) Co-authored-by: Petr Viktorin <encukou@gmail.com> Co-authored-by: Peter Bierma <zintensitydev@gmail.com> --- Doc/c-api/extension-modules.rst | 32 ++++++++-- Doc/c-api/import.rst | 5 ++ Doc/howto/abi3t-migration.rst | 102 +++++++++++++++++++++++++++++++- 3 files changed, 134 insertions(+), 5 deletions(-) diff --git a/Doc/c-api/extension-modules.rst b/Doc/c-api/extension-modules.rst index 34ee86c7876ae7..879b1ec50369ff 100644 --- a/Doc/c-api/extension-modules.rst +++ b/Doc/c-api/extension-modules.rst @@ -100,11 +100,35 @@ For example, a module called ``spam`` would be defined like this:: The export hook is typically the only non-\ ``static`` item defined in the module's C source. -The hook should be kept short -- ideally, one line as above. -If you do need to use Python C API in this function, it is recommended to call -``PyABIInfo_Check(&abi_info, "modulename")`` first to raise an exception, -rather than crash, in common cases of ABI mismatch. +.. _pymodexport-api-caveats: +The hook should be kept short. +If it does more than ``return`` a static array, several caveats apply: + +- If you need to use any Python C API, it is recommended to call + :c:func:`PyABIInfo_Check` first to raise an exception, + rather than crash, in common cases of ABI mismatch. +- Code in the export hook must never rely on the :term:`GIL`: + :term:`free-threaded builds <free-threaded build>` of Python can only check + the :c:macro:`Py_mod_gil` slot (or the lack of it) after the hook returns, +- Similarly, the hook may be called in any subinterpreter, since the + :c:macro:`Py_mod_multiple_interpreters` slot (or lack of it) + is only checked after the hook returns. + +For example:: + + PyMODEXPORT_FUNC + PyModExport_modulename(void) + { + if (PyABIInfo_Check(&abi_info, "modulename") < 0) { + /* ABI mismatch. It's not safe to examine the raised exception. */ + return NULL; + } + + /* use Python API (as little as possible); don't rely on GIL */ + + return modulename_slots; + } .. note:: diff --git a/Doc/c-api/import.rst b/Doc/c-api/import.rst index ec9462931d56c2..b48cf951137e51 100644 --- a/Doc/c-api/import.rst +++ b/Doc/c-api/import.rst @@ -304,6 +304,11 @@ Importing Modules Initialization function for a module built into the interpreter. + Note that the inittab uses "``PyInit``" + :ref:`initialization functions <extension-pyinit>`; + there is currently no way to include "``PyModExport_``" + :ref:`export hooks <extension-export-hook>`. + .. c:function:: int PyImport_ExtendInittab(struct _inittab *newtab) diff --git a/Doc/howto/abi3t-migration.rst b/Doc/howto/abi3t-migration.rst index ed7a324c4af6f0..c542efbdea8dec 100644 --- a/Doc/howto/abi3t-migration.rst +++ b/Doc/howto/abi3t-migration.rst @@ -210,6 +210,8 @@ versions you support. This will ensure that nothing breaks as you are porting. +.. _abi3t-howto-modexport: + Module export hook ================== @@ -290,6 +292,104 @@ and substitute your own values. See the :c:type:`PySlot` and :c:ref:`export hook <extension-export-hook>` documentation for details on this API. +As in the example, your ``PyModExport_`` function should *only* return a +pointer to static data. +If you cannot avoid additional code, refer to the +:ref:`caveats in PyModExport documentation <pymodexport-api-caveats>`. + + +Existing slots +-------------- + +If you have a ``Py_mod_slots`` slot, check the array it refers to. +It should be a :c:type:`PyModuleDef_Slot` array like the following: + +.. code-block:: + :class: bad + + static PyObject *create_module(PyObject *spec, PyModuleDef *def) { ... } + static int my_first_module_exec(PyObject *module) { ... } + static int my_second_module_exec(PyObject *module) { ... } + + static PyModuleDef_Slot my_slots[] = { + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_create, my_module_create}, + {Py_mod_exec, my_first_module_exec}, + {Py_mod_exec, my_second_module_exec}, + {0, NULL} + }; + +``py_mod_create`` +................. + + +If you have a :c:macro:`Py_mod_create` entry, make sure the function can be +called with ``NULL`` as its second argument (instead of the +:c:type:`PyModuleDef`, which you are removing). +Often, this argument isn't used at all; you can check by renaming it: + +.. code-block:: + :class: good + + static PyObject *create_module(PyObject *spec, PyModuleDef *_unused) { ... } + +If the argument is used, find a different way to pass in the data. +Commonly, the information is static and you can refer to it directly. +(If you're reusing a single function for several different modules, consider +defining several functions instead.) + + +Multiple ``py_mod_exec`` +........................ + +If you have *more than one* :c:macro:`Py_mod_exec` entry, consolidate them: +create a new function that calls the others, and replace existing slots +with it. + +.. code-block:: + :class: good + + static int my_module_exec(PyObject *module) { + if (my_first_module_exec(module) < 0) return -1; + if (my_second_module_exec(module) < 0) return -1; + } + + static PyModuleDef_Slot my_slots[] = { + ... + /* (remove other Py_mod_exec slots) */ + ... + {Py_mod_exec, my_module_exec}, + {0, NULL} + }; + +If the functions aren't used elsewhere, you can combine their bodies instead. + + +Merging slot arrays +................... + +Optionally, when you break compatibility with Python 3.14, you may clean up +the code by moving slots into the :c:type:`PySlot` array, and converting the +definitions to :c:macro:`PySlot_DATA` and :c:macro:`PySlot_FUNC`: + +.. code-block:: + :class: good + + static PySlot my_slot_array[] = { + ... + PySlot_DATA(Py_mod_gil, Py_MOD_GIL_NOT_USED), + PySlot_DATA(Py_mod_multiple_interpreters, + Py_MOD_PER_INTERPRETER_GIL_SUPPORTED) + PySlot_FUNC(Py_mod_create, my_module_create), + PySlot_FUNC(Py_mod_exec, my_module_exec), + PySlot_END + }; + +If you do this, delete the original :c:type:`PyModuleDef_Slot` array and +its ``Py_mod_slots`` entry. + + Associated ``PyModuleDef`` -------------------------- @@ -483,7 +583,7 @@ For example, if a user makes a subclass like this: class Sub(YourCustomClass): __slots__ = ('a', 'b') -then ``Py_TYPE(obj)`` is ``YourCustomClass``, and the underlying memory may +then ``Py_TYPE(obj)`` is ``Sub``, and the underlying memory may look like this: .. code-block:: text From 6bad84d64c63facc5f93a1ea0a053f620e05cb92 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 24 Jun 2026 14:14:01 +0200 Subject: [PATCH 419/818] [3.15] gh-151814: Fix unbounded memory growth from repeated empty writes to `io.TextIOWrapper` (GH-151817) (cherry picked from commit c61307222e18bfa06691d53e3ad336c46f432de0) Co-authored-by: Stan Ulbrych <stan@python.org> --- ...-06-20-21-15-13.gh-issue-151814.OIbgsO.rst | 2 + Modules/_io/textio.c | 44 +++++++++++-------- 2 files changed, 27 insertions(+), 19 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-06-20-21-15-13.gh-issue-151814.OIbgsO.rst diff --git a/Misc/NEWS.d/next/Library/2026-06-20-21-15-13.gh-issue-151814.OIbgsO.rst b/Misc/NEWS.d/next/Library/2026-06-20-21-15-13.gh-issue-151814.OIbgsO.rst new file mode 100644 index 00000000000000..1365fb4d8edb1d --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-20-21-15-13.gh-issue-151814.OIbgsO.rst @@ -0,0 +1,2 @@ +Fix unbounded memory growth in :class:`io.TextIOWrapper` when repeatedly +writing an empty string. diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c index 1547c04cdf06af..aea21e391dd96e 100644 --- a/Modules/_io/textio.c +++ b/Modules/_io/textio.c @@ -1755,32 +1755,38 @@ _io_TextIOWrapper_write_impl(textio *self, PyObject *text) } } - if (self->pending_bytes == NULL) { - assert(self->pending_bytes_count == 0); - self->pending_bytes = b; - } - else if (!PyList_CheckExact(self->pending_bytes)) { - PyObject *list = PyList_New(2); - if (list == NULL) { + if (bytes_len > 0) { + if (self->pending_bytes == NULL) { + assert(self->pending_bytes_count == 0); + self->pending_bytes = b; + } + else if (!PyList_CheckExact(self->pending_bytes)) { + PyObject *list = PyList_New(2); + if (list == NULL) { + Py_DECREF(b); + return NULL; + } + // Since Python 3.12, allocating GC object won't trigger GC and release + // GIL. See https://github.com/python/cpython/issues/97922 + assert(!PyList_CheckExact(self->pending_bytes)); + PyList_SET_ITEM(list, 0, self->pending_bytes); + PyList_SET_ITEM(list, 1, b); + self->pending_bytes = list; + } + else { + if (PyList_Append(self->pending_bytes, b) < 0) { + Py_DECREF(b); + return NULL; + } Py_DECREF(b); - return NULL; } - // Since Python 3.12, allocating GC object won't trigger GC and release - // GIL. See https://github.com/python/cpython/issues/97922 - assert(!PyList_CheckExact(self->pending_bytes)); - PyList_SET_ITEM(list, 0, self->pending_bytes); - PyList_SET_ITEM(list, 1, b); - self->pending_bytes = list; + + self->pending_bytes_count += bytes_len; } else { - if (PyList_Append(self->pending_bytes, b) < 0) { - Py_DECREF(b); - return NULL; - } Py_DECREF(b); } - self->pending_bytes_count += bytes_len; if (self->pending_bytes_count >= self->chunk_size || needflush || text_needflush) { if (_textiowrapper_writeflush(self) < 0) From e8b34391e557b44a6f836dff2bfb61769f7b2e39 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 24 Jun 2026 14:17:41 +0200 Subject: [PATCH 420/818] [3.15] gh-151763: Fix possible crash on `CodeType` deallocation (GH-152034) (#152069) gh-151763: Fix possible crash on `CodeType` deallocation (GH-152034) (cherry picked from commit 22dd5b5b374c8eb4def7d55bb8de5928e345c73a) Co-authored-by: sobolevn <mail@sobolevn.me> --- ...-06-23-23-48-54.gh-issue-151763.Eu8pYQ.rst | 1 + Objects/codeobject.c | 20 ++++++++++++------- 2 files changed, 14 insertions(+), 7 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-23-23-48-54.gh-issue-151763.Eu8pYQ.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-23-23-48-54.gh-issue-151763.Eu8pYQ.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-23-23-48-54.gh-issue-151763.Eu8pYQ.rst new file mode 100644 index 00000000000000..d4746e992f8779 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-23-23-48-54.gh-issue-151763.Eu8pYQ.rst @@ -0,0 +1 @@ +Fixes possible crash on :class:`types.CodeType` deallocation. diff --git a/Objects/codeobject.c b/Objects/codeobject.c index 4ede8de6e8adc5..03036020b1cb1a 100644 --- a/Objects/codeobject.c +++ b/Objects/codeobject.c @@ -743,6 +743,10 @@ _PyCode_New(struct _PyCodeConstructor *con) return NULL; } +#ifdef Py_GIL_DISABLED + co->_co_unique_id = _Py_INVALID_UNIQUE_ID; +#endif + if (init_code(co, con) < 0) { Py_DECREF(co); return NULL; @@ -2449,15 +2453,17 @@ code_dealloc(PyObject *self) FT_CLEAR_WEAKREFS(self, co->co_weakreflist); free_monitoring_data(co->_co_monitoring); #ifdef Py_GIL_DISABLED - // The first element always points to the mutable bytecode at the end of - // the code object, which will be freed when the code object is freed. - for (Py_ssize_t i = 1; i < co->co_tlbc->size; i++) { - char *entry = co->co_tlbc->entries[i]; - if (entry != NULL) { - PyMem_Free(entry); + if (co->co_tlbc != NULL) { + // The first element always points to the mutable bytecode at the end of + // the code object, which will be freed when the code object is freed. + for (Py_ssize_t i = 1; i < co->co_tlbc->size; i++) { + char *entry = co->co_tlbc->entries[i]; + if (entry != NULL) { + PyMem_Free(entry); + } } + PyMem_Free(co->co_tlbc); } - PyMem_Free(co->co_tlbc); #endif PyObject_Free(co); } From c3129e692f16a8e78fb69dfcf7b07c1577232d28 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 24 Jun 2026 14:47:07 +0200 Subject: [PATCH 421/818] [3.15] gh-152020: Fix `asyncio.all_tasks()` loosing eager tasks on FT-build (GH-152022) (#152076) gh-152020: Fix `asyncio.all_tasks()` loosing eager tasks on FT-build (GH-152022) (cherry picked from commit ad2cabfccb539dd23f9a17907bd63913013cb1e3) Co-authored-by: Timofei <128279579+deadlovelll@users.noreply.github.com> Co-authored-by: Kumar Aditya <kumaraditya@python.org> --- Lib/test/test_asyncio/test_free_threading.py | 39 +++++++++++++++++++ ...-06-23-19-50-22.gh-issue-152020.DTKXjR.rst | 3 ++ Modules/_asynciomodule.c | 10 ++--- 3 files changed, 47 insertions(+), 5 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-23-19-50-22.gh-issue-152020.DTKXjR.rst diff --git a/Lib/test/test_asyncio/test_free_threading.py b/Lib/test/test_asyncio/test_free_threading.py index d874ed00bd7e7a..0e149dadd7f121 100644 --- a/Lib/test/test_asyncio/test_free_threading.py +++ b/Lib/test/test_asyncio/test_free_threading.py @@ -165,6 +165,45 @@ async def main(): loop.set_task_factory(self.factory) r.run(main()) + def test_all_tasks_from_other_thread_includes_eager_tasks(self): + # gh-152020: all_tasks() called from another thread used to drop + # eager-started tasks on free-threaded builds. + loop = asyncio.new_event_loop() + + async def wait_forever(): + await asyncio.Event().wait() + + def eager_factory(loop, coro, **kwargs): + return self.factory(loop, coro, eager_start=True, **kwargs) + + async def setup(): + loop.set_task_factory(eager_factory) + eager = loop.create_task(wait_forever(), name="EAGER") + loop.set_task_factory(None) + normal = loop.create_task(wait_forever(), name="NORMAL") + return eager, normal + + async def teardown(): + tasks = [t for t in asyncio.all_tasks() + if t is not asyncio.current_task()] + for t in tasks: + t.cancel() + await asyncio.gather(*tasks, return_exceptions=True) + + thread = threading.Thread(target=loop.run_forever) + thread.start() + try: + held = asyncio.run_coroutine_threadsafe(setup(), loop).result() + names = {t.get_name() for t in asyncio.all_tasks(loop)} + self.assertIn("NORMAL", names) + self.assertIn("EAGER", names) + del held + finally: + asyncio.run_coroutine_threadsafe(teardown(), loop).result() + loop.call_soon_threadsafe(loop.stop) + thread.join() + loop.close() + class TestPyFreeThreading(TestFreeThreading, TestCase): diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-23-19-50-22.gh-issue-152020.DTKXjR.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-23-19-50-22.gh-issue-152020.DTKXjR.rst new file mode 100644 index 00000000000000..93c716f7a6a1c8 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-23-19-50-22.gh-issue-152020.DTKXjR.rst @@ -0,0 +1,3 @@ +On the free-threaded build, :func:`asyncio.all_tasks` no longer loses +eager-started tasks when called from a thread other than the one running the +event loop. diff --git a/Modules/_asynciomodule.c b/Modules/_asynciomodule.c index 6620ee26449b16..57c8d4a41a3a0d 100644 --- a/Modules/_asynciomodule.c +++ b/Modules/_asynciomodule.c @@ -2366,6 +2366,11 @@ _asyncio_Task___init___impl(TaskObj *self, PyObject *coro, PyObject *loop, return -1; } _PyThreadStateImpl *ts = (_PyThreadStateImpl *)_PyThreadState_GET(); +#ifdef Py_GIL_DISABLED + // This is required so that _Py_TryIncref(self) + // works correctly in non-owning threads. + _PyObject_SetMaybeWeakref((PyObject *)self); +#endif if (eager_start) { PyObject *res = PyObject_CallMethodNoArgs(loop, &_Py_ID(is_running)); if (res == NULL) { @@ -2384,11 +2389,6 @@ _asyncio_Task___init___impl(TaskObj *self, PyObject *coro, PyObject *loop, if (task_call_step_soon(state, self, NULL)) { return -1; } -#ifdef Py_GIL_DISABLED - // This is required so that _Py_TryIncref(self) - // works correctly in non-owning threads. - _PyObject_SetMaybeWeakref((PyObject *)self); -#endif register_task(ts, self); return 0; } From 9fb286eae98959e095818a857400bcb022db5463 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 24 Jun 2026 16:02:44 +0200 Subject: [PATCH 422/818] [3.15] `valgrind-python.supp`: Update suppression for readline leaks (GH-151783) (#152084) `valgrind-python.supp`: Update suppression for readline leaks (GH-151783) (cherry picked from commit 28b63d301dcfb7ecff86903094b9351d92d9c31e) Co-authored-by: Stan Ulbrych <stan@python.org> --- Misc/valgrind-python.supp | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/Misc/valgrind-python.supp b/Misc/valgrind-python.supp index 8b2027cd452767..4df8a118f089b7 100644 --- a/Misc/valgrind-python.supp +++ b/Misc/valgrind-python.supp @@ -317,13 +317,8 @@ { Avoid problems w/readline doing a putenv and leaking on exit Memcheck:Leak - fun:malloc - fun:xmalloc - fun:sh_set_lines_and_columns - fun:_rl_get_screen_size - fun:_rl_init_terminal_io - obj:/lib/libreadline.so.4.3 - fun:rl_initialize + ... + fun:setup_readline } # Valgrind emits "Conditional jump or move depends on uninitialised value(s)" From 8146fa4727314cb32af5eb53bb4f4a3fa8c6fe26 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 24 Jun 2026 16:10:54 +0200 Subject: [PATCH 423/818] [3.15] gh-152060: Fix `_pydatetime.fromisoformat()` raising `AssertionError` on invalid lengths (GH-152061) (#152081) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (cherry picked from commit ff781d52d451db56e154aac35ae7f2c41b1695a4) Co-authored-by: tonghuaroot (童话) <tonghuaroot@gmail.com> --- Lib/_pydatetime.py | 3 ++- Lib/test/datetimetester.py | 1 + .../Library/2026-06-24-10-46-35.gh-issue-152060.f2asrt.rst | 3 +++ 3 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2026-06-24-10-46-35.gh-issue-152060.f2asrt.rst diff --git a/Lib/_pydatetime.py b/Lib/_pydatetime.py index c1448374402de4..db4ea8d30c7064 100644 --- a/Lib/_pydatetime.py +++ b/Lib/_pydatetime.py @@ -358,7 +358,8 @@ def _find_isoformat_datetime_separator(dtstr): def _parse_isoformat_date(dtstr): # It is assumed that this is an ASCII-only string of lengths 7, 8 or 10, # see the comment on Modules/_datetimemodule.c:_find_isoformat_datetime_separator - assert len(dtstr) in (7, 8, 10) + if len(dtstr) not in (7, 8, 10): + raise ValueError("Invalid isoformat string") year = int(dtstr[0:4]) has_sep = dtstr[4] == '-' diff --git a/Lib/test/datetimetester.py b/Lib/test/datetimetester.py index 1cbe78c1ecbfdc..e29f5e3ecb5fd4 100644 --- a/Lib/test/datetimetester.py +++ b/Lib/test/datetimetester.py @@ -3757,6 +3757,7 @@ def test_fromisoformat_fails_datetime(self): '2009-04-19T12:30:45+00:00:90', # Time zone field out from range '2009-04-19T12:30:45-00:90:00', # Time zone field out from range '2009-04-19T12:30:45-00:00:90', # Time zone field out from range + '2020-2020', # Ambiguous 9-char date portion ] for bad_str in bad_strs: diff --git a/Misc/NEWS.d/next/Library/2026-06-24-10-46-35.gh-issue-152060.f2asrt.rst b/Misc/NEWS.d/next/Library/2026-06-24-10-46-35.gh-issue-152060.f2asrt.rst new file mode 100644 index 00000000000000..6088a6b80829bb --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-24-10-46-35.gh-issue-152060.f2asrt.rst @@ -0,0 +1,3 @@ +Fix :meth:`datetime.datetime.fromisoformat` raising :exc:`AssertionError` +instead of :exc:`ValueError` for some malformed strings in the pure-Python +implementation, matching the C implementation. From c93039d453977704e63eede668c3ded485aabe5e Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 24 Jun 2026 16:15:43 +0200 Subject: [PATCH 424/818] [3.15] gh-151496: Use process groups in TraceBackend in test_dtrace (GH-152039) (#152082) gh-151496: Use process groups in TraceBackend in test_dtrace (GH-152039) Run the generic DTrace/SystemTap commands in a new process group and terminate the whole group on timeout. This prevents a forked tracer child from keeping stdout/stderr pipes open after the direct tracer process is killed. (cherry picked from commit 1785f4b35f899704df0be54cba3776906186b2b1) Co-authored-by: stratakis <cstratak@redhat.com> --- Lib/test/test_dtrace.py | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/Lib/test/test_dtrace.py b/Lib/test/test_dtrace.py index 592f59d77f9221..3de87fc704d43e 100644 --- a/Lib/test/test_dtrace.py +++ b/Lib/test/test_dtrace.py @@ -75,10 +75,13 @@ class TraceBackend: COMMAND_ARGS = [] def run_case(self, name, optimize_python=None): - actual_output = normalize_trace_output(self.trace_python( - script_file=abspath(name + self.EXTENSION), - python_file=abspath(name + ".py"), - optimize_python=optimize_python)) + try: + actual_output = normalize_trace_output(self.trace_python( + script_file=abspath(name + self.EXTENSION), + python_file=abspath(name + ".py"), + optimize_python=optimize_python)) + except subprocess.TimeoutExpired: + raise AssertionError(f"{self.COMMAND[0]} timed out") with open(abspath(name + self.EXTENSION + ".expected")) as f: expected_output = f.read().rstrip() @@ -91,12 +94,17 @@ def generate_trace_command(self, script_file, subcommand=None): command += ["-c", subcommand] return command - def trace(self, script_file, subcommand=None): + def trace(self, script_file, subcommand=None, *, timeout=None): command = self.generate_trace_command(script_file, subcommand) - stdout, _ = subprocess.Popen(command, - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT, - universal_newlines=True).communicate() + proc = create_process_group(command, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + universal_newlines=True) + try: + stdout, _ = proc.communicate(timeout=timeout) + except subprocess.TimeoutExpired: + kill_process_group(proc) + raise return stdout def trace_python(self, script_file, python_file, optimize_python=None): @@ -104,12 +112,17 @@ def trace_python(self, script_file, python_file, optimize_python=None): if optimize_python: python_flags.extend(["-O"] * optimize_python) subcommand = " ".join([sys.executable] + python_flags + [python_file]) - return self.trace(script_file, subcommand) + return self.trace(script_file, subcommand, timeout=60) def assert_usable(self): try: - output = self.trace(abspath("assert_usable" + self.EXTENSION)) + output = self.trace(abspath("assert_usable" + self.EXTENSION), + timeout=10) output = output.strip() + except subprocess.TimeoutExpired: + raise unittest.SkipTest( + f"{self.COMMAND[0]} timed out during usability check" + ) except (FileNotFoundError, NotADirectoryError, PermissionError) as fnfe: output = str(fnfe) if output != "probe: success": From d4836f4d991ce857bcfa069bcad695bed5759bf8 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 24 Jun 2026 16:40:44 +0200 Subject: [PATCH 425/818] [3.15] gh-90949: Fix copy-paste typo in pyexpat capsule API initialization (GH-151147) (#152088) (cherry picked from commit 15696a69d672567176de3230b11dfa568e8b4ef0) Co-authored-by: Stan Ulbrych <stan@python.org> --- Modules/pyexpat.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Modules/pyexpat.c b/Modules/pyexpat.c index d204b6f27d9908..da8b0fb6b483a1 100644 --- a/Modules/pyexpat.c +++ b/Modules/pyexpat.c @@ -2456,8 +2456,8 @@ pyexpat_exec(PyObject *mod) capi->SetBillionLaughsAttackProtectionActivationThreshold = XML_SetBillionLaughsAttackProtectionActivationThreshold; capi->SetBillionLaughsAttackProtectionMaximumAmplification = XML_SetBillionLaughsAttackProtectionMaximumAmplification; #else - capi->SetAllocTrackerActivationThreshold = NULL; - capi->SetAllocTrackerMaximumAmplification = NULL; + capi->SetBillionLaughsAttackProtectionActivationThreshold = NULL; + capi->SetBillionLaughsAttackProtectionMaximumAmplification = NULL; #endif /* export using capsule */ From 4e7843ea3e7d4c01ead20ded70096a819b9d3da7 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 24 Jun 2026 18:25:28 +0200 Subject: [PATCH 426/818] [3.15] gh-151763: Fix NULL dereference in `os._path_normpath()` under OOM (GH-151779) (#152096) (cherry picked from commit ce8b81fff4094bd0cfb0c57193135bfc904c0ca2) Co-authored-by: Zain Nadeem <zainnadeemzainnadeem80@gmail.com> --- Modules/posixmodule.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index b58b2af3c5f887..ce8b6d3ff4c689 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -6145,6 +6145,9 @@ os__path_normpath_impl(PyObject *module, path_t *path) else { result = PyUnicode_FromWideChar(norm_path, norm_len); } + if (result == NULL) { + return NULL; + } if (PyBytes_Check(path->object)) { Py_SETREF(result, PyUnicode_EncodeFSDefault(result)); } From 14d23fddd9d860f81b59d0f1bd01ceffb0260c9c Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 24 Jun 2026 18:53:16 +0200 Subject: [PATCH 427/818] [3.15] Re-raise unexpected exceptions instead of swallowing them in various tests (GH-152019) (#152102) (cherry picked from commit 6c3da17d1f333f6bd4c07d11e2e304159d550822) Co-authored-by: An Long <aisk@users.noreply.github.com> Co-authored-by: Stan Ulbrych <stan@python.org> --- Lib/test/test_fcntl.py | 1 + Lib/test/test_launcher.py | 1 + Lib/test/test_pathlib/test_pathlib.py | 1 + Lib/test/test_socket.py | 2 ++ 4 files changed, 5 insertions(+) diff --git a/Lib/test/test_fcntl.py b/Lib/test/test_fcntl.py index 222b69a6d250cd..f20a9d407670a9 100644 --- a/Lib/test/test_fcntl.py +++ b/Lib/test/test_fcntl.py @@ -151,6 +151,7 @@ def test_fcntl_64_bit(self): except OSError as exc: if exc.errno == errno.EINVAL: self.skipTest("F_NOTIFY not available by this environment") + raise fcntl.fcntl(fd, cmd, flags) finally: os.close(fd) diff --git a/Lib/test/test_launcher.py b/Lib/test/test_launcher.py index c522bc1c2c093c..795890bd7e4b47 100644 --- a/Lib/test/test_launcher.py +++ b/Lib/test/test_launcher.py @@ -469,6 +469,7 @@ def test_search_major_2(self): except subprocess.CalledProcessError: if not is_installed("2.7"): raise unittest.SkipTest("requires at least one Python 2.x install") + raise self.assertEqual("PythonCore", data["env.company"]) self.assertStartsWith(data["env.tag"], "2.") diff --git a/Lib/test/test_pathlib/test_pathlib.py b/Lib/test/test_pathlib/test_pathlib.py index 2cb4876f5c6400..aff66c8efedbbc 100644 --- a/Lib/test/test_pathlib/test_pathlib.py +++ b/Lib/test/test_pathlib/test_pathlib.py @@ -2870,6 +2870,7 @@ def test_is_socket_true(self): if (isinstance(e, PermissionError) or "AF_UNIX path too long" in str(e)): self.skipTest("cannot bind Unix socket: " + str(e)) + raise self.assertTrue(P.is_socket()) self.assertFalse(P.is_fifo()) self.assertFalse(P.is_file()) diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py index e80a0868546218..ea315fd45e3a04 100644 --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -1427,6 +1427,7 @@ def testIPv6toString(self): except OSError as e: if e.winerror == 10022: self.skipTest('IPv6 might not be supported') + raise f = lambda a: inet_pton(AF_INET6, a) assertInvalid = lambda a: self.assertRaises( @@ -1517,6 +1518,7 @@ def testStringToIPv6(self): except OSError as e: if e.winerror == 10022: self.skipTest('IPv6 might not be supported') + raise f = lambda a: inet_ntop(AF_INET6, a) assertInvalid = lambda a: self.assertRaises( From 2d5187116b526b3570c0010ba58f4066b6be468d Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka <storchaka@gmail.com> Date: Wed, 24 Jun 2026 21:41:27 +0300 Subject: [PATCH 428/818] [3.15] gh-86726: Improve the structure of the tkinter reference (GH-152109 (GH-152111) Add short group intros before each cluster of Misc methods. Group the Tk and Toplevel classes in a new "Toplevel widgets" section, move the Tcl() function to the module-level functions, and move the "File handlers" section into the reference. (cherry picked from commit c7faa6936e17630ec26d4e0438ae9b95561b7151) Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --- Doc/library/tkinter.rst | 356 ++++++++++++++++++++++------------------ 1 file changed, 197 insertions(+), 159 deletions(-) diff --git a/Doc/library/tkinter.rst b/Doc/library/tkinter.rst index 317bfea9babc8b..ec598976971fe6 100644 --- a/Doc/library/tkinter.rst +++ b/Doc/library/tkinter.rst @@ -129,116 +129,6 @@ the modern themed widget set and API:: from tkinter import ttk -.. class:: Tk(screenName=None, baseName=None, className='Tk', useTk=True, sync=False, use=None) - - Construct a toplevel Tk widget, which is usually the main window of an - application, and initialize a Tcl interpreter for this widget. Each - instance has its own associated Tcl interpreter. - - The :class:`Tk` class is typically instantiated using all default values. - However, the following keyword arguments are currently recognized: - - *screenName* - When given (as a string), sets the :envvar:`DISPLAY` environment - variable. (X11 only) - *baseName* - Name of the profile file. By default, *baseName* is derived from the - program name (``sys.argv[0]``). - *className* - Name of the widget class. Used as a profile file and also as the name - with which Tcl is invoked (*argv0* in *interp*). - *useTk* - If ``True``, initialize the Tk subsystem. The :func:`tkinter.Tcl() <Tcl>` - function sets this to ``False``. - *sync* - If ``True``, execute all X server commands synchronously, so that errors - are reported immediately. Can be used for debugging. (X11 only) - *use* - Specifies the *id* of the window in which to embed the application, - instead of it being created as an independent toplevel window. *id* must - be specified in the same way as the value for the -use option for - toplevel widgets (that is, it has a form like that returned by - :meth:`~Misc.winfo_id`). - - Note that on some platforms this will only work correctly if *id* refers - to a Tk frame or toplevel that has its -container option enabled. - - :class:`Tk` reads and interprets profile files, named - :file:`.{className}.tcl` and :file:`.{baseName}.tcl`, into the Tcl - interpreter and calls :func:`exec` on the contents of - :file:`.{className}.py` and :file:`.{baseName}.py`. The path for the - profile files is the :envvar:`HOME` environment variable or, if that - isn't defined, then :data:`os.curdir`. - - .. attribute:: tk - - The Tk application object created by instantiating :class:`Tk`. This - provides access to the Tcl interpreter. Each widget that is attached - the same instance of :class:`Tk` has the same value for its :attr:`tk` - attribute. - - .. attribute:: master - - The widget object that contains this widget. - For :class:`Tk`, the :attr:`!master` is :const:`None` because it is the - main window. - The terms *master* and *parent* are similar and sometimes used - interchangeably as argument names; however, calling - :meth:`~Misc.winfo_parent` returns a string of the widget name whereas - :attr:`!master` returns the object. - *parent*/*child* reflects the tree-like relationship while *master* (or - *container*)/*content* reflects the container structure. - - .. attribute:: children - - The immediate descendants of this widget as a :class:`dict` with the - child widget names as the keys and the child instance objects as the - values. - - .. method:: destroy() - - Destroy this and all descendant widgets and, for the main window, end the - connection to the underlying Tcl interpreter. - - .. method:: loadtk() - - Finish loading and initializing the Tk subsystem. - This is needed only when the interpreter was created without Tk (for - example through :func:`Tcl`); it is called automatically when *useTk* is - true. - - .. method:: readprofile(baseName, className) - - Read and source the user's profile files :file:`.{className}.tcl` and - :file:`.{baseName}.tcl` into the Tcl interpreter, and execute the - corresponding :file:`.{className}.py` and :file:`.{baseName}.py` files. - This is called during initialization; see the description of the - constructor above. - - .. method:: report_callback_exception(exc, val, tb) - - Report a callback exception. - This is called when an exception propagates out of a Tkinter callback; - *exc*, *val* and *tb* are the exception type, value and traceback as - returned by :func:`sys.exc_info`. - The default implementation prints a traceback to :data:`sys.stderr`. - It can be overridden to customize error handling, for example to display - the traceback in a dialog. - - -.. function:: Tcl(screenName=None, baseName=None, className='Tk', useTk=False) - - The :func:`Tcl` function is a factory function which creates an object much - like that created by the :class:`Tk` class, except that it does not - initialize the Tk subsystem. - This is most often useful when driving the Tcl interpreter in an environment - where one doesn't want to create extraneous toplevel windows, or where one - cannot (such as Unix/Linux systems without an X server). - An object created by the :func:`Tcl` object can have a Toplevel window - created (and the Tk subsystem initialized) by calling its :meth:`~Tk.loadtk` - method. - - The modules that provide Tk support include: :mod:`!tkinter` @@ -1069,55 +959,6 @@ wherever the image was used. The `Pillow <https://python-pillow.org/>`_ package adds support for formats such as BMP, JPEG, TIFF, and WebP, among others. -.. _tkinter-file-handlers: - -File handlers -------------- - -Tk allows you to register and unregister a callback function which will be -called from the Tk mainloop when I/O is possible on a file descriptor. -Only one handler may be registered per file descriptor. Example code:: - - import tkinter - widget = tkinter.Tk() - mask = tkinter.READABLE | tkinter.WRITABLE - widget.tk.createfilehandler(file, mask, callback) - ... - widget.tk.deletefilehandler(file) - -This feature is not available on Windows. - -Since you don't know how many bytes are available for reading, you may not -want to use the :class:`~io.BufferedIOBase` or :class:`~io.TextIOBase` -:meth:`~io.BufferedIOBase.read` or :meth:`~io.IOBase.readline` methods, -since these will insist on reading a predefined number of bytes. -For sockets, the :meth:`~socket.socket.recv` or -:meth:`~socket.socket.recvfrom` methods will work fine; for other files, -use raw reads or ``os.read(file.fileno(), maxbytecount)``. - - -.. method:: Widget.tk.createfilehandler(file, mask, func) - - Registers the file handler callback function *func*. The *file* argument - may either be an object with a :meth:`~io.IOBase.fileno` method (such as - a file or socket object), or an integer file descriptor. The *mask* - argument is an ORed combination of any of the three constants below. - The callback is called as follows:: - - callback(file, mask) - - -.. method:: Widget.tk.deletefilehandler(file) - - Unregisters a file handler. - - -.. data:: READABLE - WRITABLE - EXCEPTION - - Constants used in the *mask* arguments. - Reference --------- @@ -1460,6 +1301,9 @@ Base and mixin classes .. versionadded:: 3.15 + The methods with the ``bind`` and ``unbind`` prefixes associate event + patterns with callbacks and remove those associations. + .. method:: bind(sequence=None, func=None, add=None) Bind the event pattern *sequence* on this widget to the callable *func*. @@ -1543,6 +1387,9 @@ Base and mixin classes binding tags are set to its elements, which determines the order in which bindings are evaluated. + The methods with the ``event_`` prefix define virtual events and generate + events programmatically. + .. method:: event_add(virtual, *sequences) Associate the virtual event *virtual*, whose name has the form @@ -1577,6 +1424,9 @@ Base and mixin classes If *virtual* is given, return a tuple of the physical event sequences currently associated with it, or an empty tuple if it is not defined. + The methods with the ``after`` prefix schedule callbacks to run after a + delay or when the application is idle. + .. method:: after(ms, func=None, *args, **kw) Schedule the callable *func* to be called after *ms* milliseconds, with @@ -1685,6 +1535,9 @@ Base and mixin classes If *window* is omitted, this widget is used. This is typically used to wait for a newly created window to become visible before acting on it. + + The methods with the ``focus_`` prefix manage the keyboard focus. + .. method:: focus_set() :no-typesetting: @@ -1752,6 +1605,9 @@ Base and mixin classes See :meth:`tk_focusNext` for how the order is defined. This method is used in the default bindings for the :kbd:`Shift-Tab` key. + The methods with the ``grab_`` prefix set and query the input grab, which + directs all input events to a single widget. + .. method:: grab_set() Set a local grab on this widget. @@ -1791,6 +1647,9 @@ Base and mixin classes Return ``None`` if no grab is currently set on this widget, ``"local"`` if a local grab is set, or ``"global"`` if a global grab is set. + The methods with the ``selection_`` prefix retrieve and manage the X + selection. + .. method:: selection_clear(**kw) Clear the X selection, so that no window owns it anymore. @@ -1849,6 +1708,8 @@ Base and mixin classes The *displayof* keyword argument names a widget that determines the display to query, and defaults to this widget. + The methods with the ``clipboard_`` prefix manage the clipboard. + .. method:: clipboard_append(string, **kw) Append *string* to the Tk clipboard and claim ownership of the clipboard @@ -1883,6 +1744,9 @@ Base and mixin classes display, and defaults to the root window of the application. This is equivalent to ``selection_get(selection='CLIPBOARD')``. + The methods with the ``option_`` prefix query and modify the Tk option + database. + .. method:: option_add(pattern, value, priority=None) Add an option to the Tk option database that associates *value* with @@ -1953,6 +1817,10 @@ Base and mixin classes A true *boolean* value enables strict Motif compliance (for example, no color change when the mouse passes over a slider). Return the resulting setting. + + The methods with the ``busy_`` prefix manage the busy state of a window, + which shows a busy cursor and ignores user input. + .. method:: busy(**kw) :no-typesetting: @@ -2068,6 +1936,9 @@ Base and mixin classes .. versionadded:: 3.13 + The methods with the ``winfo_`` prefix retrieve information about windows + managed by Tk. + .. method:: winfo_atom(name, displayof=0) Return the integer identifier for the atom whose name is *name*, creating @@ -3362,6 +3233,110 @@ Base and mixin classes derive from :class:`!Widget`. +Toplevel widgets +^^^^^^^^^^^^^^^^ + +.. class:: Tk(screenName=None, baseName=None, className='Tk', useTk=True, sync=False, use=None) + + Construct a toplevel Tk widget, which is usually the main window of an + application, and initialize a Tcl interpreter for this widget. Each + instance has its own associated Tcl interpreter. + Inherits from :class:`Misc` and :class:`Wm`. + + To create a Tcl interpreter without initializing the Tk subsystem, use the + :func:`Tcl` factory function instead. + + The :class:`Tk` class is typically instantiated using all default values. + However, the following keyword arguments are currently recognized: + + *screenName* + When given (as a string), sets the :envvar:`DISPLAY` environment + variable. (X11 only) + *baseName* + Name of the profile file. By default, *baseName* is derived from the + program name (``sys.argv[0]``). + *className* + Name of the widget class. Used as a profile file and also as the name + with which Tcl is invoked (*argv0* in *interp*). + *useTk* + If ``True``, initialize the Tk subsystem. The :func:`tkinter.Tcl() <Tcl>` + function sets this to ``False``. + *sync* + If ``True``, execute all X server commands synchronously, so that errors + are reported immediately. Can be used for debugging. (X11 only) + *use* + Specifies the *id* of the window in which to embed the application, + instead of it being created as an independent toplevel window. *id* must + be specified in the same way as the value for the -use option for + toplevel widgets (that is, it has a form like that returned by + :meth:`~Misc.winfo_id`). + + Note that on some platforms this will only work correctly if *id* refers + to a Tk frame or toplevel that has its -container option enabled. + + :class:`Tk` reads and interprets profile files, named + :file:`.{className}.tcl` and :file:`.{baseName}.tcl`, into the Tcl + interpreter and calls :func:`exec` on the contents of + :file:`.{className}.py` and :file:`.{baseName}.py`. The path for the + profile files is the :envvar:`HOME` environment variable or, if that + isn't defined, then :data:`os.curdir`. + + .. attribute:: tk + + The Tk application object created by instantiating :class:`Tk`. This + provides access to the Tcl interpreter. Each widget that is attached + the same instance of :class:`Tk` has the same value for its :attr:`tk` + attribute. + + .. attribute:: master + + The widget object that contains this widget. + For :class:`Tk`, the :attr:`!master` is :const:`None` because it is the + main window. + The terms *master* and *parent* are similar and sometimes used + interchangeably as argument names; however, calling + :meth:`~Misc.winfo_parent` returns a string of the widget name whereas + :attr:`!master` returns the object. + *parent*/*child* reflects the tree-like relationship while *master* (or + *container*)/*content* reflects the container structure. + + .. attribute:: children + + The immediate descendants of this widget as a :class:`dict` with the + child widget names as the keys and the child instance objects as the + values. + + .. method:: destroy() + + Destroy this and all descendant widgets and, for the main window, end the + connection to the underlying Tcl interpreter. + + .. method:: loadtk() + + Finish loading and initializing the Tk subsystem. + This is needed only when the interpreter was created without Tk (for + example through :func:`Tcl`); it is called automatically when *useTk* is + true. + + .. method:: readprofile(baseName, className) + + Read and source the user's profile files :file:`.{className}.tcl` and + :file:`.{baseName}.tcl` into the Tcl interpreter, and execute the + corresponding :file:`.{className}.py` and :file:`.{baseName}.py` files. + This is called during initialization; see the description of the + constructor above. + + .. method:: report_callback_exception(exc, val, tb) + + Report a callback exception. + This is called when an exception propagates out of a Tkinter callback; + *exc*, *val* and *tb* are the exception type, value and traceback as + returned by :func:`sys.exc_info`. + The default implementation prints a traceback to :data:`sys.stderr`. + It can be overridden to customize error handling, for example to display + the traceback in a dialog. + + .. class:: Toplevel(master=None, cnf={}, **kw) A :class:`!Toplevel` widget is a top-level window, similar to a @@ -6306,6 +6281,18 @@ Other classes Module-level functions ^^^^^^^^^^^^^^^^^^^^^^ +.. function:: Tcl(screenName=None, baseName=None, className='Tk', useTk=False) + + The :func:`Tcl` function is a factory function which creates an object much + like that created by the :class:`Tk` class, except that it does not + initialize the Tk subsystem. + This is most often useful when driving the Tcl interpreter in an environment + where one doesn't want to create extraneous toplevel windows, or where one + cannot (such as Unix/Linux systems without an X server). + An object created by the :func:`Tcl` object can have a Toplevel window + created (and the Tk subsystem initialized) by calling its :meth:`~Tk.loadtk` + method. + .. function:: NoDefaultRoot() Inhibit the creation of an implicit default root window. @@ -6346,6 +6333,57 @@ Module-level functions Return the available image types (such as ``'photo'`` and ``'bitmap'``) in the default root's interpreter. + +.. _tkinter-file-handlers: + +File handlers +^^^^^^^^^^^^^ + +Tk allows you to register and unregister a callback function which will be +called from the Tk mainloop when I/O is possible on a file descriptor. +Only one handler may be registered per file descriptor. Example code:: + + import tkinter + widget = tkinter.Tk() + mask = tkinter.READABLE | tkinter.WRITABLE + widget.tk.createfilehandler(file, mask, callback) + ... + widget.tk.deletefilehandler(file) + +This feature is not available on Windows. + +Since you don't know how many bytes are available for reading, you may not +want to use the :class:`~io.BufferedIOBase` or :class:`~io.TextIOBase` +:meth:`~io.BufferedIOBase.read` or :meth:`~io.IOBase.readline` methods, +since these will insist on reading a predefined number of bytes. +For sockets, the :meth:`~socket.socket.recv` or +:meth:`~socket.socket.recvfrom` methods will work fine; for other files, +use raw reads or ``os.read(file.fileno(), maxbytecount)``. + + +.. method:: Widget.tk.createfilehandler(file, mask, func) + + Registers the file handler callback function *func*. The *file* argument + may either be an object with a :meth:`~io.IOBase.fileno` method (such as + a file or socket object), or an integer file descriptor. The *mask* + argument is an ORed combination of any of the three constants below. + The callback is called as follows:: + + callback(file, mask) + + +.. method:: Widget.tk.deletefilehandler(file) + + Unregisters a file handler. + + +.. data:: READABLE + WRITABLE + EXCEPTION + + Constants used in the *mask* arguments. + + Constants ^^^^^^^^^ From ab8434a3dc1a0ede89cf0bde2062af740fd4ca39 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 25 Jun 2026 00:02:21 +0200 Subject: [PATCH 429/818] [3.15] gh-105895: Add `match` and `case` doc to `help()` (GH-152113) (#152126) gh-105895: Add `match` and `case` doc to `help()` (GH-152113) (cherry picked from commit 1d55b3778c1c31549c5f914fcc451db4a3dcc501) Co-authored-by: sobolevn <mail@sobolevn.me> Co-authored-by: dzherb <zherbin.dima@yandex.ru> Co-authored-by: Stan Ulbrych <stan@python.org> --- Doc/tools/extensions/pydoc_topics.py | 1 + Lib/pydoc.py | 4 +++- Lib/test/test_pydoc/test_pydoc.py | 2 +- .../Library/2026-06-24-22-16-35.gh-issue-105895.hRkuEw.rst | 2 ++ 4 files changed, 7 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-06-24-22-16-35.gh-issue-105895.hRkuEw.rst diff --git a/Doc/tools/extensions/pydoc_topics.py b/Doc/tools/extensions/pydoc_topics.py index 35878e2d1e43e9..6c30a9c62626fb 100644 --- a/Doc/tools/extensions/pydoc_topics.py +++ b/Doc/tools/extensions/pydoc_topics.py @@ -70,6 +70,7 @@ "lambda", "lazy", "lists", + "match", "naming", "nonlocal", "numbers", diff --git a/Lib/pydoc.py b/Lib/pydoc.py index 497cc7d90a4245..1076caefd93d5e 100644 --- a/Lib/pydoc.py +++ b/Lib/pydoc.py @@ -1829,6 +1829,7 @@ class Helper: 'async': ('async', ''), 'await': ('await', ''), 'break': ('break', 'while for'), + 'case': 'match', 'class': ('class', 'CLASSES SPECIALMETHODS'), 'continue': ('continue', 'while for'), 'def': ('function', ''), @@ -1840,12 +1841,13 @@ class Helper: 'for': ('for', 'break continue while'), 'from': 'import', 'global': ('global', 'nonlocal NAMESPACES'), - 'if': ('if', 'TRUTHVALUE'), + 'if': ('if', 'TRUTHVALUE match'), 'import': ('import', 'MODULES'), 'in': ('in', 'SEQUENCEMETHODS'), 'is': 'COMPARISON', 'lambda': ('lambda', 'FUNCTIONS'), 'lazy': ('lazy', 'MODULES'), + 'match': ('match', 'if'), 'nonlocal': ('nonlocal', 'global NAMESPACES'), 'not': 'BOOLEAN', 'or': 'BOOLEAN', diff --git a/Lib/test/test_pydoc/test_pydoc.py b/Lib/test/test_pydoc/test_pydoc.py index 5cd26923f75c31..c840212938de92 100644 --- a/Lib/test/test_pydoc/test_pydoc.py +++ b/Lib/test/test_pydoc/test_pydoc.py @@ -2172,7 +2172,7 @@ def mock_getline(prompt): def test_keywords(self): self.assertEqual(sorted(pydoc.Helper.keywords), - sorted(keyword.kwlist + ['lazy'])) + sorted(keyword.kwlist + ['case', 'match', 'lazy'])) def test_interact_empty_line_continues(self): # gh-138568: test pressing Enter without input should continue in help session diff --git a/Misc/NEWS.d/next/Library/2026-06-24-22-16-35.gh-issue-105895.hRkuEw.rst b/Misc/NEWS.d/next/Library/2026-06-24-22-16-35.gh-issue-105895.hRkuEw.rst new file mode 100644 index 00000000000000..c69e6fa7d14f4d --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-24-22-16-35.gh-issue-105895.hRkuEw.rst @@ -0,0 +1,2 @@ +Add :keyword:`match` and :keyword:`case` to the list of supported topics by +:func:`help`. From 7d5e2dd398eff5ac3aa60133a09c313f6b7b6d64 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 25 Jun 2026 02:00:32 +0200 Subject: [PATCH 430/818] [3.15] gh-151929: Get boot ID, machine ID and uptime in test.pythoninfo (GH-152127) (#152134) gh-151929: Get boot ID, machine ID and uptime in test.pythoninfo (GH-152127) (cherry picked from commit 3db3bba4d1feb3a9fbfcd368d470db17b5336dc4) GHA: Run test.pythoninfo on the "Cross build Linux" job. Co-authored-by: Victor Stinner <vstinner@python.org> --- .github/workflows/build.yml | 3 ++ Lib/test/pythoninfo.py | 64 ++++++++++++++++++++++++++++++++----- 2 files changed, 59 insertions(+), 8 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e08891ea88b540..89be2d9c8ed84d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -648,6 +648,9 @@ jobs: run: ./configure --prefix="$BUILD_DIR/cross-python" --with-build-python="$BUILD_DIR/host-python/bin/python3" - name: Install cross Python run: make -j8 install + - name: Display build info + run: | + "$BUILD_DIR/cross-python/bin/python3" -m test.pythoninfo - name: Run test subset with host build run: | "$BUILD_DIR/cross-python/bin/python3" -m test test_sysconfig test_site test_embed diff --git a/Lib/test/pythoninfo.py b/Lib/test/pythoninfo.py index 7f735d75b318e7..067e218f797364 100644 --- a/Lib/test/pythoninfo.py +++ b/Lib/test/pythoninfo.py @@ -16,6 +16,15 @@ def normalize_text(text): return text.strip() +def read_first_line(filename): + # Get the first line of a text file and strip trailing spaces + try: + with open(filename, encoding="utf-8") as fp: + return fp.readline().rstrip() + except OSError: + return '' + + class PythonInfo: def __init__(self): self.info = {} @@ -1015,14 +1024,9 @@ def collect_fips(info_add): if _hashlib is not None: call_func(info_add, 'fips.openssl_fips_mode', _hashlib, 'get_fips_mode') - try: - with open("/proc/sys/crypto/fips_enabled", encoding="utf-8") as fp: - line = fp.readline().rstrip() - - if line: - info_add('fips.linux_crypto_fips_enabled', line) - except OSError: - pass + fips_enabled = read_first_line("/proc/sys/crypto/fips_enabled") + if fips_enabled: + info_add('fips.linux_crypto_fips_enabled', fips_enabled) def collect_tempfile(info_add): @@ -1040,6 +1044,49 @@ def collect_libregrtest_utils(info_add): info_add('libregrtests.build_info', ' '.join(utils.get_build_info())) +def linux_get_uptime(): + # Use CLOCK_BOOTTIME if available + import time + try: + return time.clock_gettime(time.CLOCK_BOOTTIME) + except (AttributeError, OSError): + pass + + # Otherwise, parse the first member of /proc/uptime + uptime = read_first_line("/proc/uptime") + if not uptime: + return + try: + parts = uptime.split() + if not parts: + return + return float(parts[0]) + except ValueError: + return + + +def collect_linux(info_add): + boot_id = read_first_line("/proc/sys/kernel/random/boot_id") + if boot_id: + info_add('linux.boot_id', boot_id) + + # https://www.freedesktop.org/software/systemd/man/latest/machine-id.html + machine_id = read_first_line("/etc/machine-id") + if machine_id: + info_add('linux.machine_id', machine_id) + + uptime = linux_get_uptime() + if uptime is not None: + # truncate microseconds + uptime = int(uptime) + try: + import datetime + uptime = str(datetime.timedelta(seconds=uptime)) + except ImportError: + uptime = f'{uptime} sec' + info_add('linux.uptime', uptime) + + def collect_info(info): error = False info_add = info.add @@ -1081,6 +1128,7 @@ def collect_info(info): collect_zlib, collect_zstd, collect_libregrtest_utils, + collect_linux, # Collecting from tests should be last as they have side effects. collect_test_socket, From 703c9bf976227f2d5b90e9dfe47564ab345a7383 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 25 Jun 2026 09:32:24 +0200 Subject: [PATCH 431/818] [3.15] gh-151763: Fix crash in `_interpqueues.create` on `MemoryError` (GH-152131) (#152158) gh-151763: Fix crash in `_interpqueues.create` on `MemoryError` (GH-152131) (cherry picked from commit a6c2d4ae3bd744610e1a8b70396effdabca1593d) Co-authored-by: sobolevn <mail@sobolevn.me> --- .../next/Library/2026-06-25-01-00-43.gh-issue-151763.wWeHBe.rst | 2 ++ Modules/_interpqueuesmodule.c | 1 + 2 files changed, 3 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2026-06-25-01-00-43.gh-issue-151763.wWeHBe.rst diff --git a/Misc/NEWS.d/next/Library/2026-06-25-01-00-43.gh-issue-151763.wWeHBe.rst b/Misc/NEWS.d/next/Library/2026-06-25-01-00-43.gh-issue-151763.wWeHBe.rst new file mode 100644 index 00000000000000..2f5e84027ad31b --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-25-01-00-43.gh-issue-151763.wWeHBe.rst @@ -0,0 +1,2 @@ +Fix crash in :func:`!_interpqueues.create` whe :exc:`MemoryError` +happens on queue creation. diff --git a/Modules/_interpqueuesmodule.c b/Modules/_interpqueuesmodule.c index 9979cd3457e101..d203ddba7d9c3c 100644 --- a/Modules/_interpqueuesmodule.c +++ b/Modules/_interpqueuesmodule.c @@ -1101,6 +1101,7 @@ queue_create(_queues *queues, Py_ssize_t maxsize, } int64_t qid = _queues_add(queues, queue); if (qid < 0) { + queue->alive = 0; _queue_clear(queue); GLOBAL_FREE(queue); } From cf8051b2e782e626062bf85e223b46e92b1ab2bb Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 25 Jun 2026 11:41:48 +0200 Subject: [PATCH 432/818] [3.15] gh-152079: Fix `_datetime.fromisoformat()` mishandling a sub-second tz offset (GH-152087) (#152174) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (cherry picked from commit 6f9c76d8d86997012acfa09fed05396aa9349bbf) Co-authored-by: tonghuaroot (童话) <tonghuaroot@gmail.com> Co-authored-by: Stan Ulbrych <stan@python.org> --- Lib/test/datetimetester.py | 26 +++++++++++++++++++ ...-06-24-12-00-00.gh-issue-152079.f1tzus.rst | 3 +++ Modules/_datetimemodule.c | 4 +-- 3 files changed, 31 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-06-24-12-00-00.gh-issue-152079.f1tzus.rst diff --git a/Lib/test/datetimetester.py b/Lib/test/datetimetester.py index e29f5e3ecb5fd4..28c3ab2605c45d 100644 --- a/Lib/test/datetimetester.py +++ b/Lib/test/datetimetester.py @@ -3803,6 +3803,32 @@ def test_fromisoformat_utc(self): self.assertIs(dt.tzinfo, timezone.utc) + def test_fromisoformat_utc_subsecond_offset(self): + # A UTC offset whose whole-second part is zero but with a non-zero + # microsecond part must be preserved, not collapsed to UTC. + for us in (1, -1, 999999, -999999): + with self.subTest(microseconds=us): + tz = timezone(timedelta(microseconds=us)) + dt = self.theclass(2020, 6, 15, 12, 34, 56, tzinfo=tz) + rt = self.theclass.fromisoformat(dt.isoformat()) + self.assertEqual(rt.utcoffset(), timedelta(microseconds=us)) + self.assertEqual(rt, dt) + self.assertIsNot(rt.tzinfo, timezone.utc) + + tz = timezone(timedelta(hours=5, minutes=30, seconds=15, + microseconds=123456)) + dt = self.theclass(2020, 6, 15, 12, 34, 56, tzinfo=tz) + rt = self.theclass.fromisoformat(dt.isoformat()) + self.assertEqual(rt.utcoffset(), tz.utcoffset(None)) + self.assertEqual(rt, dt) + + for tstr in ('2020-06-15T12:34:56+00:00', + '2020-06-15T12:34:56+00:00:00.000000', + '2020-06-15T12:34:56Z'): + with self.subTest(tstr=tstr): + self.assertIs(self.theclass.fromisoformat(tstr).tzinfo, + timezone.utc) + def test_fromisoformat_subclass(self): class DateTimeSubclass(self.theclass): pass diff --git a/Misc/NEWS.d/next/Library/2026-06-24-12-00-00.gh-issue-152079.f1tzus.rst b/Misc/NEWS.d/next/Library/2026-06-24-12-00-00.gh-issue-152079.f1tzus.rst new file mode 100644 index 00000000000000..492d00724f6a46 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-24-12-00-00.gh-issue-152079.f1tzus.rst @@ -0,0 +1,3 @@ +Fix :meth:`datetime.datetime.fromisoformat` in the C implementation dropping +the sub-second part of a UTC offset whose whole-second part is zero, matching +the pure-Python implementation. diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index 21bb911d0fb03f..d52969bef0070f 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -1668,8 +1668,8 @@ tzinfo_from_isoformat_results(int rv, int tzoffset, int tz_useconds) { PyObject *tzinfo; if (rv == 1) { - // Create a timezone from offset in seconds (0 returns UTC) - if (tzoffset == 0) { + // Create a timezone from the offset (a zero offset returns UTC) + if (tzoffset == 0 && tz_useconds == 0) { return Py_NewRef(CONST_UTC(NO_STATE)); } From 93ff7c31afb24d9691a428e9b4dd959e184fa202 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 25 Jun 2026 12:19:48 +0200 Subject: [PATCH 433/818] [3.15] gh-151126: Fix missing `PyErr_NoMemory` in `testinternalcapi.c` (GH-152177) (#152179) gh-151126: Fix missing `PyErr_NoMemory` in `testinternalcapi.c` (GH-152177) (cherry picked from commit a0093282ea87e112e3758e6b3eadb8b6b9770569) Co-authored-by: sobolevn <mail@sobolevn.me> --- Modules/_testinternalcapi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/_testinternalcapi.c b/Modules/_testinternalcapi.c index b8a22c439e853d..92a49d003ca735 100644 --- a/Modules/_testinternalcapi.c +++ b/Modules/_testinternalcapi.c @@ -1912,7 +1912,7 @@ pending_identify(PyObject *self, PyObject *args) PyThread_type_lock mutex = PyThread_allocate_lock(); if (mutex == NULL) { - return NULL; + return PyErr_NoMemory(); } PyThread_acquire_lock(mutex, WAIT_LOCK); /* It gets released in _pending_identify_callback(). */ From 06506197c9633f29bcd1451588481c3283841d60 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 25 Jun 2026 12:35:45 +0200 Subject: [PATCH 434/818] [3.15] gh-151126: Fix missing memory errors in `_interpretersmodule.c` (GH-151624) (#152169) gh-151126: Fix missing memory errors in `_interpretersmodule.c` (GH-151624) (cherry picked from commit 05225aa06a4c5eceaa2eb29e99c2d44d2dbfe295) Co-authored-by: stevens <lipengyu@kylinos.cn> --- .../2026-06-18-16-00-10.gh-issue-151126.tBqn6I.rst | 3 +++ Modules/_interpretersmodule.c | 5 +++-- 2 files changed, 6 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-18-16-00-10.gh-issue-151126.tBqn6I.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-18-16-00-10.gh-issue-151126.tBqn6I.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-18-16-00-10.gh-issue-151126.tBqn6I.rst new file mode 100644 index 00000000000000..d495df43ede932 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-18-16-00-10.gh-issue-151126.tBqn6I.rst @@ -0,0 +1,3 @@ +Fix a crash when sharing :class:`memoryview` objects between interpreters +fails due to running out of memory. It now raises a proper +:exc:`MemoryError`. diff --git a/Modules/_interpretersmodule.c b/Modules/_interpretersmodule.c index d024dee906ded3..15bfd35a80806c 100644 --- a/Modules/_interpretersmodule.c +++ b/Modules/_interpretersmodule.c @@ -144,7 +144,7 @@ xibufferview_from_buffer(PyTypeObject *cls, Py_buffer *view, int64_t interpid) Py_buffer *copied = PyMem_RawMalloc(sizeof(Py_buffer)); if (copied == NULL) { - return NULL; + return PyErr_NoMemory(); } /* This steals the view->obj reference */ *copied = *view; @@ -152,7 +152,7 @@ xibufferview_from_buffer(PyTypeObject *cls, Py_buffer *view, int64_t interpid) xibufferview *self = PyObject_Malloc(sizeof(xibufferview)); if (self == NULL) { PyMem_RawFree(copied); - return NULL; + return PyErr_NoMemory(); } PyObject_Init(&self->base, cls); *self = (xibufferview){ @@ -277,6 +277,7 @@ _pybuffer_shared(PyThreadState *tstate, PyObject *obj, _PyXIData_t *data) { struct xibuffer *view = PyMem_RawMalloc(sizeof(struct xibuffer)); if (view == NULL) { + PyErr_NoMemory(); return -1; } view->used = 0; From d6fd5378e33fd1e360c0dbcfe54dcbc65f06b4c1 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 25 Jun 2026 13:15:27 +0200 Subject: [PATCH 435/818] [3.15] gh-151126: Add missing `PyErr_NoMemory` in `_winapi.c` (GH-151588) (#152182) gh-151126: Add missing `PyErr_NoMemory` in `_winapi.c` (GH-151588) (cherry picked from commit a580029f1168cf87707b157865b6a6b89a77b7ad) Co-authored-by: Ivy Xu <fakeshadow1337@gmail.com> Co-authored-by: sobolevn <mail@sobolevn.me> --- .../2026-06-17-16-46-07.gh-issue-151126.vhTL0T.rst | 2 ++ Modules/_winapi.c | 4 ++++ 2 files changed, 6 insertions(+) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-17-16-46-07.gh-issue-151126.vhTL0T.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-17-16-46-07.gh-issue-151126.vhTL0T.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-17-16-46-07.gh-issue-151126.vhTL0T.rst new file mode 100644 index 00000000000000..6f2d230b1dcfc0 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-17-16-46-07.gh-issue-151126.vhTL0T.rst @@ -0,0 +1,2 @@ +Avoid possible crash in ``_winapi.c`` where a device has no memory left. Now +it properly raises a :exc:`MemoryError`. Patch by Ivy Xu. diff --git a/Modules/_winapi.c b/Modules/_winapi.c index 74644a57eb9d47..683c19e4d0c4a1 100644 --- a/Modules/_winapi.c +++ b/Modules/_winapi.c @@ -1677,6 +1677,9 @@ _winapi_GetShortPathName_impl(PyObject *module, LPCWSTR path) } PyMem_Free((void *)buffer); } + else { + PyErr_NoMemory(); + } } else { PyErr_SetFromWindowsErr(0); } @@ -2387,6 +2390,7 @@ _winapi_BatchedWaitForMultipleObjects_impl(PyObject *module, while (i < nhandles) { BatchedWaitData *data = (BatchedWaitData*)PyMem_Malloc(sizeof(BatchedWaitData)); if (!data) { + PyErr_NoMemory(); goto error; } thread_data[thread_count++] = data; From 1deffc37fd0b95f86f2ea43cedb1f9b2dc7a1d2d Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 25 Jun 2026 14:10:18 +0200 Subject: [PATCH 436/818] [3.15] gh-151678: Add tests for ttk Menubutton and OptionMenu widget options (GH-151960) (GH-151963) Decorate ttk.MenubuttonTest with add_configure_tests() and make ttk.OptionMenuTest inherit it to cover the standard widget options. (cherry picked from commit ce147129c183b934800b539c9a85b7d6bf44ae5d) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> --- Lib/test/test_ttk/test_extensions.py | 49 ++++++++++++++++++++++++++-- Lib/test/test_ttk/test_widgets.py | 1 + 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_ttk/test_extensions.py b/Lib/test/test_ttk/test_extensions.py index 2765b226e271f9..0460f1b9aa3117 100644 --- a/Lib/test/test_ttk/test_extensions.py +++ b/Lib/test/test_ttk/test_extensions.py @@ -4,10 +4,14 @@ from tkinter import ttk from test.support import requires, gc_collect from test.test_tkinter.support import setUpModule # noqa: F401 -from test.test_tkinter.support import AbstractTkTest, AbstractDefaultRootTest +from test.test_tkinter.support import (AbstractTkTest, AbstractDefaultRootTest, + get_tk_patchlevel, widget_eq) requires('gui') +from test.test_ttk import test_widgets + + class LabeledScaleTest(AbstractTkTest, unittest.TestCase): def tearDown(self): @@ -193,7 +197,7 @@ def test_resize(self): x.destroy() -class OptionMenuTest(AbstractTkTest, unittest.TestCase): +class OptionMenuTest(test_widgets.MenubuttonTest, unittest.TestCase): def setUp(self): super().setUp() @@ -203,6 +207,47 @@ def tearDown(self): del self.textvar super().tearDown() + def create(self, default='b', values=('a', 'b', 'c'), **kwargs): + return ttk.OptionMenu(self.root, self.textvar, default, *values, **kwargs) + + def test_bad_kwarg(self): + with self.assertRaisesRegex(tkinter.TclError, r"^unknown option -image$"): + ttk.OptionMenu(self.root, self.textvar, 'b', image='') + + def test_configure_class(self): + # Unlike a plain Menubutton, OptionMenu does not accept a class at + # construction, so only the read-only nature of the option is tested. + widget = self.create() + self.assertEqual(widget['class'], '') + errmsg = 'attempt to change read-only option' + if get_tk_patchlevel(self.root) < (8, 6, 0, 'beta', 3): + errmsg = 'Attempt to change read-only option' + self.checkInvalidParam(widget, 'class', 'Foo', errmsg=errmsg) + + def test_configure_style(self): + # Like Menubutton, but OptionMenu does not accept a class at + # construction, so the custom-class part of the standard test is omitted. + widget = self.create() + self.assertEqual(widget['style'], '') + self.checkInvalidParam(widget, 'style', 'Foo', + errmsg='Layout Foo not found') + style = ttk.Style(self.root) + style.configure('Custom.TMenubutton') + self.checkParam(widget, 'style', 'Custom.TMenubutton') + + def test_configure_menu(self): + # OptionMenu manages its own menu; ['menu'] returns that Menu widget. + widget = self.create() + self.assertIsInstance(widget['menu'], tkinter.Menu) + self.checkParam(widget, 'menu', widget['menu'], eq=widget_eq) + + def test_configure_text(self): + # The displayed text is governed by the textvariable. + widget = self.create() + self.textvar.set('a') + self.assertEqual(widget['text'], 'a') + self.textvar.set('c') + self.assertEqual(widget['text'], 'c') def test_widget_destroy(self): var = tkinter.StringVar(self.root) diff --git a/Lib/test/test_ttk/test_widgets.py b/Lib/test/test_ttk/test_widgets.py index a3b3c88b46edd2..aef15a7137a06e 100644 --- a/Lib/test/test_ttk/test_widgets.py +++ b/Lib/test/test_ttk/test_widgets.py @@ -789,6 +789,7 @@ def cb_test(): self.assertEqual(str(cbtn['variable']), str(cbtn2['variable'])) +@add_configure_tests(StandardTtkOptionsTests) class MenubuttonTest(AbstractLabelTest, unittest.TestCase): OPTIONS = ( 'class', 'compound', 'cursor', 'direction', From ae4c2c126b5a67bcf22f182ce818294c1e71b1c5 Mon Sep 17 00:00:00 2001 From: Victor Stinner <vstinner@python.org> Date: Thu, 25 Jun 2026 14:34:16 +0200 Subject: [PATCH 437/818] [3.15] gh-151929: Get machine ID and uptime on Windows in pythoninfo (#152146) (#152187) gh-151929: Get machine ID and uptime on Windows in pythoninfo (#152146) * Replace "linux." prefix with "system." in pythoninfo. * Add _winapi.GetTickCount64() function. (cherry picked from commit f9910519af8beecba7d65e0348f48fb70b9a31c8) --- Lib/test/pythoninfo.py | 101 +++++++++++++++++++++++++++---------- Modules/_winapi.c | 16 ++++++ Modules/clinic/_winapi.c.h | 20 +++++++- 3 files changed, 110 insertions(+), 27 deletions(-) diff --git a/Lib/test/pythoninfo.py b/Lib/test/pythoninfo.py index 067e218f797364..7f3d566e988d80 100644 --- a/Lib/test/pythoninfo.py +++ b/Lib/test/pythoninfo.py @@ -8,6 +8,9 @@ import warnings +MS_WINDOWS = (sys.platform == "win32") + + def normalize_text(text): if text is None: return None @@ -906,8 +909,30 @@ def collect_subprocess(info_add): copy_attributes(info_add, subprocess, 'subprocess.%s', ('_USE_POSIX_SPAWN',)) +def winreg_query(path): + try: + import winreg + except ImportError: + return None + + key, path = path.split('\\', 1) + sub_key, value = path.rsplit('\\', 1) + if key == "HKEY_LOCAL_MACHINE": + key = winreg.HKEY_LOCAL_MACHINE + else: + raise ValueError(f"unknown key {key!r}") + + try: + access = winreg.KEY_READ | winreg.KEY_WOW64_64KEY + with winreg.OpenKey(key, sub_key, access=access) as key_handle: + result, _ = winreg.QueryValueEx(key_handle, value) + return result + except OSError: + return None + + def collect_windows(info_add): - if sys.platform != "win32": + if not MS_WINDOWS: # Code specific to Windows return @@ -999,19 +1024,10 @@ def collect_windows(info_add): info_add('windows.ver', line) # windows.developer_mode: get AllowDevelopmentWithoutDevLicense registry - import winreg - try: - key = winreg.OpenKey( - winreg.HKEY_LOCAL_MACHINE, - r"SOFTWARE\Microsoft\Windows\CurrentVersion\AppModelUnlock") - subkey = "AllowDevelopmentWithoutDevLicense" - try: - value, value_type = winreg.QueryValueEx(key, subkey) - finally: - winreg.CloseKey(key) - except OSError: - pass - else: + value = winreg_query(r"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows" + r"\CurrentVersion\AppModelUnlock" + r"\AllowDevelopmentWithoutDevLicense") + if value is not None: info_add('windows.developer_mode', "enabled" if value else "disabled") @@ -1044,20 +1060,22 @@ def collect_libregrtest_utils(info_add): info_add('libregrtests.build_info', ' '.join(utils.get_build_info())) -def linux_get_uptime(): - # Use CLOCK_BOOTTIME if available +def uptime_boottime(): + # Use CLOCK_BOOTTIME import time try: return time.clock_gettime(time.CLOCK_BOOTTIME) except (AttributeError, OSError): - pass + return None + - # Otherwise, parse the first member of /proc/uptime - uptime = read_first_line("/proc/uptime") - if not uptime: +def uptime_linux(): + # Parse the first member of /proc/uptime + line = read_first_line("/proc/uptime") + if not line: return try: - parts = uptime.split() + parts = line.split() if not parts: return return float(parts[0]) @@ -1065,17 +1083,48 @@ def linux_get_uptime(): return +def uptime_windows(): + try: + import _winapi + except ImportError: + return None + else: + return _winapi.GetTickCount64() / 1000. + + +def get_uptime(): + for func in (uptime_boottime, uptime_linux, uptime_windows): + uptime = func() + if uptime is not None: + return uptime + return None + + +def get_machine_id(): + if MS_WINDOWS: + machine_guid = winreg_query(r"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft" + r"\Cryptography\MachineGuid") + if machine_guid: + return machine_guid + + machine_id = read_first_line("/etc/machine-id") + if machine_id: + return machine_id + + return None + + def collect_linux(info_add): boot_id = read_first_line("/proc/sys/kernel/random/boot_id") if boot_id: - info_add('linux.boot_id', boot_id) + info_add('system.boot_id', boot_id) # https://www.freedesktop.org/software/systemd/man/latest/machine-id.html - machine_id = read_first_line("/etc/machine-id") + machine_id = get_machine_id() if machine_id: - info_add('linux.machine_id', machine_id) + info_add('system.machine_id', machine_id) - uptime = linux_get_uptime() + uptime = get_uptime() if uptime is not None: # truncate microseconds uptime = int(uptime) @@ -1084,7 +1133,7 @@ def collect_linux(info_add): uptime = str(datetime.timedelta(seconds=uptime)) except ImportError: uptime = f'{uptime} sec' - info_add('linux.uptime', uptime) + info_add('system.uptime', uptime) def collect_info(info): diff --git a/Modules/_winapi.c b/Modules/_winapi.c index 683c19e4d0c4a1..1ca9c90f107bb7 100644 --- a/Modules/_winapi.c +++ b/Modules/_winapi.c @@ -3087,6 +3087,21 @@ _winapi_ReportEvent_impl(PyObject *module, HANDLE handle, } +/*[clinic input] +_winapi.GetTickCount64 + +Number of milliseconds that have elapsed since the system was started. +[clinic start generated code]*/ + +static PyObject * +_winapi_GetTickCount64_impl(PyObject *module) +/*[clinic end generated code: output=cb33c0568f0b3ed1 input=77ed6539ac7d6590]*/ +{ + ULONGLONG ticks = GetTickCount64(); + return PyLong_FromUnsignedLongLong(ticks); +} + + static PyMethodDef winapi_functions[] = { _WINAPI_CLOSEHANDLE_METHODDEF _WINAPI_CONNECTNAMEDPIPE_METHODDEF @@ -3137,6 +3152,7 @@ static PyMethodDef winapi_functions[] = { _WINAPI__MIMETYPES_READ_WINDOWS_REGISTRY_METHODDEF _WINAPI_NEEDCURRENTDIRECTORYFOREXEPATH_METHODDEF _WINAPI_COPYFILE2_METHODDEF + _WINAPI_GETTICKCOUNT64_METHODDEF {NULL, NULL} }; diff --git a/Modules/clinic/_winapi.c.h b/Modules/clinic/_winapi.c.h index 00cce91dca43b1..029c6e32e8f874 100644 --- a/Modules/clinic/_winapi.c.h +++ b/Modules/clinic/_winapi.c.h @@ -2331,7 +2331,25 @@ _winapi_ReportEvent(PyObject *module, PyObject *const *args, Py_ssize_t nargs) return return_value; } +PyDoc_STRVAR(_winapi_GetTickCount64__doc__, +"GetTickCount64($module, /)\n" +"--\n" +"\n" +"Number of milliseconds that have elapsed since the system was started."); + +#define _WINAPI_GETTICKCOUNT64_METHODDEF \ + {"GetTickCount64", (PyCFunction)_winapi_GetTickCount64, METH_NOARGS, _winapi_GetTickCount64__doc__}, + +static PyObject * +_winapi_GetTickCount64_impl(PyObject *module); + +static PyObject * +_winapi_GetTickCount64(PyObject *module, PyObject *Py_UNUSED(ignored)) +{ + return _winapi_GetTickCount64_impl(module); +} + #ifndef _WINAPI_GETSHORTPATHNAME_METHODDEF #define _WINAPI_GETSHORTPATHNAME_METHODDEF #endif /* !defined(_WINAPI_GETSHORTPATHNAME_METHODDEF) */ -/*[clinic end generated code: output=4ab94eaee93a0a90 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=daa24d62e7db458d input=a9049054013a1b77]*/ From a53c6ca1433eaf45cdb941854ff3c15791b0af15 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 25 Jun 2026 14:34:47 +0200 Subject: [PATCH 438/818] [3.15] gh-127802: Schedule removal of legacy tkinter variable trace methods in 3.17 (GH-152012) (GH-152186) The tkinter.Variable methods trace_variable(), trace(), trace_vdelete() and trace_vinfo(), deprecated since Python 3.14, are now scheduled for removal in Python 3.17. (cherry picked from commit deeae2ac07a5aaa6fc1025a048592afe3516e57e) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --- Doc/deprecations/pending-removal-in-3.17.rst | 10 ++++++++ Lib/tkinter/__init__.py | 24 ++++++++++++------- ...-06-23-17-14-04.gh-issue-127802.nGSxo6.rst | 3 +++ 3 files changed, 28 insertions(+), 9 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-06-23-17-14-04.gh-issue-127802.nGSxo6.rst diff --git a/Doc/deprecations/pending-removal-in-3.17.rst b/Doc/deprecations/pending-removal-in-3.17.rst index 8ee7f335cc9514..d6e4e81afbbd63 100644 --- a/Doc/deprecations/pending-removal-in-3.17.rst +++ b/Doc/deprecations/pending-removal-in-3.17.rst @@ -68,3 +68,13 @@ Pending removal in Python 3.17 See :pep:`PEP 688 <688#current-options>` for more details. (Contributed by Shantanu Jain in :gh:`91896`.) + +* :mod:`tkinter`: + + - The :class:`!tkinter.Variable` methods :meth:`!trace_variable`, + :meth:`!trace` (an alias of :meth:`!trace_variable`), + :meth:`!trace_vdelete` and :meth:`!trace_vinfo`, deprecated since + Python 3.14, are scheduled for removal in Python 3.17. + Use :meth:`!trace_add`, :meth:`!trace_remove` and :meth:`!trace_info` + instead. + (Contributed by Serhiy Storchaka in :gh:`120220`.) diff --git a/Lib/tkinter/__init__.py b/Lib/tkinter/__init__.py index 6875deaf5a5cca..42cd8204d0ac51 100644 --- a/Lib/tkinter/__init__.py +++ b/Lib/tkinter/__init__.py @@ -505,12 +505,14 @@ def trace_variable(self, mode, callback): Return the name of the callback. This deprecated method wraps a deprecated Tcl method removed - in Tcl 9.0. Use trace_add() instead. + in Tcl 9.0 and will be removed in Python 3.17. Use trace_add() + instead. """ import warnings warnings.warn( - "trace_variable() is deprecated and not supported with Tcl 9; " - "use trace_add() instead.", + "trace_variable() is deprecated and will be removed in Python " + "3.17; use trace_add() instead. It is not supported with " + "Tcl 9.", DeprecationWarning, stacklevel=2) cbname = self._register(callback) self._tk.call("trace", "variable", self._name, mode, cbname) @@ -525,12 +527,14 @@ def trace_vdelete(self, mode, cbname): CBNAME is the name of the callback returned from trace_variable or trace. This deprecated method wraps a deprecated Tcl method removed - in Tcl 9.0. Use trace_remove() instead. + in Tcl 9.0 and will be removed in Python 3.17. Use trace_remove() + instead. """ import warnings warnings.warn( - "trace_vdelete() is deprecated and not supported with Tcl 9; " - "use trace_remove() instead.", + "trace_vdelete() is deprecated and will be removed in Python " + "3.17; use trace_remove() instead. It is not supported with " + "Tcl 9.", DeprecationWarning, stacklevel=2) self._tk.call("trace", "vdelete", self._name, mode, cbname) cbname = self._tk.splitlist(cbname)[0] @@ -548,12 +552,14 @@ def trace_vinfo(self): """Return all trace callback information. This deprecated method wraps a deprecated Tcl method removed - in Tcl 9.0. Use trace_info() instead. + in Tcl 9.0 and will be removed in Python 3.17. Use trace_info() + instead. """ import warnings warnings.warn( - "trace_vinfo() is deprecated and not supported with Tcl 9; " - "use trace_info() instead.", + "trace_vinfo() is deprecated and will be removed in Python " + "3.17; use trace_info() instead. It is not supported with " + "Tcl 9.", DeprecationWarning, stacklevel=2) return [self._tk.splitlist(x) for x in self._tk.splitlist( self._tk.call("trace", "vinfo", self._name))] diff --git a/Misc/NEWS.d/next/Library/2026-06-23-17-14-04.gh-issue-127802.nGSxo6.rst b/Misc/NEWS.d/next/Library/2026-06-23-17-14-04.gh-issue-127802.nGSxo6.rst new file mode 100644 index 00000000000000..9484c9dbd23b2f --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-23-17-14-04.gh-issue-127802.nGSxo6.rst @@ -0,0 +1,3 @@ +The deprecated :class:`tkinter.Variable` methods :meth:`!trace_variable`, +:meth:`!trace`, :meth:`!trace_vdelete` and :meth:`!trace_vinfo` are now +scheduled for removal in Python 3.17. From 1926cf3dc9e8bae3f169687c715d548ee5c9bf83 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 25 Jun 2026 15:41:18 +0200 Subject: [PATCH 439/818] [3.15] gh-151929: Get uptime on BSD/macOS in pythoninfo (GH-152189) (#152196) gh-151929: Get uptime on BSD/macOS in pythoninfo (GH-152189) * Check sysctlbyname() function and sys/sysctl.h header in configure. * Add _testcapi.uptime_bsd() function. (cherry picked from commit b6d89edc4a13a71734ae1f1e386122bf62d68ed8) Co-authored-by: Victor Stinner <vstinner@python.org> --- Lib/test/pythoninfo.py | 27 ++++++++++++++++++++++----- Modules/_testcapimodule.c | 31 +++++++++++++++++++++++++++++++ configure | 12 ++++++++++++ configure.ac | 5 +++-- pyconfig.h.in | 6 ++++++ 5 files changed, 74 insertions(+), 7 deletions(-) diff --git a/Lib/test/pythoninfo.py b/Lib/test/pythoninfo.py index 7f3d566e988d80..a2767f3975bed2 100644 --- a/Lib/test/pythoninfo.py +++ b/Lib/test/pythoninfo.py @@ -1083,6 +1083,18 @@ def uptime_linux(): return +def uptime_bsd(): + # Get sysctlbyname("kern.boottime") + try: + import _testcapi + except ImportError: + return None + try: + return _testcapi.uptime_bsd() + except (AttributeError, OSError): + return None + + def uptime_windows(): try: import _winapi @@ -1093,7 +1105,7 @@ def uptime_windows(): def get_uptime(): - for func in (uptime_boottime, uptime_linux, uptime_windows): + for func in (uptime_boottime, uptime_linux, uptime_bsd, uptime_windows): uptime = func() if uptime is not None: return uptime @@ -1107,9 +1119,15 @@ def get_machine_id(): if machine_guid: return machine_guid - machine_id = read_first_line("/etc/machine-id") - if machine_id: - return machine_id + for filename in ( + # https://www.freedesktop.org/software/systemd/man/latest/machine-id.html + "/etc/machine-id", + # BSD + "/etc/hostid", + ): + machine_id = read_first_line(filename) + if machine_id: + return machine_id return None @@ -1119,7 +1137,6 @@ def collect_linux(info_add): if boot_id: info_add('system.boot_id', boot_id) - # https://www.freedesktop.org/software/systemd/man/latest/machine-id.html machine_id = get_machine_id() if machine_id: info_add('system.machine_id', machine_id) diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 9c90d1fc36f398..799390c2705328 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -22,6 +22,9 @@ #ifdef HAVE_SYS_WAIT_H # include <sys/wait.h> // W_STOPCODE #endif +#ifdef HAVE_SYS_SYSCTL_H +# include <sys/sysctl.h> // sysctlbyname() +#endif #ifdef bool # error "The public headers should not include <stdbool.h>, see gh-48924" @@ -2970,6 +2973,31 @@ test_soft_deprecated_macros(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(args) Py_RETURN_NONE; } + +#ifdef HAVE_SYSCTLBYNAME +static PyObject* +uptime_bsd(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(args)) +{ + struct timeval tv; + size_t size = sizeof(tv); + int res = sysctlbyname("kern.boottime", &tv, &size, NULL, 0); + if (res != 0) { + return PyErr_SetFromErrno(PyExc_OSError); + } + double boottime = (double)tv.tv_sec + tv.tv_usec * 1e-6; + + PyTime_t now_t; + if (PyTime_Time(&now_t) < 0) { + return NULL; + } + double now = PyTime_AsSecondsDouble(now_t); + + double uptime = now - boottime; + return PyFloat_FromDouble(uptime); +} +#endif + + static PyMethodDef TestMethods[] = { {"set_errno", set_errno, METH_VARARGS}, {"test_config", test_config, METH_NOARGS}, @@ -3076,6 +3104,9 @@ static PyMethodDef TestMethods[] = { {"test_thread_state_ensure_detachment", test_thread_state_ensure_detachment, METH_NOARGS}, {"test_thread_state_ensure_detached_gilstate", test_thread_state_ensure_detached_gilstate, METH_NOARGS}, {"test_thread_state_release_with_destructor", test_thread_state_release_with_destructor, METH_NOARGS}, +#ifdef HAVE_SYSCTLBYNAME + {"uptime_bsd", uptime_bsd, METH_NOARGS}, +#endif {NULL, NULL} /* sentinel */ }; diff --git a/configure b/configure index e60a71cff469bc..a296f76a030aaa 100755 --- a/configure +++ b/configure @@ -12093,6 +12093,12 @@ if test "x$ac_cv_header_sys_syscall_h" = xyes then : printf "%s\n" "#define HAVE_SYS_SYSCALL_H 1" >>confdefs.h +fi +ac_fn_c_check_header_compile "$LINENO" "sys/sysctl.h" "ac_cv_header_sys_sysctl_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_sysctl_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_SYSCTL_H 1" >>confdefs.h + fi ac_fn_c_check_header_compile "$LINENO" "sys/sysmacros.h" "ac_cv_header_sys_sysmacros_h" "$ac_includes_default" if test "x$ac_cv_header_sys_sysmacros_h" = xyes @@ -20966,6 +20972,12 @@ if test "x$ac_cv_func_sysconf" = xyes then : printf "%s\n" "#define HAVE_SYSCONF 1" >>confdefs.h +fi +ac_fn_c_check_func "$LINENO" "sysctlbyname" "ac_cv_func_sysctlbyname" +if test "x$ac_cv_func_sysctlbyname" = xyes +then : + printf "%s\n" "#define HAVE_SYSCTLBYNAME 1" >>confdefs.h + fi ac_fn_c_check_func "$LINENO" "tcgetpgrp" "ac_cv_func_tcgetpgrp" if test "x$ac_cv_func_tcgetpgrp" = xyes diff --git a/configure.ac b/configure.ac index c6485093032439..f7931cfab580b3 100644 --- a/configure.ac +++ b/configure.ac @@ -3159,7 +3159,8 @@ AC_CHECK_HEADERS([ \ sys/endian.h sys/epoll.h sys/event.h sys/eventfd.h sys/file.h sys/ioctl.h sys/kern_control.h \ sys/loadavg.h sys/lock.h sys/memfd.h sys/mkdev.h sys/mman.h sys/modem.h sys/param.h sys/pidfd.h sys/poll.h \ sys/random.h sys/resource.h sys/select.h sys/sendfile.h sys/socket.h sys/soundcard.h sys/stat.h \ - sys/statvfs.h sys/sys_domain.h sys/syscall.h sys/sysmacros.h sys/termio.h sys/time.h sys/times.h sys/timerfd.h \ + sys/statvfs.h sys/sys_domain.h sys/syscall.h sys/sysctl.h \ + sys/sysmacros.h sys/termio.h sys/time.h sys/times.h sys/timerfd.h \ sys/types.h sys/uio.h sys/un.h sys/utsname.h sys/wait.h sys/xattr.h sysexits.h syslog.h \ termios.h util.h utime.h utmp.h \ ]) @@ -5496,7 +5497,7 @@ AC_CHECK_FUNCS([ \ setresuid setreuid setsid setuid setvbuf shutdown sigaction sigaltstack \ sigfillset siginterrupt sigpending sigrelse sigtimedwait sigwait \ sigwaitinfo snprintf splice strftime strlcpy strsignal symlinkat sync \ - sysconf tcgetpgrp tcsetpgrp tempnam timegm times tmpfile \ + sysconf sysctlbyname tcgetpgrp tcsetpgrp tempnam timegm times tmpfile \ tmpnam tmpnam_r truncate ttyname_r umask uname unlinkat unlockpt utimensat utimes vfork \ wait wait3 wait4 waitid waitpid wcscoll wcsftime wcsxfrm wmemcmp writev \ ]) diff --git a/pyconfig.h.in b/pyconfig.h.in index f26c67644d5e5d..318a9e1ba06364 100644 --- a/pyconfig.h.in +++ b/pyconfig.h.in @@ -1387,6 +1387,9 @@ /* Define to 1 if you have the 'sysconf' function. */ #undef HAVE_SYSCONF +/* Define to 1 if you have the 'sysctlbyname' function. */ +#undef HAVE_SYSCTLBYNAME + /* Define to 1 if you have the <sysexits.h> header file. */ #undef HAVE_SYSEXITS_H @@ -1491,6 +1494,9 @@ /* Define to 1 if you have the <sys/syscall.h> header file. */ #undef HAVE_SYS_SYSCALL_H +/* Define to 1 if you have the <sys/sysctl.h> header file. */ +#undef HAVE_SYS_SYSCTL_H + /* Define to 1 if you have the <sys/sysmacros.h> header file. */ #undef HAVE_SYS_SYSMACROS_H From 06e6515e36ce0e187b60e3700a1f91b0ea64a1e1 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 25 Jun 2026 15:58:50 +0200 Subject: [PATCH 440/818] [3.15] gh-152168: Don't skip `test_bigmem` if `_testcapi` is missing (GH-152171) (#152198) (cherry picked from commit 6a82832a0bd12ff6154fcfcccc3b7b5644eab0e8) Co-authored-by: Shahar Naveh <50263213+ShaharNaveh@users.noreply.github.com> --- Lib/test/test_bigmem.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_bigmem.py b/Lib/test/test_bigmem.py index 6d0879ad65d53c..7f53379a952dfc 100644 --- a/Lib/test/test_bigmem.py +++ b/Lib/test/test_bigmem.py @@ -10,7 +10,6 @@ from test import support from test.support import bigmemtest, _1G, _2G, _4G, import_helper -_testcapi = import_helper.import_module('_testcapi') import unittest import operator @@ -1264,6 +1263,7 @@ class ImmortalityTest(unittest.TestCase): def test_stickiness(self, size): """Check that immortality is "sticky", so that once an object is immortal it remains so.""" + _testcapi = import_helper.import_module('_testcapi') if size < _2G: # Not enough memory to cause immortality on overflow return From 0222238e3a54b3f4955334e7dc28a572dcf07c20 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 25 Jun 2026 16:02:49 +0200 Subject: [PATCH 441/818] [3.15] Don't require `_testcapi` for `test_code` (GH-152185) (#152202) (cherry picked from commit 11c241e1a8a71b5f25a304b1f428467b746f5d43) Co-authored-by: Shahar Naveh <50263213+ShaharNaveh@users.noreply.github.com> Co-authored-by: Stan Ulbrych <stan@python.org> --- Lib/test/test_code.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_code.py b/Lib/test/test_code.py index 3588872ed23ac4..657e70a92f09b9 100644 --- a/Lib/test/test_code.py +++ b/Lib/test/test_code.py @@ -215,7 +215,6 @@ from test.support import threading_helper, import_helper from test.support.bytecode_helper import instructions_with_positions from opcode import opmap, opname -from _testcapi import code_offset_to_line try: import _testinternalcapi except ModuleNotFoundError: @@ -1491,6 +1490,8 @@ async def async_func(): rc, out, err = assert_python_ok('-OO', '-c', code) def test_co_branches(self): + _testcapi = import_helper.import_module("_testcapi") + code_offset_to_line = _testcapi.code_offset_to_line def get_line_branches(func): code = func.__code__ From eaf4d7311292c67061cae117808e14216ca969df Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 25 Jun 2026 16:36:04 +0200 Subject: [PATCH 442/818] [3.15] gh-148825: Fix build error if specialization is disabled (GH-148826) (#152206) gh-148825: Fix build error if specialization is disabled (GH-148826) (cherry picked from commit 56ae0b8e4f78c612f7b3095cd1c936e54ee0db5f) Co-authored-by: Marc Mueller <30130371+cdce8p@users.noreply.github.com> --- .../2026-04-21-15-07-03.gh-issue-148825.AbJzmZ.rst | 1 + Python/specialize.c | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-04-21-15-07-03.gh-issue-148825.AbJzmZ.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-04-21-15-07-03.gh-issue-148825.AbJzmZ.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-04-21-15-07-03.gh-issue-148825.AbJzmZ.rst new file mode 100644 index 00000000000000..5cf727b5d91fad --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-04-21-15-07-03.gh-issue-148825.AbJzmZ.rst @@ -0,0 +1 @@ +Fix build error if specialization is disabled. diff --git a/Python/specialize.c b/Python/specialize.c index 459e69de5709b8..fb75ca8d58e851 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -113,7 +113,8 @@ _PyCode_Quicken(_Py_CODEUNIT *instructions, Py_ssize_t size, int enable_counters } #else for (Py_ssize_t i = 0; i < size-1; i++) { - if (instructions[i].op.code == GET_ITER) { + int opcode = instructions[i].op.code; + if (opcode == GET_ITER) { fixup_getiter(&instructions[i], flags); } i += _PyOpcode_Caches[opcode]; From 25c7b0c4c891713250d0342bd38eeb9b730b6d9f Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 25 Jun 2026 18:51:32 +0200 Subject: [PATCH 443/818] [3.15] gh-151929: Add pythoninfo-build command to Platforms/emscripten (GH-152210) (#152217) gh-151929: Add pythoninfo-build command to Platforms/emscripten (GH-152210) * Add also "pythoninfo-host" command. * Add pythoninfo to the "build" command. (cherry picked from commit 7676427cd875a4b7b3d1ad8521b0de151b9e1e63) Co-authored-by: Victor Stinner <vstinner@python.org> --- .github/workflows/reusable-emscripten.yml | 10 +++--- Platforms/emscripten/__main__.py | 44 ++++++++++++++++++----- 2 files changed, 41 insertions(+), 13 deletions(-) diff --git a/.github/workflows/reusable-emscripten.yml b/.github/workflows/reusable-emscripten.yml index 69a780a9aebc25..38e6dcceb8f47c 100644 --- a/.github/workflows/reusable-emscripten.yml +++ b/.github/workflows/reusable-emscripten.yml @@ -63,15 +63,17 @@ jobs: run: python3 Platforms/emscripten configure-build-python -- --config-cache --with-pydebug - name: "Make build Python" run: python3 Platforms/emscripten make-build-python + - name: "Display build info of the build Python" + run: python3 Platforms/emscripten pythoninfo-build - name: "Make dependencies" run: >- python3 Platforms/emscripten make-dependencies ${{ steps.emsdk-cache.outputs.cache-hit == 'true' && '--check-up-to-date' || '' }} - - name: "Configure host Python" + - name: "Configure host/Emscripten Python" run: python3 Platforms/emscripten configure-host --host-runner node -- --config-cache - - name: "Make host Python" + - name: "Make host/Emscripten Python" run: python3 Platforms/emscripten make-host - - name: "Display build info" - run: python3 Platforms/emscripten run --pythoninfo + - name: "Display build info of the host/Emscripten Python" + run: python3 Platforms/emscripten pythoninfo-host - name: "Test" run: python3 Platforms/emscripten run --test diff --git a/Platforms/emscripten/__main__.py b/Platforms/emscripten/__main__.py index c2fb1c4c36e608..84a1589b81f6a2 100644 --- a/Platforms/emscripten/__main__.py +++ b/Platforms/emscripten/__main__.py @@ -290,6 +290,12 @@ def make_build_python(context, working_dir): print(f"🎉 {binary} {version}") +@subdir("native_build_dir") +def pythoninfo_build_python(context, working_dir): + """Display build info of the build Python.""" + call(["make", "pythoninfo"], quiet=context.quiet) + + def check_shasum(file: str, expected_shasum: str): with open(file, "rb") as f: digest = hashlib.file_digest(f, "sha256") @@ -580,7 +586,7 @@ def make_emscripten_python(context, working_dir): subprocess.check_call([exec_script, "--version"]) -def run_emscripten_python(context): +def run_emscripten_python(context, args=None): """Run the built emscripten Python.""" host_dir = context.build_paths["host_dir"] exec_script = host_dir / "python.sh" @@ -588,19 +594,25 @@ def run_emscripten_python(context): print("Emscripten not built", file=sys.stderr) sys.exit(1) - args = context.args - # Strip the "--" separator if present - if args and args[0] == "--": - args = args[1:] + if args is None: + args = context.args + # Strip the "--" separator if present + if args and args[0] == "--": + args = args[1:] - if context.test: - args = load_config_toml()["test-args"] + args - elif context.pythoninfo: - args = load_config_toml()["pythoninfo-args"] + args + if context.test: + args = load_config_toml()["test-args"] + args + elif context.pythoninfo: + args = load_config_toml()["pythoninfo-args"] + args os.execv(str(exec_script), [str(exec_script), *args]) +def pythoninfo_emscripten_python(context): + """Display build info of the host/Emscripten Python.""" + run_emscripten_python(context, ["-m", "test.pythoninfo"]) + + def build_target(context): """Build one or more targets.""" steps = [] @@ -608,6 +620,7 @@ def build_target(context): steps.extend([ configure_build_python, make_build_python, + pythoninfo_build_python, ]) if context.target in {"host", "all"}: steps.extend([ @@ -615,6 +628,7 @@ def build_target(context): make_mpdec, configure_emscripten_python, make_emscripten_python, + pythoninfo_emscripten_python, ]) for step in steps: @@ -707,6 +721,10 @@ def main(): "make-build-python", help="Run `make` for the build Python" ) + pythoninfo_build = subcommands.add_parser( + "pythoninfo-build", help="Display build info of the build Python" + ) + configure_host = subcommands.add_parser( "configure-host", help=( @@ -719,6 +737,10 @@ def main(): "make-host", help="Run `make` for the host/emscripten" ) + pythoninfo_host = subcommands.add_parser( + "pythoninfo-host", help="Display build info of the host/Emscripten Python" + ) + run = subcommands.add_parser( "run", help="Run the built emscripten Python", @@ -770,8 +792,10 @@ def main(): make_mpdec_cmd, make_dependencies_cmd, make_build, + pythoninfo_build, configure_host, make_host, + pythoninfo_host, clean, ): subcommand.add_argument( @@ -840,8 +864,10 @@ def main(): "make-dependencies": make_dependencies, "configure-build-python": configure_build_python, "make-build-python": make_build_python, + "pythoninfo-build": pythoninfo_build_python, "configure-host": configure_emscripten_python, "make-host": make_emscripten_python, + "pythoninfo-host": pythoninfo_emscripten_python, "build": build_target, "run": run_emscripten_python, "clean": clean_contents, From 59e54f5ce9039f09da03f021d1d7574a84f2834f Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 25 Jun 2026 19:22:24 +0200 Subject: [PATCH 444/818] [3.15] gh-151929: Add pythoninfo commands to Platforms/WASI (GH-152136) (#152222) gh-151929: Add pythoninfo commands to Platforms/WASI (GH-152136) The "build" command now also runs "pythoninfo-build" and "pythoninfo-host" commands. If no subcommand is provided, display the help. GitHub Action "WASI": * Add "pythoninfo-build" and "pythoninfo-host" commands. * Remove unused and outdated CROSS_BUILD_PYTHON environment variable. (cherry picked from commit 7c8163719cd23d41daeaed0b243be45de3e82e05) Co-authored-by: Victor Stinner <vstinner@python.org> --- .github/workflows/reusable-wasi.yml | 11 ++++++----- Platforms/WASI/__main__.py | 27 ++++++++++++++++++++++++++- Platforms/WASI/_build.py | 12 ++++++++++++ 3 files changed, 44 insertions(+), 6 deletions(-) diff --git a/.github/workflows/reusable-wasi.yml b/.github/workflows/reusable-wasi.yml index 48fb70cbff8009..4b4888c3844409 100644 --- a/.github/workflows/reusable-wasi.yml +++ b/.github/workflows/reusable-wasi.yml @@ -16,7 +16,6 @@ jobs: timeout-minutes: 60 env: WASMTIME_VERSION: 38.0.3 - CROSS_BUILD_PYTHON: cross-build/build CROSS_BUILD_WASI: cross-build/wasm32-wasip1 steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 @@ -54,14 +53,16 @@ jobs: run: python3 Platforms/WASI configure-build-python -- --config-cache --with-pydebug - name: "Make build Python" run: python3 Platforms/WASI make-build-python - - name: "Configure host" + - name: "Display build info of the build Python" + run: python3 Platforms/WASI pythoninfo-build + - name: "Configure host/WASI Python" # `--with-pydebug` inferred from configure-build-python run: python3 Platforms/WASI configure-host -- --config-cache env: WASI_SDK_PATH: ${{ steps.install-wasi-sdk.outputs.wasi-sdk-path }} - - name: "Make host" + - name: "Make host/WASI Python" run: python3 Platforms/WASI make-host - - name: "Display build info" - run: make --directory "${CROSS_BUILD_WASI}" pythoninfo + - name: "Display build info of the host/WASI Python" + run: python3 Platforms/WASI pythoninfo-host - name: "Test" run: make --directory "${CROSS_BUILD_WASI}" test diff --git a/Platforms/WASI/__main__.py b/Platforms/WASI/__main__.py index b8513a004f18e5..880058bad660be 100644 --- a/Platforms/WASI/__main__.py +++ b/Platforms/WASI/__main__.py @@ -40,6 +40,9 @@ def main(): build_python = subcommands.add_parser( "build-python", help="Build the build Python" ) + pythoninfo_build = subcommands.add_parser( + "pythoninfo-build", help="Display build info of the build Python" + ) configure_host = subcommands.add_parser( "configure-host", help="Run `configure` for the " @@ -53,6 +56,9 @@ def main(): build_host = subcommands.add_parser( "build-host", help="Build the host/WASI Python" ) + pythoninfo_host = subcommands.add_parser( + "pythoninfo-host", help="Display build info of the host/WASI Python" + ) subcommands.add_parser( "clean", help="Delete files and directories created by this script" ) @@ -61,8 +67,10 @@ def main(): configure_build, make_build, build_python, + pythoninfo_build, configure_host, make_host, + pythoninfo_host, build_host, ): subcommand.add_argument( @@ -118,7 +126,13 @@ def main(): help="Command template for running the WASI host; defaults to " f"`{default_host_runner}`", ) - for subcommand in build, configure_host, make_host, build_host: + for subcommand in ( + build, + configure_host, + make_host, + build_host, + pythoninfo_host, + ): subcommand.add_argument( "--host-triple", action="store", @@ -137,6 +151,8 @@ def main(): case "build-python": _build.configure_build_python(context) _build.make_build_python(context) + case "pythoninfo-build": + _build.pythoninfo_build_python(context) case "configure-host": _build.configure_wasi_python(context) case "make-host": @@ -144,13 +160,22 @@ def main(): case "build-host": _build.configure_wasi_python(context) _build.make_wasi_python(context) + case "pythoninfo-host": + _build.pythoninfo_wasi_python(context) case "build": + # Configure and build the build Python _build.configure_build_python(context) _build.make_build_python(context) + _build.pythoninfo_build_python(context) + + # Configure and build the host/WASI Python _build.configure_wasi_python(context) _build.make_wasi_python(context) + _build.pythoninfo_wasi_python(context) case "clean": _build.clean_contents(context) + case None: + parser.print_help() case _: raise ValueError(f"Unknown subcommand {context.subcommand!r}") diff --git a/Platforms/WASI/_build.py b/Platforms/WASI/_build.py index c1a91a9c833b8e..792f8edd994313 100644 --- a/Platforms/WASI/_build.py +++ b/Platforms/WASI/_build.py @@ -418,3 +418,15 @@ def clean_contents(context): if LOCAL_SETUP.exists(): if LOCAL_SETUP.read_bytes() == LOCAL_SETUP_MARKER: log("🧹", f"Deleting generated {LOCAL_SETUP} ...") + + +@subdir(BUILD_DIR) +def pythoninfo_build_python(context, working_dir): + """Display build info of the build Python.""" + call(["make", "pythoninfo"], context=context) + + +@subdir(lambda context: CROSS_BUILD_DIR / host_triple(context)) +def pythoninfo_wasi_python(context, working_dir): + """Display build info of the host/WASI Python.""" + call(["make", "pythoninfo"], context=context) From 30f9c8a3ef503271947a6a1e2066fd95a194c9b5 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 25 Jun 2026 20:48:52 +0200 Subject: [PATCH 445/818] [3.15] gh-151722: Do not track the frozendict in the GC in _PyDict_FromKeys() (GH-152067) (#152225) gh-151722: Do not track the frozendict in the GC in _PyDict_FromKeys() (GH-152067) _PyDict_FromKeys() now creates a frozendict copy which is not tracked by the GC. dict_merge() no longer requires the dictionary to be tracked by the GC. (cherry picked from commit 55bc3126e0a09a8e940da73e51ab1ffeecaf02d4) Co-authored-by: Victor Stinner <vstinner@python.org> Co-authored-by: Donghee Na <donghee.na@python.org> Co-authored-by: Inada Naoki <songofacandy@gmail.com> --- Doc/library/stdtypes.rst | 7 + Lib/test/test_dict.py | 31 ++-- ...-06-24-13-36-31.gh-issue-151722.lWKfE1.rst | 3 + Objects/dictobject.c | 173 ++++++++++++------ 4 files changed, 149 insertions(+), 65 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-24-13-36-31.gh-issue-151722.lWKfE1.rst diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index 9ad4b27cf2fc87..92c89bfc46af2e 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -5757,6 +5757,13 @@ Frozen dictionaries Like dictionaries, frozendicts are :ref:`generic <generics>` over two types, signifying (respectively) the types of the frozendict's keys and values. + .. classmethod:: fromkeys(iterable, value=None, /) + + Similar to :meth:`dict.fromkeys`, but call again the type constructor + with an initialized :class:`frozendict` if the type is a + :class:`frozendict` subclass or if the constructor returned a + :class:`frozendict`. + .. versionadded:: 3.15 diff --git a/Lib/test/test_dict.py b/Lib/test/test_dict.py index f26586809238f0..6d61c71e162f8b 100644 --- a/Lib/test/test_dict.py +++ b/Lib/test/test_dict.py @@ -1939,8 +1939,11 @@ def test_fromkeys(self): # Subclass which overrides the constructor created = frozendict(x=1) class FrozenDictSubclass(frozendict): - def __new__(self): - return created + def __new__(cls, *args, **kwargs): + if args or kwargs: + return super().__new__(cls, *args, **kwargs) + else: + return created fd = FrozenDictSubclass.fromkeys("abc") self.assertEqual(fd, frozendict(x=1, a=None, b=None, c=None)) @@ -1952,6 +1955,20 @@ def __new__(self): self.assertEqual(type(fd), FrozenDictSubclass) self.assertEqual(created, frozendict(x=1)) + # Dict subclass with a constructor which returns a frozendict + # by default + class DictSubclass(dict): + def __new__(cls, *args, **kwargs): + if args or kwargs: + return super().__new__(cls, *args, **kwargs) + else: + return created + + fd = DictSubclass.fromkeys("abc") + self.assertEqual(fd, frozendict(x=1, a=None, b=None, c=None)) + self.assertEqual(type(fd), DictSubclass) + self.assertEqual(created, frozendict(x=1)) + # Subclass which doesn't override the constructor class FrozenDictSubclass2(frozendict): pass @@ -1960,16 +1977,6 @@ class FrozenDictSubclass2(frozendict): self.assertEqual(fd, frozendict(a=None, b=None, c=None)) self.assertEqual(type(fd), FrozenDictSubclass2) - # Dict subclass which overrides the constructor - class DictSubclass(dict): - def __new__(self): - return created - - fd = DictSubclass.fromkeys("abc") - self.assertEqual(fd, frozendict(x=1, a=None, b=None, c=None)) - self.assertEqual(type(fd), DictSubclass) - self.assertEqual(created, frozendict(x=1)) - def test_pickle(self): for proto in range(pickle.HIGHEST_PROTOCOL + 1): for fd in ( diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-24-13-36-31.gh-issue-151722.lWKfE1.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-24-13-36-31.gh-issue-151722.lWKfE1.rst new file mode 100644 index 00000000000000..db50b0058bdbdd --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-24-13-36-31.gh-issue-151722.lWKfE1.rst @@ -0,0 +1,3 @@ +:meth:`!frozendict.fromkeys` now only tracks the :class:`frozendict` in the +garbage collector once the dictionary is fully initialized. Patch by Donghee Na +and Victor Stinner. diff --git a/Objects/dictobject.c b/Objects/dictobject.c index 0782b4022f3a81..d57ef37fb0fdac 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -140,6 +140,7 @@ static PyObject* frozendict_new(PyTypeObject *type, PyObject *args, PyObject *kwds); static PyObject* frozendict_new_untracked(PyTypeObject *type); static PyObject* dict_new(PyTypeObject *type, PyObject *args, PyObject *kwds); +static PyObject* dict_new_untracked(PyTypeObject *type); static int dict_merge(PyObject *a, PyObject *b, int override, PyObject **dupkey); static int dict_contains(PyObject *op, PyObject *key); static int dict_merge_from_seq2(PyObject *d, PyObject *seq2, int override); @@ -3387,40 +3388,47 @@ dict_set_fromkeys(PyDictObject *mp, PyObject *iterable, PyObject *value) PyObject * _PyDict_FromKeys(PyObject *cls, PyObject *iterable, PyObject *value) { - PyObject *it; /* iter(iterable) */ - PyObject *key; + PyObject *it = NULL; /* iter(iterable) */ PyObject *d; - int status; + int need_copy = 0; - d = _PyObject_CallNoArgs(cls); + if (cls == (PyObject*)&PyFrozenDict_Type) { + // gh-151722: Create a frozendict which is not tracked by the GC. + d = frozendict_new_untracked(&PyFrozenDict_Type); + } + else { + // Dict subclass, or frozendict subclass which overrides + // the constructor. + d = _PyObject_CallNoArgs(cls); + } if (d == NULL) { return NULL; } - // If cls is a dict or frozendict subclass with overridden constructor, - // copy the frozendict. - PyTypeObject *cls_type = _PyType_CAST(cls); - if (PyFrozenDict_Check(d) && cls_type->tp_new != frozendict_new) { - // Subclass-friendly copy - PyObject *copy; - if (PyObject_IsSubclass(cls, (PyObject*)&PyFrozenDict_Type)) { - copy = frozendict_new(cls_type, NULL, NULL); - } - else { - copy = dict_new(cls_type, NULL, NULL); - } + // gh-151722: If cls constructor returns a frozendict which is tracked by + // the GC, create a frozendict copy which is not tracked by the GC. + // + // At the function exit, return cls(fd) where fd is a frozendict. + // + // Untracking the frozendict requires tracking again the frozendict on + // error which is more complicated. It's easier to work on a copy. + if (PyFrozenDict_Check(d) && _PyObject_GC_IS_TRACKED(d)) { + need_copy = 1; + + PyObject *copy = frozendict_new_untracked(&PyFrozenDict_Type); if (copy == NULL) { - Py_DECREF(d); - return NULL; + goto Fail; } if (dict_merge(copy, d, 1, NULL) < 0) { - Py_DECREF(d); Py_DECREF(copy); - return NULL; + goto Fail; } Py_SETREF(d, copy); } - assert(!PyFrozenDict_Check(d) || can_modify_dict((PyDictObject*)d)); + if (PyFrozenDict_Check(d)) { + assert(can_modify_dict((PyDictObject*)d)); + assert(!_PyObject_GC_IS_TRACKED(d)); + } if (PyDict_CheckExact(d)) { if (PyDict_CheckExact(iterable)) { @@ -3429,7 +3437,7 @@ _PyDict_FromKeys(PyObject *cls, PyObject *iterable, PyObject *value) Py_BEGIN_CRITICAL_SECTION2(d, iterable); d = (PyObject *)dict_dict_fromkeys(mp, iterable, value); Py_END_CRITICAL_SECTION2(); - return d; + goto Done; } else if (PyFrozenDict_CheckExact(iterable)) { PyDictObject *mp = (PyDictObject *)d; @@ -3437,7 +3445,7 @@ _PyDict_FromKeys(PyObject *cls, PyObject *iterable, PyObject *value) Py_BEGIN_CRITICAL_SECTION(d); d = (PyObject *)dict_dict_fromkeys(mp, iterable, value); Py_END_CRITICAL_SECTION(); - return d; + goto Done; } else if (PyAnySet_CheckExact(iterable)) { PyDictObject *mp = (PyDictObject *)d; @@ -3445,7 +3453,7 @@ _PyDict_FromKeys(PyObject *cls, PyObject *iterable, PyObject *value) Py_BEGIN_CRITICAL_SECTION2(d, iterable); d = (PyObject *)dict_set_fromkeys(mp, iterable, value); Py_END_CRITICAL_SECTION2(); - return d; + goto Done; } } else if (PyFrozenDict_CheckExact(d)) { @@ -3455,12 +3463,12 @@ _PyDict_FromKeys(PyObject *cls, PyObject *iterable, PyObject *value) Py_BEGIN_CRITICAL_SECTION(iterable); d = (PyObject *)dict_dict_fromkeys(mp, iterable, value); Py_END_CRITICAL_SECTION(); - return d; + goto Done; } else if (PyFrozenDict_CheckExact(iterable)) { PyDictObject *mp = (PyDictObject *)d; d = (PyObject *)dict_dict_fromkeys(mp, iterable, value); - return d; + goto Done; } else if (PyAnySet_CheckExact(iterable)) { PyDictObject *mp = (PyDictObject *)d; @@ -3468,58 +3476,100 @@ _PyDict_FromKeys(PyObject *cls, PyObject *iterable, PyObject *value) Py_BEGIN_CRITICAL_SECTION(iterable); d = (PyObject *)dict_set_fromkeys(mp, iterable, value); Py_END_CRITICAL_SECTION(); - return d; + goto Done; } } it = PyObject_GetIter(iterable); if (it == NULL){ - Py_DECREF(d); - return NULL; + goto Fail; } if (PyDict_CheckExact(d)) { + int status = 0; + Py_BEGIN_CRITICAL_SECTION(d); - while ((key = PyIter_Next(it)) != NULL) { + while (1) { + PyObject *key; + status = PyIter_NextItem(it, &key); + if (status <= 0) { + break; + } + status = setitem_lock_held((PyDictObject *)d, key, value); Py_DECREF(key); if (status < 0) { - assert(PyErr_Occurred()); - goto dict_iter_exit; + break; } } -dict_iter_exit:; Py_END_CRITICAL_SECTION(); + + if (status < 0) { + goto Fail; + } } else if (PyFrozenDict_Check(d)) { - while ((key = PyIter_Next(it)) != NULL) { + while (1) { + PyObject *key; + int status = PyIter_NextItem(it, &key); + if (status < 0) { + goto Fail; + } + if (status == 0) { + break; + } + // setitem_take2_lock_held consumes a reference to key status = setitem_take2_lock_held((PyDictObject *)d, key, Py_NewRef(value)); if (status < 0) { - assert(PyErr_Occurred()); goto Fail; } } } else { - while ((key = PyIter_Next(it)) != NULL) { + while (1) { + PyObject *key; + int status = PyIter_NextItem(it, &key); + if (status < 0) { + goto Fail; + } + if (status == 0) { + break; + } + status = PyObject_SetItem(d, key, value); Py_DECREF(key); - if (status < 0) + if (status < 0) { goto Fail; + } } + } - if (PyErr_Occurred()) - goto Fail; + assert(!PyErr_Occurred()); Py_DECREF(it); - return d; + goto Done; Fail: - Py_DECREF(it); + assert(PyErr_Occurred()); + Py_XDECREF(it); Py_DECREF(d); return NULL; + +Done: + if (d == NULL) { + return NULL; + } + + if (need_copy) { + PyObject *copy = _PyObject_CallOneArg(cls, d); + Py_SETREF(d, copy); + } + else if (!_PyObject_GC_IS_TRACKED(d)) { + _PyObject_GC_TRACK(d); + } + return d; } /* Methods */ @@ -4120,9 +4170,6 @@ dict_dict_merge(PyDictObject *mp, PyDictObject *other, int override, PyObject ** set_keys(mp, keys); STORE_USED(mp, other->ma_used); ASSERT_CONSISTENT(mp); - if (PyDict_Check(mp)) { - assert(_PyObject_GC_IS_TRACKED(mp)); - } return 0; } } @@ -4289,7 +4336,12 @@ dict_merge_api(PyObject *a, PyObject *b, int override, PyObject **dupkey) } return -1; } - return dict_merge(a, b, override, dupkey); + + int res = dict_merge(a, b, override, dupkey); + if (PyDict_Check(a)) { + assert(_PyObject_GC_IS_TRACKED(a)); + } + return res; } int @@ -4448,10 +4500,15 @@ copy_lock_held(PyObject *o, int as_frozendict) } if (copy == NULL) return NULL; - if (dict_merge(copy, o, 1, NULL) == 0) - return copy; - Py_DECREF(copy); - return NULL; + if (dict_merge(copy, o, 1, NULL) < 0) { + Py_DECREF(copy); + return NULL; + } + + if (PyDict_Check(copy)) { + assert(_PyObject_GC_IS_TRACKED(copy)); + } + return copy; } PyObject * @@ -5212,11 +5269,11 @@ static PyNumberMethods dict_as_number = { .nb_inplace_or = _PyDict_IOr, }; -static PyObject * -dict_new_untracked(PyTypeObject *type) +static PyObject* +anydict_new_untracked(PyTypeObject *type) { assert(type != NULL); - // dict subclasses must implement the GC protocol + // dict and frozendict subclasses must implement the GC protocol assert(_PyType_IS_GC(type)); PyObject *self = _PyType_AllocNoTrack(type, 0); @@ -5235,6 +5292,14 @@ dict_new_untracked(PyTypeObject *type) return self; } +static PyObject* +dict_new_untracked(PyTypeObject *type) +{ + assert(PyObject_IsSubclass((PyObject*)type, (PyObject*)&PyDict_Type)); + + return anydict_new_untracked(type); +} + static PyObject * dict_new(PyTypeObject *type, PyObject *Py_UNUSED(args), PyObject *Py_UNUSED(kwds)) { @@ -8323,7 +8388,9 @@ frozendict_hash(PyObject *op) static PyObject * frozendict_new_untracked(PyTypeObject *type) { - PyObject *d = dict_new_untracked(type); + assert(PyObject_IsSubclass((PyObject*)type, (PyObject*)&PyFrozenDict_Type)); + + PyObject *d = anydict_new_untracked(type); if (d == NULL) { return NULL; } From b7a41375ff9b247f53cc4264d4fe8a9fd45d8f7d Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 26 Jun 2026 05:49:15 +0200 Subject: [PATCH 446/818] [3.15] gh-152235: Defer GC tracking of set and frozenset to end of construction (gh-152237) (gh-152242) gh-152235: Defer GC tracking of set and frozenset to end of construction (gh-152237) (cherry picked from commit 908f438e198a753d40d1166b5f8725e650a9ed6e) Co-authored-by: Donghee Na <donghee.na@python.org> --- .../2026-06-26-05-49-13.gh-issue-152235.YU20T9.rst | 2 ++ Objects/setobject.c | 10 +++++++--- 2 files changed, 9 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-26-05-49-13.gh-issue-152235.YU20T9.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-26-05-49-13.gh-issue-152235.YU20T9.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-26-05-49-13.gh-issue-152235.YU20T9.rst new file mode 100644 index 00000000000000..8d386ad458dfff --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-26-05-49-13.gh-issue-152235.YU20T9.rst @@ -0,0 +1,2 @@ +Defer GC tracking of a :class:`set` or :class:`frozenset` to the end of its +construction from iterable. Patch by Donghee Na. diff --git a/Objects/setobject.c b/Objects/setobject.c index 7644ea0baf73dd..0c63ef7fb272c5 100644 --- a/Objects/setobject.c +++ b/Objects/setobject.c @@ -1351,7 +1351,9 @@ make_new_set(PyTypeObject *type, PyObject *iterable) assert(PyType_Check(type)); PySetObject *so; - so = (PySetObject *)type->tp_alloc(type, 0); + // Allocate untracked: the fill below runs user code, and a half-built + // set must not be reachable from another thread via gc.get_objects(). + so = (PySetObject *)_PyType_AllocNoTrack(type, 0); if (so == NULL) return NULL; @@ -1370,6 +1372,8 @@ make_new_set(PyTypeObject *type, PyObject *iterable) } } + // Track only once fully built. + _PyObject_GC_TRACK(so); return (PyObject *)so; } @@ -2875,7 +2879,7 @@ PyTypeObject PySet_Type = { 0, /* tp_descr_set */ 0, /* tp_dictoffset */ set_init, /* tp_init */ - PyType_GenericAlloc, /* tp_alloc */ + _PyType_AllocNoTrack, /* tp_alloc */ set_new, /* tp_new */ PyObject_GC_Del, /* tp_free */ .tp_vectorcall = set_vectorcall, @@ -2967,7 +2971,7 @@ PyTypeObject PyFrozenSet_Type = { 0, /* tp_descr_set */ 0, /* tp_dictoffset */ 0, /* tp_init */ - PyType_GenericAlloc, /* tp_alloc */ + _PyType_AllocNoTrack, /* tp_alloc */ frozenset_new, /* tp_new */ PyObject_GC_Del, /* tp_free */ .tp_vectorcall = frozenset_vectorcall, From 41f5b920e436408c5412b598823e80000c62064b Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 26 Jun 2026 14:08:15 +0200 Subject: [PATCH 447/818] [3.15] gh-152246: Fix pure-Python `zoneinfo` accepting invalid seperators in POSIX TZ rules (GH-152247) (#152265) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (cherry picked from commit f47acc7f0920cb5ef507352172914876cea18a48) Co-authored-by: tonghuaroot (童话) <tonghuaroot@gmail.com> Co-authored-by: Stan Ulbrych <stan@python.org> --- Lib/test/test_zoneinfo/test_zoneinfo.py | 5 +++++ Lib/zoneinfo/_zoneinfo.py | 2 +- .../Library/2026-06-26-12-50-26.gh-issue-152246.MfXMd1.rst | 2 ++ 3 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2026-06-26-12-50-26.gh-issue-152246.MfXMd1.rst diff --git a/Lib/test/test_zoneinfo/test_zoneinfo.py b/Lib/test/test_zoneinfo/test_zoneinfo.py index 7502b120825fbc..d4d57b8f727584 100644 --- a/Lib/test/test_zoneinfo/test_zoneinfo.py +++ b/Lib/test/test_zoneinfo/test_zoneinfo.py @@ -1184,6 +1184,11 @@ def test_invalid_tzstr(self): # Invalid weekday "AAA4BBB,M1.1.7/2,M2.1.1/2", "AAA4BBB,M1.1.1/2,M2.1.7/2", + # Invalid Mm.w.d separator + "AAA4BBB,M3.2X0,M11.1.0", + "AAA4BBB,M3.2.0,M11.1X0", + "AAA4BBB,M3.2-0,M11.1.0/3", + "AAA4BBB,M3.2.0/2,M11.1:0", # Invalid numeric offset "AAA4BBB,-1/2,20/2", "AAA4BBB,1/2,-1/2", diff --git a/Lib/zoneinfo/_zoneinfo.py b/Lib/zoneinfo/_zoneinfo.py index 7063eb6a9025ac..3903d57d55417e 100644 --- a/Lib/zoneinfo/_zoneinfo.py +++ b/Lib/zoneinfo/_zoneinfo.py @@ -707,7 +707,7 @@ def _parse_dst_start_end(dststr): type = date[:1] if type == "M": n_is_julian = False - m = re.fullmatch(r"M(\d{1,2})\.(\d).(\d)", date, re.ASCII) + m = re.fullmatch(r"M(\d{1,2})\.(\d)\.(\d)", date, re.ASCII) if m is None: raise ValueError(f"Invalid dst start/end date: {dststr}") date_offset = tuple(map(int, m.groups())) diff --git a/Misc/NEWS.d/next/Library/2026-06-26-12-50-26.gh-issue-152246.MfXMd1.rst b/Misc/NEWS.d/next/Library/2026-06-26-12-50-26.gh-issue-152246.MfXMd1.rst new file mode 100644 index 00000000000000..0858199a9fa279 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-26-12-50-26.gh-issue-152246.MfXMd1.rst @@ -0,0 +1,2 @@ +Fix the pure-Python :mod:`zoneinfo` parser accepting an invalid POSIX TZ +transition rule with a non-period separator. Patch by tonghuaroot. From 62842c9ff592114ade3049d6a85aea031b783beb Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 26 Jun 2026 14:11:14 +0200 Subject: [PATCH 448/818] [3.15] gh-152156: Fix a crash in `interpeters.create` under limited memory conditions (GH-152163) (#152269) gh-152156: Fix a crash in `interpeters.create` under limited memory conditions (GH-152163) (cherry picked from commit 3ad66bf10dbb929bcf8efd889e56a9b9068319ca) Co-authored-by: sobolevn <mail@sobolevn.me> --- .../Library/2026-06-25-10-07-54.gh-issue-152156.gscPU9.rst | 2 ++ Modules/_interpchannelsmodule.c | 6 ++---- 2 files changed, 4 insertions(+), 4 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-06-25-10-07-54.gh-issue-152156.gscPU9.rst diff --git a/Misc/NEWS.d/next/Library/2026-06-25-10-07-54.gh-issue-152156.gscPU9.rst b/Misc/NEWS.d/next/Library/2026-06-25-10-07-54.gh-issue-152156.gscPU9.rst new file mode 100644 index 00000000000000..30e561274dc50c --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-25-10-07-54.gh-issue-152156.gscPU9.rst @@ -0,0 +1,2 @@ +Fix a possible crash in :func:`concurrent.interpreters.create` under limited +memory conditions. diff --git a/Modules/_interpchannelsmodule.c b/Modules/_interpchannelsmodule.c index 3614890757d69d..05957081079d4a 100644 --- a/Modules/_interpchannelsmodule.c +++ b/Modules/_interpchannelsmodule.c @@ -2951,10 +2951,8 @@ channelsmod_create(PyObject *self, PyObject *args, PyObject *kwds) &cidobj); if (handle_channel_error(err, self, cid)) { assert(cidobj == NULL); - err = channel_destroy(&_globals.channels, cid); - if (handle_channel_error(err, self, cid)) { - // XXX issue a warning? - } + assert(PyErr_Occurred()); + (void)channel_destroy(&_globals.channels, cid); return NULL; } assert(cidobj != NULL); From c48673b4b6eb0544bc70a99a2ff5ce5238c12b1a Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 26 Jun 2026 14:26:17 +0200 Subject: [PATCH 449/818] [3.15] gh-151722: Defer GC tracking in frozendict.copy() (GH-152230) (#152271) gh-151722: Defer GC tracking in frozendict.copy() (GH-152230) Fix _PyDict_Or() and frozendict.copy(): only track the frozendict by the GC once the dictionary is fully initialized. Functions modifying frozendict now ensures that the object is not tracked by the GC (in debug mode). * can_modify_dict() checks that _PyObject_GC_IS_TRACKED() is false for frozendicts. * dict_merge_api() makes sure that the dictionary is tracked by the GC. (cherry picked from commit 05679f3576ed3298c9b0f86e8a3462f0b92dff8f) Co-authored-by: Victor Stinner <vstinner@python.org> --- Objects/dictobject.c | 109 ++++++++++++++++++++++++++++--------------- 1 file changed, 72 insertions(+), 37 deletions(-) diff --git a/Objects/dictobject.c b/Objects/dictobject.c index d57ef37fb0fdac..eebb896f5d785b 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -296,16 +296,20 @@ static inline int can_modify_dict(PyDictObject *mp) { if (PyFrozenDict_Check(mp)) { + // gh-151722: A frozendict must not be tracked by the GC + // when it's being modified. + assert(!_PyObject_GC_IS_TRACKED(mp)); + // No locking required to modify a newly created frozendict // since it's only accessible from the current thread. - return PyUnstable_Object_IsUniquelyReferenced(_PyObject_CAST(mp)); + assert(PyUnstable_Object_IsUniquelyReferenced(_PyObject_CAST(mp))); } else { // Locking is only required if the dictionary is not // uniquely referenced. ASSERT_DICT_LOCKED(mp); - return 1; } + return 1; } #endif @@ -902,7 +906,7 @@ free_values(PyDictValues *values, bool use_qsbr) static inline PyObject * new_dict_impl(PyDictObject *mp, PyDictKeysObject *keys, PyDictValues *values, Py_ssize_t used, - int free_values_on_failure, int frozendict) + int free_values_on_failure, int frozendict, int gc_track) { assert(keys != NULL); if (mp == NULL) { @@ -921,12 +925,14 @@ new_dict_impl(PyDictObject *mp, PyDictKeysObject *keys, ((PyFrozenDictObject *)mp)->ma_hash = -1; } ASSERT_CONSISTENT(mp); - _PyObject_GC_TRACK(mp); + if (gc_track) { + _PyObject_GC_TRACK(mp); + } return (PyObject *)mp; } /* Consumes a reference to the keys object */ -static PyObject * +static PyObject* new_dict(PyDictKeysObject *keys, PyDictValues *values, Py_ssize_t used, int free_values_on_failure) { @@ -936,16 +942,30 @@ new_dict(PyDictKeysObject *keys, PyDictValues *values, } assert(mp == NULL || Py_IS_TYPE(mp, &PyDict_Type)); - return new_dict_impl(mp, keys, values, used, free_values_on_failure, 0); + return new_dict_impl(mp, keys, values, used, free_values_on_failure, 0, 1); } /* Consumes a reference to the keys object */ -static PyObject * -new_frozendict(PyDictKeysObject *keys, PyDictValues *values, - Py_ssize_t used, int free_values_on_failure) +static PyObject* +new_dict_untracked(PyDictKeysObject *keys, PyDictValues *values, + Py_ssize_t used, int free_values_on_failure) +{ + PyDictObject *mp = _Py_FREELIST_POP(PyDictObject, dicts); + if (mp == NULL) { + mp = PyObject_GC_New(PyDictObject, &PyDict_Type); + } + assert(mp == NULL || Py_IS_TYPE(mp, &PyDict_Type)); + + return new_dict_impl(mp, keys, values, used, free_values_on_failure, 0, 0); +} + +/* Consumes a reference to the keys object */ +static PyObject* +new_frozendict_untracked(PyDictKeysObject *keys, PyDictValues *values, + Py_ssize_t used, int free_values_on_failure) { PyDictObject *mp = PyObject_GC_New(PyDictObject, &PyFrozenDict_Type); - return new_dict_impl(mp, keys, values, used, free_values_on_failure, 1); + return new_dict_impl(mp, keys, values, used, free_values_on_failure, 1, 0); } static PyObject * @@ -3427,7 +3447,6 @@ _PyDict_FromKeys(PyObject *cls, PyObject *iterable, PyObject *value) } if (PyFrozenDict_Check(d)) { assert(can_modify_dict((PyDictObject*)d)); - assert(!_PyObject_GC_IS_TRACKED(d)); } if (PyDict_CheckExact(d)) { @@ -4032,6 +4051,7 @@ merge_from_seq2_lock_held(PyObject *d, PyObject *seq2, int override) assert(d != NULL); assert(PyAnyDict_Check(d)); assert(seq2 != NULL); + assert(can_modify_dict((PyDictObject*)d)); it = PyObject_GetIter(seq2); if (it == NULL) @@ -4233,11 +4253,13 @@ dict_merge(PyObject *a, PyObject *b, int override, PyObject **dupkey) assert(0 <= override && override <= 2); PyDictObject *mp = _PyAnyDict_CAST(a); + int res = 0; if (PyAnyDict_Check(b) && (Py_TYPE(b)->tp_iter == dict_iter)) { PyDictObject *other = (PyDictObject*)b; int res; Py_BEGIN_CRITICAL_SECTION2(a, b); + assert(can_modify_dict(mp)); res = dict_dict_merge((PyDictObject *)a, other, override, dupkey); ASSERT_CONSISTENT(a); Py_END_CRITICAL_SECTION2(); @@ -4246,6 +4268,8 @@ dict_merge(PyObject *a, PyObject *b, int override, PyObject **dupkey) else { /* Do it the generic, slower way */ Py_BEGIN_CRITICAL_SECTION(a); + assert(can_modify_dict(mp)); + PyObject *keys = PyMapping_Keys(b); PyObject *iter; PyObject *key, *value; @@ -4338,9 +4362,7 @@ dict_merge_api(PyObject *a, PyObject *b, int override, PyObject **dupkey) } int res = dict_merge(a, b, override, dupkey); - if (PyDict_Check(a)) { - assert(_PyObject_GC_IS_TRACKED(a)); - } + assert(_PyObject_GC_IS_TRACKED(a)); return res; } @@ -4398,7 +4420,7 @@ copy_values(PyDictValues *values) } static PyObject * -copy_lock_held(PyObject *o, int as_frozendict) +copy_lock_held_untracked(PyObject *o, int as_frozendict) { PyObject *copy; PyDictObject *mp; @@ -4411,12 +4433,15 @@ copy_lock_held(PyObject *o, int as_frozendict) mp = (PyDictObject *)o; if (mp->ma_used == 0) { /* The dict is empty; just return a new dict. */ + PyObject *d; if (as_frozendict) { - return PyFrozenDict_New(NULL); + d = frozendict_new_untracked(&PyFrozenDict_Type); } else { - return PyDict_New(); + d = dict_new_untracked(&PyDict_Type); } + assert(!_PyObject_GC_IS_TRACKED(d)); + return d; } if (_PyDict_HasSplitTable(mp)) { @@ -4448,7 +4473,7 @@ copy_lock_held(PyObject *o, int as_frozendict) PyFrozenDictObject *frozen = (PyFrozenDictObject *)split_copy; frozen->ma_hash = -1; } - _PyObject_GC_TRACK(split_copy); + assert(!_PyObject_GC_IS_TRACKED(split_copy)); return (PyObject *)split_copy; } @@ -4476,10 +4501,10 @@ copy_lock_held(PyObject *o, int as_frozendict) } PyDictObject *new; if (as_frozendict) { - new = (PyDictObject *)new_frozendict(keys, NULL, 0, 0); + new = (PyDictObject *)new_frozendict_untracked(keys, NULL, 0, 0); } else { - new = (PyDictObject *)new_dict(keys, NULL, 0, 0); + new = (PyDictObject *)new_dict_untracked(keys, NULL, 0, 0); } if (new == NULL) { /* In case of an error, new_dict()/new_frozendict() takes care of @@ -4489,14 +4514,15 @@ copy_lock_held(PyObject *o, int as_frozendict) new->ma_used = mp->ma_used; ASSERT_CONSISTENT(new); + assert(!_PyObject_GC_IS_TRACKED(new)); return (PyObject *)new; } if (as_frozendict) { - copy = PyFrozenDict_New(NULL); + copy = frozendict_new_untracked(&PyFrozenDict_Type); } else { - copy = PyDict_New(); + copy = dict_new_untracked(&PyDict_Type); } if (copy == NULL) return NULL; @@ -4505,9 +4531,7 @@ copy_lock_held(PyObject *o, int as_frozendict) return NULL; } - if (PyDict_Check(copy)) { - assert(_PyObject_GC_IS_TRACKED(copy)); - } + assert(!_PyObject_GC_IS_TRACKED(copy)); return copy; } @@ -4521,25 +4545,28 @@ PyDict_Copy(PyObject *o) PyObject *res; Py_BEGIN_CRITICAL_SECTION(o); - res = copy_lock_held(o, 0); + res = copy_lock_held_untracked(o, 0); Py_END_CRITICAL_SECTION(); + if (res != NULL) { + _PyObject_GC_TRACK(res); + } return res; } // Similar to PyDict_Copy(), but return a frozendict if the argument // is a frozendict. static PyObject * -anydict_copy(PyObject *o) +anydict_copy_untracked(PyObject *o) { assert(PyAnyDict_Check(o)); PyObject *res; if (PyFrozenDict_Check(o)) { - res = copy_lock_held(o, 1); + res = copy_lock_held_untracked(o, 1); } else { Py_BEGIN_CRITICAL_SECTION(o); - res = copy_lock_held(o, 0); + res = copy_lock_held_untracked(o, 0); Py_END_CRITICAL_SECTION(); } return res; @@ -4554,13 +4581,16 @@ _PyDict_CopyAsDict(PyObject *o) PyObject *res; if (PyFrozenDict_Check(o)) { - res = copy_lock_held(o, 0); + res = copy_lock_held_untracked(o, 0); } else { Py_BEGIN_CRITICAL_SECTION(o); - res = copy_lock_held(o, 0); + res = copy_lock_held_untracked(o, 0); Py_END_CRITICAL_SECTION(); } + if (res != NULL) { + _PyObject_GC_TRACK(res); + } return res; } @@ -5113,7 +5143,7 @@ _PyDict_Or(PyObject *self, PyObject *other) if (!PyAnyDict_Check(self) || !PyAnyDict_Check(other)) { Py_RETURN_NOTIMPLEMENTED; } - PyObject *new = anydict_copy(self); + PyObject *new = anydict_copy_untracked(self); if (new == NULL) { return NULL; } @@ -5121,6 +5151,7 @@ _PyDict_Or(PyObject *self, PyObject *other) Py_DECREF(new); return NULL; } + _PyObject_GC_TRACK(new); return new; } @@ -5308,7 +5339,6 @@ dict_new(PyTypeObject *type, PyObject *Py_UNUSED(args), PyObject *Py_UNUSED(kwds if (self == NULL) { return NULL; } - assert(!_PyObject_GC_IS_TRACKED(self)); _PyObject_GC_TRACK(self); return self; } @@ -5390,7 +5420,7 @@ frozendict_vectorcall(PyObject *type, PyObject * const*args, } } } - assert(!_PyObject_GC_IS_TRACKED(self)); + _PyObject_GC_TRACK(self); return self; } @@ -6709,10 +6739,12 @@ dictitems_xor_lock_held(PyObject *d1, PyObject *d2) ASSERT_DICT_LOCKED(d1); ASSERT_DICT_LOCKED(d2); - PyObject *temp_dict = copy_lock_held(d1, 0); + PyObject *temp_dict = copy_lock_held_untracked(d1, 0); if (temp_dict == NULL) { return NULL; } + _PyObject_GC_TRACK(temp_dict); + PyObject *result_set = PySet_New(NULL); if (result_set == NULL) { Py_CLEAR(temp_dict); @@ -8417,7 +8449,6 @@ frozendict_new(PyTypeObject *type, PyObject *args, PyObject *kwds) assert(kwds == NULL); } - assert(!_PyObject_GC_IS_TRACKED(d)); _PyObject_GC_TRACK(d); return d; } @@ -8462,7 +8493,11 @@ frozendict_copy_impl(PyFrozenDictObject *self) return Py_NewRef(self); } - return anydict_copy((PyObject*)self); + PyObject *copy = anydict_copy_untracked((PyObject*)self); + if (copy != NULL) { + _PyObject_GC_TRACK(copy); + } + return copy; } From 7ed673718b1b3021ee4bd352f750d5746b268998 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 26 Jun 2026 16:02:58 +0200 Subject: [PATCH 450/818] [3.15] gh-152235: Defer GC tracking in more set operations (gh-152273) (gh-152278) gh-152235: Defer GC tracking in more set operations (gh-152273) (cherry picked from commit a87d24a69d1e97a1e9643c8951d180918ef36e4c) Co-authored-by: Donghee Na <donghee.na@python.org> --- ...-06-26-22-03-16.gh-issue-152235.ZKWiWk.rst | 2 + Objects/setobject.c | 44 ++++++++++++++----- 2 files changed, 36 insertions(+), 10 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-26-22-03-16.gh-issue-152235.ZKWiWk.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-26-22-03-16.gh-issue-152235.ZKWiWk.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-26-22-03-16.gh-issue-152235.ZKWiWk.rst new file mode 100644 index 00000000000000..bcc128404897da --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-26-22-03-16.gh-issue-152235.ZKWiWk.rst @@ -0,0 +1,2 @@ +Defer GC tracking of :meth:`set.intersection`, :meth:`set.difference` and +:meth:`set.symmetric_difference`. Patch by Donghee Na. diff --git a/Objects/setobject.c b/Objects/setobject.c index 0c63ef7fb272c5..aec73993451f65 100644 --- a/Objects/setobject.c +++ b/Objects/setobject.c @@ -1345,14 +1345,14 @@ set_update_impl(PySetObject *so, PyObject * const *others, can be retrieved or updated in a single cache line. */ +// Build a set/frozenset left GC-untracked; the caller must _PyObject_GC_TRACK() +// it once fully built, so a half-built set is never exposed during filling. static PyObject * -make_new_set(PyTypeObject *type, PyObject *iterable) +make_new_set_untracked(PyTypeObject *type, PyObject *iterable) { assert(PyType_Check(type)); PySetObject *so; - // Allocate untracked: the fill below runs user code, and a half-built - // set must not be reachable from another thread via gc.get_objects(). so = (PySetObject *)_PyType_AllocNoTrack(type, 0); if (so == NULL) return NULL; @@ -1372,13 +1372,21 @@ make_new_set(PyTypeObject *type, PyObject *iterable) } } - // Track only once fully built. - _PyObject_GC_TRACK(so); return (PyObject *)so; } static PyObject * -make_new_set_basetype(PyTypeObject *type, PyObject *iterable) +make_new_set(PyTypeObject *type, PyObject *iterable) +{ + PyObject *so = make_new_set_untracked(type, iterable); + if (so != NULL) { + _PyObject_GC_TRACK(so); + } + return so; +} + +static PyObject * +make_new_set_basetype_untracked(PyTypeObject *type, PyObject *iterable) { if (type != &PySet_Type && type != &PyFrozenSet_Type) { if (PyType_IsSubtype(type, &PySet_Type)) @@ -1386,7 +1394,17 @@ make_new_set_basetype(PyTypeObject *type, PyObject *iterable) else type = &PyFrozenSet_Type; } - return make_new_set(type, iterable); + return make_new_set_untracked(type, iterable); +} + +static PyObject * +make_new_set_basetype(PyTypeObject *type, PyObject *iterable) +{ + PyObject *so = make_new_set_basetype_untracked(type, iterable); + if (so != NULL) { + _PyObject_GC_TRACK(so); + } + return so; } // gh-140232: check whether a frozenset can be untracked from the GC @@ -1686,7 +1704,7 @@ set_intersection(PySetObject *so, PyObject *other) if ((PyObject *)so == other) return set_copy_impl(so); - result = (PySetObject *)make_new_set_basetype(Py_TYPE(so), NULL); + result = (PySetObject *)make_new_set_basetype_untracked(Py_TYPE(so), NULL); if (result == NULL) return NULL; @@ -1719,6 +1737,7 @@ set_intersection(PySetObject *so, PyObject *other) } Py_DECREF(key); } + _PyObject_GC_TRACK(result); return (PyObject *)result; } @@ -1750,6 +1769,7 @@ set_intersection(PySetObject *so, PyObject *other) Py_DECREF(result); return NULL; } + _PyObject_GC_TRACK(result); return (PyObject *)result; error: Py_DECREF(it); @@ -2064,7 +2084,7 @@ set_difference(PySetObject *so, PyObject *other) return set_copy_and_difference(so, other); } - result = make_new_set_basetype(Py_TYPE(so), NULL); + result = make_new_set_basetype_untracked(Py_TYPE(so), NULL); if (result == NULL) return NULL; @@ -2088,6 +2108,7 @@ set_difference(PySetObject *so, PyObject *other) } Py_DECREF(key); } + _PyObject_GC_TRACK(result); return result; } @@ -2111,6 +2132,7 @@ set_difference(PySetObject *so, PyObject *other) } Py_DECREF(key); } + _PyObject_GC_TRACK(result); return result; } @@ -2312,7 +2334,8 @@ static PyObject * set_symmetric_difference_impl(PySetObject *so, PyObject *other) /*[clinic end generated code: output=270ee0b5d42b0797 input=8c29b0be90d47feb]*/ { - PySetObject *result = (PySetObject *)make_new_set_basetype(Py_TYPE(so), NULL); + PySetObject *result = + (PySetObject *)make_new_set_basetype_untracked(Py_TYPE(so), NULL); if (result == NULL) { return NULL; } @@ -2324,6 +2347,7 @@ set_symmetric_difference_impl(PySetObject *so, PyObject *other) Py_DECREF(result); return NULL; } + _PyObject_GC_TRACK(result); return (PyObject *)result; } From a89de4b230f3003280e44546de8713e604d4c4eb Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 26 Jun 2026 16:03:29 +0200 Subject: [PATCH 451/818] [3.15] gh-152236: Fix skips on `_testcapi.set_nomemory` tests (GH-152253) (#152281) gh-152236: Fix skips on `_testcapi.set_nomemory` tests (GH-152253) (cherry picked from commit 1cbe460eb6c5f40980463f381b3096c92320ff84) Co-authored-by: sobolevn <mail@sobolevn.me> --- Lib/test/support/__init__.py | 18 +++++++++++++++++- Lib/test/test_atexit.py | 4 +--- Lib/test/test_capi/test_mem.py | 4 +--- Lib/test/test_class.py | 6 +----- Lib/test/test_exceptions.py | 18 +++--------------- Lib/test/test_interpreters/test_stress.py | 11 ++++++----- Lib/test/test_list.py | 4 +--- Lib/test/test_repl.py | 7 +------ Lib/test/test_weakref.py | 2 +- 9 files changed, 32 insertions(+), 42 deletions(-) diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index ebbce63852c4b8..65bf3e7feb837f 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -35,7 +35,7 @@ "requires_gil_enabled", "requires_linux_version", "requires_mac_ver", "check_syntax_error", "requires_gzip", "requires_bz2", "requires_lzma", "requires_zstd", - "bigmemtest", "bigaddrspacetest", "cpython_only", "get_attribute", + "bigmemtest", "nomemtest", "bigaddrspacetest", "cpython_only", "get_attribute", "requires_IEEE_754", "requires_zlib", "has_fork_support", "requires_fork", "has_subprocess_support", "requires_subprocess", @@ -1314,6 +1314,22 @@ def wrapper(self): return wrapper return decorator +def nomemtest(f): + """Check that we can use this test with `_testcapi.set_nomemory`.""" + from .import_helper import import_module + + @functools.wraps(f) + def internal(*args, **kwargs): + import_module('_testcapi') + return f(*args, **kwargs) + + return unittest.skipIf( + # Python built with Py_TRACE_REFS fail with a fatal error in + # _PyRefchain_Trace() on memory allocation error. + Py_TRACE_REFS, + 'cannot test Py_TRACE_REFS build', + )(cpython_only(internal)) + def bigaddrspacetest(f): """Decorator for tests that fill the address space.""" def wrapper(self): diff --git a/Lib/test/test_atexit.py b/Lib/test/test_atexit.py index 8256ff183f28c9..33c37648da31fc 100644 --- a/Lib/test/test_atexit.py +++ b/Lib/test/test_atexit.py @@ -191,9 +191,7 @@ def callback(): self.assertEqual(os.read(r, len(expected)), expected) os.close(r) - # Python built with Py_TRACE_REFS fail with a fatal error in - # _PyRefchain_Trace() on memory allocation error. - @unittest.skipIf(support.Py_TRACE_REFS, 'cannot test Py_TRACE_REFS build') + @support.nomemtest def test_atexit_with_low_memory(self): # gh-140080: Test that setting low memory after registering an atexit # callback doesn't cause an infinite loop during finalization. diff --git a/Lib/test/test_capi/test_mem.py b/Lib/test/test_capi/test_mem.py index 5035b2b4829bf6..66ab072733e17b 100644 --- a/Lib/test/test_capi/test_mem.py +++ b/Lib/test/test_capi/test_mem.py @@ -117,9 +117,7 @@ def test_pyobject_forbidden_bytes_is_freed(self): def test_pyobject_freed_is_freed(self): self.check_pyobject_is_freed('check_pyobject_freed_is_freed') - # Python built with Py_TRACE_REFS fail with a fatal error in - # _PyRefchain_Trace() on memory allocation error. - @unittest.skipIf(support.Py_TRACE_REFS, 'cannot test Py_TRACE_REFS build') + @support.nomemtest def test_set_nomemory(self): code = """if 1: import _testcapi diff --git a/Lib/test/test_class.py b/Lib/test/test_class.py index 64222555166a2e..e401941c6d6970 100644 --- a/Lib/test/test_class.py +++ b/Lib/test/test_class.py @@ -449,7 +449,6 @@ def __delattr__(self, *args): def testHasAttrString(self): import sys - from test.support import import_helper _testlimitedcapi = import_helper.import_module('_testlimitedcapi') class A: @@ -1013,11 +1012,8 @@ class C: C.a = X() C.a = X() - @cpython_only + @support.nomemtest def test_detach_materialized_dict_no_memory(self): - # Skip test if _testcapi is not available: - import_helper.import_module('_testcapi') - code = """if 1: import test.support import _testcapi diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py index df7a04273b9b41..cc7faef93e1af7 100644 --- a/Lib/test/test_exceptions.py +++ b/Lib/test/test_exceptions.py @@ -1583,11 +1583,7 @@ def recurse_in_body_and_except(): sys.setrecursionlimit(recursionlimit) - @cpython_only - # Python built with Py_TRACE_REFS fail with a fatal error in - # _PyRefchain_Trace() on memory allocation error. - @unittest.skipIf(support.Py_TRACE_REFS, 'cannot test Py_TRACE_REFS build') - @unittest.skipIf(_testcapi is None, "requires _testcapi") + @support.nomemtest def test_recursion_normalizing_with_no_memory(self): # Issue #30697. Test that in the abort that occurs when there is no # memory left and the size of the Python frames stack is greater than @@ -1774,11 +1770,7 @@ def test_unhandled(self): self.assertIn("test message", report) self.assertEndsWith(report, "\n") - @cpython_only - # Python built with Py_TRACE_REFS fail with a fatal error in - # _PyRefchain_Trace() on memory allocation error. - @unittest.skipIf(support.Py_TRACE_REFS, 'cannot test Py_TRACE_REFS build') - @unittest.skipIf(_testcapi is None, "requires _testcapi") + @support.nomemtest def test_memory_error_in_PyErr_PrintEx(self): code = """if 1: import _testcapi @@ -1936,12 +1928,8 @@ def test_keyerror_context(self): exc2 = None - @cpython_only - # Python built with Py_TRACE_REFS fail with a fatal error in - # _PyRefchain_Trace() on memory allocation error. - @unittest.skipIf(support.Py_TRACE_REFS, 'cannot test Py_TRACE_REFS build') + @support.nomemtest def test_exec_set_nomemory_hang(self): - import_module("_testcapi") # gh-134163: A MemoryError inside code that was wrapped by a try/except # block would lead to an infinite loop. diff --git a/Lib/test/test_interpreters/test_stress.py b/Lib/test/test_interpreters/test_stress.py index 6b40a536bd3c31..50d87a6ccd3cad 100644 --- a/Lib/test/test_interpreters/test_stress.py +++ b/Lib/test/test_interpreters/test_stress.py @@ -5,7 +5,7 @@ from test.support import import_helper from test.support import threading_helper # Raise SkipTest if subinterpreters not supported. -import_helper.import_module('_interpreters') +_interpreters = import_helper.import_module('_interpreters') from concurrent import interpreters from concurrent.interpreters import InterpreterError from .utils import TestBase @@ -75,12 +75,13 @@ def run(): start.set() support.gc_collect() + @support.nomemtest def test_create_interpreter_no_memory(self): - import _interpreters - _testcapi = import_helper.import_module("_testcapi") + import _testcapi - with self.assertRaises(InterpreterError): - _testcapi.set_nomemory(0, 1) + assertion = self.assertRaises(InterpreterError) + _testcapi.set_nomemory(0, 1) + with assertion: _interpreters.create() diff --git a/Lib/test/test_list.py b/Lib/test/test_list.py index 642b54d34849da..44ecd62d6735de 100644 --- a/Lib/test/test_list.py +++ b/Lib/test/test_list.py @@ -3,7 +3,6 @@ import textwrap from test import list_tests, support from test.support import cpython_only -from test.support.import_helper import import_module from test.support.script_helper import assert_python_failure, assert_python_ok import pickle import unittest @@ -326,10 +325,9 @@ def test_tier2_invalidates_iterator(self): a.append(4) self.assertEqual(list(it), []) - @support.cpython_only + @support.nomemtest def test_no_memory(self): # gh-118331: Make sure we don't crash if list allocation fails - import_module("_testcapi") code = textwrap.dedent(""" import _testcapi, sys # Prime the freelist diff --git a/Lib/test/test_repl.py b/Lib/test/test_repl.py index 850cb66a89ba84..0f5009c3212490 100644 --- a/Lib/test/test_repl.py +++ b/Lib/test/test_repl.py @@ -17,7 +17,6 @@ SHORT_TIMEOUT, ) from test.support.script_helper import kill_python -from test.support.import_helper import import_module try: import pty @@ -99,12 +98,8 @@ def run_on_interactive_mode(source): @support.force_not_colorized_test_class class TestInteractiveInterpreter(unittest.TestCase): - @cpython_only - # Python built with Py_TRACE_REFS fail with a fatal error in - # _PyRefchain_Trace() on memory allocation error. - @unittest.skipIf(support.Py_TRACE_REFS, 'cannot test Py_TRACE_REFS build') + @support.nomemtest def test_no_memory(self): - import_module("_testcapi") # Issue #30696: Fix the interactive interpreter looping endlessly when # no memory. Check also that the fix does not break the interactive # loop when an exception is raised. diff --git a/Lib/test/test_weakref.py b/Lib/test/test_weakref.py index b187643e84521c..f02691bf300200 100644 --- a/Lib/test/test_weakref.py +++ b/Lib/test/test_weakref.py @@ -1019,7 +1019,7 @@ def __del__(self): pass del x support.gc_collect() - @support.cpython_only + @support.nomemtest def test_no_memory_when_clearing(self): # gh-118331: Make sure we do not raise an exception from the destructor # when clearing weakrefs if allocating the intermediate tuple fails. From f3e6bdafd2804c1bf7d4cb31fed3f983fd5936ba Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 26 Jun 2026 16:15:21 +0200 Subject: [PATCH 452/818] [3.15] gh-152052: Fix misleading `json` error for `\uXXXX` escape at the end of input (GH-152053) (#152283) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (cherry picked from commit 588be7af08c04d63c1a920539c64885fbc4c6d38) Co-authored-by: tonghuaroot (童话) <tonghuaroot@gmail.com> Co-authored-by: Stan Ulbrych <stan@python.org> --- Lib/test/test_json/test_fail.py | 7 +++++++ Lib/test/test_json/test_scanstring.py | 3 +++ .../Library/2026-06-24-12-00-00.gh-issue-152052.yBssDE.rst | 2 ++ Modules/_json.c | 2 +- 4 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2026-06-24-12-00-00.gh-issue-152052.yBssDE.rst diff --git a/Lib/test/test_json/test_fail.py b/Lib/test/test_json/test_fail.py index 79c44af2fbf0e1..7f99a6331d3625 100644 --- a/Lib/test/test_json/test_fail.py +++ b/Lib/test/test_json/test_fail.py @@ -144,6 +144,13 @@ def test_truncated_input(self): ('"', 'Unterminated string starting at', 0), ('"spam', 'Unterminated string starting at', 0), ] + # A complete \uXXXX escape at end of input leaves it unterminated. + test_cases += [ + (r'"\u0041', 'Unterminated string starting at', 0), + (r'"\ud834', 'Unterminated string starting at', 0), + (r'"\ud834\udd1e', 'Unterminated string starting at', 0), + (r'{"a": "\u0041', 'Unterminated string starting at', 6), + ] for data, msg, idx in test_cases: with self.assertRaises(self.JSONDecodeError) as cm: self.loads(data) diff --git a/Lib/test/test_json/test_scanstring.py b/Lib/test/test_json/test_scanstring.py index 9a6cdfe12d266c..a52b01c71130d8 100644 --- a/Lib/test/test_json/test_scanstring.py +++ b/Lib/test/test_json/test_scanstring.py @@ -137,6 +137,9 @@ def test_bad_escapes(self): '"\\ud834\\u-123"', '"\\ud834\\u+123"', '"\\ud834\\u1_23"', + # Truncated or non-hex \uXXXX escape at end of input. + '"\\u004', + '"\\uXYZW', ] for s in bad_escapes: with self.assertRaises(self.JSONDecodeError, msg=s): diff --git a/Misc/NEWS.d/next/Library/2026-06-24-12-00-00.gh-issue-152052.yBssDE.rst b/Misc/NEWS.d/next/Library/2026-06-24-12-00-00.gh-issue-152052.yBssDE.rst new file mode 100644 index 00000000000000..f9ffbbd342fc81 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-24-12-00-00.gh-issue-152052.yBssDE.rst @@ -0,0 +1,2 @@ +The :mod:`json` C accelerator now correctly reports an unterminated string for a +``\uXXXX`` escape at the end of the input. diff --git a/Modules/_json.c b/Modules/_json.c index 6c4f38834631d3..858702e6f4500e 100644 --- a/Modules/_json.c +++ b/Modules/_json.c @@ -574,7 +574,7 @@ scanstring_unicode(PyObject *pystr, Py_ssize_t end, int strict, Py_ssize_t *next c = 0; next++; end = next + 4; - if (end >= len) { + if (end > len) { raise_errmsg("Invalid \\uXXXX escape", pystr, next - 1); goto bail; } From f2402cba9dcbd78a267e60d65bbf40595dc78b3a Mon Sep 17 00:00:00 2001 From: Victor Stinner <vstinner@python.org> Date: Fri, 26 Jun 2026 16:26:52 +0200 Subject: [PATCH 453/818] [3.15] gh-121249: Soft deprecate F and D struct format types (#149346) (#152274) gh-121249: Soft deprecate F and D struct format types (#149346) Remove F/D type codes from table in the struct module documentation. (cherry picked from commit 5f17434a1ec9a121eb38f71dc3d5809020b5fbb4) Co-authored-by: Sergey B Kirpichev <skirpichev@gmail.com> --- Doc/deprecations/soft-deprecations.rst | 5 +++++ Doc/library/struct.rst | 11 +++++------ Doc/whatsnew/3.15.rst | 5 +++++ 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/Doc/deprecations/soft-deprecations.rst b/Doc/deprecations/soft-deprecations.rst index a270052788ef2a..d1dd2b2d8c520d 100644 --- a/Doc/deprecations/soft-deprecations.rst +++ b/Doc/deprecations/soft-deprecations.rst @@ -19,3 +19,8 @@ There are no plans to remove :term:`soft deprecated` APIs. (Contributed by Gregory P. Smith in :gh:`86519` and Hugo van Kemenade in :gh:`148100`.) + +* Using ``'F'`` and ``'D'`` format type codes of the :mod:`struct` module + now are :term:`soft deprecated` in favor of two-letter forms ``'Zf'`` + and ``'Zd'``. + (Contributed by Sergey B Kirpichev in :gh:`121249`.) diff --git a/Doc/library/struct.rst b/Doc/library/struct.rst index 05662c6c2d898d..ef535e3ca6e882 100644 --- a/Doc/library/struct.rst +++ b/Doc/library/struct.rst @@ -260,10 +260,6 @@ platform-dependent. +--------+--------------------------+--------------------+----------------+------------+ | ``d`` | :c:expr:`double` | float | 8 | \(4) | +--------+--------------------------+--------------------+----------------+------------+ -| ``F`` | :c:expr:`float complex` | complex | 8 | \(10) | -+--------+--------------------------+--------------------+----------------+------------+ -| ``D`` | :c:expr:`double complex` | complex | 16 | \(10) | -+--------+--------------------------+--------------------+----------------+------------+ | ``Zf`` | :c:expr:`float complex` | complex | 8 | \(10) | +--------+--------------------------+--------------------+----------------+------------+ | ``Zd`` | :c:expr:`double complex` | complex | 16 | \(10) | @@ -286,6 +282,7 @@ platform-dependent. .. versionchanged:: 3.15 Added support for the ``'Zf'`` and ``'Zd'`` formats. + ``'F'`` and ``'D'`` formats are :term:`soft deprecated`. .. seealso:: @@ -376,13 +373,15 @@ Notes: are accepted. (10) - For the ``'F'`` and ``'D'`` format characters, the packed representation uses + For the ``'Zf'`` and ``'Zd'`` type codes, the packed representation uses the IEEE 754 binary32 and binary64 format for components of the complex number, regardless of the floating-point format used by the platform. - Note that complex types (``F``/``Zf`` and ``D``/``Zd``) are available unconditionally, + Note that complex types are available unconditionally, despite complex types being an optional feature in C. As specified in the C11 standard, each complex type is represented by a two-element C array containing, respectively, the real and imaginary parts. + The ``'F'`` and ``'D'`` (for ``'Zf'`` and ``'Zd'``, respectively) format + characters are supported for compatibility. A format character may be preceded by an integral repeat count. For example, diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst index 88b238c709dd0e..bad9e2d8dff37f 100644 --- a/Doc/whatsnew/3.15.rst +++ b/Doc/whatsnew/3.15.rst @@ -2280,6 +2280,11 @@ New deprecations (Contributed by Sergey B Kirpichev and Serhiy Storchaka in :gh:`143715`.) + * Using ``'F'`` and ``'D'`` type codes now are :term:`soft deprecated` + in favor of two-letter forms ``'Zf'`` and ``'Zd'``. + (Contributed by Sergey B Kirpichev in :gh:`121249`.) + + * :mod:`typing`: * The following statements now cause ``DeprecationWarning``\ s to be emitted From 52bdfcc141079806b73e28d7901552c9b667bfc2 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 26 Jun 2026 17:00:56 +0200 Subject: [PATCH 454/818] [3.15] gh-139145: Fix tkinter event loop in interactive mode (GH-152257) (GH-152291) When a Tcl command running its own event loop (such as vwait or wait_variable) was active and the user typed input on stdin, the event loop kept spinning at 100% CPU. The stdin file handler is now removed as soon as input becomes available. Also fix gh-139816: an exception raised in a callback no longer stops the event loop to wait for Enter on a Python built without readline; pending callbacks keep running until input is actually available on stdin. (cherry picked from commit 3ffda34f5cd3809a8755c9596948e4e477661d5f) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: mdehoon <mjldehoon@yahoo.com> Co-authored-by: Christopher Chavez <chrischavez@gmx.us> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --- ...-06-25-14-32-42.gh-issue-139145.kT9rmP.rst | 5 ++++ ...-06-25-14-32-43.gh-issue-139816.Lq2vXa.rst | 4 +++ Modules/_tkinter.c | 30 +++++++++++++------ 3 files changed, 30 insertions(+), 9 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-06-25-14-32-42.gh-issue-139145.kT9rmP.rst create mode 100644 Misc/NEWS.d/next/Library/2026-06-25-14-32-43.gh-issue-139816.Lq2vXa.rst diff --git a/Misc/NEWS.d/next/Library/2026-06-25-14-32-42.gh-issue-139145.kT9rmP.rst b/Misc/NEWS.d/next/Library/2026-06-25-14-32-42.gh-issue-139145.kT9rmP.rst new file mode 100644 index 00000000000000..3fa639c5f727ba --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-25-14-32-42.gh-issue-139145.kT9rmP.rst @@ -0,0 +1,5 @@ +Fix a busy loop in :mod:`tkinter` on interactive Python. When a Tcl command +running its own event loop (such as ``vwait`` or :meth:`!wait_variable`) was +active and input arrived on stdin, the event loop kept spinning at 100% CPU. +The stdin file handler is now removed as soon as input is available. Based on +a patch by Michiel de Hoon. diff --git a/Misc/NEWS.d/next/Library/2026-06-25-14-32-43.gh-issue-139816.Lq2vXa.rst b/Misc/NEWS.d/next/Library/2026-06-25-14-32-43.gh-issue-139816.Lq2vXa.rst new file mode 100644 index 00000000000000..b180dee686caf8 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-25-14-32-43.gh-issue-139816.Lq2vXa.rst @@ -0,0 +1,4 @@ +Fix a hang in :mod:`tkinter` on interactive Python built without +:mod:`readline`. An exception raised in a callback no longer causes the +event loop to stop and wait for the user to press Enter; pending callbacks +now keep running until input is actually available on stdin. diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c index 466e275c5cecf0..86b1b2d9a534d8 100644 --- a/Modules/_tkinter.c +++ b/Modules/_tkinter.c @@ -3433,7 +3433,13 @@ static int stdin_ready = 0; static void MyFileProc(void *clientData, int mask) { + int tfile = (int)(Py_intptr_t)clientData; stdin_ready = 1; + /* Stop watching stdin now that input is available. Doing it here rather + than after the loop below ensures that a nested event loop (e.g. the one + started by wait_variable) does not keep waking up on the same unread + input, spinning at 100% CPU. */ + Tcl_DeleteFileHandler(tfile); } #endif @@ -3450,9 +3456,10 @@ EventHook(void) errorInCmd = 0; #ifndef MS_WINDOWS tfile = fileno(stdin); - Tcl_CreateFileHandler(tfile, TCL_READABLE, MyFileProc, NULL); + Tcl_CreateFileHandler(tfile, TCL_READABLE, MyFileProc, + (void *)(Py_intptr_t)tfile); #endif - while (!errorInCmd && !stdin_ready) { + while (!stdin_ready) { int result; #ifdef MS_WINDOWS if (_kbhit()) { @@ -3472,18 +3479,23 @@ EventHook(void) Sleep(Tkinter_busywaitinterval); Py_END_ALLOW_THREADS + /* Report an exception raised in a callback, but keep pumping events + instead of returning to the prompt: without readline there is no + input waiting on stdin yet, so returning here would block in fgets + until the user hits enter, freezing later callbacks. */ + if (errorInCmd) { + errorInCmd = 0; + PyErr_SetRaisedException(excInCmd); + excInCmd = NULL; + PyErr_Print(); + } if (result < 0) break; } #ifndef MS_WINDOWS - Tcl_DeleteFileHandler(tfile); + if (!stdin_ready) + Tcl_DeleteFileHandler(tfile); #endif - if (errorInCmd) { - errorInCmd = 0; - PyErr_SetRaisedException(excInCmd); - excInCmd = NULL; - PyErr_Print(); - } PyEval_SaveThread(); return 0; } From 073b658dd317ecdcab99898bca053aab59ea590d Mon Sep 17 00:00:00 2001 From: Donghee Na <donghee.na@python.org> Date: Sat, 27 Jun 2026 02:54:25 +0900 Subject: [PATCH 455/818] [3.15] gh-152235: Defer GC tracking in set.union and set.difference (gh-152290) (gh-152316) (cherry picked from commit 5a549e82b81378cb294904dab49cbee853bddd64) --- ...-06-26-22-03-16.gh-issue-152235.ZKWiWk.rst | 5 +- Objects/setobject.c | 50 ++++++++++++------- 2 files changed, 35 insertions(+), 20 deletions(-) diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-26-22-03-16.gh-issue-152235.ZKWiWk.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-26-22-03-16.gh-issue-152235.ZKWiWk.rst index bcc128404897da..ff89a2445cb4fe 100644 --- a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-26-22-03-16.gh-issue-152235.ZKWiWk.rst +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-26-22-03-16.gh-issue-152235.ZKWiWk.rst @@ -1,2 +1,3 @@ -Defer GC tracking of :meth:`set.intersection`, :meth:`set.difference` and -:meth:`set.symmetric_difference`. Patch by Donghee Na. +Defer GC tracking of :meth:`set.intersection`, :meth:`set.difference`, +:meth:`set.symmetric_difference`, :meth:`set.union` and ``set.__sub__``. +Patch by Donghee Na. diff --git a/Objects/setobject.c b/Objects/setobject.c index aec73993451f65..bb407ceabadf1c 100644 --- a/Objects/setobject.c +++ b/Objects/setobject.c @@ -1567,6 +1567,21 @@ set_swap_bodies(PySetObject *a, PySetObject *b) FT_ATOMIC_STORE_PTR_RELEASE(b->table, b_table); } +static PyObject * +set_copy_untracked_lock_held(PySetObject *so) +{ + _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(so); + PyObject *copy = make_new_set_basetype_untracked(Py_TYPE(so), NULL); + if (copy == NULL) { + return NULL; + } + if (set_merge_lock_held((PySetObject *)copy, (PyObject *)so) < 0) { + Py_DECREF(copy); + return NULL; + } + return copy; +} + /*[clinic input] @critical_section set.copy @@ -1579,14 +1594,9 @@ static PyObject * set_copy_impl(PySetObject *so) /*[clinic end generated code: output=c9223a1e1cc6b041 input=c169a4fbb8209257]*/ { - _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(so); - PyObject *copy = make_new_set_basetype(Py_TYPE(so), NULL); - if (copy == NULL) { - return NULL; - } - if (set_merge_lock_held((PySetObject *)copy, (PyObject *)so) < 0) { - Py_DECREF(copy); - return NULL; + PyObject *copy = set_copy_untracked_lock_held(so); + if (copy != NULL) { + _PyObject_GC_TRACK(copy); } return copy; } @@ -1642,7 +1652,8 @@ set_union_impl(PySetObject *so, PyObject * const *others, PyObject *other; Py_ssize_t i; - result = (PySetObject *)set_copy((PyObject *)so, NULL); + result = (PySetObject *)make_new_set_basetype_untracked(Py_TYPE(so), + (PyObject *)so); if (result == NULL) return NULL; @@ -1655,6 +1666,7 @@ set_union_impl(PySetObject *so, PyObject * const *others, return NULL; } } + _PyObject_GC_TRACK(result); return (PyObject *)result; } @@ -2045,11 +2057,11 @@ set_difference_update_impl(PySetObject *so, PyObject * const *others, } static PyObject * -set_copy_and_difference(PySetObject *so, PyObject *other) +set_copy_and_difference_untracked(PySetObject *so, PyObject *other) { PyObject *result; - result = set_copy_impl(so); + result = set_copy_untracked_lock_held(so); if (result == NULL) return NULL; if (set_difference_update_internal((PySetObject *) result, other) == 0) @@ -2059,7 +2071,7 @@ set_copy_and_difference(PySetObject *so, PyObject *other) } static PyObject * -set_difference(PySetObject *so, PyObject *other) +set_difference_untracked(PySetObject *so, PyObject *other) { PyObject *result; PyObject *key; @@ -2075,13 +2087,13 @@ set_difference(PySetObject *so, PyObject *other) other_size = PyDict_GET_SIZE(other); } else { - return set_copy_and_difference(so, other); + return set_copy_and_difference_untracked(so, other); } /* If len(so) much more than len(other), it's more efficient to simply copy * so and then iterate other looking for common elements. */ if ((PySet_GET_SIZE(so) >> 2) > other_size) { - return set_copy_and_difference(so, other); + return set_copy_and_difference_untracked(so, other); } result = make_new_set_basetype_untracked(Py_TYPE(so), NULL); @@ -2108,7 +2120,6 @@ set_difference(PySetObject *so, PyObject *other) } Py_DECREF(key); } - _PyObject_GC_TRACK(result); return result; } @@ -2132,7 +2143,6 @@ set_difference(PySetObject *so, PyObject *other) } Py_DECREF(key); } - _PyObject_GC_TRACK(result); return result; } @@ -2159,7 +2169,7 @@ set_difference_multi_impl(PySetObject *so, PyObject * const *others, other = others[0]; Py_BEGIN_CRITICAL_SECTION2(so, other); - result = set_difference(so, other); + result = set_difference_untracked(so, other); Py_END_CRITICAL_SECTION2(); if (result == NULL) return NULL; @@ -2175,6 +2185,7 @@ set_difference_multi_impl(PySetObject *so, PyObject * const *others, return NULL; } } + _PyObject_GC_TRACK(result); return result; } @@ -2187,8 +2198,11 @@ set_sub(PyObject *self, PyObject *other) PyObject *rv; Py_BEGIN_CRITICAL_SECTION2(so, other); - rv = set_difference(so, other); + rv = set_difference_untracked(so, other); Py_END_CRITICAL_SECTION2(); + if (rv != NULL) { + _PyObject_GC_TRACK(rv); + } return rv; } From 2a3189ce67e415c84874f2f94cf10b52928c47c0 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 26 Jun 2026 21:22:21 +0200 Subject: [PATCH 456/818] [3.15] gh-80937: Fix memory leak in tkinter createcommand (GH-152294) (GH-152327) A command created with createcommand() held a strong reference to the interpreter, forming an uncollectable cycle (interpreter -> command -> interpreter) that kept the interpreter and the callback alive until the command was removed with deletecommand() or destroy(). The command now borrows the reference; it cannot outlive the interpreter, which deletes its commands when finalized. (cherry picked from commit bbf7786a904e558a15d01475356167e29b2e3708) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --- Lib/test/test_tkinter/test_misc.py | 12 ++++++++++++ .../2026-06-26-13-10-00.gh-issue-80937.Hq3mNp.rst | 4 ++++ Modules/_tkinter.c | 7 +++++-- 3 files changed, 21 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-06-26-13-10-00.gh-issue-80937.Hq3mNp.rst diff --git a/Lib/test/test_tkinter/test_misc.py b/Lib/test/test_tkinter/test_misc.py index 4a95f5550878d3..2924fa0caacc71 100644 --- a/Lib/test/test_tkinter/test_misc.py +++ b/Lib/test/test_tkinter/test_misc.py @@ -1,6 +1,7 @@ import collections.abc import functools import unittest +import weakref import tkinter from tkinter import TclError import enum @@ -348,6 +349,17 @@ def callback(): self.root.deletecommand(name) self.assertRaises(TclError, self.root.tk.call, name) + def test_createcommand_no_leak(self): + # gh-80937: dropping the interpreter must release a command's callback, + # even without an explicit deletecommand(). + interp = tkinter.Tcl() + callback = lambda: '' + ref = weakref.ref(callback) + interp.tk.createcommand('cb', callback) + del callback, interp + support.gc_collect() + self.assertIsNone(ref()) + def test_option(self): self.addCleanup(self.root.option_clear) self.root.option_add('*Button.background', 'red') diff --git a/Misc/NEWS.d/next/Library/2026-06-26-13-10-00.gh-issue-80937.Hq3mNp.rst b/Misc/NEWS.d/next/Library/2026-06-26-13-10-00.gh-issue-80937.Hq3mNp.rst new file mode 100644 index 00000000000000..4ea0179c6586d4 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-26-13-10-00.gh-issue-80937.Hq3mNp.rst @@ -0,0 +1,4 @@ +Fix a memory leak in :mod:`tkinter` when a Tcl command created with +``createcommand`` was not explicitly removed before the interpreter was +deleted. The command no longer keeps the interpreter alive through a +reference cycle. diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c index 86b1b2d9a534d8..137eba40a762c0 100644 --- a/Modules/_tkinter.c +++ b/Modules/_tkinter.c @@ -2464,7 +2464,7 @@ PythonCmdDelete(ClientData clientData) PythonCmd_ClientData *data = (PythonCmd_ClientData *)clientData; ENTER_PYTHON - Py_XDECREF(data->self); + /* data->self is borrowed. */ Py_XDECREF(data->func); PyMem_Free(data); LEAVE_PYTHON @@ -2533,7 +2533,9 @@ _tkinter_tkapp_createcommand_impl(TkappObject *self, const char *name, data = PyMem_NEW(PythonCmd_ClientData, 1); if (!data) return PyErr_NoMemory(); - Py_INCREF(self); + /* Borrow the interpreter: a strong reference would form an uncollectable + cycle (interp -> command -> data->self -> interp) and leak the command + (gh-80937). The command cannot outlive the interpreter. */ data->self = self; data->func = Py_NewRef(func); if (self->threaded && self->thread_id != Tcl_GetCurrentThread()) { @@ -2566,6 +2568,7 @@ _tkinter_tkapp_createcommand_impl(TkappObject *self, const char *name, } if (err) { PyErr_SetString(Tkinter_TclError, "can't create Tcl command"); + Py_DECREF(data->func); PyMem_Free(data); return NULL; } From d19b93a6fcacd2914ab60f181b27614f07189a08 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 26 Jun 2026 22:59:17 +0200 Subject: [PATCH 457/818] [3.15] gh-98894: Skip test_dtrace when building without dtrace (GH-152239) (#152300) gh-98894: Skip test_dtrace when building without dtrace (GH-152239) (cherry picked from commit 671357691f84820d4a4799012e937ab9dcbfdaca) Co-authored-by: stratakis <cstratak@redhat.com> --- Lib/test/test_dtrace.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/Lib/test/test_dtrace.py b/Lib/test/test_dtrace.py index 3de87fc704d43e..2cfd94239aee24 100644 --- a/Lib/test/test_dtrace.py +++ b/Lib/test/test_dtrace.py @@ -14,6 +14,10 @@ if not support.has_subprocess_support: raise unittest.SkipTest("test module requires subprocess") +if not sysconfig.get_config_var('WITH_DTRACE'): + raise unittest.SkipTest( + "CPython must be configured with the --with-dtrace option." + ) def abspath(filename): @@ -397,12 +401,9 @@ class BPFTraceOptimizedTests(TraceTests, unittest.TestCase): class CheckDtraceProbes(unittest.TestCase): @classmethod def setUpClass(cls): - if sysconfig.get_config_var('WITH_DTRACE'): - readelf_major_version, readelf_minor_version = cls.get_readelf_version() - if support.verbose: - print(f"readelf version: {readelf_major_version}.{readelf_minor_version}") - else: - raise unittest.SkipTest("CPython must be configured with the --with-dtrace option.") + readelf_major_version, readelf_minor_version = cls.get_readelf_version() + if support.verbose: + print(f"readelf version: {readelf_major_version}.{readelf_minor_version}") @staticmethod From ba4084fa1767278b5703cad90c7a15067a3e5017 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 27 Jun 2026 01:13:47 +0200 Subject: [PATCH 458/818] [3.15] IDLE: fix dedent() usage in htest (GH-152256) (#152342) IDLE: fix dedent() usage in htest (GH-152256) Fix typos: in GH-112642, initial string concatenation quotes were left when switching to textwrap.dedent(). (cherry picked from commit 74272d4f0b8478c1d879671ba35ec4ddaae50178) Co-authored-by: Inada Naoki <songofacandy@gmail.com> --- Lib/idlelib/idle_test/htest.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Lib/idlelib/idle_test/htest.py b/Lib/idlelib/idle_test/htest.py index b63ff9ec2877b9..778e5c3d84e496 100644 --- a/Lib/idlelib/idle_test/htest.py +++ b/Lib/idlelib/idle_test/htest.py @@ -216,9 +216,9 @@ 'file': 'browser', 'kwds': {}, 'msg': textwrap.dedent(""" - "Inspect names of module, class(with superclass if applicable), - "methods and functions. Toggle nested items. Double clicking - "on items prints a traceback for an exception that is ignored.""") + Inspect names of module, class(with superclass if applicable), + methods and functions. Toggle nested items. Double clicking + on items prints a traceback for an exception that is ignored.""") } _multistatus_bar_spec = { From 90528ec04001f0a01e1a6c1565f3837751c013db Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 27 Jun 2026 01:30:32 +0200 Subject: [PATCH 459/818] [3.15] gh-88758: Handle non-tkinter widgets in tkinter focus methods (GH-152337) (GH-152346) focus_get(), focus_displayof(), focus_lastfor() and winfo_containing() now return None instead of raising KeyError when the focused widget was not created by tkinter (for example a torn-off menu). (cherry picked from commit 5fed5ce85d9c862673cc68294f757f345bbcc9b1) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --- Lib/test/test_tkinter/test_misc.py | 16 +++++++++++++++ Lib/tkinter/__init__.py | 20 +++++++++++++++---- ...6-06-26-15-30-00.gh-issue-88758.Qw7nLp.rst | 4 ++++ 3 files changed, 36 insertions(+), 4 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-06-26-15-30-00.gh-issue-88758.Qw7nLp.rst diff --git a/Lib/test/test_tkinter/test_misc.py b/Lib/test/test_tkinter/test_misc.py index 2924fa0caacc71..11f40df21b1ebd 100644 --- a/Lib/test/test_tkinter/test_misc.py +++ b/Lib/test/test_tkinter/test_misc.py @@ -405,6 +405,22 @@ def test_focus_methods(self): self.root.update() self.assertIs(self.root.focus_get(), b) + def test_focus_methods_unresolvable(self): + # The focus may be on a widget that tkinter did not create and so + # cannot map to an instance (e.g. a torn-off menu). The focus + # methods return None instead of raising KeyError (gh-88758). + menu = tkinter.Menu(self.root, tearoff=1) + menu.add_command(label='Hello') + tearoff = self.root.tk.call('tk::TearOffMenu', str(menu), 0, 0) + self.addCleanup(self.root.tk.call, 'destroy', tearoff) + self.root.update() + self.assertRaises(KeyError, self.root.nametowidget, tearoff) + + self.root.tk.call('focus', '-force', tearoff) + self.root.update() + self.assertIsNone(self.root.focus_get()) + self.assertIsNone(self.root.focus_displayof()) + def test_grab(self): f = tkinter.Frame(self.root) f.pack() diff --git a/Lib/tkinter/__init__.py b/Lib/tkinter/__init__.py index 42cd8204d0ac51..6b2f21b9c0d557 100644 --- a/Lib/tkinter/__init__.py +++ b/Lib/tkinter/__init__.py @@ -827,7 +827,10 @@ def focus_get(self): the focus.""" name = self.tk.call('focus') if name == 'none' or not name: return None - return self._nametowidget(name) + try: + return self._nametowidget(name) + except KeyError: + return None def focus_displayof(self): """Return the widget which has currently the focus on the @@ -836,14 +839,20 @@ def focus_displayof(self): Return None if the application does not have the focus.""" name = self.tk.call('focus', '-displayof', self._w) if name == 'none' or not name: return None - return self._nametowidget(name) + try: + return self._nametowidget(name) + except KeyError: + return None def focus_lastfor(self): """Return the widget which would have the focus if top level for this widget gets the focus from the window manager.""" name = self.tk.call('focus', '-lastfor', self._w) if name == 'none' or not name: return None - return self._nametowidget(name) + try: + return self._nametowidget(name) + except KeyError: + return None def tk_focusFollowsMouse(self): """The widget under mouse will get automatically focus. Can not @@ -1246,7 +1255,10 @@ def winfo_containing(self, rootX, rootY, displayof=0): + self._displayof(displayof) + (rootX, rootY) name = self.tk.call(args) if not name: return None - return self._nametowidget(name) + try: + return self._nametowidget(name) + except KeyError: + return None def winfo_depth(self): """Return the number of bits per pixel.""" diff --git a/Misc/NEWS.d/next/Library/2026-06-26-15-30-00.gh-issue-88758.Qw7nLp.rst b/Misc/NEWS.d/next/Library/2026-06-26-15-30-00.gh-issue-88758.Qw7nLp.rst new file mode 100644 index 00000000000000..31d567194fb903 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-26-15-30-00.gh-issue-88758.Qw7nLp.rst @@ -0,0 +1,4 @@ +:meth:`!tkinter.Misc.focus_get`, :meth:`!focus_displayof`, +:meth:`!focus_lastfor` and :meth:`!winfo_containing` now return ``None`` +instead of raising :exc:`KeyError` when the widget was not created by +:mod:`tkinter` (for example a torn-off menu). From 029016654ec08142f59d4f46113b3c1ec0830387 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 27 Jun 2026 01:31:46 +0200 Subject: [PATCH 460/818] [3.15] gh-38464: Make tkinter nametowidget() work with cloned menus (GH-152336) (GH-152349) Map the auto-generated name of a cloned menu (a menu used as a menubar or a cascade) back to the original widget instead of raising KeyError. (cherry picked from commit 5c3555bdc56a8e110a7d366f8ac0a93cd082e90f) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --- Lib/test/test_tkinter/test_misc.py | 26 +++++++++++++++++++ Lib/tkinter/__init__.py | 11 +++++++- ...6-06-26-15-00-00.gh-issue-38464.yDPjKH.rst | 3 +++ 3 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2026-06-26-15-00-00.gh-issue-38464.yDPjKH.rst diff --git a/Lib/test/test_tkinter/test_misc.py b/Lib/test/test_tkinter/test_misc.py index 11f40df21b1ebd..2a66ce01e0cf11 100644 --- a/Lib/test/test_tkinter/test_misc.py +++ b/Lib/test/test_tkinter/test_misc.py @@ -388,6 +388,32 @@ def test_nametowidget(self): self.assertIs(self.root.nametowidget(str(b)), b) self.assertRaises(KeyError, self.root.nametowidget, '.nonexistent') + def test_nametowidget_menu_clone(self): + # A menu used as a menubar or cascade is cloned by Tk under an + # auto-generated name (each path component is the original name + # prefixed with one or more '#' clone markers). nametowidget() + # maps such a name back to the original widget (gh-38464). + menubar = tkinter.Menu(self.root) + filemenu = tkinter.Menu(menubar, tearoff=0) + menubar.add_cascade(label='File', menu=filemenu) + submenu = tkinter.Menu(filemenu, tearoff=0) + filemenu.add_cascade(label='More', menu=submenu) + self.root['menu'] = menubar + self.root.update_idletasks() + + originals = {menubar, filemenu, submenu} + clones = [] + def collect(parent): + for name in self.root.tk.splitlist( + self.root.tk.call('winfo', 'children', parent)): + clones.append(name) + collect(name) + collect('.') + # Every menu (originals and clones) resolves to an original widget. + self.assertTrue(any('#' in name for name in clones)) + for name in clones: + self.assertIn(self.root.nametowidget(name), originals) + def test_focus_methods(self): f = tkinter.Frame(self.root, width=150, height=100) f.pack() diff --git a/Lib/tkinter/__init__.py b/Lib/tkinter/__init__.py index 6b2f21b9c0d557..9899d7622c672d 100644 --- a/Lib/tkinter/__init__.py +++ b/Lib/tkinter/__init__.py @@ -1724,7 +1724,16 @@ def nametowidget(self, name): for n in name: if not n: break - w = w.children[n] + try: + w = w.children[n] + except KeyError: + # Menu clones (a menu used as a menubar or a cascade) get + # auto-generated names where each path component is the + # original name prefixed with one or more '#' clone markers. + # Map such a name back to the original widget. + if not n.startswith('#'): + raise + w = w.children[n.rsplit('#', 1)[-1]] return w diff --git a/Misc/NEWS.d/next/Library/2026-06-26-15-00-00.gh-issue-38464.yDPjKH.rst b/Misc/NEWS.d/next/Library/2026-06-26-15-00-00.gh-issue-38464.yDPjKH.rst new file mode 100644 index 00000000000000..c1c272b97d4b0a --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-26-15-00-00.gh-issue-38464.yDPjKH.rst @@ -0,0 +1,3 @@ +:meth:`!tkinter.Misc.nametowidget` now resolves the auto-generated names of +cloned menus (a menu used as a menubar or a cascade) back to the original +widget. From fbf61fbd4deede7deecb7af65e3dee236ce18775 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 27 Jun 2026 09:41:21 +0200 Subject: [PATCH 461/818] [3.15] gh-151678: Add more tests for tkinter.dnd (GH-152362) (GH-152367) Cover the drag cursor, the Motion and ButtonRelease bindings, switching between targets, the target search up the master chain, dnd_accept() returning None, and restarting after a drag has finished. (cherry picked from commit 389e00f13fb5b20b424980b08678753441db7529) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --- Lib/test/test_tkinter/test_dnd.py | 73 +++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/Lib/test/test_tkinter/test_dnd.py b/Lib/test/test_tkinter/test_dnd.py index 501b0d7f78586c..fe3685aefe48be 100644 --- a/Lib/test/test_tkinter/test_dnd.py +++ b/Lib/test/test_tkinter/test_dnd.py @@ -60,6 +60,15 @@ def setUp(self): self.source = Source(self.log) self.target = Target(self.canvas, self.log) + def tearDown(self): + # Make sure no drag-and-drop is left active between tests: the + # recursion guard is a name-mangled attribute on the root. + try: + del self.root._DndHandler__dnd + except AttributeError: + pass + super().tearDown() + def test_drag_and_drop(self): handler = dnd.dnd_start(self.source, FakeEvent(self.canvas)) self.assertIsNotNone(handler) @@ -93,6 +102,70 @@ def test_no_recursive_start(self): def test_high_button_number_ignored(self): self.assertIsNone(dnd.dnd_start(self.source, FakeEvent(self.canvas, num=6))) + def test_restart_after_finish(self): + handler = dnd.dnd_start(self.source, FakeEvent(self.canvas)) + handler.cancel() + # Once a drag has finished a new one can start. + handler = dnd.dnd_start(self.source, FakeEvent(self.canvas)) + self.assertIsNotNone(handler) + handler.cancel() + + def test_drag_cursor(self): + self.canvas['cursor'] = 'watch' + handler = dnd.dnd_start(self.source, FakeEvent(self.canvas)) + # The drag cursor is shown while dragging, the original restored after. + self.assertEqual(handler.save_cursor, 'watch') + self.assertEqual(str(self.canvas['cursor']), 'hand2') + handler.cancel() + self.assertEqual(str(self.canvas['cursor']), 'watch') + + def test_bindings_added_and_removed(self): + handler = dnd.dnd_start(self.source, FakeEvent(self.canvas)) + self.assertIn('<Motion>', self.canvas.bind()) + self.assertIn('<B1-ButtonRelease-1>', self.canvas.bind()) + handler.cancel() + self.assertNotIn('<Motion>', self.canvas.bind()) + self.assertNotIn('<B1-ButtonRelease-1>', self.canvas.bind()) + + def test_switch_target(self): + log1, log2 = [], [] + w1, w2 = tkinter.Frame(self.root), tkinter.Frame(self.root) + target1, target2 = Target(w1, log1), Target(w2, log2) + handler = dnd.dnd_start(self.source, FakeEvent(self.canvas)) + self.canvas.winfo_containing = lambda x, y: w1 + handler.on_motion(FakeEvent(self.canvas)) # Enter target1. + self.canvas.winfo_containing = lambda x, y: w2 + handler.on_motion(FakeEvent(self.canvas)) # Leave target1, enter target2. + self.assertIs(handler.target, target2) + self.assertEqual(log1, ['accept', 'enter', 'leave']) + self.assertEqual(log2, ['accept', 'enter']) + handler.cancel() + + def test_target_in_ancestor(self): + # The widget under the pointer has no dnd_accept, but an ancestor + # does: the search walks up the master chain to find it. + parent = tkinter.Frame(self.root) + target = Target(parent, self.log) + child = tkinter.Frame(parent) + self.canvas.winfo_containing = lambda x, y: child + handler = dnd.dnd_start(self.source, FakeEvent(self.canvas)) + handler.on_motion(FakeEvent(self.canvas)) + self.assertIs(handler.target, target) + self.assertEqual(self.log, ['accept', 'enter']) + handler.cancel() + + def test_accept_returning_none_continues(self): + # dnd_accept() returning None means "not me, keep looking up". + parent = tkinter.Frame(self.root) + target = Target(parent, self.log) + child = tkinter.Frame(parent) + child.dnd_accept = lambda source, event: None + self.canvas.winfo_containing = lambda x, y: child + handler = dnd.dnd_start(self.source, FakeEvent(self.canvas)) + handler.on_motion(FakeEvent(self.canvas)) + self.assertIs(handler.target, target) + handler.cancel() + if __name__ == "__main__": unittest.main() From d3eea1be60d7125ba17bc300e3c5320aac065005 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 27 Jun 2026 09:50:59 +0200 Subject: [PATCH 462/818] [3.15] gh-71880: Allow editing the last cell in curses.textpad.Textbox (GH-152363) (GH-152364) Textbox.edit() ignored typing in the lower-right cell of the window. It is now written with insch(), which fills the cell without moving the cursor out of the window (addch() there raises an error and scrolls a scrollable window). (cherry picked from commit 11b394381f30815a8ad0123afb0a55e7a0369f79) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --- Lib/curses/textpad.py | 19 ++++++------ Lib/test/test_curses.py | 29 +++++++++++++++++++ ...6-06-26-23-56-40.gh-issue-71880.782D31.rst | 5 ++++ 3 files changed, 43 insertions(+), 10 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-06-26-23-56-40.gh-issue-71880.782D31.rst diff --git a/Lib/curses/textpad.py b/Lib/curses/textpad.py index c8dbf9fb614fcb..57b2f4a523c95b 100644 --- a/Lib/curses/textpad.py +++ b/Lib/curses/textpad.py @@ -74,16 +74,16 @@ def _insert_printable_char(self, ch): self._update_max_yx() (y, x) = self.win.getyx() backyx = None - while y < self.maxy or x < self.maxx: + while True: if self.insert_mode: oldch = self.win.inch() - # The try-catch ignores the error we trigger from some curses - # versions by trying to write into the lowest-rightmost spot - # in the window. - try: - self.win.addch(ch) - except curses.error: - pass + if y >= self.maxy and x >= self.maxx: + # Use insch() in the lower-right cell: addch() there would move + # the cursor out of the window, raising an error and scrolling + # a scrollable window. + self.win.insch(ch) + break + self.win.addch(ch) if not self.insert_mode or not curses.ascii.isprint(oldch): break ch = oldch @@ -101,8 +101,7 @@ def do_command(self, ch): (y, x) = self.win.getyx() self.lastcmd = ch if curses.ascii.isprint(ch): - if y < self.maxy or x < self.maxx: - self._insert_printable_char(ch) + self._insert_printable_char(ch) elif ch == curses.ascii.SOH: # ^a self.win.move(y, 0) elif ch in (curses.ascii.STX,curses.KEY_LEFT, diff --git a/Lib/test/test_curses.py b/Lib/test/test_curses.py index c6a762c04e0525..48a0b6a175eaff 100644 --- a/Lib/test/test_curses.py +++ b/Lib/test/test_curses.py @@ -1291,6 +1291,35 @@ def test_textbox_insert_mode(self): self._type(box, 'b') self.assertEqual(box.gather(), 'abXc ') + def test_textbox_fill_last_cell(self): + # The lower-right cell can be written, even though addch() there + # cannot advance the cursor past the end of the window. + box, win = self._make_textbox(1, 4, stripspaces=0) + self._type(box, 'abcd') + self.assertEqual(box.gather(), 'abcd') + + def test_textbox_fill_last_cell_multiline(self): + box, win = self._make_textbox(2, 3, stripspaces=0) + self._type(box, 'abc') + box.do_command(curses.ascii.NL) # ^j -> start of next line + self._type(box, 'def') # 'f' lands in the lower-right cell + self.assertEqual(box.gather(), 'abc\ndef\n') + + def test_textbox_fill_last_cell_insert_mode(self): + box, win = self._make_textbox(1, 4, insert_mode=True, stripspaces=0) + self._type(box, 'abcd') + self.assertEqual(box.gather(), 'abcd') + + def test_textbox_fill_last_cell_scrollok(self): + # Writing the lower-right cell must not scroll the window even if it + # has scrolling enabled. + box, win = self._make_textbox(2, 3, stripspaces=0) + win.scrollok(True) + self._type(box, 'abc') + box.do_command(curses.ascii.NL) + self._type(box, 'def') + self.assertEqual(box.gather(), 'abc\ndef\n') + def test_textbox_movement(self): box, win = self._make_textbox(3, 10) self._type(box, 'abc') diff --git a/Misc/NEWS.d/next/Library/2026-06-26-23-56-40.gh-issue-71880.782D31.rst b/Misc/NEWS.d/next/Library/2026-06-26-23-56-40.gh-issue-71880.782D31.rst new file mode 100644 index 00000000000000..5a12f428f2a8b6 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-26-23-56-40.gh-issue-71880.782D31.rst @@ -0,0 +1,5 @@ +:class:`curses.textpad.Textbox` now lets the lower-right cell of the window be +edited. Writing it with :meth:`~curses.window.addch` would move the cursor +past the end of the window, raising an error and scrolling a scrollable window, +so it is now written with :meth:`~curses.window.insch`, which keeps the cursor +in place. From cab3bb8e3057da6035fc1967cb1eacf1bbf89e27 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 27 Jun 2026 11:45:43 +0200 Subject: [PATCH 463/818] [3.15] gh-152212: Reject a POSIX TZ footer with a missing std offset in pure-Python `zoneinfo` (GH-152213) (#152379) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (cherry picked from commit 93454fe0daa2b29e8fefbe76aed7af4fa1eb8623) Co-authored-by: tonghuaroot (童话) <tonghuaroot@gmail.com> --- Lib/test/test_zoneinfo/test_zoneinfo.py | 5 +++++ Lib/zoneinfo/_zoneinfo.py | 3 ++- .../Library/2026-06-25-12-00-00.gh-issue-152212.Zk7Qm2.rst | 3 +++ 3 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2026-06-25-12-00-00.gh-issue-152212.Zk7Qm2.rst diff --git a/Lib/test/test_zoneinfo/test_zoneinfo.py b/Lib/test/test_zoneinfo/test_zoneinfo.py index d4d57b8f727584..cf3f82db75b0b6 100644 --- a/Lib/test/test_zoneinfo/test_zoneinfo.py +++ b/Lib/test/test_zoneinfo/test_zoneinfo.py @@ -1142,6 +1142,11 @@ def test_extreme_tzstr(self): def test_invalid_tzstr(self): invalid_tzstrs = [ "PST8PDT", # DST but no transition specified + # gh-152212: the std offset is required (POSIX TZ grammar) + "AAA", + "A", + "AA", + "B", "+11", # Unquoted alphanumeric "GMT,M3.2.0/2,M11.1.0/3", # Transition rule but no DST "GMT0+11,M3.2.0/2,M11.1.0/3", # Unquoted alphanumeric in DST diff --git a/Lib/zoneinfo/_zoneinfo.py b/Lib/zoneinfo/_zoneinfo.py index 3903d57d55417e..52832f600c3044 100644 --- a/Lib/zoneinfo/_zoneinfo.py +++ b/Lib/zoneinfo/_zoneinfo.py @@ -672,7 +672,8 @@ def _parse_tz_str(tz_str): except ValueError as e: raise ValueError(f"Invalid STD offset in {tz_str}") from e else: - std_offset = 0 + # The STD offset is required + raise ValueError(f"Invalid STD offset in {tz_str}") if dst_abbr is not None: if dst_offset := m.group("dstoff"): diff --git a/Misc/NEWS.d/next/Library/2026-06-25-12-00-00.gh-issue-152212.Zk7Qm2.rst b/Misc/NEWS.d/next/Library/2026-06-25-12-00-00.gh-issue-152212.Zk7Qm2.rst new file mode 100644 index 00000000000000..2b1d272638b11a --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-25-12-00-00.gh-issue-152212.Zk7Qm2.rst @@ -0,0 +1,3 @@ +Fix the pure-Python :mod:`zoneinfo` parser accepting a POSIX TZ string with a +``std`` abbreviation but no offset. This is invalid per POSIX and now +raises :exc:`ValueError`, matching the C accelerator. Patch by tonghuaroot. From d0a23186f050d2940898d3677946f775c85f8d6f Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 27 Jun 2026 13:30:15 +0200 Subject: [PATCH 464/818] [3.15] gh-82830: Improve tkinter messagebox docstrings and cursor documentation (GH-152380) (GH-152386) Document Windows cursor files (gh-99089). (cherry picked from commit ea7f64a65cb52b8b720cbf5d590c2cf89de8d407) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --- Doc/library/tkinter.messagebox.rst | 2 +- Doc/library/tkinter.rst | 2 ++ Lib/tkinter/messagebox.py | 10 +++++----- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/Doc/library/tkinter.messagebox.rst b/Doc/library/tkinter.messagebox.rst index b4529e2329ebfb..7fd561ade2f8bc 100644 --- a/Doc/library/tkinter.messagebox.rst +++ b/Doc/library/tkinter.messagebox.rst @@ -113,7 +113,7 @@ Common message box styles and layouts include but are not limited to: .. function:: askretrycancel(title=None, message=None, **options) Ask if operation should be retried. Shows buttons :data:`RETRY` and :data:`CANCEL`. - Return ``True`` if the answer is yes and ``False`` otherwise. + Return ``True`` if the answer is retry and ``False`` otherwise. .. function:: askyesno(title=None, message=None, **options) diff --git a/Doc/library/tkinter.rst b/Doc/library/tkinter.rst index ec598976971fe6..c9c19c21e7358c 100644 --- a/Doc/library/tkinter.rst +++ b/Doc/library/tkinter.rst @@ -770,6 +770,8 @@ cursor The standard X cursor names from :file:`cursorfont.h` can be used, without the ``XC_`` prefix. For example to get a hand cursor (``XC_hand2``), use the string ``"hand2"``. You can also specify a bitmap and mask file of your own. + On Windows a cursor file (:file:`.cur` or :file:`.ani`) may be used directly, + giving its path preceded with an ``@``, as in ``"@C:/cursors/bart.ani"``. See page 179 of Ousterhout's book. distance diff --git a/Lib/tkinter/messagebox.py b/Lib/tkinter/messagebox.py index 5f0343b660c68c..dd2816cffb1140 100644 --- a/Lib/tkinter/messagebox.py +++ b/Lib/tkinter/messagebox.py @@ -99,24 +99,24 @@ def showerror(title=None, message=None, **options): def askquestion(title=None, message=None, **options): - "Ask a question" + "Ask a question; return the symbolic name of the selected button" return _show(title, message, QUESTION, YESNO, **options) def askokcancel(title=None, message=None, **options): - "Ask if operation should proceed; return true if the answer is ok" + "Ask if operation should proceed; return True if the answer is ok" s = _show(title, message, QUESTION, OKCANCEL, **options) return s == OK def askyesno(title=None, message=None, **options): - "Ask a question; return true if the answer is yes" + "Ask a question; return True if the answer is yes" s = _show(title, message, QUESTION, YESNO, **options) return s == YES def askyesnocancel(title=None, message=None, **options): - "Ask a question; return true if the answer is yes, None if cancelled." + "Ask a question; return True if the answer is yes, None if cancelled" s = _show(title, message, QUESTION, YESNOCANCEL, **options) # s might be a Tcl index object, so convert it to a string s = str(s) @@ -126,7 +126,7 @@ def askyesnocancel(title=None, message=None, **options): def askretrycancel(title=None, message=None, **options): - "Ask if operation should be retried; return true if the answer is yes" + "Ask if operation should be retried; return True if the answer is retry" s = _show(title, message, WARNING, RETRYCANCEL, **options) return s == RETRY From 01cab1119e40585a12096c1c82002749bd069985 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 27 Jun 2026 13:47:07 +0200 Subject: [PATCH 465/818] [3.15] gh-70273: Document default class bindings in tkinter (GH-152389) (GH-152393) Note in the Bindings and events section that every widget inherits Tk class bindings for its standard behavior, where they are documented, and how to suppress an unwanted one by returning "break" from a callback. (cherry picked from commit 4fd69ef97a67fc935e0d4f30662f2a1985ba6be9) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --- Doc/library/tkinter.rst | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Doc/library/tkinter.rst b/Doc/library/tkinter.rst index c9c19c21e7358c..682d507c2d2d88 100644 --- a/Doc/library/tkinter.rst +++ b/Doc/library/tkinter.rst @@ -885,6 +885,20 @@ they are denoted in Tk, which can be useful when referring to the Tk man pages. | %d | detail | %D | delta | +----+---------------------+----+---------------------+ +The ``add`` parameter above only affects the bindings you make yourself. +Every widget also inherits *class bindings* +that implement its standard behavior -- +for example a :class:`Text` widget binds :kbd:`Control-t` +to transpose two characters. +These are described in the bindings section of the widget's Tk man page +(such as :manpage:`text(3tk)` or :manpage:`entry(3tk)`). + +Class bindings are processed separately from your own, +so binding an event yourself does not replace the default; both run. +To suppress an unwanted default binding, +bind the event on the widget +and return the string ``"break"`` from your callback. + The index parameter ^^^^^^^^^^^^^^^^^^^ From 400c7eca4a4c942f791fda4e8b0f1176a23e1b3a Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 27 Jun 2026 15:52:57 +0200 Subject: [PATCH 466/818] [3.15] Docs: Fix incomplete sentence in `tp_itemsize` documentation (GH-152381) (GH-152417) (cherry picked from commit 0a21a248cc97eba3d75c7bd07c849ec645aea87b) Co-authored-by: da-woods <dw-git@d-woods.co.uk> --- Doc/c-api/type.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/c-api/type.rst b/Doc/c-api/type.rst index 48eb16bd90834b..6b68c0d085589a 100644 --- a/Doc/c-api/type.rst +++ b/Doc/c-api/type.rst @@ -639,7 +639,7 @@ but need extra remarks for use as slots: in the following situations: - The base is not variable-sized (its - :c:member:`~PyTypeObject.tp_itemsize`). + :c:member:`~PyTypeObject.tp_itemsize` is zero). - The requested :c:member:`PyType_Spec.basicsize` is positive, suggesting that the memory layout of the base class is known. - The requested :c:member:`PyType_Spec.basicsize` is zero, From 2c7e8908cd57a9810fd9cc5c77a11d61fbfcde3c Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 27 Jun 2026 15:58:20 +0200 Subject: [PATCH 467/818] [3.15] gh-152402: Use `support.nomemtest` in `test_pyexpat` (GH-152403) (#152411) gh-152402: Use `support.nomemtest` in `test_pyexpat` (GH-152403) (cherry picked from commit 109c59e25f558732bfde8b65bbbf305a6a8a05d8) Co-authored-by: sobolevn <mail@sobolevn.me> --- Lib/test/test_pyexpat.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Lib/test/test_pyexpat.py b/Lib/test/test_pyexpat.py index 5a42bbb5f087f4..b69e093392def3 100644 --- a/Lib/test/test_pyexpat.py +++ b/Lib/test/test_pyexpat.py @@ -1008,8 +1008,7 @@ class ExternalEntityParserCreateErrorTest(unittest.TestCase): def setUpClass(cls): cls.testcapi = import_helper.import_module('_testcapi') - @unittest.skipIf(support.Py_TRACE_REFS, - 'Py_TRACE_REFS conflicts with testcapi.set_nomemory') + @support.nomemtest def test_error_path_no_crash(self): # When an allocation inside ExternalEntityParserCreate fails, # the partially-initialized subparser is deallocated. This From 592575ca7a6f3892eafb5fe305a15d3dfee61be8 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 27 Jun 2026 17:28:27 +0200 Subject: [PATCH 468/818] [3.15] gh-151126: Sets missing exceptions in `tkinter` and `socket` modules initializations (GH-152418) (#152420) gh-151126: Sets missing exceptions in `tkinter` and `socket` modules initializations (GH-152418) (cherry picked from commit a9fa8560143098168e0380386acbf4846c37472b) Co-authored-by: sobolevn <mail@sobolevn.me> --- .../next/Library/2026-06-27-17-19-09.gh-issue-151126.huUyOM.rst | 2 ++ Modules/_tkinter.c | 2 +- Modules/socketmodule.c | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2026-06-27-17-19-09.gh-issue-151126.huUyOM.rst diff --git a/Misc/NEWS.d/next/Library/2026-06-27-17-19-09.gh-issue-151126.huUyOM.rst b/Misc/NEWS.d/next/Library/2026-06-27-17-19-09.gh-issue-151126.huUyOM.rst new file mode 100644 index 00000000000000..2e51fd45b59548 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-27-17-19-09.gh-issue-151126.huUyOM.rst @@ -0,0 +1,2 @@ +Fix two crashes in :mod:`tkinter` and :mod:`socket` modules initialization +under a memory pressure. Sets missing :exc:`MemoryError`. diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c index 137eba40a762c0..8fa58d07096e30 100644 --- a/Modules/_tkinter.c +++ b/Modules/_tkinter.c @@ -3574,7 +3574,7 @@ PyInit__tkinter(void) tcl_lock = PyThread_allocate_lock(); if (tcl_lock == NULL) - return NULL; + return PyErr_NoMemory(); m = PyModule_Create(&_tkintermodule); if (m == NULL) diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c index c69a9cc0498272..97abd064ffd5e9 100644 --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -9288,6 +9288,7 @@ socket_exec(PyObject *m) #if defined(USE_GETHOSTBYNAME_LOCK) netdb_lock = PyThread_allocate_lock(); if (netdb_lock == NULL) { + PyErr_NoMemory(); goto error; } #endif From bfb01d8a0c4283553463d87da07e4ff816e69260 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 27 Jun 2026 17:36:31 +0200 Subject: [PATCH 469/818] [3.15] gh-152305: Fix `_pydatetime.time.strftime()` raising on year directives (GH-152306) (#152425) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (cherry picked from commit 5733361fdd85519c931e67fd7cab0ff3a11b8ec0) Co-authored-by: tonghuaroot (童话) <tonghuaroot@gmail.com> Co-authored-by: Stan Ulbrych <stan@python.org> --- Lib/_pydatetime.py | 6 +++--- Lib/test/datetimetester.py | 5 +++++ .../Library/2026-06-26-15-41-34.gh-issue-152305.WnbbBc.rst | 2 ++ 3 files changed, 10 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-06-26-15-41-34.gh-issue-152305.WnbbBc.rst diff --git a/Lib/_pydatetime.py b/Lib/_pydatetime.py index db4ea8d30c7064..c47f4e671b39de 100644 --- a/Lib/_pydatetime.py +++ b/Lib/_pydatetime.py @@ -272,12 +272,12 @@ def _wrap_strftime(object, format, timetuple): newformat.append(Zreplace) # Note that datetime(1000, 1, 1).strftime('%G') == '1000' so # year 1000 for %G can go on the fast path. - elif ((ch in 'YG' or ch in 'FC') and - object.year < 1000 and _need_normalize_century()): + elif (ch in 'YGFC' and timetuple[0] < 1000 and + _need_normalize_century()): if ch == 'G': year = int(_time.strftime("%G", timetuple)) else: - year = object.year + year = timetuple[0] if ch == 'C': push('{:02}'.format(year // 100)) else: diff --git a/Lib/test/datetimetester.py b/Lib/test/datetimetester.py index 28c3ab2605c45d..192b22ff754003 100644 --- a/Lib/test/datetimetester.py +++ b/Lib/test/datetimetester.py @@ -4119,6 +4119,11 @@ def test_strftime_special(self): self.assertEqual(t.strftime('\0'*1000), '\0'*1000) self.assertEqual(t.strftime('\0%I%p%Z\0%X'), f'\0{s1}\0{s2}') self.assertEqual(t.strftime('%I%p%Z\0%X\0'), f'{s1}\0{s2}\0') + # gh-152305: the year directives must not raise on a time. + for directive, expected in (('%Y', '1900'), ('%G', '1900'), + ('%C', '19'), ('%F', '1900-01-01')): + with self.subTest(directive=directive): + self.assertEqual(t.strftime(directive), expected) def test_format(self): t = self.theclass(1, 2, 3, 4) diff --git a/Misc/NEWS.d/next/Library/2026-06-26-15-41-34.gh-issue-152305.WnbbBc.rst b/Misc/NEWS.d/next/Library/2026-06-26-15-41-34.gh-issue-152305.WnbbBc.rst new file mode 100644 index 00000000000000..4f27e2ed016d69 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-26-15-41-34.gh-issue-152305.WnbbBc.rst @@ -0,0 +1,2 @@ +Fix the pure-Python :meth:`datetime.time.strftime` implementation raising :exc:`AttributeError` for the +year directives. Patch by tonghuaroot. From 3206fc74fbb4a99e0a7e43ebbad86f68ab32a631 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 27 Jun 2026 17:37:40 +0200 Subject: [PATCH 470/818] [3.15] gh-152391: Improve `test_interpreters.test_stress` test (GH-152396) (#152427) gh-152391: Improve `test_interpreters.test_stress` test (GH-152396) (cherry picked from commit 219f7a9453a2a89266f6e65d75df1606b4816043) Co-authored-by: sobolevn <mail@sobolevn.me> --- Lib/test/test_interpreters/test_stress.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_interpreters/test_stress.py b/Lib/test/test_interpreters/test_stress.py index 50d87a6ccd3cad..50d2444a4c72d3 100644 --- a/Lib/test/test_interpreters/test_stress.py +++ b/Lib/test/test_interpreters/test_stress.py @@ -25,6 +25,7 @@ def test_create_many_sequential(self): del alive support.gc_collect() + @threading_helper.requires_working_threading() @support.bigmemtest(size=200, memuse=32*2**20, dry_run=False) def test_create_many_threaded(self, size): alive = [] @@ -80,9 +81,12 @@ def test_create_interpreter_no_memory(self): import _testcapi assertion = self.assertRaises(InterpreterError) - _testcapi.set_nomemory(0, 1) - with assertion: - _interpreters.create() + try: + _testcapi.set_nomemory(0, 1) + with assertion: + _interpreters.create() + finally: + _testcapi.remove_mem_hooks() if __name__ == '__main__': From e88d41685bd1a79283f4d91f72373b7576be4183 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 27 Jun 2026 18:49:40 +0200 Subject: [PATCH 471/818] [3.15] gh-151029: Fix sys.remote_exec() unable to find writable memory when libpython replaced on disk (GH-151032) (#152443) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gh-151029: Fix sys.remote_exec() unable to find writable memory when libpython replaced on disk (GH-151032) (cherry picked from commit a69d0fc41ef339378022f1c0190a9692cb276a7f) Co-authored-by: Łukasz Langa <lukasz@langa.pl> Co-authored-by: Pablo Galindo <pablogsal@gmail.com> --- Lib/test/test_sys.py | 94 ++++++++++++- ...-06-06-20-15-08.gh-issue-151029.A33CKK.rst | 2 + Python/remote_debug.h | 129 +++++++++++++++++- 3 files changed, 218 insertions(+), 7 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-06-20-15-08.gh-issue-151029.A33CKK.rst diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index 8be7e50624054e..049b36a82c8226 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -6,6 +6,7 @@ import operator import os import random +import shutil import socket import struct import subprocess @@ -2013,7 +2014,8 @@ def tearDown(self): test.support.reap_children() def _run_remote_exec_test(self, script_code, python_args=None, env=None, - prologue='', + python_executable=None, prologue='', + after_ready=None, script_path=os_helper.TESTFN + '_remote.py'): # Create the script that will be remotely executed self.addCleanup(os_helper.unlink, script_path) @@ -2061,7 +2063,10 @@ def _run_remote_exec_test(self, script_code, python_args=None, env=None, ''') # Start the target process and capture its output - cmd = [sys.executable] + if python_executable is None: + python_executable = sys.executable + + cmd = [python_executable] if python_args: cmd.extend(python_args) cmd.append(target) @@ -2086,6 +2091,9 @@ def _run_remote_exec_test(self, script_code, python_args=None, env=None, response = client_socket.recv(1024) self.assertEqual(response, b"ready") + if after_ready is not None: + after_ready(proc) + # Try remote exec on the target process sys.remote_exec(proc.pid, script_path) @@ -2108,6 +2116,19 @@ def _run_remote_exec_test(self, script_code, python_args=None, env=None, proc.terminate() proc.wait(timeout=SHORT_TIMEOUT) + def _run_remote_exec_with_deleted_mapping(self, deleted_path, **kwargs): + def delete_loaded_mapping(proc): + os_helper.unlink(deleted_path) + with open(f'/proc/{proc.pid}/maps', encoding='utf-8') as maps: + self.assertIn(f'{deleted_path} (deleted)', maps.read()) + + script = 'print("Remote script executed successfully!")' + returncode, stdout, stderr = self._run_remote_exec_test( + script, after_ready=delete_loaded_mapping, **kwargs) + self.assertEqual(returncode, 0) + self.assertIn(b"Remote script executed successfully!", stdout) + self.assertEqual(stderr, b"") + def test_remote_exec(self): """Test basic remote exec functionality""" script = 'print("Remote script executed successfully!")' @@ -2234,6 +2255,75 @@ def test_remote_exec_invalid_script_path(self): with self.assertRaises(OSError): sys.remote_exec(os.getpid(), "invalid_script_path") + @unittest.skipUnless(sys.platform == 'linux', 'Linux-only regression test') + @unittest.skipUnless( + sysconfig.get_config_var('Py_ENABLE_SHARED') == 1, + 'requires a shared libpython build') + def test_remote_exec_deleted_libpython(self): + """Test remote exec when the target libpython was deleted.""" + build_dir = sysconfig.get_config_var('abs_builddir') + ldlibrary = sysconfig.get_config_var('LDLIBRARY') + instsoname = sysconfig.get_config_var('INSTSONAME') + if not build_dir or not ldlibrary or not instsoname: + self.skipTest('cannot determine shared libpython location') + + source_libpython = os.path.join(build_dir, instsoname) + if not os.path.exists(source_libpython): + self.skipTest(f'{source_libpython!r} does not exist') + + with os_helper.temp_dir() as lib_dir: + copied_libpython = os.path.join(lib_dir, instsoname) + shutil.copy2(source_libpython, copied_libpython) + if ldlibrary != instsoname: + os.symlink(instsoname, os.path.join(lib_dir, ldlibrary)) + + env = os.environ.copy() + ld_library_path = env.get('LD_LIBRARY_PATH') + env['LD_LIBRARY_PATH'] = lib_dir if not ld_library_path else ( + lib_dir + os.pathsep + ld_library_path) + + self._run_remote_exec_with_deleted_mapping(copied_libpython, + env=env) + + @unittest.skipUnless(sys.platform == 'linux', 'Linux-only regression test') + @unittest.skipUnless( + sysconfig.get_config_var('Py_ENABLE_SHARED') == 0, + 'requires a static Python build') + def test_remote_exec_deleted_static_executable(self): + """Test remote exec when the target static executable was deleted.""" + build_dir = sysconfig.get_config_var('abs_builddir') + srcdir = sysconfig.get_config_var('srcdir') + if not build_dir or not srcdir: + self.skipTest('cannot determine build-tree locations') + + pybuilddir_txt = os.path.join(build_dir, 'pybuilddir.txt') + if not os.path.exists(pybuilddir_txt): + self.skipTest(f'{pybuilddir_txt!r} does not exist') + + with open(pybuilddir_txt, encoding='utf-8') as pybuilddir_file: + pybuilddir = pybuilddir_file.read().strip() + source_ext_dir = os.path.join(build_dir, pybuilddir) + if not os.path.isdir(source_ext_dir): + self.skipTest(f'{source_ext_dir!r} does not exist') + + with os_helper.temp_dir() as copied_root: + copied_build_dir = os.path.join(copied_root, 'build') + copied_pybuilddir = os.path.join(copied_build_dir, pybuilddir) + os.makedirs(os.path.dirname(copied_pybuilddir)) + os.symlink(os.path.join(srcdir, 'Lib'), + os.path.join(copied_root, 'Lib')) + os.symlink(source_ext_dir, copied_pybuilddir) + shutil.copy2(pybuilddir_txt, + os.path.join(copied_build_dir, 'pybuilddir.txt')) + + copied_python = os.path.join(copied_build_dir, + os.path.basename(sys.executable)) + shutil.copy2(sys.executable, copied_python) + + self._run_remote_exec_with_deleted_mapping( + copied_python, python_args=['-S'], + python_executable=copied_python) + def test_remote_exec_in_process_without_debug_fails_envvar(self): """Test remote exec in a process without remote debugging enabled""" script = os_helper.TESTFN + '_remote.py' diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-06-20-15-08.gh-issue-151029.A33CKK.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-06-20-15-08.gh-issue-151029.A33CKK.rst new file mode 100644 index 00000000000000..cbfe5952627ad8 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-06-20-15-08.gh-issue-151029.A33CKK.rst @@ -0,0 +1,2 @@ +On Linux, fix :func:`sys.remote_exec` unable to find remote writable memory +when ``libpython`` replaced on disk. diff --git a/Python/remote_debug.h b/Python/remote_debug.h index 6fecc23502b46e..7b7380d25bf496 100644 --- a/Python/remote_debug.h +++ b/Python/remote_debug.h @@ -781,6 +781,106 @@ search_elf_file_for_section( return result; } +static const char * +find_debug_cookie(const char *buffer, size_t len) +{ + const char *cookie = _Py_Debug_Cookie; + const size_t cookie_len = sizeof(_Py_Debug_Cookie) - 1; + if (len < cookie_len) { + return NULL; + } + + size_t pos = 0; + size_t last = len - cookie_len; + while (pos <= last) { + const char *candidate = memchr( + buffer + pos, cookie[0], last - pos + 1); + if (candidate == NULL) { + return NULL; + } + pos = (size_t)(candidate - buffer); + if (memcmp(candidate, cookie, cookie_len) == 0) { + return candidate; + } + pos++; + } + return NULL; +} + +static int +linux_map_path_is_deleted(const char *path) +{ + static const char deleted_suffix[] = " (deleted)"; + size_t path_len = strlen(path); + size_t suffix_len = sizeof(deleted_suffix) - 1; + return path_len >= suffix_len + && strcmp(path + path_len - suffix_len, deleted_suffix) == 0; +} + +static int +linux_map_perms_are_readwrite(const char *perms) +{ + return perms[0] == 'r' && perms[1] == 'w'; +} + +static uintptr_t +scan_linux_mapping_for_pyruntime_cookie( + proc_handle_t *handle, + uintptr_t start, + uintptr_t end) +{ + if (end <= start) { + return 0; + } + + const size_t cookie_len = sizeof(_Py_Debug_Cookie) - 1; + const size_t overlap = cookie_len - 1; + const size_t chunk_size = 1024 * 1024; + char *buffer = PyMem_Malloc(chunk_size); + if (buffer == NULL) { + PyErr_NoMemory(); + _set_debug_exception_cause(PyExc_MemoryError, + "Cannot allocate memory while scanning PID %d for PyRuntime cookie", + handle->pid); + return 0; + } + + uintptr_t retval = 0; + uintptr_t mapping_size = end - start; + uintptr_t offset = 0; + while (offset < mapping_size) { + uintptr_t remaining = mapping_size - offset; + size_t wanted = remaining > chunk_size + ? chunk_size : (size_t)remaining; + if (_Py_RemoteDebug_ReadRemoteMemory( + handle, start + offset, wanted, buffer) < 0) { + if (_Py_RemoteDebug_HasPermissionError()) { + goto exit; + } + // A candidate mapping can disappear or contain unreadable holes while + // the target process keeps running. Treat those as non-matches and + // keep scanning other candidate mappings. + PyErr_Clear(); + } + else { + const char *hit = find_debug_cookie(buffer, wanted); + if (hit != NULL) { + retval = start + offset + (uintptr_t)(hit - buffer); + goto exit; + } + } + + if (wanted <= overlap) { + break; + } + offset += wanted - overlap; + } + +exit: + PyMem_Free(buffer); + return retval; +} + static uintptr_t search_linux_map_for_section(proc_handle_t *handle, const char* secname, const char* substr, section_validator_t validator) @@ -835,16 +935,22 @@ search_linux_map_for_section(proc_handle_t *handle, const char* secname, const c linelen = 0; unsigned long start = 0; - unsigned long path_pos = 0; - sscanf(line, "%lx-%*x %*s %*s %*s %*s %ln", &start, &path_pos); + unsigned long end = 0; + int path_pos = 0; + char perms[5] = ""; + int fields = sscanf(line, "%lx-%lx %4s %*s %*s %*s %n", + &start, &end, perms, &path_pos); - if (!path_pos) { + if (fields < 3 || !path_pos) { // Line didn't match our format string. This shouldn't be // possible, but let's be defensive and skip the line. continue; } const char *path = line + path_pos; + if (path[0] == '\0') { + continue; + } if (path[0] == '[' && path[strlen(path)-1] == ']') { // Skip [heap], [stack], [anon:cpython:pymalloc], etc. continue; @@ -858,8 +964,21 @@ search_linux_map_for_section(proc_handle_t *handle, const char* secname, const c } if (strstr(filename, substr)) { - PyErr_Clear(); - retval = search_elf_file_for_section(handle, secname, start, path); + int deleted_pyruntime_mapping = + strcmp(secname, "PyRuntime") == 0 + && linux_map_path_is_deleted(path); + if (deleted_pyruntime_mapping + && linux_map_perms_are_readwrite(perms)) { + PyErr_Clear(); + retval = scan_linux_mapping_for_pyruntime_cookie( + handle, (uintptr_t)start, (uintptr_t)end); + } + if (!deleted_pyruntime_mapping + && retval == 0 && !PyErr_Occurred()) { + PyErr_Clear(); + retval = search_elf_file_for_section( + handle, secname, start, path); + } if (retval) { if (validator == NULL || validator(handle, retval)) { break; From 61bb57fa3fb59e545561df65b655ac137063a30e Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 27 Jun 2026 19:24:53 +0200 Subject: [PATCH 472/818] [3.15] gh-152434: Block --async-aware with --binary (GH-152444) (#152446) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gh-152434: Block --async-aware with --binary (GH-152444) The binary writer does not currently handle AwaitedInfo samples and crashes when running in --async-aware mode. (cherry picked from commit 876c06cab9e824747d708a031c6b81b1f8a4f8dc) Co-authored-by: László Kiss Kollár <kiss.kollar.laszlo@gmail.com> --- Lib/profiling/sampling/cli.py | 4 +++- .../test_sampling_profiler/test_cli.py | 17 +++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/Lib/profiling/sampling/cli.py b/Lib/profiling/sampling/cli.py index a5d9573ae6b6dd..0330c15c014545 100644 --- a/Lib/profiling/sampling/cli.py +++ b/Lib/profiling/sampling/cli.py @@ -875,13 +875,15 @@ def _validate_args(args, parser): if hasattr(args, 'live') and args.live: parser.error("--subprocesses is incompatible with --live mode.") - # Async-aware mode is incompatible with --native, --no-gc, --mode, and --all-threads + # Async-aware mode is incompatible with options that need thread data. if getattr(args, 'async_aware', False): issues = [] if getattr(args, 'native', False): issues.append("--native") if not getattr(args, 'gc', True): issues.append("--no-gc") + if getattr(args, 'format', None) == "binary": + issues.append("--binary") if hasattr(args, 'mode') and args.mode != "wall": issues.append(f"--mode={args.mode}") if hasattr(args, 'all_threads') and args.all_threads: diff --git a/Lib/test/test_profiling/test_sampling_profiler/test_cli.py b/Lib/test/test_profiling/test_sampling_profiler/test_cli.py index 9c0734ac804e1b..0181095ca21e37 100644 --- a/Lib/test/test_profiling/test_sampling_profiler/test_cli.py +++ b/Lib/test/test_profiling/test_sampling_profiler/test_cli.py @@ -866,6 +866,23 @@ def test_async_aware_incompatible_with_all_threads(self): self.assertIn("--all-threads", error_msg) self.assertIn("incompatible with --async-aware", error_msg) + def test_async_aware_incompatible_with_binary(self): + """Test --async-aware is incompatible with --binary.""" + test_args = ["profiling.sampling.cli", "attach", "12345", + "--async-aware", "--binary"] + + with ( + mock.patch("sys.argv", test_args), + mock.patch("sys.stderr", io.StringIO()) as mock_stderr, + self.assertRaises(SystemExit) as cm, + ): + main() + + self.assertEqual(cm.exception.code, 2) # argparse error + error_msg = mock_stderr.getvalue() + self.assertIn("--binary", error_msg) + self.assertIn("incompatible with --async-aware", error_msg) + @unittest.skipIf(is_emscripten, "subprocess not available") def test_run_nonexistent_script_exits_cleanly(self): """Test that running a non-existent script exits with a clean error.""" From 5d0fa7a5c47b99c84c9b7c24511f8fa9381fbb49 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 27 Jun 2026 19:36:38 +0200 Subject: [PATCH 473/818] [3.15] gh-145306: Fix browser open after empty export (GH-150017) (#152447) gh-145306: Fix browser open after empty export (GH-150017) (cherry picked from commit 860f8a5addcb556c251b8b9caa95d80518928067) Co-authored-by: ivonastojanovic <80911834+ivonastojanovic@users.noreply.github.com> --- Lib/profiling/sampling/binary_collector.py | 1 + Lib/profiling/sampling/cli.py | 26 +++++++++++++------ Lib/profiling/sampling/collector.py | 6 ++++- Lib/profiling/sampling/gecko_collector.py | 1 + Lib/profiling/sampling/heatmap_collector.py | 3 ++- Lib/profiling/sampling/jsonl_collector.py | 1 + Lib/profiling/sampling/pstats_collector.py | 1 + Lib/profiling/sampling/stack_collector.py | 4 ++- .../test_sampling_profiler/test_cli.py | 22 ++++++++++++++++ .../test_sampling_profiler/test_collectors.py | 21 +++++++++++++-- 10 files changed, 73 insertions(+), 13 deletions(-) diff --git a/Lib/profiling/sampling/binary_collector.py b/Lib/profiling/sampling/binary_collector.py index 64afe632fae175..afbbc829269067 100644 --- a/Lib/profiling/sampling/binary_collector.py +++ b/Lib/profiling/sampling/binary_collector.py @@ -94,6 +94,7 @@ def export(self, filename=None): filename: Ignored (binary files are written incrementally) """ self._writer.finalize() + return True @property def total_samples(self): diff --git a/Lib/profiling/sampling/cli.py b/Lib/profiling/sampling/cli.py index 0330c15c014545..466b0aceae2dcc 100644 --- a/Lib/profiling/sampling/cli.py +++ b/Lib/profiling/sampling/cli.py @@ -117,6 +117,9 @@ def __call__(self, parser, namespace, values, option_string=None): "binary": BinaryCollector, } +BROWSER_COMPATIBLE_FORMATS = ("flamegraph", "diff_flamegraph", "heatmap") + + def _setup_child_monitor(args, parent_pid): # Build CLI args for child profilers (excluding --subprocesses to avoid recursion) child_cli_args = _build_child_profiler_args(args) @@ -528,8 +531,12 @@ def _add_format_options(parser, include_compression=True, include_binary=True): output_group.add_argument( "--browser", action="store_true", - help="Automatically open HTML output (flamegraph, heatmap) in browser. " - "When using `--subprocesses`, only the main process opens the browser", + help=( + "Automatically open HTML output " + f"({', '.join('--' + f.replace('_', '-') for f in BROWSER_COMPATIBLE_FORMATS)}) " + "in browser. " + "When using `--subprocesses`, only the main process opens the browser" + ), ) @@ -789,13 +796,12 @@ def progress_callback(current, total): args.outfile or _generate_output_filename(args.format, os.getpid()) ) - collector.export(filename) + export_ok = collector.export(filename) # Auto-open browser for HTML output if --browser flag is set if ( - args.format in ( - 'flamegraph', 'diff_flamegraph', 'heatmap' - ) + export_ok + and args.format in BROWSER_COMPATIBLE_FORMATS and getattr(args, 'browser', False) ): _open_in_browser(filename) @@ -840,10 +846,14 @@ def _handle_output(collector, args, pid, mode): filename = os.path.join(args.outfile, _generate_output_filename(args.format, pid)) else: filename = args.outfile or _generate_output_filename(args.format, pid) - collector.export(filename) + export_ok = collector.export(filename) # Auto-open browser for HTML output if --browser flag is set - if args.format in ('flamegraph', 'diff_flamegraph', 'heatmap') and getattr(args, 'browser', False): + if ( + export_ok + and args.format in BROWSER_COMPATIBLE_FORMATS + and getattr(args, 'browser', False) + ): _open_in_browser(filename) diff --git a/Lib/profiling/sampling/collector.py b/Lib/profiling/sampling/collector.py index 8e0f0c44c4f8f3..1dc3656e0ebe97 100644 --- a/Lib/profiling/sampling/collector.py +++ b/Lib/profiling/sampling/collector.py @@ -163,7 +163,11 @@ def collect_failed_sample(self): @abstractmethod def export(self, filename): - """Export collected data to a file.""" + """Export collected data. + + Returns: + bool: True if output was generated, False if there was no data to export. + """ @staticmethod def _filter_internal_frames(frames): diff --git a/Lib/profiling/sampling/gecko_collector.py b/Lib/profiling/sampling/gecko_collector.py index 361f6037f216fd..2bb5bd2f664d59 100644 --- a/Lib/profiling/sampling/gecko_collector.py +++ b/Lib/profiling/sampling/gecko_collector.py @@ -756,6 +756,7 @@ def spin(): print( f"Open in Firefox Profiler: https://profiler.firefox.com/" ) + return True def _build_marker_schema(self): """Build marker schema definitions for Firefox Profiler.""" diff --git a/Lib/profiling/sampling/heatmap_collector.py b/Lib/profiling/sampling/heatmap_collector.py index 6e650ec08f410b..0361fd357b222d 100644 --- a/Lib/profiling/sampling/heatmap_collector.py +++ b/Lib/profiling/sampling/heatmap_collector.py @@ -598,7 +598,7 @@ def export(self, output_path): """ if not self.file_samples: print("Warning: No heatmap data to export") - return + return False try: output_dir = self._prepare_output_directory(output_path) @@ -612,6 +612,7 @@ def export(self, output_path): self._generate_index_html(output_dir / 'index.html', file_stats) self._print_export_summary(output_dir, file_stats) + return True except Exception as e: print(f"Error: Failed to export heatmap: {e}") diff --git a/Lib/profiling/sampling/jsonl_collector.py b/Lib/profiling/sampling/jsonl_collector.py index 5aa42ef09024dc..41b0456d6f56d3 100644 --- a/Lib/profiling/sampling/jsonl_collector.py +++ b/Lib/profiling/sampling/jsonl_collector.py @@ -165,6 +165,7 @@ def export(self, filename): ) self._write_message(output, self._build_end_record()) print(f"JSONL profile written to {filename}") + return True def _build_meta_record(self): record = { diff --git a/Lib/profiling/sampling/pstats_collector.py b/Lib/profiling/sampling/pstats_collector.py index 43b1daf2a119d4..7132cffd58f094 100644 --- a/Lib/profiling/sampling/pstats_collector.py +++ b/Lib/profiling/sampling/pstats_collector.py @@ -63,6 +63,7 @@ def collect(self, stack_frames, timestamps_us=None): def export(self, filename): self.create_stats() self._dump_stats(filename) + return True def _dump_stats(self, file): stats_with_marker = dict(self.stats) diff --git a/Lib/profiling/sampling/stack_collector.py b/Lib/profiling/sampling/stack_collector.py index 42281dc6454c83..eb1a3fba93cf33 100644 --- a/Lib/profiling/sampling/stack_collector.py +++ b/Lib/profiling/sampling/stack_collector.py @@ -64,6 +64,7 @@ def export(self, filename): for stack, count in lines: f.write(f"{stack} {count}\n") print(f"Collapsed stack output written to {filename}") + return True class FlamegraphCollector(StackTraceCollector): @@ -161,7 +162,7 @@ def export(self, filename): print( "Warning: No functions found in profiling data. Check if sampling captured any data." ) - return + return False html_content = self._create_flamegraph_html(flamegraph_data) @@ -169,6 +170,7 @@ def export(self, filename): f.write(html_content) print(f"Flamegraph saved to: {filename}") + return True @staticmethod @functools.lru_cache(maxsize=None) diff --git a/Lib/test/test_profiling/test_sampling_profiler/test_cli.py b/Lib/test/test_profiling/test_sampling_profiler/test_cli.py index 0181095ca21e37..3448258eca5d6c 100644 --- a/Lib/test/test_profiling/test_sampling_profiler/test_cli.py +++ b/Lib/test/test_profiling/test_sampling_profiler/test_cli.py @@ -7,6 +7,7 @@ import sys import tempfile import unittest +from types import SimpleNamespace from unittest import mock try: @@ -26,6 +27,7 @@ FORMAT_EXTENSIONS, _create_collector, _generate_output_filename, + _handle_output, main, ) from profiling.sampling.constants import ( @@ -727,6 +729,26 @@ def test_async_aware_flag_defaults_to_running(self): call_kwargs = mock_sample.call_args[1] self.assertEqual(call_kwargs.get("async_aware"), "running") + def test_handle_output_browser_not_opened_when_export_fails(self): + for format_type in ("flamegraph", "diff_flamegraph", "heatmap"): + with self.subTest(format=format_type): + collector = mock.MagicMock() + collector.export.return_value = False + args = SimpleNamespace( + format=format_type, + outfile="profile.html", + browser=True, + ) + + with ( + mock.patch("profiling.sampling.cli.os.path.isdir", return_value=False), + mock.patch("profiling.sampling.cli._open_in_browser") as mock_open, + ): + _handle_output(collector, args, pid=12345, mode=0) + + collector.export.assert_called_once_with("profile.html") + mock_open.assert_not_called() + def test_async_aware_with_async_mode_all(self): """Test --async-aware with --async-mode all.""" test_args = ["profiling.sampling.cli", "attach", "12345", "--async-aware", "--async-mode", "all"] diff --git a/Lib/test/test_profiling/test_sampling_profiler/test_collectors.py b/Lib/test/test_profiling/test_sampling_profiler/test_collectors.py index 1ab31af67fec52..56f3fe5e1c2605 100644 --- a/Lib/test/test_profiling/test_sampling_profiler/test_collectors.py +++ b/Lib/test/test_profiling/test_sampling_profiler/test_collectors.py @@ -539,9 +539,10 @@ def test_flamegraph_collector_export(self): # Export flamegraph with captured_stdout(), captured_stderr(): - collector.export(flamegraph_out.name) + export_ok = collector.export(flamegraph_out.name) # Verify file was created and contains valid data + self.assertTrue(export_ok) self.assertTrue(os.path.exists(flamegraph_out.name)) self.assertGreater(os.path.getsize(flamegraph_out.name), 0) @@ -560,6 +561,21 @@ def test_flamegraph_collector_export(self): self.assertIn('"value":', content) self.assertIn('"children":', content) + def test_flamegraph_collector_empty_export_fails(self): + """Test empty flamegraph export reports no output.""" + flamegraph_out = tempfile.NamedTemporaryFile( + suffix=".html", delete=False + ) + self.addCleanup(close_and_unlink, flamegraph_out) + + collector = FlamegraphCollector(1000) + + with captured_stdout(), captured_stderr(): + export_ok = collector.export(flamegraph_out.name) + + self.assertFalse(export_ok) + self.assertEqual(os.path.getsize(flamegraph_out.name), 0) + def test_gecko_collector_basic(self): """Test basic GeckoCollector functionality.""" collector = GeckoCollector(1000) @@ -1666,8 +1682,9 @@ def test_diff_flamegraph_export(self): self.addCleanup(close_and_unlink, flamegraph_out) with captured_stdout(), captured_stderr(): - diff.export(flamegraph_out.name) + export_ok = diff.export(flamegraph_out.name) + self.assertTrue(export_ok) self.assertTrue(os.path.exists(flamegraph_out.name)) self.assertGreater(os.path.getsize(flamegraph_out.name), 0) From 65fbec64f6a4a6a8fb68f86e323efed54e5a083d Mon Sep 17 00:00:00 2001 From: Pablo Galindo Salgado <Pablogsal@gmail.com> Date: Sat, 27 Jun 2026 19:42:31 +0200 Subject: [PATCH 474/818] [3.15] gh-151613: Fix remote debugging frame cache ABA (#152448) gh-151613: Fix remote debugging frame cache ABA (#151614) The remote debugging frame cache previously used only the last_profiled_frame address as its cache anchor. If a frame returned and a later frame reused the same _PyInterpreterFrame address, the profiler could accept a stale cache entry and splice parent frames from a different call chain into the current stack. This adds a last_profiled_frame_seq counter next to last_profiled_frame, increments it when the anchor advances, stores it in frame cache entries, and validates cache hits against both the frame address and the sequence. Cache miss walks now copy stack chunks before storing new cache entries so stored continuations come from a stable snapshot. The new regression test exercises alternating call chains and checks that cached stacks never contain frames from both branches. (cherry picked from commit 8cda6ae2f1f86f2d26c29586ffc9687b410abfcf) --- Include/cpython/pystate.h | 1 + Include/internal/pycore_debug_offsets.h | 2 + Include/internal/pycore_interpframe.h | 3 + InternalDocs/frames.md | 30 +++--- ...-06-17-22-31-57.gh-issue-151613.n0nua1.rst | 3 + Modules/_remote_debugging/_remote_debugging.h | 17 +++- .../debug_offsets_validation.h | 5 +- Modules/_remote_debugging/frame_cache.c | 96 ++++++++++++++++--- Modules/_remote_debugging/frames.c | 59 ++++++++---- Modules/_remote_debugging/module.c | 4 +- Modules/_remote_debugging/threads.c | 14 +-- Python/pystate.c | 2 + 12 files changed, 181 insertions(+), 55 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-06-17-22-31-57.gh-issue-151613.n0nua1.rst diff --git a/Include/cpython/pystate.h b/Include/cpython/pystate.h index a9d97e47e005df..f367146e262bfe 100644 --- a/Include/cpython/pystate.h +++ b/Include/cpython/pystate.h @@ -143,6 +143,7 @@ struct _ts { struct _PyInterpreterFrame *base_frame; struct _PyInterpreterFrame *last_profiled_frame; + uintptr_t last_profiled_frame_seq; Py_tracefunc c_profilefunc; Py_tracefunc c_tracefunc; diff --git a/Include/internal/pycore_debug_offsets.h b/Include/internal/pycore_debug_offsets.h index 18490f98a918a7..6e1eb573c8c2c8 100644 --- a/Include/internal/pycore_debug_offsets.h +++ b/Include/internal/pycore_debug_offsets.h @@ -104,6 +104,7 @@ typedef struct _Py_DebugOffsets { uint64_t current_frame; uint64_t base_frame; uint64_t last_profiled_frame; + uint64_t last_profiled_frame_seq; uint64_t thread_id; uint64_t native_thread_id; uint64_t datastack_chunk; @@ -294,6 +295,7 @@ typedef struct _Py_DebugOffsets { .current_frame = offsetof(PyThreadState, current_frame), \ .base_frame = offsetof(PyThreadState, base_frame), \ .last_profiled_frame = offsetof(PyThreadState, last_profiled_frame), \ + .last_profiled_frame_seq = offsetof(PyThreadState, last_profiled_frame_seq), \ .thread_id = offsetof(PyThreadState, thread_id), \ .native_thread_id = offsetof(PyThreadState, native_thread_id), \ .datastack_chunk = offsetof(PyThreadState, datastack_chunk), \ diff --git a/Include/internal/pycore_interpframe.h b/Include/internal/pycore_interpframe.h index 3fc7c48ddececc..926eda85fb843a 100644 --- a/Include/internal/pycore_interpframe.h +++ b/Include/internal/pycore_interpframe.h @@ -287,12 +287,15 @@ _PyThreadState_GetFrame(PyThreadState *tstate) // This avoids corrupting the cache when transient frames (called and returned // between profiler samples) update last_profiled_frame to addresses the // profiler never saw. +// The sequence distinguishes this anchor from a later frame that reuses the +// same _PyInterpreterFrame address. #define _PyThreadState_UpdateLastProfiledFrame(tstate, frame, previous) \ do { \ PyThreadState *tstate_ = (tstate); \ _PyInterpreterFrame *frame_ = (frame); \ if (tstate_->last_profiled_frame == frame_) { \ tstate_->last_profiled_frame = (previous); \ + tstate_->last_profiled_frame_seq++; \ } \ } while (0) diff --git a/InternalDocs/frames.md b/InternalDocs/frames.md index 60ab2055afa7b1..475ca75e28e1a5 100644 --- a/InternalDocs/frames.md +++ b/InternalDocs/frames.md @@ -142,22 +142,26 @@ since the frame chain may have been in an inconsistent state due to concurrent u ### Remote Profiling Frame Cache -The `last_profiled_frame` field in `PyThreadState` supports an optimization for -remote profilers that sample call stacks from external processes. When a remote -profiler reads the call stack, it writes the current frame address to this field. -The eval loop then keeps this pointer valid by updating it to the parent frame -whenever a frame returns (in `_PyEval_FrameClearAndPop`). +The `last_profiled_frame` and `last_profiled_frame_seq` fields in +`PyThreadState` support an optimization for remote profilers that sample call +stacks from external processes. When a remote profiler reads the call stack, it +writes the current frame address to `last_profiled_frame`. The eval loop then +keeps this pointer valid by updating it to the parent frame whenever a frame +returns (in `_PyEval_FrameClearAndPop`) and increments the sequence. This creates a "high-water mark" that always points to a frame still on the stack. On subsequent samples, the profiler can walk from `current_frame` until it reaches -`last_profiled_frame`, knowing that frames from that point downward are unchanged -and can be retrieved from a cache. This significantly reduces the amount of remote -memory reads needed when call stacks are deep and stable at their base. - -The update in `_PyEval_FrameClearAndPop` is guarded: it only writes when -`last_profiled_frame` is non-NULL AND matches the frame being popped. This -prevents transient frames (called and returned between profiler samples) from -corrupting the cache pointer, while avoiding any overhead when profiling is inactive. +`last_profiled_frame`, then validate the pointer and sequence before using cached +callers. This prevents a later frame that reuses the same `_PyInterpreterFrame` +address from being mistaken for the sampled frame. The cache significantly +reduces the amount of remote memory reads needed when call stacks are deep and +stable at their base. + +The update in `_PyEval_FrameClearAndPop` is guarded: it only advances the +pointer and sequence when `last_profiled_frame` is non-NULL AND matches the +frame being popped. This prevents transient frames (called and returned between +profiler samples) from corrupting the cache anchor, while avoiding any overhead +when profiling is inactive. ### The Instruction Pointer diff --git a/Misc/NEWS.d/next/Library/2026-06-17-22-31-57.gh-issue-151613.n0nua1.rst b/Misc/NEWS.d/next/Library/2026-06-17-22-31-57.gh-issue-151613.n0nua1.rst new file mode 100644 index 00000000000000..fbf3ce47ff2739 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-17-22-31-57.gh-issue-151613.n0nua1.rst @@ -0,0 +1,3 @@ +Fix another way the Tachyon profiler frame cache could produce impossible +mixed stack traces when ``_PyInterpreterFrame`` addresses are reused, by +validating cached frame anchors with a sequence counter. diff --git a/Modules/_remote_debugging/_remote_debugging.h b/Modules/_remote_debugging/_remote_debugging.h index 635e6e208902af..fa37fb7b2167ec 100644 --- a/Modules/_remote_debugging/_remote_debugging.h +++ b/Modules/_remote_debugging/_remote_debugging.h @@ -225,9 +225,15 @@ typedef struct { #define FRAME_CACHE_MAX_THREADS 32 #define FRAME_CACHE_MAX_FRAMES 1024 +typedef struct { + uintptr_t frame; + uintptr_t seq; +} FrameCacheAnchor; + typedef struct { uint64_t thread_id; // 0 = empty slot uintptr_t thread_state_addr; + uintptr_t last_profiled_frame_seq; // sequence paired with addrs[0] uintptr_t addrs[FRAME_CACHE_MAX_FRAMES]; Py_ssize_t num_addrs; PyObject *thread_id_obj; // owned reference, NULL if empty @@ -434,7 +440,7 @@ typedef struct { uintptr_t thread_state_addr; // Owning thread state address uintptr_t base_frame_addr; // Sentinel at bottom (for validation) uintptr_t gc_frame; // GC frame address (0 if not tracking) - uintptr_t last_profiled_frame; // Last cached frame (0 if no cache) + FrameCacheAnchor last_profiled; // Last cached frame anchor StackChunkList *chunks; // Pre-copied stack chunks int skip_first_frame; // Skip frame_addr itself (continue from its caller) RemoteReadPrefetch prefetch; // Optional already-read thread/frame buffers @@ -622,15 +628,21 @@ extern void frame_cache_cleanup(RemoteUnwinderObject *unwinder); extern FrameCacheEntry *frame_cache_find(RemoteUnwinderObject *unwinder, uint64_t thread_id); extern FrameCacheEntry *frame_cache_find_by_tstate(RemoteUnwinderObject *unwinder, uintptr_t tstate_addr); extern int clear_last_profiled_frames(RemoteUnwinderObject *unwinder); +extern int set_last_profiled_frame(RemoteUnwinderObject *unwinder, uintptr_t tstate_addr, uintptr_t frame_addr); extern void frame_cache_invalidate_stale(RemoteUnwinderObject *unwinder, PyObject *result); extern int frame_cache_lookup_and_extend( RemoteUnwinderObject *unwinder, uint64_t thread_id, - uintptr_t last_profiled_frame, + uintptr_t thread_state_addr, + FrameCacheAnchor anchor, PyObject *frame_info, uintptr_t *frame_addrs, Py_ssize_t *num_addrs, Py_ssize_t max_addrs); +extern int frame_cache_anchor_matches( + RemoteUnwinderObject *unwinder, + uintptr_t thread_state_addr, + FrameCacheAnchor anchor); // Returns: 1 = stored, 0 = not stored (graceful), -1 = error // Only stores complete stacks that reach base_frame_addr extern int frame_cache_store( @@ -640,6 +652,7 @@ extern int frame_cache_store( const uintptr_t *addrs, Py_ssize_t num_addrs, uintptr_t thread_state_addr, + uintptr_t last_profiled_frame_seq, uintptr_t base_frame_addr, uintptr_t last_frame_visited); diff --git a/Modules/_remote_debugging/debug_offsets_validation.h b/Modules/_remote_debugging/debug_offsets_validation.h index f070f03ac459dc..c0c01a0a639e19 100644 --- a/Modules/_remote_debugging/debug_offsets_validation.h +++ b/Modules/_remote_debugging/debug_offsets_validation.h @@ -31,7 +31,7 @@ #define FIELD_SIZE(type, member) sizeof(((type *)0)->member) enum { - PY_REMOTE_DEBUG_OFFSETS_TOTAL_SIZE = 880, + PY_REMOTE_DEBUG_OFFSETS_TOTAL_SIZE = 888, PY_REMOTE_ASYNC_DEBUG_OFFSETS_TOTAL_SIZE = 104, }; @@ -261,7 +261,8 @@ validate_fixed_field( APPLY(thread_state, next, sizeof(uintptr_t), _Alignof(uintptr_t), buffer_size); \ APPLY(thread_state, current_frame, sizeof(uintptr_t), _Alignof(uintptr_t), buffer_size); \ APPLY(thread_state, base_frame, sizeof(uintptr_t), _Alignof(uintptr_t), buffer_size); \ - APPLY(thread_state, last_profiled_frame, sizeof(uintptr_t), _Alignof(uintptr_t), buffer_size) + APPLY(thread_state, last_profiled_frame, sizeof(uintptr_t), _Alignof(uintptr_t), buffer_size); \ + APPLY(thread_state, last_profiled_frame_seq, sizeof(uintptr_t), _Alignof(uintptr_t), buffer_size) #define PY_REMOTE_DEBUG_INTERPRETER_STATE_FIELDS(APPLY, buffer_size) \ APPLY(interpreter_state, id, sizeof(int64_t), _Alignof(int64_t), buffer_size); \ diff --git a/Modules/_remote_debugging/frame_cache.c b/Modules/_remote_debugging/frame_cache.c index 19fc406bca9ac9..1b2d9a60f408b9 100644 --- a/Modules/_remote_debugging/frame_cache.c +++ b/Modules/_remote_debugging/frame_cache.c @@ -147,25 +147,87 @@ frame_cache_invalidate_stale(RemoteUnwinderObject *unwinder, PyObject *result) Py_CLEAR(unwinder->frame_cache[i].frame_list); unwinder->frame_cache[i].thread_id = 0; unwinder->frame_cache[i].thread_state_addr = 0; + unwinder->frame_cache[i].last_profiled_frame_seq = 0; unwinder->frame_cache[i].num_addrs = 0; STATS_INC(unwinder, stale_cache_invalidations); } } } +static int +read_last_profiled_anchor(RemoteUnwinderObject *unwinder, + uintptr_t thread_state_addr, + FrameCacheAnchor *anchor) +{ + uintptr_t frame_offset = (uintptr_t)unwinder->debug_offsets.thread_state.last_profiled_frame; + uintptr_t seq_offset = (uintptr_t)unwinder->debug_offsets.thread_state.last_profiled_frame_seq; + + // These fields are adjacent in PyThreadState. Read them together when the + // layout allows it so validation uses a pointer and sequence from the same + // remote-memory read. + if (seq_offset == frame_offset + sizeof(uintptr_t)) { + uintptr_t live_anchor[2]; + if (_Py_RemoteDebug_ReadRemoteMemory(&unwinder->handle, + thread_state_addr + frame_offset, + sizeof(live_anchor), + live_anchor) < 0) { + return -1; + } + anchor->frame = live_anchor[0]; + anchor->seq = live_anchor[1]; + return 0; + } + + if (read_ptr(unwinder, thread_state_addr + frame_offset, &anchor->frame) < 0) { + return -1; + } + return read_ptr(unwinder, thread_state_addr + seq_offset, &anchor->seq); +} + +static Py_ssize_t +find_cached_frame_addr(const FrameCacheEntry *entry, uintptr_t frame_addr, + uintptr_t *real_pops) +{ + *real_pops = 0; + for (Py_ssize_t i = 0; i < entry->num_addrs; i++) { + if (entry->addrs[i] == frame_addr) { + return i; + } + if (entry->addrs[i] != 0) { + (*real_pops)++; + } + } + return -1; +} + +int +frame_cache_anchor_matches( + RemoteUnwinderObject *unwinder, + uintptr_t thread_state_addr, + FrameCacheAnchor anchor) +{ + FrameCacheAnchor live_anchor = {0, 0}; + if (read_last_profiled_anchor(unwinder, thread_state_addr, &live_anchor) < 0) { + PyErr_Clear(); + return 0; + } + return live_anchor.frame == anchor.frame && live_anchor.seq == anchor.seq; +} + // Find last_profiled_frame in cache and extend frame_info with cached continuation // If frame_addrs is provided (not NULL), also extends it with cached addresses int frame_cache_lookup_and_extend( RemoteUnwinderObject *unwinder, uint64_t thread_id, - uintptr_t last_profiled_frame, + uintptr_t thread_state_addr, + FrameCacheAnchor anchor, PyObject *frame_info, uintptr_t *frame_addrs, Py_ssize_t *num_addrs, Py_ssize_t max_addrs) { - if (!unwinder->frame_cache || last_profiled_frame == 0) { + if (!unwinder->frame_cache || anchor.frame == 0) { return 0; } @@ -173,24 +235,31 @@ frame_cache_lookup_and_extend( if (!entry || !entry->frame_list) { return 0; } + if (entry->thread_state_addr != thread_state_addr) { + return 0; + } assert(entry->num_addrs >= 0 && entry->num_addrs <= FRAME_CACHE_MAX_FRAMES); - // Find the index where last_profiled_frame matches - Py_ssize_t start_idx = -1; - for (Py_ssize_t i = 0; i < entry->num_addrs; i++) { - if (entry->addrs[i] == last_profiled_frame) { - start_idx = i; - break; - } - } - + uintptr_t real_pops = 0; + Py_ssize_t start_idx = find_cached_frame_addr(entry, anchor.frame, &real_pops); if (start_idx < 0) { return 0; // Not found } assert(start_idx < entry->num_addrs); + // Synthetic marker frames (<native>/<GC>) are stored as addr-0 entries but + // never increment last_profiled_frame_seq in the target (only real frame + // pops do). Count the real frames before start_idx so the sequence check is + // not thrown off by markers sitting between the leaf and the anchor. + if (entry->last_profiled_frame_seq + real_pops != anchor.seq) { + return 0; + } + Py_ssize_t num_frames = PyList_GET_SIZE(entry->frame_list); + if (start_idx >= num_frames) { + return 0; + } // Extend frame_info with frames ABOVE start_idx (not including it). // The frame at start_idx (last_profiled_frame) was the executing frame @@ -200,6 +269,9 @@ frame_cache_lookup_and_extend( if (cache_start >= num_frames) { return 0; // Nothing above last_profiled_frame to extend with } + if (!frame_cache_anchor_matches(unwinder, thread_state_addr, anchor)) { + return 0; + } PyObject *slice = PyList_GetSlice(entry->frame_list, cache_start, num_frames); if (!slice) { @@ -235,6 +307,7 @@ frame_cache_store( const uintptr_t *addrs, Py_ssize_t num_addrs, uintptr_t thread_state_addr, + uintptr_t last_profiled_frame_seq, uintptr_t base_frame_addr, uintptr_t last_frame_visited) { @@ -277,6 +350,7 @@ frame_cache_store( } entry->thread_id = thread_id; entry->thread_state_addr = thread_state_addr; + entry->last_profiled_frame_seq = last_profiled_frame_seq; if (entry->thread_id_obj == NULL) { entry->thread_id_obj = PyLong_FromUnsignedLongLong(thread_id); if (entry->thread_id_obj == NULL) { diff --git a/Modules/_remote_debugging/frames.c b/Modules/_remote_debugging/frames.c index e7d2a276439026..46968acc6ff1fe 100644 --- a/Modules/_remote_debugging/frames.c +++ b/Modules/_remote_debugging/frames.c @@ -416,7 +416,7 @@ process_frame_chain( Py_DECREF(frame); } - if (ctx->last_profiled_frame != 0 && frame_addr == ctx->last_profiled_frame) { + if (ctx->last_profiled.frame != 0 && frame_addr == ctx->last_profiled.frame) { ctx->stopped_at_cached_frame = 1; break; } @@ -437,14 +437,23 @@ process_frame_chain( return 0; } -// Clear last_profiled_frame for all threads in the target process. -// This must be called at the start of profiling to avoid stale values -// from previous profilers causing us to stop frame walking early. +int +set_last_profiled_frame(RemoteUnwinderObject *unwinder, uintptr_t tstate_addr, + uintptr_t frame_addr) +{ + uintptr_t lpf_addr = tstate_addr + + (uintptr_t)unwinder->debug_offsets.thread_state.last_profiled_frame; + return _Py_RemoteDebug_WriteRemoteMemory(&unwinder->handle, lpf_addr, + sizeof(uintptr_t), &frame_addr); +} + +// Clear the profiler anchor frame for all threads in the target process. The +// sequence is intentionally preserved: a zero frame disables cache lookup, and +// the next profiler-owned anchor should use the target's current generation. int clear_last_profiled_frames(RemoteUnwinderObject *unwinder) { uintptr_t current_interp = unwinder->interpreter_addr; - uintptr_t zero = 0; const size_t MAX_INTERPRETERS = 256; size_t interp_count = 0; @@ -467,11 +476,8 @@ clear_last_profiled_frames(RemoteUnwinderObject *unwinder) size_t thread_count = 0; while (tstate_addr != 0 && thread_count < MAX_THREADS_PER_INTERP) { thread_count++; - // Clear last_profiled_frame - uintptr_t lpf_addr = tstate_addr + unwinder->debug_offsets.thread_state.last_profiled_frame; - if (_Py_RemoteDebug_WriteRemoteMemory(&unwinder->handle, lpf_addr, - sizeof(uintptr_t), &zero) < 0) { - // Non-fatal: just continue + uintptr_t no_frame = 0; + if (set_last_profiled_frame(unwinder, tstate_addr, no_frame) < 0) { PyErr_Clear(); } @@ -512,10 +518,10 @@ try_full_cache_hit( const FrameWalkContext *ctx, uint64_t thread_id) { - if (!unwinder->frame_cache || ctx->last_profiled_frame == 0) { + if (!unwinder->frame_cache || ctx->last_profiled.frame == 0) { return 0; } - if (ctx->frame_addr != ctx->last_profiled_frame) { + if (ctx->frame_addr != ctx->last_profiled.frame) { return 0; } @@ -523,10 +529,16 @@ try_full_cache_hit( if (!entry || !entry->frame_list) { return 0; } + if (entry->thread_state_addr != ctx->thread_state_addr) { + return 0; + } if (entry->num_addrs == 0 || entry->addrs[0] != ctx->frame_addr) { return 0; } + if (entry->last_profiled_frame_seq != ctx->last_profiled.seq) { + return 0; + } PyObject *current_frame = NULL; uintptr_t code_object_addr = 0; @@ -544,6 +556,11 @@ try_full_cache_hit( if (parse_result < 0) { return -1; } + if (!frame_cache_anchor_matches(unwinder, ctx->thread_state_addr, + ctx->last_profiled)) { + Py_XDECREF(current_frame); + return 0; + } if (current_frame != NULL) { if (PyList_Append(ctx->frame_info, current_frame) < 0) { @@ -582,9 +599,12 @@ collect_frames_with_cache( assert(ctx->chunks != NULL); + // Cache misses copy stack chunks before walking. Frames found there are + // parsed from a stable snapshot, which keeps moving stacks from seeding the + // cache with an impossible parent chain. if (ctx->chunks->count == 0) { if (copy_stack_chunks(unwinder, ctx->thread_state_addr, ctx->chunks) < 0) { - PyErr_Clear(); + return -1; } } @@ -598,7 +618,9 @@ collect_frames_with_cache( if (ctx->stopped_at_cached_frame) { Py_ssize_t frames_before_cache = PyList_GET_SIZE(ctx->frame_info); - int cache_result = frame_cache_lookup_and_extend(unwinder, thread_id, ctx->last_profiled_frame, + int cache_result = frame_cache_lookup_and_extend(unwinder, thread_id, + ctx->thread_state_addr, + ctx->last_profiled, ctx->frame_info, ctx->frame_addrs, &ctx->num_addrs, ctx->max_addrs); if (cache_result < 0) { @@ -610,7 +632,7 @@ collect_frames_with_cache( // Continue walking from last_profiled_frame, skipping it (already processed) Py_ssize_t frames_before_walk = PyList_GET_SIZE(ctx->frame_info); FrameWalkContext continue_ctx = { - .frame_addr = ctx->last_profiled_frame, + .frame_addr = ctx->last_profiled.frame, .base_frame_addr = ctx->base_frame_addr, .gc_frame = ctx->gc_frame, .chunks = ctx->chunks, @@ -634,13 +656,14 @@ collect_frames_with_cache( STATS_ADD(unwinder, frames_read_from_cache, PyList_GET_SIZE(ctx->frame_info) - frames_before_cache); } } else { - if (ctx->last_profiled_frame == 0) { + if (ctx->last_profiled.frame == 0) { STATS_INC(unwinder, frame_cache_misses); } } - if (frame_cache_store(unwinder, thread_id, ctx->frame_info, ctx->frame_addrs, ctx->num_addrs, - ctx->thread_state_addr, ctx->base_frame_addr, + if (frame_cache_store(unwinder, thread_id, ctx->frame_info, ctx->frame_addrs, + ctx->num_addrs, ctx->thread_state_addr, + ctx->last_profiled.seq, ctx->base_frame_addr, ctx->last_frame_visited) < 0) { return -1; } diff --git a/Modules/_remote_debugging/module.c b/Modules/_remote_debugging/module.c index 36115f20d9d4cc..7979cd43c6a127 100644 --- a/Modules/_remote_debugging/module.c +++ b/Modules/_remote_debugging/module.c @@ -475,8 +475,8 @@ _remote_debugging_RemoteUnwinder___init___impl(RemoteUnwinderObject *self, return -1; } - // Clear stale last_profiled_frame values from previous profilers - // This prevents us from stopping frame walking early due to stale values + // Clear stale profiler anchors from previous profilers. This prevents us + // from stopping frame walking early due to stale frame pointers. if (cache_frames) { clear_last_profiled_frames(self); } diff --git a/Modules/_remote_debugging/threads.c b/Modules/_remote_debugging/threads.c index 81735e85395ac9..29f22f14c9b29f 100644 --- a/Modules/_remote_debugging/threads.c +++ b/Modules/_remote_debugging/threads.c @@ -503,7 +503,8 @@ unwind_stack_for_thread( goto error; } - // In cache mode, copying stack chunks is more expensive than direct memory reads + // Cache mode skips this for full hits, but cache misses copy chunks before + // walking so newly stored cache entries come from a stable stack snapshot. if (!unwinder->cache_frames) { if (copy_stack_chunks(unwinder, *current_tstate, &chunks) < 0) { set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to copy stack chunks"); @@ -528,18 +529,17 @@ unwind_stack_for_thread( if (unwinder->cache_frames) { // Use cache to avoid re-reading unchanged parent frames - ctx.last_profiled_frame = GET_MEMBER(uintptr_t, ts, + ctx.last_profiled.frame = GET_MEMBER(uintptr_t, ts, unwinder->debug_offsets.thread_state.last_profiled_frame); + ctx.last_profiled.seq = GET_MEMBER(uintptr_t, ts, + unwinder->debug_offsets.thread_state.last_profiled_frame_seq); if (collect_frames_with_cache(unwinder, &ctx, tid) < 0) { set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to collect frames"); goto error; } // Update last_profiled_frame for next sample if it changed - if (frame_addr != ctx.last_profiled_frame) { - uintptr_t lpf_addr = - *current_tstate + (uintptr_t)unwinder->debug_offsets.thread_state.last_profiled_frame; - if (_Py_RemoteDebug_WriteRemoteMemory(&unwinder->handle, lpf_addr, - sizeof(uintptr_t), &frame_addr) < 0) { + if (frame_addr != ctx.last_profiled.frame) { + if (set_last_profiled_frame(unwinder, *current_tstate, frame_addr) < 0) { PyErr_Clear(); // Non-fatal } } diff --git a/Python/pystate.c b/Python/pystate.c index 530bd567b770be..b0c924adbe0fc2 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -1573,6 +1573,8 @@ init_threadstate(_PyThreadStateImpl *_tstate, tstate->current_frame = &_tstate->base_frame; // base_frame pointer for profilers to validate stack unwinding tstate->base_frame = &_tstate->base_frame; + tstate->last_profiled_frame = NULL; + tstate->last_profiled_frame_seq = 0; tstate->datastack_chunk = NULL; tstate->datastack_top = NULL; tstate->datastack_limit = NULL; From 68abb378afd3ae2272e31146ff1540529eb45001 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 27 Jun 2026 20:00:28 +0200 Subject: [PATCH 475/818] [3.15] gh-152434: Fix async-aware Gecko collection (GH-152442) (#152450) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gh-152434: Fix async-aware Gecko collection (GH-152442) (cherry picked from commit 87ac0bc66a298b040c4b4c6c2eb83628bf10abf9) Co-authored-by: László Kiss Kollár <kiss.kollar.laszlo@gmail.com> --- Lib/profiling/sampling/gecko_collector.py | 81 ++++++++++++------- .../test_sampling_profiler/test_collectors.py | 53 +++++++++++- ...-06-25-20-00-00.gh-issue-151496.kMnT3x.rst | 3 + 3 files changed, 108 insertions(+), 29 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-06-25-20-00-00.gh-issue-151496.kMnT3x.rst diff --git a/Lib/profiling/sampling/gecko_collector.py b/Lib/profiling/sampling/gecko_collector.py index 2bb5bd2f664d59..2de8cce387e7f2 100644 --- a/Lib/profiling/sampling/gecko_collector.py +++ b/Lib/profiling/sampling/gecko_collector.py @@ -250,6 +250,25 @@ def collect(self, stack_frames, timestamps_us=None): self.interval = (times[-1] - self.last_sample_time) / self.sample_count self.last_sample_time = times[-1] + # Process async tasks + if stack_frames and hasattr(stack_frames[0], "awaited_by"): + for frames, thread_id, _ in self._iter_async_frames(stack_frames): + frames = filter_internal_frames(frames) + if not frames: + continue + + if thread_id not in self.threads: + self.threads[thread_id] = self._create_thread( + thread_id, False + ) + + self._record_stack_sample( + self.threads[thread_id], frames, thread_id, times, first_time + ) + + self.sample_count += len(times) + return + # Process threads for interpreter_info in stack_frames: for thread_info in interpreter_info.threads: @@ -333,37 +352,43 @@ def collect(self, stack_frames, timestamps_us=None): if not frames: continue - # Process stack once to get stack_index - stack_index = self._process_stack(thread_data, frames) - - # Add samples with timestamps - thread_spill = thread_data["_spill"] - for t in times: - thread_spill.append_sample(stack_index, t) - - # Handle opcodes - if self.opcodes_enabled and frames: - leaf_frame = frames[0] - filename, location, funcname, opcode = leaf_frame - if isinstance(location, tuple): - lineno, _, col_offset, _ = location - else: - lineno = location - col_offset = -1 - - current_state = (opcode, lineno, col_offset, funcname, filename) - - if tid not in self.opcode_state: - self.opcode_state[tid] = (*current_state, first_time) - elif self.opcode_state[tid][:5] != current_state: - prev_opcode, prev_lineno, prev_col, prev_funcname, prev_filename, prev_start = self.opcode_state[tid] - self._add_opcode_interval_marker( - tid, prev_opcode, prev_lineno, prev_col, prev_funcname, prev_start, first_time - ) - self.opcode_state[tid] = (*current_state, first_time) + self._record_stack_sample( + thread_data, frames, tid, times, first_time + ) self.sample_count += len(times) + def _record_stack_sample(self, thread_data, frames, tid, times, first_time): + stack_index = self._process_stack(thread_data, frames) + + thread_spill = thread_data["_spill"] + for t in times: + thread_spill.append_sample(stack_index, t) + + if self.opcodes_enabled and frames: + leaf_frame = frames[0] + filename, location, funcname, opcode = leaf_frame + if isinstance(location, tuple): + lineno, _, col_offset, _ = location + else: + lineno = location + col_offset = -1 + + current_state = (opcode, lineno, col_offset, funcname, filename) + + if tid not in self.opcode_state: + self.opcode_state[tid] = (*current_state, first_time) + elif self.opcode_state[tid][:5] != current_state: + ( + prev_opcode, prev_lineno, prev_col, prev_funcname, + prev_filename, prev_start + ) = self.opcode_state[tid] + self._add_opcode_interval_marker( + tid, prev_opcode, prev_lineno, prev_col, prev_funcname, + prev_start, first_time + ) + self.opcode_state[tid] = (*current_state, first_time) + def _create_thread(self, tid, is_main_thread): """Create a new thread structure with processed profile format.""" if self.spill_dir is None: diff --git a/Lib/test/test_profiling/test_sampling_profiler/test_collectors.py b/Lib/test/test_profiling/test_sampling_profiler/test_collectors.py index 56f3fe5e1c2605..d440c44385e671 100644 --- a/Lib/test/test_profiling/test_sampling_profiler/test_collectors.py +++ b/Lib/test/test_profiling/test_sampling_profiler/test_collectors.py @@ -40,7 +40,16 @@ from test.support import captured_stdout, captured_stderr -from .mocks import MockFrameInfo, MockThreadInfo, MockInterpreterInfo, LocationInfo, make_diff_collector_with_mock_baseline +from .mocks import ( + MockAwaitedInfo, + MockCoroInfo, + MockFrameInfo, + MockInterpreterInfo, + MockTaskInfo, + MockThreadInfo, + LocationInfo, + make_diff_collector_with_mock_baseline, +) from .helpers import close_and_unlink, jsonl_tables @@ -673,6 +682,48 @@ def test_gecko_collector_basic(self): self.assertGreater(stack_table["length"], 0) self.assertGreater(len(stack_table["frame"]), 0) + def test_gecko_collector_async_aware(self): + collector = GeckoCollector(1000) + + parent = MockTaskInfo( + task_id=1, + task_name="Parent", + coroutine_stack=[ + MockCoroInfo( + task_name="Parent", + call_stack=[MockFrameInfo("parent.py", 10, "parent_fn")], + ) + ], + ) + child = MockTaskInfo( + task_id=2, + task_name="Child", + coroutine_stack=[ + MockCoroInfo( + task_name="Child", + call_stack=[MockFrameInfo("child.py", 20, "child_fn")], + ) + ], + awaited_by=[MockCoroInfo(task_name=1, call_stack=[])], + ) + + collector.collect( + [MockAwaitedInfo(thread_id=100, awaited_by=[parent, child])], + timestamps_us=[1000, 2000], + ) + profile_data = export_gecko_profile(self, collector) + + self.assertEqual(len(profile_data["threads"]), 1) + thread_data = profile_data["threads"][0] + self.assertEqual(thread_data["samples"]["length"], 2) + + string_array = profile_data["shared"]["stringArray"] + self.assertIn("parent_fn", string_array) + self.assertIn("child_fn", string_array) + self.assertIn("Parent", string_array) + self.assertIn("Child", string_array) + self.assertEqual(thread_data["markers"]["length"], 0) + @unittest.skipIf(is_emscripten, "threads not available") def test_gecko_collector_export(self): """Test Gecko profile export functionality.""" diff --git a/Misc/NEWS.d/next/Library/2026-06-25-20-00-00.gh-issue-151496.kMnT3x.rst b/Misc/NEWS.d/next/Library/2026-06-25-20-00-00.gh-issue-151496.kMnT3x.rst new file mode 100644 index 00000000000000..994e5dadcf2e8a --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-25-20-00-00.gh-issue-151496.kMnT3x.rst @@ -0,0 +1,3 @@ +Fixed ``profiling.sampling --gecko`` with ``--async-aware`` by flattening +async task stacks before generating Gecko samples. ``--binary`` now rejects +``--async-aware`` until the binary format supports async task data. From a75aa418deeec926a10eef12cf4e8215fd67c947 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka <storchaka@gmail.com> Date: Sat, 27 Jun 2026 23:40:13 +0300 Subject: [PATCH 476/818] [3.15] gh-152415: Exercise curses non-ASCII tests under 8-bit locale encodings (GH-152416) (#152453) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The non-ASCII tests only exercised what the runner's locale could encode (in practice UTF-8). Add 8-bit-encoding cases to the character and string I/O tests, each guarded by the existing encodability check: ASCII, a character common to the Latin encodings ('é'), and ones distinctive to a single encoding (byte 0xA4 is '¤' in ISO-8859-1, '€' in ISO-8859-15, 'є' in KOI8-U). Run the whole suite under different locales to cover them; unrepresentable cases skip. * gh-152415: Verify character output round-trips in test_output_character Read each written character back with in_wch() or instr() rather than inch(), which on a wide build returns the low byte of the code point instead of the locale-encoded byte and so mangles a non-ASCII character of an 8-bit locale. This lets the int-argument cases cover '€'/'є', and adds matching coverage for the str argument. insch() with an int byte > 127 is checked only for Latin-1: on a wide build ncurses winsch stores a printable byte directly as a code point instead of decoding it through the locale. (cherry picked from commit 003d3620cc0f44caca7bf26c3e6964f5f379645f) Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --- Lib/test/test_curses.py | 269 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 242 insertions(+), 27 deletions(-) diff --git a/Lib/test/test_curses.py b/Lib/test/test_curses.py index 48a0b6a175eaff..15511c2fe6d039 100644 --- a/Lib/test/test_curses.py +++ b/Lib/test/test_curses.py @@ -252,6 +252,33 @@ def test_refresh_control(self): self.assertIs(win.is_wintouched(), syncok) self.assertIs(stdscr.is_wintouched(), syncok) + # Many tests below use a common set of non-ASCII cases, each applied only + # when the window encoding can represent it -- so the whole suite is meant to + # be run under several locales (e.g. ISO-8859-1, ISO-8859-15, KOI8-U): + # 'A'/'a' ASCII + # 'é' common to the Latin encodings + # '¤'/'€'/'є' byte 0xA4 in ISO-8859-1 / ISO-8859-15 / KOI8-U + # Precomposed characters are used so a round-trip does not depend on the form. + + def _encodable(self, s): + # Wide characters are only supported in a locale that can encode them. + try: + s.encode(self.stdscr.encoding) + except UnicodeEncodeError: + return False + return True + + def _read_char(self, y, x): + # The character written to a cell, read back for output checks. inch() + # is unusable here: on a wide build it returns the low 8 bits of the + # character's code point rather than its locale-encoded byte, mangling + # anything outside Latin-1. in_wch() reads the wide cell directly; + # without it, instr() re-encodes the cell to the window encoding. + stdscr = self.stdscr + if hasattr(stdscr, 'in_wch'): + return str(stdscr.in_wch(y, x)) + return stdscr.instr(y, x, 1).decode(stdscr.encoding) + def test_output_character(self): stdscr = self.stdscr encoding = stdscr.encoding @@ -261,32 +288,98 @@ def test_output_character(self): stdscr.addch('A') stdscr.addch(b'A') stdscr.addch(65) - c = '\u20ac' - try: - stdscr.addch(c) - except UnicodeEncodeError: - self.assertRaises(UnicodeEncodeError, c.encode, encoding) - except OverflowError: - encoded = c.encode(encoding) - self.assertNotEqual(len(encoded), 1, repr(encoded)) + # See _encodable for the character set. Each is either written (mapped + # to a single byte), or raises UnicodeEncodeError (not in the encoding) + # or OverflowError (a multibyte sequence, e.g. in UTF-8). + for c in ('A', '\u00e9', '\u00a4', '\u20ac', '\u0454'): + try: + stdscr.addch(c) + except UnicodeEncodeError: + self.assertRaises(UnicodeEncodeError, c.encode, encoding) + except OverflowError: + encoded = c.encode(encoding) + self.assertNotEqual(len(encoded), 1, repr(encoded)) stdscr.addch('A', curses.A_BOLD) stdscr.addch(1, 2, 'A') stdscr.addch(2, 3, 'A', curses.A_BOLD) self.assertIs(stdscr.is_wintouched(), True) + # The same characters supplied as an int chtype (a byte > 127). The + # cell is read back with _read_char(), not inch(): on a wide build the + # int is stored through the locale as a wide character that inch() + # cannot represent for a character outside Latin-1. + for c in ('é', '¤', '€', 'є'): + try: + b = c.encode(encoding) + except UnicodeEncodeError: + continue + if len(b) != 1: + continue + # A wide build stores a character outside Latin-1 as a wide cell, + # not as its encoded byte, so it cannot round-trip here. + if ord(c) > 0xff and hasattr(stdscr, 'get_wch'): + continue + v = b[0] + with self.subTest(c=c): + stdscr.addch(0, 0, v) + self.assertEqual(self._read_char(0, 0), c) + stdscr.addch(0, 1, v, curses.A_BOLD) + self.assertEqual(self._read_char(0, 1), c) + self.assertTrue(stdscr.inch(0, 1) & curses.A_BOLD) + stdscr.move(2, 0) + stdscr.echochar(v) + self.assertEqual(self._read_char(2, 0), c) + # insch() round-trips a byte only where its code point equals + # the byte value (Latin-1): on a wide build ncurses winsch + # stores a printable byte directly as a code point instead of + # decoding it through the locale. + if ord(c) < 0x100: + stdscr.insch(1, 0, v) + self.assertEqual(self._read_char(1, 0), c) + + # The same characters supplied as a str. Unlike the int path above, a + # str is stored as a wide-character cell on a wide build, so every + # encodable character round-trips, insch() included. A multibyte + # character does not fit a cell on a narrow build and is skipped. + wide = hasattr(stdscr, 'in_wch') + for c in ('é', '¤', '€', 'є'): + if not self._encodable(c): + continue + if not wide and len(c.encode(encoding)) != 1: + continue + # A wide build stores a character outside Latin-1 as a wide cell, + # not as its encoded byte, so it cannot round-trip here. + if ord(c) > 0xff and hasattr(stdscr, 'get_wch'): + continue + with self.subTest(c=c): + stdscr.addch(0, 0, c) + self.assertEqual(self._read_char(0, 0), c) + stdscr.addch(0, 1, c, curses.A_BOLD) + self.assertEqual(self._read_char(0, 1), c) + self.assertTrue(stdscr.inch(0, 1) & curses.A_BOLD) + stdscr.insch(1, 0, c) + self.assertEqual(self._read_char(1, 0), c) + stdscr.move(2, 0) + stdscr.echochar(c) + self.assertEqual(self._read_char(2, 0), c) + # echochar() stdscr.refresh() stdscr.move(0, 0) stdscr.echochar('A') stdscr.echochar(b'A') stdscr.echochar(65) - with self.assertRaises((UnicodeEncodeError, OverflowError)): - # Unicode is not fully supported yet, but at least it does - # not crash. - # It is supposed to fail because either the character is - # not encodable with the current encoding, or it is encoded to - # a multibyte sequence. - stdscr.echochar('\u0114') + # See _encodable for the character set; as in the addch() loop above. + for c in ('A', '\u00e9', '\u00a4', '\u20ac', '\u0454'): + try: + stdscr.echochar(c) + except UnicodeEncodeError: + # The character is not encodable with the current encoding. + self.assertRaises(UnicodeEncodeError, c.encode, encoding) + except OverflowError: + # The character is encoded to a multibyte sequence. + encoded = c.encode(encoding) + self.assertNotEqual(len(encoded), 1, repr(encoded)) stdscr.echochar('A', curses.A_BOLD) self.assertIs(stdscr.is_wintouched(), False) @@ -296,14 +389,18 @@ def test_output_string(self): # addstr()/insstr() for func in [stdscr.addstr, stdscr.insstr]: with self.subTest(func.__qualname__): - stdscr.move(0, 0) func('abcd') func(b'abcd') - s = 'àßçđ' - try: - func(s) - except UnicodeEncodeError: - self.assertRaises(UnicodeEncodeError, s.encode, encoding) + # Common and encoding-distinctive strings (see _encodable for the + # 0xA4 set); 'àßçđ' is UTF-8-only. Each is written if the + # encoding allows, else raises UnicodeEncodeError. + for s in ('soupçon', 'àßçđ', 'soupçon ¤', 'soupçon €', 'дякую'): + stdscr.move(0, 0) + try: + func(s) + except UnicodeEncodeError: + self.assertRaises(UnicodeEncodeError, s.encode, encoding) + stdscr.move(0, 0) func('abcd', curses.A_BOLD) func(1, 2, 'abcd') func(2, 3, 'abcd', curses.A_BOLD) @@ -314,11 +411,14 @@ def test_output_string(self): stdscr.move(0, 0) func('1234', 3) func(b'1234', 3) - s = '\u0661\u0662\u0663\u0664' - try: - func(s, 3) - except UnicodeEncodeError: - self.assertRaises(UnicodeEncodeError, s.encode, encoding) + # As above (see _encodable); Arabic-Indic digits are UTF-8-only. + for s in ('caf\u00e9', '\u0661\u0662\u0663\u0664', 'caf\u00e9 \u00a4', 'caf\u00e9 \u20ac', '\u0434\u044f\u043a\u0443\u044e'): + stdscr.move(0, 0) + try: + func(s, 3) + except UnicodeEncodeError: + self.assertRaises(UnicodeEncodeError, s.encode, encoding) + stdscr.move(0, 0) func('1234', 5) func('1234', 3, curses.A_BOLD) func(1, 2, '1234', 3) @@ -408,6 +508,24 @@ def test_read_from_window(self): self.assertEqual(stdscr.instr(0, 2, 4), b'BCD ') self.assertRaises(ValueError, stdscr.instr, -2) self.assertRaises(ValueError, stdscr.instr, 0, 2, -2) + # A non-ASCII character of an 8-bit locale reads back as its encoded + # byte (see _encodable for the set). instr() returns the locale bytes + # for any single-byte character; inch() packs the text into a chtype, so + # on a wide build it only round-trips a Latin-1 codepoint (byte == + # codepoint). + encoding = stdscr.encoding + for ch in ('A', 'é', '¤', '€', 'є'): + try: + b = ch.encode(encoding) + except UnicodeEncodeError: + continue + if len(b) != 1: + continue + with self.subTest(ch=ch): + stdscr.addstr(2, 0, ch) + self.assertEqual(stdscr.instr(2, 0, 1), b) + if ord(ch) < 0x100: + self.assertEqual(stdscr.inch(2, 0) & curses.A_CHARTEXT, b[0]) def test_coordinate_errors(self): # Addressing a cell outside the window raises curses.error. @@ -445,6 +563,10 @@ def test_getch(self): self.assertEqual(win.getch(), b'm'[0]) self.assertEqual(win.getch(), b'\n'[0]) + # A key value > 127 is delivered unchanged (it is not locale text). + curses.ungetch(0xE9) + self.assertEqual(win.getch(), 0xE9) + def test_getstr(self): win = curses.newwin(5, 12, 5, 2) curses.echo() @@ -617,6 +739,33 @@ def test_background(self): self.assertEqual(win.inch(0, 0), b'L'[0] | curses.A_REVERSE) self.assertEqual(win.inch(0, 5), b'#'[0] | curses.A_REVERSE) + # A non-ASCII background character of an 8-bit locale reads back as its + # encoded byte. See _encodable for the character set. + win.bkgd(' ') + encoding = win.encoding + for ch in ('é', '¤', '€', 'є'): + try: + b = ch.encode(encoding) + except UnicodeEncodeError: + continue + if len(b) != 1: + continue + # A wide build stores a character outside Latin-1 as a wide cell, + # not as its encoded byte, so it cannot round-trip here. + if ord(ch) > 0xff and hasattr(win, 'get_wch'): + continue + with self.subTest(ch=ch): + win.bkgd(ch) + self.assertEqual(win.getbkgd(), b[0]) + if ord(ch) < 0x100: + # The same byte given as an int. A wide build stores it + # through the locale, so only a Latin-1 byte round-trips. + win.bkgd(' ') + win.bkgdset(b[0]) + self.assertEqual(win.getbkgd(), b[0]) + win.bkgd(b[0]) + self.assertEqual(win.getbkgd(), b[0]) + def test_overlay(self): srcwin = curses.newwin(5, 18, 3, 4) lorem_ipsum(srcwin) @@ -709,6 +858,16 @@ def test_borders_and_lines(self): win.border(65, 66) win.border(65) win.border() + # With no arguments, border() fills the edges with ACS line and corner + # characters. + chartext = curses.A_CHARTEXT + maxy, maxx = win.getmaxyx() + self.assertEqual(win.inch(0, 0) & chartext, curses.ACS_ULCORNER & chartext) + self.assertEqual(win.inch(0, maxx-1) & chartext, curses.ACS_URCORNER & chartext) + self.assertEqual(win.inch(maxy-1, 0) & chartext, curses.ACS_LLCORNER & chartext) + self.assertEqual(win.inch(maxy-1, maxx-1) & chartext, curses.ACS_LRCORNER & chartext) + self.assertEqual(win.inch(0, 1) & chartext, curses.ACS_HLINE & chartext) + self.assertEqual(win.inch(1, 0) & chartext, curses.ACS_VLINE & chartext) win.box(':', '~') self.assertEqual(win.instr(0, 1, 8), b'~~~~~~~~') @@ -719,6 +878,11 @@ def test_borders_and_lines(self): self.assertRaises(TypeError, win.box, 65, 66, 67) self.assertRaises(TypeError, win.box, 65) win.box() + # With no arguments, box() likewise draws ACS corners and lines. + self.assertEqual(win.inch(0, 0) & chartext, curses.ACS_ULCORNER & chartext) + self.assertEqual(win.inch(0, maxx-1) & chartext, curses.ACS_URCORNER & chartext) + self.assertEqual(win.inch(0, 1) & chartext, curses.ACS_HLINE & chartext) + self.assertEqual(win.inch(1, 0) & chartext, curses.ACS_VLINE & chartext) win.move(1, 2) win.hline('-', 5) @@ -740,6 +904,43 @@ def test_borders_and_lines(self): self.assertEqual(win.inch(2, 1), b';'[0] | curses.A_STANDOUT) self.assertEqual(win.inch(3, 1), b'a'[0]) + # A border or line character of an 8-bit locale round-trips as its + # encoded byte. See _encodable for the character set. + encoding = win.encoding + for ch in ('é', '¤', '€', 'є'): + try: + b = ch.encode(encoding) + except UnicodeEncodeError: + continue + if len(b) != 1: + continue + # A wide build stores a character outside Latin-1 as a wide cell, + # not as its encoded byte, so it cannot round-trip here. + if ord(ch) > 0xff and hasattr(win, 'get_wch'): + continue + with self.subTest(ch=ch): + win.erase() + win.hline(2, 0, ch, 5) + self.assertEqual(win.instr(2, 0, 5), b * 5) + win.vline(0, 0, ch, 3) + self.assertEqual(win.instr(0, 0, 1), b) + self.assertEqual(win.instr(1, 0, 1), b) + win.border(ch, ch, ch, ch, ch, ch, ch, ch) + self.assertEqual(win.instr(0, 0), b * maxx) + if ord(ch) < 0x100: + # The same byte given as an int. A wide build stores it + # through the locale, so only a Latin-1 byte round-trips. + v = b[0] + win.erase() + win.hline(2, 0, v, 5) + self.assertEqual(win.instr(2, 0, 5), b * 5) + win.vline(0, 0, v, 3) + self.assertEqual(win.instr(1, 0, 1), b) + win.border(v, v, v, v, v, v, v, v) + self.assertEqual(win.instr(0, 0), b * maxx) + win.box(v, v) + self.assertEqual(win.instr(0, 1, 1), b) + def test_unctrl(self): # TODO: wunctrl() self.assertEqual(curses.unctrl(b'A'), b'A') @@ -748,6 +949,19 @@ def test_unctrl(self): self.assertEqual(curses.unctrl(b'\n'), b'^J') self.assertEqual(curses.unctrl('\n'), b'^J') self.assertEqual(curses.unctrl(10), b'^J') + # A printable non-ASCII byte of an 8-bit locale is returned unchanged. + # See _encodable for the character set. + encoding = self.stdscr.encoding + for ch in ('é', '¤', '€', 'є'): + try: + b = ch.encode(encoding) + except UnicodeEncodeError: + continue + if len(b) != 1: + continue + with self.subTest(ch=ch): + self.assertEqual(curses.unctrl(ch), b) + self.assertEqual(curses.unctrl(b[0]), b) # the byte as an int self.assertRaises(TypeError, curses.unctrl, b'') self.assertRaises(TypeError, curses.unctrl, b'AB') self.assertRaises(TypeError, curses.unctrl, '') @@ -1459,7 +1673,8 @@ def test_issue6243(self): def test_unget_wch(self): stdscr = self.stdscr encoding = stdscr.encoding - for ch in ('a', '\xe9', '\u20ac', '\U0010FFFF'): + # See _encodable for the character set, plus a non-BMP character. + for ch in ('a', '\xe9', '\xa4', '\u20ac', '\u0454', '\U0010FFFF'): try: ch.encode(encoding) except UnicodeEncodeError: From 26caf56ec3a5b5c4c89f25e3ca8b4720eb4af976 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 28 Jun 2026 05:55:04 +0200 Subject: [PATCH 477/818] [3.15] gh-152397: Provide a cross-reference to PEP 798 unpacking syntax (GH-152454) (#152460) Co-authored-by: Raymond Hettinger <rhettinger@users.noreply.github.com> Co-authored-by: Rishit Agnihotri <Twix1288@users.noreply.github.com> --- Doc/library/itertools.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Doc/library/itertools.rst b/Doc/library/itertools.rst index 06f8bf2a8b6fa8..65442021ce1795 100644 --- a/Doc/library/itertools.rst +++ b/Doc/library/itertools.rst @@ -197,6 +197,10 @@ loops that truncate the stream. for iterable in iterables: yield from iterable + Note that :pep:`798` unpacking syntax provides similar functionality + so that ``list(chain(p, q))`` could be written as + ``[*s for s in (p, q)]``. + .. classmethod:: chain.from_iterable(iterable) @@ -208,6 +212,10 @@ loops that truncate the stream. for iterable in iterables: yield from iterable + Note that :pep:`798` unpacking syntax provides similar functionality + so that ``list(chain.from_iterable(iterables))`` could be written as + ``[*s for s in iterables]``. + .. function:: combinations(iterable, r) From 45cf30805c96a5e0bcaa05b10cb829879f021cfb Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 28 Jun 2026 18:19:01 +0200 Subject: [PATCH 478/818] [3.15] gh-152434: Avoid Gecko export in async-aware test (GH-152496) (#152498) --- .../test_profiling/test_sampling_profiler/test_collectors.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_profiling/test_sampling_profiler/test_collectors.py b/Lib/test/test_profiling/test_sampling_profiler/test_collectors.py index d440c44385e671..7746811014a9e2 100644 --- a/Lib/test/test_profiling/test_sampling_profiler/test_collectors.py +++ b/Lib/test/test_profiling/test_sampling_profiler/test_collectors.py @@ -711,7 +711,7 @@ def test_gecko_collector_async_aware(self): [MockAwaitedInfo(thread_id=100, awaited_by=[parent, child])], timestamps_us=[1000, 2000], ) - profile_data = export_gecko_profile(self, collector) + profile_data = collector._build_profile() self.assertEqual(len(profile_data["threads"]), 1) thread_data = profile_data["threads"][0] From 49f865bcd42851d45a91f3abe11c95a3d039ee1c Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 28 Jun 2026 18:38:19 +0200 Subject: [PATCH 479/818] [3.15] gh-110904: Recommend windows-curses in the curses HOWTO (GH-152491) (GH-152506) The HOWTO pointed at UniCurses, which is unmaintained and exposes its own API. windows-curses provides the standard curses interface on Windows, so existing code runs unchanged. (cherry picked from commit 7b0dff7d16ce59df44847ab04567eb97bfbc3576) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --- Doc/howto/curses.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/howto/curses.rst b/Doc/howto/curses.rst index e5f85e0110321c..7bcf63c0b45896 100644 --- a/Doc/howto/curses.rst +++ b/Doc/howto/curses.rst @@ -52,8 +52,8 @@ code, all the functions described here will probably be available. The older versions of curses carried by some proprietary Unixes may not support everything, though. -The Windows version of Python doesn't include the :mod:`curses` -module. A ported version called :pypi:`UniCurses` is available. +The Windows version of Python doesn't include the :mod:`curses` module. +The third-party :pypi:`windows-curses` package provides the same interface on Windows. The Python curses module From 8777a0cf026befb9161d5a65ccbb8967d1ed9396 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 28 Jun 2026 18:53:52 +0200 Subject: [PATCH 480/818] [3.15] gh-78335: Complete the widget option lists in tkinter docstrings (GH-152485) (GH-152500) Several widget __init__ docstrings omitted valid options, and Menubutton and Message had no option list at all. List every option supported by the widget, tagging those added in Tk 9.0 and 9.1. Add test_options_in_docstring, asserting that every option in OPTIONS is named in the widget's __init__ docstring. Options reported by keys() but not in the docstring are only printed in verbose mode, as some depend on the Tk version. (cherry picked from commit ba0c0e6be18ea56d00b4534cc9e32d1acaba96d6) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --- .../test_tkinter/test_geometry_managers.py | 3 + Lib/test/test_tkinter/widget_tests.py | 53 +++++++-- Lib/test/test_ttk/test_extensions.py | 4 + Lib/tkinter/__init__.py | 112 +++++++++++------- Lib/tkinter/ttk.py | 59 +++++---- ...6-06-28-11-00-40.gh-issue-78335.Kp3mWq.rst | 4 + 6 files changed, 161 insertions(+), 74 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-06-28-11-00-40.gh-issue-78335.Kp3mWq.rst diff --git a/Lib/test/test_tkinter/test_geometry_managers.py b/Lib/test/test_tkinter/test_geometry_managers.py index 7fb0abff0049b5..e98a6af060e80b 100644 --- a/Lib/test/test_tkinter/test_geometry_managers.py +++ b/Lib/test/test_tkinter/test_geometry_managers.py @@ -19,6 +19,7 @@ class PackTest(AbstractWidgetTest, unittest.TestCase): test_keys = None + test_options_in_docstring = None def create2(self): pack = tkinter.Toplevel(self.root, name='pack') @@ -312,6 +313,7 @@ def test_pack_short_aliases(self): class PlaceTest(AbstractWidgetTest, unittest.TestCase): test_keys = None + test_options_in_docstring = None def create2(self): t = tkinter.Toplevel(self.root, width=300, height=200, bd=0) @@ -538,6 +540,7 @@ def test_place_method_aliases(self): class GridTest(AbstractWidgetTest, unittest.TestCase): test_keys = None + test_options_in_docstring = None def tearDown(self): cols, rows = self.root.grid_size() diff --git a/Lib/test/test_tkinter/widget_tests.py b/Lib/test/test_tkinter/widget_tests.py index 94244a8b3fe244..014906cba2902c 100644 --- a/Lib/test/test_tkinter/widget_tests.py +++ b/Lib/test/test_tkinter/widget_tests.py @@ -8,6 +8,16 @@ _sentinel = object() +# Abbreviated option names accepted by Tk in addition to the full names. +_OPTION_ALIASES = { + 'bd': 'borderwidth', + 'bg': 'background', + 'bgimg': 'backgroundimage', + 'fg': 'foreground', + 'invcmd': 'invalidcommand', + 'vcmd': 'validatecommand', +} + # Options which accept all values allowed by Tk_GetPixels # borderwidth = bd @@ -214,23 +224,44 @@ def test_keys(self): widget[k] # Test if OPTIONS contains all keys if test.support.verbose: - aliases = { - 'bd': 'borderwidth', - 'bg': 'background', - 'bgimg': 'backgroundimage', - 'fg': 'foreground', - 'invcmd': 'invalidcommand', - 'vcmd': 'validatecommand', - } keys = set(keys) expected = set(self.OPTIONS) for k in sorted(keys - expected): - if not (k in aliases and - aliases[k] in keys and - aliases[k] in expected): + if not (k in _OPTION_ALIASES and + _OPTION_ALIASES[k] in keys and + _OPTION_ALIASES[k] in expected): print('%s.OPTIONS doesn\'t contain "%s"' % (self.__class__.__name__, k)) + def test_options_in_docstring(self): + # Every option in OPTIONS must be listed in the docstring of the + # __init__ method (see gh-78335). Options reported by keys() but + # missing from the docstring are only printed in verbose mode, as + # some of them depend on the Tk version. + widget = self.create() + doc = type(widget).__init__.__doc__ + if doc is None: + self.skipTest('docstrings are not available (run with -OO)') + # Look at the option list only, not the leading description. + start = doc.find('Valid option names') + if start < 0: + start = doc.find('OPTIONS') + if start < 0: + self.skipTest('the __init__ docstring does not list options') + documented = set(re.findall(r'[a-z][a-z0-9]+', doc[start:])) + def is_documented(option): + return (option in documented or + _OPTION_ALIASES.get(option) in documented) + missing = sorted(o for o in self.OPTIONS if not is_documented(o)) + self.assertEqual(missing, [], + '%s options missing from the __init__ docstring: %s' + % (type(widget).__name__, missing)) + if test.support.verbose: + for key in sorted(set(widget.keys())): + if not is_documented(key): + print('%s.__init__ docstring doesn\'t contain "%s"' + % (type(widget).__name__, key)) + class PixelOptionsTests: """Standard options that accept all formats acceptable to Tk_GetPixels. diff --git a/Lib/test/test_ttk/test_extensions.py b/Lib/test/test_ttk/test_extensions.py index 0460f1b9aa3117..fb6bd24b4b9147 100644 --- a/Lib/test/test_ttk/test_extensions.py +++ b/Lib/test/test_ttk/test_extensions.py @@ -199,6 +199,10 @@ def test_resize(self): class OptionMenuTest(test_widgets.MenubuttonTest, unittest.TestCase): + # OptionMenu documents only its own options, not the inherited + # Menubutton options (like the classic tkinter.OptionMenu). + test_options_in_docstring = None + def setUp(self): super().setUp() self.textvar = tkinter.StringVar(self.root) diff --git a/Lib/tkinter/__init__.py b/Lib/tkinter/__init__.py index 9899d7622c672d..7189471ee3fa0e 100644 --- a/Lib/tkinter/__init__.py +++ b/Lib/tkinter/__init__.py @@ -2929,10 +2929,11 @@ class Toplevel(BaseWidget, Wm): def __init__(self, master=None, cnf={}, **kw): """Construct a toplevel widget with the parent MASTER. - Valid option names: background, bd, bg, borderwidth, class, - colormap, container, cursor, height, highlightbackground, - highlightcolor, highlightthickness, menu, relief, screen, takefocus, - use, visual, width.""" + Valid option names: background, backgroundimage (Tk 9.0+), bd, bg, + bgimg (Tk 9.0+), borderwidth, class, colormap, container, + cursor, height, highlightbackground, highlightcolor, + highlightthickness, menu, padx, pady, relief, screen, + takefocus, tile (Tk 9.0+), use, visual, width.""" if kw: cnf = _cnfmerge((cnf, kw)) extra = () @@ -3315,12 +3316,13 @@ def __init__(self, master=None, cnf={}, **kw): """Construct a checkbutton widget with the parent MASTER. Valid option names: activebackground, activeforeground, anchor, - background, bd, bg, bitmap, borderwidth, command, cursor, - disabledforeground, fg, font, foreground, height, - highlightbackground, highlightcolor, highlightthickness, image, - indicatoron, justify, offvalue, onvalue, padx, pady, relief, - selectcolor, selectimage, state, takefocus, text, textvariable, - underline, variable, width, wraplength.""" + background, bd, bg, bitmap, borderwidth, command, compound, + cursor, disabledforeground, fg, font, foreground, height, + highlightbackground, highlightcolor, highlightthickness, + image, indicatoron, justify, offrelief, offvalue, onvalue, + overrelief, padx, pady, relief, selectcolor, selectimage, + state, takefocus, text, textvariable, tristateimage, + tristatevalue, underline, variable, width, wraplength.""" Widget.__init__(self, master, 'checkbutton', cnf, kw) def _setup(self, master, cnf): @@ -3364,13 +3366,15 @@ def __init__(self, master=None, cnf={}, **kw): """Construct an entry widget with the parent MASTER. Valid option names: background, bd, bg, borderwidth, cursor, - exportselection, fg, font, foreground, highlightbackground, - highlightcolor, highlightthickness, insertbackground, - insertborderwidth, insertofftime, insertontime, insertwidth, - invalidcommand, invcmd, justify, relief, selectbackground, - selectborderwidth, selectforeground, show, state, takefocus, - textvariable, validate, validatecommand, vcmd, width, - xscrollcommand.""" + disabledbackground, disabledforeground, exportselection, fg, + font, foreground, highlightbackground, highlightcolor, + highlightthickness, insertbackground, insertborderwidth, + insertofftime, insertontime, insertwidth, invalidcommand, + invcmd, justify, locale (Tk 9.1+), placeholder (Tk 9.0+), + placeholderforeground (Tk 9.0+), readonlybackground, relief, + selectbackground, selectborderwidth, selectforeground, show, + state, takefocus, textvariable, validate, validatecommand, + vcmd, width, xscrollcommand.""" Widget.__init__(self, master, 'entry', cnf, kw) def delete(self, first, last=None): @@ -3449,9 +3453,11 @@ class Frame(Widget): def __init__(self, master=None, cnf={}, **kw): """Construct a frame widget with the parent MASTER. - Valid option names: background, bd, bg, borderwidth, class, - colormap, container, cursor, height, highlightbackground, - highlightcolor, highlightthickness, relief, takefocus, visual, width.""" + Valid option names: background, backgroundimage (Tk 9.0+), bd, bg, + bgimg (Tk 9.0+), borderwidth, class, colormap, container, + cursor, height, highlightbackground, highlightcolor, + highlightthickness, padx, pady, relief, takefocus, tile (Tk + 9.0+), visual, width.""" cnf = _cnfmerge((cnf, kw)) extra = () if 'class_' in cnf: @@ -3481,7 +3487,8 @@ def __init__(self, master=None, cnf={}, **kw): WIDGET-SPECIFIC OPTIONS - height, state, width + compound, height, state, + textangle (Tk 9.1+), width """ Widget.__init__(self, master, 'label', cnf, kw) @@ -3493,11 +3500,14 @@ class Listbox(Widget, XView, YView): def __init__(self, master=None, cnf={}, **kw): """Construct a listbox widget with the parent MASTER. - Valid option names: background, bd, bg, borderwidth, cursor, - exportselection, fg, font, foreground, height, highlightbackground, - highlightcolor, highlightthickness, relief, selectbackground, - selectborderwidth, selectforeground, selectmode, setgrid, takefocus, - width, xscrollcommand, yscrollcommand, listvariable.""" + Valid option names: activestyle, background, bd, bg, borderwidth, + cursor, disabledforeground, exportselection, fg, font, + foreground, height, highlightbackground, highlightcolor, + highlightthickness, inactiveselectbackground (Tk 9.1+), + inactiveselectforeground (Tk 9.1+), justify, listvariable, + relief, selectbackground, selectborderwidth, selectforeground, + selectmode, setgrid, state, takefocus, width, xscrollcommand, + yscrollcommand.""" Widget.__init__(self, master, 'listbox', cnf, kw) def activate(self, index): @@ -3607,7 +3617,8 @@ def __init__(self, master=None, cnf={}, **kw): """Construct menu widget with the parent MASTER. Valid option names: activebackground, activeborderwidth, - activeforeground, background, bd, bg, borderwidth, cursor, + activeforeground, activerelief (Tk 9.0+), background, bd, bg, + borderwidth, cursor, disabledforeground, fg, font, foreground, postcommand, relief, selectcolor, takefocus, tearoff, tearoffcommand, title, type.""" Widget.__init__(self, master, 'menu', cnf, kw) @@ -3737,6 +3748,14 @@ class Menubutton(Widget): """Menubutton widget, obsolete since Tk8.0.""" def __init__(self, master=None, cnf={}, **kw): + """Construct a menubutton widget with the parent MASTER. + + Valid option names: activebackground, activeforeground, anchor, + background, bd, bg, bitmap, borderwidth, compound, cursor, + direction, disabledforeground, fg, font, foreground, height, + highlightbackground, highlightcolor, highlightthickness, + image, indicatoron, justify, menu, padx, pady, relief, state, + takefocus, text, textvariable, underline, width, wraplength.""" Widget.__init__(self, master, 'menubutton', cnf, kw) @@ -3744,6 +3763,12 @@ class Message(Widget): """Message widget to display multiline text. Obsolete since Label does it too.""" def __init__(self, master=None, cnf={}, **kw): + """Construct a message widget with the parent MASTER. + + Valid option names: anchor, aspect, background, bd, bg, borderwidth, + cursor, fg, font, foreground, highlightbackground, + highlightcolor, highlightthickness, justify, padx, pady, + relief, takefocus, text, textvariable, width.""" Widget.__init__(self, master, 'message', cnf, kw) @@ -3754,12 +3779,13 @@ def __init__(self, master=None, cnf={}, **kw): """Construct a radiobutton widget with the parent MASTER. Valid option names: activebackground, activeforeground, anchor, - background, bd, bg, bitmap, borderwidth, command, cursor, - disabledforeground, fg, font, foreground, height, - highlightbackground, highlightcolor, highlightthickness, image, - indicatoron, justify, padx, pady, relief, selectcolor, selectimage, - state, takefocus, text, textvariable, underline, value, variable, - width, wraplength.""" + background, bd, bg, bitmap, borderwidth, command, compound, + cursor, disabledforeground, fg, font, foreground, height, + highlightbackground, highlightcolor, highlightthickness, + image, indicatoron, justify, offrelief, overrelief, padx, + pady, relief, selectcolor, selectimage, state, takefocus, + text, textvariable, tristateimage, tristatevalue, underline, + value, variable, width, wraplength.""" Widget.__init__(self, master, 'radiobutton', cnf, kw) def deselect(self): @@ -3890,9 +3916,11 @@ def __init__(self, master=None, cnf={}, **kw): WIDGET-SPECIFIC OPTIONS - autoseparators, height, maxundo, - spacing1, spacing2, spacing3, - state, tabs, undo, width, wrap, + autoseparators, blockcursor, endline, + height, inactiveselectbackground, + insertunfocussed, locale (Tk 9.1+), maxundo, + spacing1, spacing2, spacing3, startline, + state, tabs, tabstyle, undo, width, wrap, """ Widget.__init__(self, master, 'text', cnf, kw) @@ -4750,9 +4778,12 @@ def __init__(self, master=None, cnf={}, **kw): buttondownrelief, buttonuprelief, command, disabledbackground, disabledforeground, format, from, - invalidcommand, increment, + invalidcommand, invcmd, increment, + locale (Tk 9.1+), + placeholder (Tk 9.0+), + placeholderforeground (Tk 9.0+), readonlybackground, state, to, - validate, validatecommand values, + validate, validatecommand, vcmd, values, width, wrap, """ Widget.__init__(self, master, 'spinbox', cnf, kw) @@ -4941,8 +4972,9 @@ def __init__(self, master=None, cnf={}, **kw): WIDGET-SPECIFIC OPTIONS handlepad, handlesize, opaqueresize, - sashcursor, sashpad, sashrelief, - sashwidth, showhandle, + proxybackground, proxyborderwidth, + proxyrelief, sashcursor, sashpad, + sashrelief, sashwidth, showhandle, """ Widget.__init__(self, master, 'panedwindow', cnf, kw) diff --git a/Lib/tkinter/ttk.py b/Lib/tkinter/ttk.py index cb66420d1cd129..36f21453dc7390 100644 --- a/Lib/tkinter/ttk.py +++ b/Lib/tkinter/ttk.py @@ -579,8 +579,8 @@ def __init__(self, master=None, **kw): STANDARD OPTIONS - class, compound, cursor, image, state, style, takefocus, - text, textvariable, underline, width + class, compound, cursor, image, justify (Tk 9.0+), padding, + state, style, takefocus, text, textvariable, underline, width WIDGET-SPECIFIC OPTIONS @@ -602,8 +602,8 @@ def __init__(self, master=None, **kw): STANDARD OPTIONS - class, compound, cursor, image, state, style, takefocus, - text, textvariable, underline, width + class, compound, cursor, image, justify (Tk 9.0+), padding, + state, style, takefocus, text, textvariable, underline, width WIDGET-SPECIFIC OPTIONS @@ -636,8 +636,10 @@ def __init__(self, master=None, widget=None, **kw): WIDGET-SPECIFIC OPTIONS - exportselection, invalidcommand, justify, show, state, - textvariable, validate, validatecommand, width + background, exportselection, font, foreground, invalidcommand, + justify, locale (Tk 9.1+), placeholder (Tk 9.0+), + placeholderforeground (Tk 9.0+), show, state, textvariable, + validate, validatecommand, width VALIDATION MODES @@ -674,12 +676,14 @@ def __init__(self, master=None, **kw): STANDARD OPTIONS - class, cursor, style, takefocus + class, cursor, style, takefocus, xscrollcommand WIDGET-SPECIFIC OPTIONS - exportselection, justify, height, postcommand, state, - textvariable, values, width + background, exportselection, font, foreground, height, + invalidcommand, justify, locale (Tk 9.1+), placeholder (Tk 9.0+), + placeholderforeground (Tk 9.0+), postcommand, show, state, + textvariable, validate, validatecommand, values, width """ Entry.__init__(self, master, "ttk::combobox", **kw) @@ -728,13 +732,13 @@ def __init__(self, master=None, **kw): STANDARD OPTIONS - class, compound, cursor, image, style, takefocus, text, - textvariable, underline, width + class, compound, cursor, image, state, style, takefocus, + text, textvariable, underline, width WIDGET-SPECIFIC OPTIONS - anchor, background, font, foreground, justify, padding, - relief, text, wraplength + anchor, background, borderwidth, font, foreground, justify, + padding, relief, text, textangle (Tk 9.1+), wraplength """ Widget.__init__(self, master, "ttk::label", kw) @@ -752,8 +756,9 @@ def __init__(self, master=None, **kw): class, cursor, style, takefocus WIDGET-SPECIFIC OPTIONS - labelanchor, text, underline, padding, labelwidget, width, - height + + borderwidth, height, labelanchor, labelwidget, padding, + relief, text, underline, width """ Widget.__init__(self, master, "ttk::labelframe", kw) @@ -769,8 +774,8 @@ def __init__(self, master=None, **kw): STANDARD OPTIONS - class, compound, cursor, image, state, style, takefocus, - text, textvariable, underline, width + class, compound, cursor, image, justify (Tk 9.0+), padding, + state, style, takefocus, text, textvariable, underline, width WIDGET-SPECIFIC OPTIONS @@ -983,7 +988,9 @@ def __init__(self, master=None, **kw): STANDARD OPTIONS - class, cursor, style, takefocus + anchor (Tk 9.0+), class, cursor, font (Tk 9.0+), + foreground (Tk 9.0+), justify (Tk 9.0+), style, takefocus, + text (Tk 9.0+), wraplength (Tk 9.0+) WIDGET-SPECIFIC OPTIONS @@ -1022,8 +1029,8 @@ def __init__(self, master=None, **kw): STANDARD OPTIONS - class, compound, cursor, image, state, style, takefocus, - text, textvariable, underline, width + class, compound, cursor, image, justify (Tk 9.0+), padding, + state, style, takefocus, text, textvariable, underline, width WIDGET-SPECIFIC OPTIONS @@ -1050,7 +1057,7 @@ def __init__(self, master=None, **kw): STANDARD OPTIONS - class, cursor, style, takefocus + class, cursor, state, style, takefocus WIDGET-SPECIFIC OPTIONS @@ -1147,7 +1154,10 @@ def __init__(self, master=None, **kw): WIDGET-SPECIFIC OPTIONS - to, from_, increment, values, wrap, format, command + background, command, exportselection, font, foreground, + format, from_, increment, justify, locale (Tk 9.1+), + placeholder (Tk 9.0+), placeholderforeground (Tk 9.0+), show, + state, textvariable, to, values, width, wrap """ Entry.__init__(self, master, "ttk::spinbox", **kw) @@ -1174,7 +1184,10 @@ def __init__(self, master=None, **kw): WIDGET-SPECIFIC OPTIONS - columns, displaycolumns, height, padding, selectmode, show + columns, displaycolumns, headingheight (Tk 9.1+), height, + padding, rowheight (Tk 9.1+), selectmode, selecttype (Tk 9.0+), + show, striped (Tk 9.0+), titlecolumns (Tk 9.0+), + titleitems (Tk 9.0+) ITEM OPTIONS diff --git a/Misc/NEWS.d/next/Library/2026-06-28-11-00-40.gh-issue-78335.Kp3mWq.rst b/Misc/NEWS.d/next/Library/2026-06-28-11-00-40.gh-issue-78335.Kp3mWq.rst new file mode 100644 index 00000000000000..641889cfa9ef41 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-28-11-00-40.gh-issue-78335.Kp3mWq.rst @@ -0,0 +1,4 @@ +Update the docstrings of :mod:`tkinter` and :mod:`tkinter.ttk` widget classes +to list all supported widget options, including options added in Tk 9.0 and +9.1. ``tkinter.Menubutton`` and ``tkinter.Message`` previously had no option +list at all. From 09013312bbdf9ff6583c95ba6bc2698e61c66be6 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka <storchaka@gmail.com> Date: Sun, 28 Jun 2026 20:06:55 +0300 Subject: [PATCH 481/818] [3.15] gh-87881: Document the result of curses inch() and getbkgd() (GH-152488) (GH-152511) Explain the character/attribute bit layout and how to extract the parts (A_CHARTEXT and A_ATTRIBUTES bit-masks, pair_number() for the color pair). (cherry picked from commit d831a690766e92b3be5e40134f64407bd041bcbf) Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --- Doc/library/curses.rst | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Doc/library/curses.rst b/Doc/library/curses.rst index 5726aee5af89b1..621e3d6ad2043a 100644 --- a/Doc/library/curses.rst +++ b/Doc/library/curses.rst @@ -975,6 +975,7 @@ Window objects .. method:: window.getbkgd() Return the given window's current background character/attribute pair. + Its components can be extracted like those of :meth:`inch`. .. method:: window.getch([y, x]) @@ -1065,8 +1066,10 @@ Window objects .. method:: window.inch([y, x]) - Return the character at the given position in the window. The bottom 8 bits are - the character proper, and upper bits are the attributes. + Return the character at the given position in the window. + The bottom 8 bits are the character proper and the upper bits are the attributes; + extract them with the :data:`A_CHARTEXT` and :data:`A_ATTRIBUTES` bit-masks, + and the color pair with :func:`pair_number`. .. method:: window.insch(ch[, attr]) From f08fc4ad5141a99ebd8187b870791102117c00d8 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 28 Jun 2026 19:27:42 +0200 Subject: [PATCH 482/818] [3.15] gh-152356: Fix Windows blocking sampling after target process exit (GH-152471) (#152512) --- .../test_sampling_profiler/test_blocking.py | 57 ++++++++++++++++++- ...-06-28-12-45-09.gh-issue-152356.Dr4w2Q.rst | 3 + Modules/_remote_debugging/threads.c | 6 ++ 3 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2026-06-28-12-45-09.gh-issue-152356.Dr4w2Q.rst diff --git a/Lib/test/test_profiling/test_sampling_profiler/test_blocking.py b/Lib/test/test_profiling/test_sampling_profiler/test_blocking.py index 1f4b6da3281056..0a5541c733d4c7 100644 --- a/Lib/test/test_profiling/test_sampling_profiler/test_blocking.py +++ b/Lib/test/test_profiling/test_sampling_profiler/test_blocking.py @@ -1,6 +1,9 @@ """Tests for blocking mode sampling profiler.""" import io +import os +import subprocess +import sys import textwrap import unittest from unittest import mock @@ -15,7 +18,11 @@ "Test only runs when _remote_debugging is available" ) -from test.support import requires_remote_subprocess_debugging +from test.support import ( + SHORT_TIMEOUT, + os_helper, + requires_remote_subprocess_debugging, +) from .helpers import test_subprocess @@ -158,3 +165,51 @@ def test_generator_not_under_consumer_arithmetic(self): f"fibonacci_generator appears in the stack when consume_generator " f"is the leaf frame on an arithmetic line. This indicates " f"torn/inconsistent stack traces are being captured.") + + +@requires_remote_subprocess_debugging() +@unittest.skipUnless(sys.platform == "win32", "Windows only") +class TestBlockingModeCLI(unittest.TestCase): + def test_run_blocking_exits_after_target_process_exits(self): + script = 'print("done")\n' + + tmpdir = os.path.abspath(os_helper.TESTFN + "_profiling_blocking") + with os_helper.temp_dir(tmpdir) as tmpdir: + script_path = os.path.join(tmpdir, "tiny_target.py") + profile_path = os.path.join(tmpdir, "blocking.bin") + with open(script_path, "w", encoding="utf-8") as file: + file.write(script) + + cmd = [ + sys.executable, "-m", "profiling.sampling", "run", + "--binary", "-o", profile_path, + "--mode=cpu", "--blocking", "-r", "100", + script_path, + ] + result = subprocess.run( + cmd, + cwd=tmpdir, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True, + timeout=SHORT_TIMEOUT, + ) + + self.assertEqual( + result.returncode, 0, + f"stdout:\n{result.stdout}\nstderr:\n{result.stderr}", + ) + self.assertGreater(os.path.getsize(profile_path), 0) + + replay = subprocess.run( + [sys.executable, "-m", "profiling.sampling", "replay", + profile_path], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True, + timeout=SHORT_TIMEOUT, + ) + self.assertEqual( + replay.returncode, 0, + f"stdout:\n{replay.stdout}\nstderr:\n{replay.stderr}", + ) diff --git a/Misc/NEWS.d/next/Library/2026-06-28-12-45-09.gh-issue-152356.Dr4w2Q.rst b/Misc/NEWS.d/next/Library/2026-06-28-12-45-09.gh-issue-152356.Dr4w2Q.rst new file mode 100644 index 00000000000000..6a4ceecbe9279e --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-28-12-45-09.gh-issue-152356.Dr4w2Q.rst @@ -0,0 +1,3 @@ +Fix a hang in ``profiling.sampling run --blocking`` on Windows when the +target process exits. The profiler now finalizes binary profiles instead of +continuing to sample the exited process. diff --git a/Modules/_remote_debugging/threads.c b/Modules/_remote_debugging/threads.c index 29f22f14c9b29f..04c70cc96d6bd1 100644 --- a/Modules/_remote_debugging/threads.c +++ b/Modules/_remote_debugging/threads.c @@ -862,6 +862,12 @@ _Py_RemoteDebug_StopAllThreads(RemoteUnwinderObject *unwinder, _Py_RemoteDebug_T return 0; } + if (!is_process_alive(unwinder->handle.hProcess)) { + PyErr_Format(PyExc_ProcessLookupError, + "Process %d has terminated", unwinder->handle.pid); + return -1; + } + PyErr_Format(PyExc_RuntimeError, "NtSuspendProcess failed: 0x%lx", status); return -1; } From 3334842f893f706e93bd386a712f617c3e295da2 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 28 Jun 2026 21:13:06 +0200 Subject: [PATCH 483/818] [3.15] Docs: link to language reference instead of PEP (GH-152462) (#152522) Docs: link to language reference instead of PEP (GH-152462) (cherry picked from commit 54524ab669a566623336c36994e1b3f2a6711c77) Co-authored-by: Ned Batchelder <ned@nedbatchelder.com> --- Doc/library/itertools.rst | 12 ++++++------ Doc/reference/expressions.rst | 2 ++ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/Doc/library/itertools.rst b/Doc/library/itertools.rst index 65442021ce1795..e1730608887b3d 100644 --- a/Doc/library/itertools.rst +++ b/Doc/library/itertools.rst @@ -197,9 +197,9 @@ loops that truncate the stream. for iterable in iterables: yield from iterable - Note that :pep:`798` unpacking syntax provides similar functionality - so that ``list(chain(p, q))`` could be written as - ``[*s for s in (p, q)]``. + Note that :ref:`unpacking in comprehensions <unpacking-comprehensions>` + provides similar functionality so that ``list(chain(p, q))`` could be + written as ``[*s for s in (p, q)]``. .. classmethod:: chain.from_iterable(iterable) @@ -212,9 +212,9 @@ loops that truncate the stream. for iterable in iterables: yield from iterable - Note that :pep:`798` unpacking syntax provides similar functionality - so that ``list(chain.from_iterable(iterables))`` could be written as - ``[*s for s in iterables]``. + Note that :ref:`unpacking in comprehensions <unpacking-comprehensions>` + provides similar functionality so that ``list(chain.from_iterable(iterables))`` + could be written as ``[*s for s in iterables]``. .. function:: combinations(iterable, r) diff --git a/Doc/reference/expressions.rst b/Doc/reference/expressions.rst index 9f55e9ad7eb5c1..93b2cdc1e17010 100644 --- a/Doc/reference/expressions.rst +++ b/Doc/reference/expressions.rst @@ -848,6 +848,8 @@ appear directly in a class definition. ``yield`` and ``yield from`` prohibited in the implicitly nested scope. +.. _unpacking-comprehensions: + Unpacking in comprehensions ^^^^^^^^^^^^^^^^^^^^^^^^^^^ From aa06529dfb8ceeeae631cb432fa761d1389eda72 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 28 Jun 2026 21:35:27 +0200 Subject: [PATCH 484/818] [3.15] gh-150743: Limit trailer lines and interim responses read by http.client (GH-150741) (#152523) gh-150743: Limit trailer lines and interim responses read by http.client (GH-150741) http.client read chunked-response trailer lines and skipped interim (1xx) responses in unbounded loops, so a server streaming either forever would hang the client even with a socket timeout set (data keeps arriving, so the timeout never fires). Trailer lines are now limited to max_response_headers (100 by default) and interim responses to 100; HTTPException is raised past either limit. Follow-up to gh-88188 for CVE-2021-3737, which bounded header lines within an interim response but not these two sibling loops. (cherry picked from commit 41cc78a7a47fe584e2c2899737fec877d61ae331) Co-authored-by: Gregory P. Smith <68491+gpshead@users.noreply.github.com> --- This issue was reported to us via [GHSA-w4q2-g22w-6fr4](https://github.com/python/cpython/security/advisories/GHSA-w4q2-g22w-6fr4) and was determined not to be high enough severity to handle privately. Co-authored-by: Gregory P. Smith <68491+gpshead@users.noreply.github.com> --- Doc/library/http.client.rst | 1 + Lib/http/client.py | 29 ++++++- Lib/test/test_httplib.py | 87 +++++++++++++++++++ ...05-30-00-00-00.gh-issue-150743.httpdos.rst | 7 ++ 4 files changed, 123 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Security/2026-05-30-00-00-00.gh-issue-150743.httpdos.rst diff --git a/Doc/library/http.client.rst b/Doc/library/http.client.rst index ddf3d40d221fcd..98ea09d8f72d8b 100644 --- a/Doc/library/http.client.rst +++ b/Doc/library/http.client.rst @@ -433,6 +433,7 @@ HTTPConnection Objects The maximum number of allowed response headers to help prevent denial-of-service attacks. By default, the maximum number of allowed headers is set to 100. + The same limit applies to the trailer section of a chunked response. .. versionadded:: 3.15 diff --git a/Lib/http/client.py b/Lib/http/client.py index 1e1a535c4c4eb1..7ef99e7201c005 100644 --- a/Lib/http/client.py +++ b/Lib/http/client.py @@ -111,6 +111,13 @@ _MAXLINE = 65536 _MAXHEADERS = 100 +# maximal number of interim (1xx) responses tolerated before the final +# response. Real servers send at most a few; without a bound, a server +# streaming "100 Continue" responses would hang getresponse() forever. +# A socket timeout cannot detect that as data keeps arriving within every +# timeout window. +_MAXINTERIMRESPONSES = 100 + # Data larger than this will be read in chunks, to prevent extreme # overallocation. _MIN_READ_BUF_SIZE = 1 << 20 @@ -293,6 +300,7 @@ def __init__(self, sock, debuglevel=0, method=None, url=None): self.chunk_left = _UNKNOWN # bytes left to read in current chunk self.length = _UNKNOWN # number of bytes left in response self.will_close = _UNKNOWN # conn will close at end of response + self._max_headers = None # configured header count limit def _read_status(self): line = str(self.fp.readline(_MAXLINE + 1), "iso-8859-1") @@ -332,8 +340,13 @@ def begin(self, *, _max_headers=None): # we've already started reading the response return + # Trailers of a chunked response are read by read() long after + # begin() returns, so remember the configured header count limit + # for _read_and_discard_trailer() to enforce. + self._max_headers = _max_headers + # read until we get a non-100 response - while True: + for _ in range(_MAXINTERIMRESPONSES): version, status, reason = self._read_status() if status != CONTINUE: break @@ -342,6 +355,9 @@ def begin(self, *, _max_headers=None): if self.debuglevel > 0: print("headers:", skipped_headers) del skipped_headers + else: + raise HTTPException( + f"got more than {_MAXINTERIMRESPONSES} interim responses") self.code = self.status = status self.reason = reason.strip() @@ -561,6 +577,10 @@ def _read_next_chunk_size(self): def _read_and_discard_trailer(self): # read and discard trailer up to the CRLF terminator ### note: we shouldn't have any trailers! + max_trailers = self._max_headers + if max_trailers is None: + max_trailers = _MAXHEADERS + trailers_read = 0 while True: line = self.fp.readline(_MAXLINE + 1) if len(line) > _MAXLINE: @@ -571,6 +591,13 @@ def _read_and_discard_trailer(self): break if line in (b'\r\n', b'\n', b''): break + # Bound the trailer count just as response headers are bounded. + # A server streaming trailer lines forever would otherwise hang + # the client; a socket timeout cannot detect that as data keeps + # arriving within every timeout window. + trailers_read += 1 + if trailers_read > max_trailers: + raise HTTPException(f"got more than {max_trailers} trailers") def _get_chunk_left(self): # return self.chunk_left, reading a new chunk if necessary. diff --git a/Lib/test/test_httplib.py b/Lib/test/test_httplib.py index f771fc48dada36..5b1d6e0aa52079 100644 --- a/Lib/test/test_httplib.py +++ b/Lib/test/test_httplib.py @@ -478,6 +478,35 @@ def test_max_connection_headers(self): response = conn.getresponse() response.read() + def test_max_connection_trailers(self): + # max_response_headers also limits trailer lines of a chunked + # response, which are read and discarded by read(). + max_trailers = client._MAXHEADERS + 20 + trailer_lines = "".join( + f"X-Trailer{i}: {i}\r\n" for i in range(max_trailers - 1) + ) + body = chunked_start + last_chunk + trailer_lines + chunked_end + + with self.subTest(max_response_headers=None): + conn = client.HTTPConnection("example.com") + conn.sock = FakeSocket(body) + conn.request("GET", "/") + response = conn.getresponse() + with self.assertRaisesRegex( + client.HTTPException, + f"got more than {client._MAXHEADERS} trailers", + ): + response.read() + + with self.subTest(max_response_headers=max_trailers): + conn = client.HTTPConnection( + "example.com", max_response_headers=max_trailers + ) + conn.sock = FakeSocket(body) + conn.request("GET", "/") + response = conn.getresponse() + self.assertEqual(response.read(), chunked_expected) + class HttpMethodTests(TestCase): def test_invalid_method_names(self): methods = ( @@ -1378,6 +1407,35 @@ def test_overflowing_header_limit_after_100(self): self.assertIn('got more than ', str(cm.exception)) self.assertIn('headers', str(cm.exception)) + def test_too_many_interim_responses(self): + # A server streaming "100 Continue" responses forever must not + # hang getresponse(). + body = ( + 'HTTP/1.1 100 Continue\r\n\r\n' + * (client._MAXINTERIMRESPONSES + 1) + ) + resp = client.HTTPResponse(FakeSocket(body)) + with self.assertRaises(client.HTTPException) as cm: + resp.begin() + self.assertIn('got more than ', str(cm.exception)) + self.assertIn('interim responses', str(cm.exception)) + + def test_multiple_interim_responses(self): + # A reasonable number of interim responses before the final + # response is skipped as before. + body = ( + 'HTTP/1.1 100 Continue\r\n\r\n' * 3 + + 'HTTP/1.1 200 OK\r\n' + 'Content-Length: 5\r\n' + '\r\n' + 'hello' + ) + resp = client.HTTPResponse(FakeSocket(body), method="GET") + resp.begin() + self.assertEqual(resp.status, 200) + self.assertEqual(resp.read(), b'hello') + resp.close() + def test_overflowing_chunked_line(self): body = ( 'HTTP/1.1 200 OK\r\n' @@ -1449,6 +1507,35 @@ def test_chunked_trailers(self): self.assertEqual(sock.file.read(), b"") #we read to the end resp.close() + def test_chunked_too_many_trailers(self): + """A response streaming endless trailer lines must raise, not hang""" + too_many_trailers = "".join( + f"X-Trailer{i}: {i}\r\n" for i in range(client._MAXHEADERS + 1) + ) + # An unbounded read() reaches the trailers via the final 0 chunk. + sock = FakeSocket( + chunked_start + last_chunk + too_many_trailers + chunked_end) + resp = client.HTTPResponse(sock, method="GET") + resp.begin() + with self.assertRaisesRegex( + client.HTTPException, + f"got more than {client._MAXHEADERS} trailers", + ): + resp.read() + resp.close() + + # A bounded read(amt) larger than the body hits the same limit. + sock = FakeSocket( + chunked_start + last_chunk + too_many_trailers + chunked_end) + resp = client.HTTPResponse(sock, method="GET") + resp.begin() + with self.assertRaisesRegex( + client.HTTPException, + f"got more than {client._MAXHEADERS} trailers", + ): + resp.read(len(chunked_expected) + 1) + resp.close() + def test_chunked_sync(self): """Check that we don't read past the end of the chunked-encoding stream""" expected = chunked_expected diff --git a/Misc/NEWS.d/next/Security/2026-05-30-00-00-00.gh-issue-150743.httpdos.rst b/Misc/NEWS.d/next/Security/2026-05-30-00-00-00.gh-issue-150743.httpdos.rst new file mode 100644 index 00000000000000..abc07d91c63fca --- /dev/null +++ b/Misc/NEWS.d/next/Security/2026-05-30-00-00-00.gh-issue-150743.httpdos.rst @@ -0,0 +1,7 @@ +:mod:`http.client` now limits the number of chunked-response trailer lines +it will read to :attr:`~http.client.HTTPConnection.max_response_headers` +(100 by default), and the number of interim (1xx) responses it will skip +to 100. A malicious or broken server could previously stream trailer +lines or ``100 Continue`` responses forever, hanging the client even when +a socket timeout was in use. +Reported by ``@YLChen-007`` via GHSA-w4q2-g22w-6fr4. From 65695ebffa649ba7c339f1abad0276e94e5b8689 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 29 Jun 2026 00:53:20 +0200 Subject: [PATCH 485/818] [3.15] GH-151619: Ensure non-module global/builtin namespaces are watched for lazy imports (GH-151762) (#152533) GH-151619: Ensure non-module global/builtin namespaces are watched for lazy imports (GH-151762) (cherry picked from commit 7ed9062dd05e735505f75e9caac56ccd64913371) Co-authored-by: Brandt Bucher <brandt@python.org> --- Lib/test/test_lazy_import/__init__.py | 75 +++++++++++++++++++ ...-06-19-16-40-01.gh-issue-151619.35yyJW.rst | 3 + Python/specialize.c | 9 ++- 3 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-19-16-40-01.gh-issue-151619.35yyJW.rst diff --git a/Lib/test/test_lazy_import/__init__.py b/Lib/test/test_lazy_import/__init__.py index b531a4227bc9a8..2c9dd0627f697c 100644 --- a/Lib/test/test_lazy_import/__init__.py +++ b/Lib/test/test_lazy_import/__init__.py @@ -957,6 +957,81 @@ def f(): self.assertEqual(result.returncode, 0, f"stdout: {result.stdout}, stderr: {result.stderr}") self.assertIn("OK", result.stdout) + def test_add_lazy_to_exec_globals_after_specialization(self): + code = textwrap.dedent(""" + source = ''' + import sys + import types + + lazy from test.test_lazy_import.data import basic2 + + assert 'test.test_lazy_import.data.basic2' not in sys.modules + + class C: pass + sneaky = C() + sneaky.x = 1 + + def f(): + t = 0 + for _ in range(5): + t += sneaky.x + return t + + f() + globals()["sneaky"] = globals()["basic2"] + assert f() == 210 + print("OK") + ''' + ns = {"__name__": "lazy_exec_globals"} + exec(source, ns) + """) + result = subprocess.run( + [sys.executable, "-c", code], + capture_output=True, + text=True + ) + self.assertEqual(result.returncode, 0, f"stdout: {result.stdout}, stderr: {result.stderr}") + self.assertIn("OK", result.stdout) + + def test_add_lazy_to_exec_builtins_after_specialization(self): + code = textwrap.dedent(""" + import builtins + source = ''' + import sys + import types + + lazy from test.test_lazy_import.data import basic2 + + assert 'test.test_lazy_import.data.basic2' not in sys.modules + + class C: pass + sneaky = C() + sneaky.x = 1 + __builtins__["sneaky"] = sneaky + del sneaky + + def f(): + t = 0 + for _ in range(5): + t += sneaky.x + return t + + f() + __builtins__["sneaky"] = globals()["basic2"] + assert f() == 210 + print("OK") + ''' + ns = {"__name__": "lazy_exec_builtins", "__builtins__": builtins.__dict__.copy()} + exec(source, ns) + """) + result = subprocess.run( + [sys.executable, "-c", code], + capture_output=True, + text=True + ) + self.assertEqual(result.returncode, 0, f"stdout: {result.stdout}, stderr: {result.stderr}") + self.assertIn("OK", result.stdout) + @support.requires_subprocess() class MultipleNameFromImportTests(LazyImportTestCase): diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-19-16-40-01.gh-issue-151619.35yyJW.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-19-16-40-01.gh-issue-151619.35yyJW.rst new file mode 100644 index 00000000000000..28ba2038e876fa --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-19-16-40-01.gh-issue-151619.35yyJW.rst @@ -0,0 +1,3 @@ +Fix an issue where using non-module global or builtin namespaces (such as +dictionaries passed to :func:`exec`) could cause cached global loads to +produce unresolved :ref:`lazy imports <lazy-imports>`. diff --git a/Python/specialize.c b/Python/specialize.c index fb75ca8d58e851..12a8c624f24d71 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -1388,6 +1388,7 @@ specialize_load_global_lock_held( SPECIALIZATION_FAIL(LOAD_GLOBAL, SPEC_FAIL_OUT_OF_RANGE); goto fail; } + PyDict_Watch(MODULE_WATCHER_ID, globals); #ifdef Py_GIL_DISABLED maybe_enable_deferred_ref_count(value); #endif @@ -1405,11 +1406,15 @@ specialize_load_global_lock_held( SPECIALIZATION_FAIL(LOAD_GLOBAL, SPEC_FAIL_LOAD_GLOBAL_NON_STRING_OR_SPLIT); goto fail; } - index = _PyDictKeys_StringLookup(builtin_keys, name); + index = _PyDict_LookupIndexAndValue((PyDictObject *)builtins, name, &value); if (index == DKIX_ERROR) { SPECIALIZATION_FAIL(LOAD_GLOBAL, SPEC_FAIL_EXPECTED_ERROR); goto fail; } + if (value != NULL && PyLazyImport_CheckExact(value)) { + SPECIALIZATION_FAIL(LOAD_GLOBAL, SPEC_FAIL_ATTR_MODULE_LAZY_VALUE); + goto fail; + } if (index != (uint16_t)index) { SPECIALIZATION_FAIL(LOAD_GLOBAL, SPEC_FAIL_OUT_OF_RANGE); goto fail; @@ -1424,6 +1429,7 @@ specialize_load_global_lock_held( SPECIALIZATION_FAIL(LOAD_GLOBAL, SPEC_FAIL_OUT_OF_RANGE); goto fail; } + PyDict_Watch(MODULE_WATCHER_ID, globals); uint32_t builtins_version = _PyDict_GetKeysVersionForCurrentState( interp, (PyDictObject*) builtins); if (builtins_version == 0) { @@ -1434,6 +1440,7 @@ specialize_load_global_lock_held( SPECIALIZATION_FAIL(LOAD_GLOBAL, SPEC_FAIL_OUT_OF_RANGE); goto fail; } + PyDict_Watch(MODULE_WATCHER_ID, builtins); cache->index = (uint16_t)index; cache->module_keys_version = (uint16_t)globals_version; cache->builtin_keys_version = (uint16_t)builtins_version; From 9a45ab1d654fd2c91f79c1f6bc8caa3b12c28d2b Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 29 Jun 2026 02:56:40 +0200 Subject: [PATCH 486/818] [3.15] gh-151416: fix a borrowed ref potential use after free via fspath in os.spawnv/spawnve (GH-151417) (#152535) gh-151416: fix a borrowed ref potential use after free via fspath in os.spawnv/spawnve (GH-151417) * gh-151416: Fix use-after-free in os.spawnv/spawnve when __fspath__ mutates argv The argv conversion loops passed references borrowed from the argv list into fsconvert_strdup(). An item's __fspath__() can mutate the list and release its reference to the item, leaving the converter operating on a freed object. A shrunk list could also make PyList_GetItem() return NULL, which PyUnicode_FS{Converter,Decoder}() treat as a request to release an uninitialized output variable. Hold a strong reference to each item across the conversion, matching parse_arglist() and parse_envlist(). * gh-151416: Don't mask non-TypeError argv conversion errors in os.spawnv os.spawnv() replaced any error raised during argv item conversion, such as MemoryError, codec errors, or the embedded-null ValueError, with a generic TypeError. Only add the contextual message when the conversion actually raised TypeError, matching how os.spawnve() and the exec functions propagate these errors. The test is gated to the native C spawnv: the Python fallback used elsewhere reports conversion failures from the forked child as exit status 127 instead of raising. (cherry picked from commit f57d3d6db39ea0bd39743f1a614b46cbefbfdab6) Co-authored-by: Gregory P. Smith <68491+gpshead@users.noreply.github.com> --- Lib/test/test_os/test_os.py | 28 +++++++++++ ...06-12-00-00-00.gh-issue-151416.spawnUA.rst | 5 ++ Modules/posixmodule.c | 46 +++++++++++++------ 3 files changed, 65 insertions(+), 14 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-06-12-00-00-00.gh-issue-151416.spawnUA.rst diff --git a/Lib/test/test_os/test_os.py b/Lib/test/test_os/test_os.py index fef4f495fa5679..930a06963ac058 100644 --- a/Lib/test/test_os/test_os.py +++ b/Lib/test/test_os/test_os.py @@ -86,6 +86,15 @@ def requires_os_func(name): return unittest.skipUnless(hasattr(os, name), 'requires os.%s' % name) +# On platforms without a native spawnv(), os.py provides a Python fallback +# built on fork()+exec*() that reports argument conversion failures from the +# child as exit status 127 instead of raising, so tests of the C +# implementation's error paths cannot run against it. +requires_native_spawnv = unittest.skipUnless( + isinstance(getattr(os, 'spawnv', None), types.BuiltinFunctionType), + 'requires the native C os.spawnv') + + # bpo-41625: On AIX, splice() only works with a socket, not with a pipe. requires_splice_pipe = unittest.skipIf(sys.platform.startswith("aix"), 'on AIX, splice() only accepts sockets') @@ -3498,6 +3507,25 @@ def test_spawnve_noargs(self): self.assertRaises(ValueError, os.spawnve, os.P_NOWAIT, program, ('',), {}) self.assertRaises(ValueError, os.spawnve, os.P_NOWAIT, program, [''], {}) + @requires_native_spawnv + def test_spawnv_arg_conversion_errors(self): + # A non-path argv item gets a TypeError naming the argument... + with self.assertRaisesRegex(TypeError, 'must contain only strings'): + os.spawnv(os.P_NOWAIT, sys.executable, [sys.executable, 123]) + # ...but other conversion errors must not be masked as TypeError + # (gh-151416). + with self.assertRaises(ValueError): + os.spawnv(os.P_NOWAIT, sys.executable, + [sys.executable, 'embedded\0null']) + + class RaisingPath: + def __fspath__(self): + raise RuntimeError('gotcha') + + with self.assertRaisesRegex(RuntimeError, 'gotcha'): + os.spawnv(os.P_NOWAIT, sys.executable, + [sys.executable, RaisingPath()]) + def _test_invalid_env(self, spawn): program = sys.executable args = self.quote_args([program, '-c', 'pass']) diff --git a/Misc/NEWS.d/next/Library/2026-06-12-00-00-00.gh-issue-151416.spawnUA.rst b/Misc/NEWS.d/next/Library/2026-06-12-00-00-00.gh-issue-151416.spawnUA.rst new file mode 100644 index 00000000000000..fd034d9885a830 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-12-00-00-00.gh-issue-151416.spawnUA.rst @@ -0,0 +1,5 @@ +Fix a crash in :func:`os.spawnv` and :func:`os.spawnve` when an *argv* +item's :meth:`~os.PathLike.__fspath__` method mutates the *argv* list +during argument conversion. :func:`!os.spawnv` argument conversion errors +other than :exc:`TypeError`, such as the :exc:`ValueError` for an embedded +null, are no longer replaced with a generic :exc:`TypeError`. diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index ce8b6d3ff4c689..27ee07389f125f 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -8195,18 +8195,15 @@ os_spawnv_impl(PyObject *module, int mode, path_t *path, PyObject *argv) int i; Py_ssize_t argc; intptr_t spawnval; - PyObject *(*getitem)(PyObject *, Py_ssize_t); /* spawnv has three arguments: (mode, path, argv), where argv is a list or tuple of strings. */ if (PyList_Check(argv)) { argc = PyList_Size(argv); - getitem = PyList_GetItem; } else if (PyTuple_Check(argv)) { argc = PyTuple_Size(argv); - getitem = PyTuple_GetItem; } else { PyErr_SetString(PyExc_TypeError, @@ -8224,14 +8221,29 @@ os_spawnv_impl(PyObject *module, int mode, path_t *path, PyObject *argv) return PyErr_NoMemory(); } for (i = 0; i < argc; i++) { - if (!fsconvert_strdup((*getitem)(argv, i), - &argvlist[i])) { + // The item must be a strong reference because of possible + // side-effects of PyUnicode_FS{Converter,Decoder}() in + // fsconvert_strdup(): an item's __fspath__() can mutate a list + // *argv*, releasing the list's reference to the item (gh-151416). + PyObject *item = PySequence_ITEM(argv, i); + if (item == NULL) { free_string_array(argvlist, i); - PyErr_SetString( - PyExc_TypeError, - "spawnv() arg 2 must contain only strings"); return NULL; } + if (!fsconvert_strdup(item, &argvlist[i])) { + Py_DECREF(item); + free_string_array(argvlist, i); + // Add argument context to the converter's terse TypeError, but + // let MemoryError, codec errors, embedded-null ValueError, etc. + // propagate unmasked. + if (PyErr_ExceptionMatches(PyExc_TypeError)) { + PyErr_SetString( + PyExc_TypeError, + "spawnv() arg 2 must contain only strings"); + } + return NULL; + } + Py_DECREF(item); if (i == 0 && !argvlist[0][0]) { free_string_array(argvlist, i + 1); PyErr_SetString( @@ -8302,7 +8314,6 @@ os_spawnve_impl(PyObject *module, int mode, path_t *path, PyObject *argv, PyObject *res = NULL; Py_ssize_t argc, i, envc; intptr_t spawnval; - PyObject *(*getitem)(PyObject *, Py_ssize_t); Py_ssize_t lastarg = 0; /* spawnve has four arguments: (mode, path, argv, env), where @@ -8311,11 +8322,9 @@ os_spawnve_impl(PyObject *module, int mode, path_t *path, PyObject *argv, if (PyList_Check(argv)) { argc = PyList_Size(argv); - getitem = PyList_GetItem; } else if (PyTuple_Check(argv)) { argc = PyTuple_Size(argv); - getitem = PyTuple_GetItem; } else { PyErr_SetString(PyExc_TypeError, @@ -8339,12 +8348,21 @@ os_spawnve_impl(PyObject *module, int mode, path_t *path, PyObject *argv, goto fail_0; } for (i = 0; i < argc; i++) { - if (!fsconvert_strdup((*getitem)(argv, i), - &argvlist[i])) - { + // The item must be a strong reference because of possible + // side-effects of PyUnicode_FS{Converter,Decoder}() in + // fsconvert_strdup(): an item's __fspath__() can mutate a list + // *argv*, releasing the list's reference to the item (gh-151416). + PyObject *item = PySequence_ITEM(argv, i); + if (item == NULL) { lastarg = i; goto fail_1; } + if (!fsconvert_strdup(item, &argvlist[i])) { + Py_DECREF(item); + lastarg = i; + goto fail_1; + } + Py_DECREF(item); if (i == 0 && !argvlist[0][0]) { lastarg = i + 1; PyErr_SetString( From 404113bd37625215d03545e51f8caa9fb7f1eea8 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 29 Jun 2026 04:34:20 +0200 Subject: [PATCH 487/818] [3.15] gh-148660: Fix use-after-free in OrderedDict.copy() on reentrant mutation (GH-151573) (#152540) gh-148660: Fix use-after-free in OrderedDict.copy() on reentrant mutation (GH-151573) * gh-148660: Fix use-after-free in OrderedDict.copy() on reentrant mutation OrderedDict.copy() walks the internal linked list while building the new dict. The loop body can run arbitrary Python (a key's __eq__/__hash__, or a subclass __getitem__/__setitem__) which can clear the source dict and free the nodes being iterated. Detect this the same way OrderedDict.__eq__ already does (gh-119004): snapshot od_state before the loop, hold a strong reference to the key and read the hash before any reentrant call, and raise RuntimeError if the state changed before advancing to the next node. * gh-148660: fix NEWS nit, suppress undocumented OrderedDict.copy xref (cherry picked from commit 7d128e319f3730e776a9161a4b5e9de95c802eaf) Co-authored-by: Gregory P. Smith <68491+gpshead@users.noreply.github.com> --- Lib/test/test_ordered_dict.py | 33 +++++++++++++++++ ...-06-17-00-00-00.gh-issue-148660.odcopy.rst | 3 ++ Objects/odictobject.c | 36 +++++++++++++------ 3 files changed, 62 insertions(+), 10 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-06-17-00-00-00.gh-issue-148660.odcopy.rst diff --git a/Lib/test/test_ordered_dict.py b/Lib/test/test_ordered_dict.py index 642c2722711c7c..84bb3fdfbaaa6e 100644 --- a/Lib/test/test_ordered_dict.py +++ b/Lib/test/test_ordered_dict.py @@ -879,6 +879,39 @@ def side_effect(self): self.assertDictEqual(dict1, dict.fromkeys((0, 4.2))) self.assertDictEqual(dict2, dict.fromkeys((0, Key(), 4.2))) + def test_issue148660_copy_clear_in_key_eq(self): + # gh-148660: od.copy() must not crash when a key's __eq__ clears od + # while copy() is inserting into the new dict. + armed = False + calls = 0 + class Key: + def __hash__(self): + return 1 + def __eq__(self, other): + nonlocal calls + if armed: + calls += 1 + if calls == 2: + od.clear() + return self is other + od = self.OrderedDict() + od[Key()] = "v1" + od[Key()] = "v2" + armed = True + msg = "OrderedDict mutated during iteration" + self.assertRaisesRegex(RuntimeError, msg, od.copy) + + def test_issue148660_copy_clear_in_subclass_getitem(self): + # gh-148660: od.copy() must not crash when a subclass __getitem__ + # clears od. + class OD(self.OrderedDict): + def __getitem__(self, key): + od.clear() + return "v" + od = OD([(1, "v1"), (2, "v2")]) + msg = "OrderedDict mutated during iteration" + self.assertRaisesRegex(RuntimeError, msg, od.copy) + @unittest.skipUnless(c_coll, 'requires the C version of the collections module') class CPythonOrderedDictTests(OrderedDictTests, diff --git a/Misc/NEWS.d/next/Library/2026-06-17-00-00-00.gh-issue-148660.odcopy.rst b/Misc/NEWS.d/next/Library/2026-06-17-00-00-00.gh-issue-148660.odcopy.rst new file mode 100644 index 00000000000000..30c2e366ca2ba0 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-17-00-00-00.gh-issue-148660.odcopy.rst @@ -0,0 +1,3 @@ +Fix a crash in :meth:`!collections.OrderedDict.copy` when a key's +``__eq__`` or a subclass method mutates the dict during the copy. Now +raises :exc:`RuntimeError` instead, as iteration does. diff --git a/Objects/odictobject.c b/Objects/odictobject.c index 6f05395b18d781..33914cdffb1dcc 100644 --- a/Objects/odictobject.c +++ b/Objects/odictobject.c @@ -1251,36 +1251,52 @@ OrderedDict_copy_impl(PyObject *od) if (od_copy == NULL) return NULL; + /* The loop body may run arbitrary Python code which could mutate od and + free its nodes (gh-148660); detect that the same way __eq__ does. */ + size_t state = _PyODictObject_CAST(od)->od_state; + if (PyODict_CheckExact(od)) { _odict_FOREACH(od, node) { - PyObject *key = _odictnode_KEY(node); - PyObject *value = _odictnode_VALUE(node, od); + PyObject *key = Py_NewRef(_odictnode_KEY(node)); + Py_hash_t hash = _odictnode_HASH(node); + PyObject *value = PyODict_GetItemWithError(od, key); if (value == NULL) { if (!PyErr_Occurred()) PyErr_SetObject(PyExc_KeyError, key); + Py_DECREF(key); goto fail; } - if (_PyODict_SetItem_KnownHash_LockHeld((PyObject *)od_copy, key, value, - _odictnode_HASH(node)) != 0) + int res = _PyODict_SetItem_KnownHash_LockHeld((PyObject *)od_copy, + key, value, hash); + Py_DECREF(key); + if (res != 0) goto fail; + if (_PyODictObject_CAST(od)->od_state != state) + goto mutated; } } else { _odict_FOREACH(od, node) { - int res; - PyObject *value = PyObject_GetItem((PyObject *)od, - _odictnode_KEY(node)); - if (value == NULL) + PyObject *key = Py_NewRef(_odictnode_KEY(node)); + PyObject *value = PyObject_GetItem(od, key); + if (value == NULL) { + Py_DECREF(key); goto fail; - res = PyObject_SetItem((PyObject *)od_copy, - _odictnode_KEY(node), value); + } + int res = PyObject_SetItem((PyObject *)od_copy, key, value); Py_DECREF(value); + Py_DECREF(key); if (res != 0) goto fail; + if (_PyODictObject_CAST(od)->od_state != state) + goto mutated; } } return od_copy; +mutated: + PyErr_SetString(PyExc_RuntimeError, + "OrderedDict mutated during iteration"); fail: Py_DECREF(od_copy); return NULL; From 4f140148c45214dd43ebcd6546ed5799521b536b Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 29 Jun 2026 08:38:47 +0200 Subject: [PATCH 488/818] [3.15] gh-87577: Document that wm_manage does not accept ttk widgets (GH-152532) (GH-152543) wm_manage() works only with the classic tkinter Frame, LabelFrame and Toplevel widgets, not their tkinter.ttk counterparts. (cherry picked from commit 2670cb062c9ec31cd6df7be645f929a8398601c7) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --- Doc/library/tkinter.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Doc/library/tkinter.rst b/Doc/library/tkinter.rst index 682d507c2d2d88..dfade1345ca901 100644 --- a/Doc/library/tkinter.rst +++ b/Doc/library/tkinter.rst @@ -2620,7 +2620,8 @@ Base and mixin classes Make *widget* a stand-alone top-level window, decorated by the window manager with a title bar and so on. Only :class:`Frame`, :class:`LabelFrame` and :class:`Toplevel` widgets - may be used; passing any other widget type raises an error. + may be used (the :mod:`tkinter.ttk` versions are **not** accepted); + passing any other widget type raises an error. :meth:`wm_manage` is an alias of :meth:`!manage`. .. versionadded:: 3.3 From af665032a599d84edf87457435059393ec38779a Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 29 Jun 2026 10:39:32 +0200 Subject: [PATCH 489/818] [3.15] gh-110357: hashlib no longer logs at import when a guaranteed hash is unavailable (GH-152538) (#152554) gh-110357: hashlib no longer logs at import when a guaranteed hash is unavailable (GH-152538) When a normally-guaranteed hash algorithm cannot be constructed at import time (e.g. an OpenSSL FIPS configuration excludes it from the default provider, or the build used --without-builtin-hashlib-hashes), importing hashlib emitted an "ERROR:root:hash algorithm ... will not be supported at runtime" message to stderr. For the many programs that never use the missing algorithm this is pure noise. Worse, logging.error() lazily calls logging.basicConfig(), which mutates the root logger's handlers -- a global side effect that the test suite flags as an altered execution environment. Stop logging in that path. Code that actually uses a missing algorithm still gets a clear ValueError from the stub constructor installed in its place. The stray output has shown up incidentally in FIPS / "No Builtin Hashes" buildbot reports for years (e.g. gh-110357, gh-76902) without being the reported subject. (cherry picked from commit 8ae1a236fd334a590e90028f615cd4a822ae6f97) Co-authored-by: Gregory P. Smith <68491+gpshead@users.noreply.github.com> --- Doc/library/hashlib.rst | 15 +++++++++------ Lib/hashlib.py | 12 +++++------- ...2026-06-29-01-08-53.gh-issue-110357.QGWdZQ.rst | 6 ++++++ 3 files changed, 20 insertions(+), 13 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-06-29-01-08-53.gh-issue-110357.QGWdZQ.rst diff --git a/Doc/library/hashlib.rst b/Doc/library/hashlib.rst index ed0b0b2735b5c3..5b666c5adac645 100644 --- a/Doc/library/hashlib.rst +++ b/Doc/library/hashlib.rst @@ -50,12 +50,15 @@ hash supplied more than 2047 bytes of data at once in its constructor or .. index:: single: OpenSSL; (use in module hashlib) Constructors for hash algorithms that are always present in this module are -:func:`sha1`, :func:`sha224`, :func:`sha256`, :func:`sha384`, :func:`sha512`, -:func:`sha3_224`, :func:`sha3_256`, :func:`sha3_384`, :func:`sha3_512`, -:func:`shake_128`, :func:`shake_256`, :func:`blake2b`, and :func:`blake2s`. -:func:`md5` is normally available as well, though it may be missing or blocked -if you are using a rare "FIPS compliant" build of Python. -These correspond to :data:`algorithms_guaranteed`. +:func:`md5`, :func:`sha1`, :func:`sha224`, :func:`sha256`, :func:`sha384`, +:func:`sha512`, :func:`sha3_224`, :func:`sha3_256`, :func:`sha3_384`, +:func:`sha3_512`, :func:`shake_128`, :func:`shake_256`, :func:`blake2b`, and +:func:`blake2s`. These correspond to :data:`algorithms_guaranteed`. + +Any of these may nonetheless be missing or blocked in unusual environments, +such as a rare "FIPS compliant" build of Python or when OpenSSL's "FIPS mode" +is configured to exclude some algorithms from its default provider. Calling +the constructor of an algorithm that is unavailable raises :exc:`ValueError`. Additional algorithms may also be available if your Python distribution's :mod:`!hashlib` was linked against a build of OpenSSL that provides others. diff --git a/Lib/hashlib.py b/Lib/hashlib.py index 6c73eb9f31f8e4..c1e2d07c4357ff 100644 --- a/Lib/hashlib.py +++ b/Lib/hashlib.py @@ -261,16 +261,15 @@ def file_digest(fileobj, digest, /, *, _bufsize=2**18): return digestobj -__logging = None for __func_name in __always_supported: # try them all, some may not work due to the OpenSSL # version not supporting that algorithm. try: globals()[__func_name] = __get_hash(__func_name) - except ValueError as __exc: - import logging as __logging - __logging.error('hash algorithm %s will not be supported at runtime ' - '[reason: %s]', __func_name, __exc) + except ValueError: + # Don't log here: logging at import time has global side effects and + # would tell the wrong audience; code that uses a missing algorithm + # gets a ValueError from the stub installed below. # The following code can be simplified in Python 3.19 # once "string" is removed from the signature. __code = f'''\ @@ -291,9 +290,8 @@ def {__func_name}(data=__UNSET, *, usedforsecurity=True, string=__UNSET): ''' exec(__code, {"__UNSET": object()}, __locals := {}) globals()[__func_name] = __locals[__func_name] - del __exc, __code, __locals + del __code, __locals # Cleanup locals() del __always_supported, __func_name, __get_hash del __py_new, __hash_new, __get_openssl_constructor -del __logging diff --git a/Misc/NEWS.d/next/Library/2026-06-29-01-08-53.gh-issue-110357.QGWdZQ.rst b/Misc/NEWS.d/next/Library/2026-06-29-01-08-53.gh-issue-110357.QGWdZQ.rst new file mode 100644 index 00000000000000..7c2384ea76fe53 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-29-01-08-53.gh-issue-110357.QGWdZQ.rst @@ -0,0 +1,6 @@ +Importing :mod:`hashlib` no longer logs an error to stderr when a normally +guaranteed hash algorithm is unavailable in the current runtime (for example +under an OpenSSL FIPS configuration or a build using +:option:`--without-builtin-hashlib-hashes <--with-builtin-hashlib-hashes>`). +Code that actually uses the missing algorithm still gets a clear +:exc:`ValueError`. From ac30e9bc7d70b249e4e1190c022d5cddc728bb5f Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 29 Jun 2026 10:44:24 +0200 Subject: [PATCH 490/818] [3.15] gh-85320: Use UTF-8 for IDLE configuration and breakpoint files (GH-152475) (GH-152555) They were read and written using the locale encoding, which could corrupt non-ASCII paths and made them non-portable. (cherry picked from commit f6e904e1a666cb1e5664750b1c3d8f89cba3a769) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --- Lib/idlelib/News3.txt | 5 +++++ Lib/idlelib/config.py | 9 +++++---- Lib/idlelib/pyshell.py | 8 +++++--- .../IDLE/2026-06-28-06-46-46.gh-issue-85320.Hq2vKn.rst | 4 ++++ 4 files changed, 19 insertions(+), 7 deletions(-) create mode 100644 Misc/NEWS.d/next/IDLE/2026-06-28-06-46-46.gh-issue-85320.Hq2vKn.rst diff --git a/Lib/idlelib/News3.txt b/Lib/idlelib/News3.txt index 0f61da8368f211..97becb858fea33 100644 --- a/Lib/idlelib/News3.txt +++ b/Lib/idlelib/News3.txt @@ -4,6 +4,11 @@ Released on 2026-10-01 ========================= +gh-85320: IDLE now reads and writes its configuration files and the +breakpoints file using UTF-8 instead of the locale encoding. +Files with non-ASCII characters and non-UTF-8 encoding may need +to be opened in an editor and resaved with UTF-8 encoding. + gh-143774: Better explain the operation of Format / Format Paragraph. Patch by Terry J. Reedy. diff --git a/Lib/idlelib/config.py b/Lib/idlelib/config.py index 1cabe479450015..82afd6c49269d2 100644 --- a/Lib/idlelib/config.py +++ b/Lib/idlelib/config.py @@ -73,8 +73,9 @@ def GetOptionList(self, section): def Load(self): "Load the configuration file from disk." - if self.file: - self.read(self.file) + if self.file and os.path.exists(self.file): + with open(self.file, encoding='utf-8', errors='replace') as f: + self.read_file(f) class IdleUserConfParser(IdleConfParser): """ @@ -133,10 +134,10 @@ def Save(self): if fname and fname[0] != '#': if not self.IsEmpty(): try: - cfgFile = open(fname, 'w') + cfgFile = open(fname, 'w', encoding='utf-8') except OSError: os.unlink(fname) - cfgFile = open(fname, 'w') + cfgFile = open(fname, 'w', encoding='utf-8') with cfgFile: self.write(cfgFile) elif os.path.exists(self.file): diff --git a/Lib/idlelib/pyshell.py b/Lib/idlelib/pyshell.py index b80c8e56c92810..b1662491935e4a 100755 --- a/Lib/idlelib/pyshell.py +++ b/Lib/idlelib/pyshell.py @@ -242,12 +242,13 @@ def store_file_breaks(self): breaks = self.breakpoints filename = self.io.filename try: - with open(self.breakpointPath) as fp: + with open(self.breakpointPath, + encoding='utf-8', errors='replace') as fp: lines = fp.readlines() except OSError: lines = [] try: - with open(self.breakpointPath, "w") as new_file: + with open(self.breakpointPath, "w", encoding='utf-8') as new_file: for line in lines: if not line.startswith(filename + '='): new_file.write(line) @@ -272,7 +273,8 @@ def restore_file_breaks(self): if filename is None: return if os.path.isfile(self.breakpointPath): - with open(self.breakpointPath) as fp: + with open(self.breakpointPath, + encoding='utf-8', errors='replace') as fp: lines = fp.readlines() for line in lines: if line.startswith(filename + '='): diff --git a/Misc/NEWS.d/next/IDLE/2026-06-28-06-46-46.gh-issue-85320.Hq2vKn.rst b/Misc/NEWS.d/next/IDLE/2026-06-28-06-46-46.gh-issue-85320.Hq2vKn.rst new file mode 100644 index 00000000000000..ec34bf8ead9eb9 --- /dev/null +++ b/Misc/NEWS.d/next/IDLE/2026-06-28-06-46-46.gh-issue-85320.Hq2vKn.rst @@ -0,0 +1,4 @@ +IDLE now reads and writes its configuration files and the breakpoints file +using UTF-8 instead of the locale encoding. This keeps non-ASCII data (such +as non-ASCII paths) from being corrupted and makes the files portable between +environments. From d97d52cfb587213322026069ea27b91b41ba0efe Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 29 Jun 2026 11:13:05 +0200 Subject: [PATCH 491/818] [3.15] gh-140146: Fix for stdin redirection to a pipe with interactive tkinter on Windows (GH-148819) (GH-152560) (cherry picked from commit 6d209cbb93d0871ad4a5883637a8f0aebc053f76) Co-authored-by: mdehoon <mjldehoon@yahoo.com> --- Lib/test/test_tkinter/test_tkinter_pipe.py | 55 +++++++++++++++++++ ...-04-21-16-07-11.gh-issue-140146.TAcUHA.rst | 3 + Modules/_tkinter.c | 32 ++++++++--- 3 files changed, 83 insertions(+), 7 deletions(-) create mode 100644 Lib/test/test_tkinter/test_tkinter_pipe.py create mode 100644 Misc/NEWS.d/next/Windows/2026-04-21-16-07-11.gh-issue-140146.TAcUHA.rst diff --git a/Lib/test/test_tkinter/test_tkinter_pipe.py b/Lib/test/test_tkinter/test_tkinter_pipe.py new file mode 100644 index 00000000000000..775d0ff5e19b0c --- /dev/null +++ b/Lib/test/test_tkinter/test_tkinter_pipe.py @@ -0,0 +1,55 @@ +# test_tkinter_pipe.py +import unittest +import subprocess +import sys +from test import support + + +@unittest.skipUnless(support.has_subprocess_support, "test requires subprocess") +class TkinterPipeTest(unittest.TestCase): + + def test_tkinter_pipe_buffered(self): + args = [sys.executable, "-i"] + proc = subprocess.Popen(args, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + proc.stdin.write(b"import tkinter\n") + proc.stdin.write(b"interpreter = tkinter.Tcl()\n") + proc.stdin.write(b"print('hello')\n") + proc.stdin.write(b"print('goodbye')\n") + proc.stdin.write(b"quit()\n") + stdout, stderr = proc.communicate(timeout=support.SHORT_TIMEOUT) + stdout = stdout.decode() + self.assertEqual(stdout.split(), ['hello', 'goodbye']) + + def test_tkinter_pipe_unbuffered(self): + args = [sys.executable, "-i", "-u"] + proc = subprocess.Popen(args, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + proc.stdin.write(b"import tkinter\n") + proc.stdin.write(b"interpreter = tkinter.Tcl()\n") + + proc.stdin.write(b"print('hello')\n") + proc.stdin.flush() + stdout = proc.stdout.readline() + stdout = stdout.decode() + self.assertEqual(stdout.strip(), 'hello') + + proc.stdin.write(b"print('hello again')\n") + proc.stdin.flush() + stdout = proc.stdout.readline() + stdout = stdout.decode() + self.assertEqual(stdout.strip(), 'hello again') + + proc.stdin.write(b"print('goodbye')\n") + proc.stdin.write(b"quit()\n") + stdout, stderr = proc.communicate(timeout=support.SHORT_TIMEOUT) + stdout = stdout.decode() + self.assertEqual(stdout.strip(), 'goodbye') + + +if __name__ == "__main__": + unittest.main() diff --git a/Misc/NEWS.d/next/Windows/2026-04-21-16-07-11.gh-issue-140146.TAcUHA.rst b/Misc/NEWS.d/next/Windows/2026-04-21-16-07-11.gh-issue-140146.TAcUHA.rst new file mode 100644 index 00000000000000..2d3e42c86fd521 --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2026-04-21-16-07-11.gh-issue-140146.TAcUHA.rst @@ -0,0 +1,3 @@ +Prevent :mod:`tkinter` from hanging on Windows if stdin is redirected to a pipe in an +interactive session. This is helpful for testing interactive usage of +tkinter from a script, for example as part of the cpython test suite. diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c index 8fa58d07096e30..7361fd04e21671 100644 --- a/Modules/_tkinter.c +++ b/Modules/_tkinter.c @@ -3429,10 +3429,10 @@ static PyMethodDef moduleMethods[] = }; #ifdef WAIT_FOR_STDIN +#ifndef MS_WINDOWS static int stdin_ready = 0; -#ifndef MS_WINDOWS static void MyFileProc(void *clientData, int mask) { @@ -3451,22 +3451,40 @@ static PyThreadState *event_tstate = NULL; static int EventHook(void) { -#ifndef MS_WINDOWS +#ifdef MS_WINDOWS + HANDLE hStdin; + DWORD type; +#else int tfile; + stdin_ready = 0; #endif PyEval_RestoreThread(event_tstate); - stdin_ready = 0; errorInCmd = 0; -#ifndef MS_WINDOWS +#ifdef MS_WINDOWS + hStdin = GetStdHandle(STD_INPUT_HANDLE); + type = GetFileType(hStdin); + while (1) { +#else tfile = fileno(stdin); Tcl_CreateFileHandler(tfile, TCL_READABLE, MyFileProc, (void *)(Py_intptr_t)tfile); -#endif while (!stdin_ready) { +#endif int result; #ifdef MS_WINDOWS - if (_kbhit()) { - stdin_ready = 1; + if (type == FILE_TYPE_CHAR) { + if (_kbhit()) break; + } + else if (type == FILE_TYPE_PIPE) { + DWORD available; + if (PeekNamedPipe(hStdin, NULL, 0, NULL, &available, NULL)) { + if (available > 0) break; + } + else { + if (GetLastError() == ERROR_BROKEN_PIPE) break; + } + } + else if (type == FILE_TYPE_DISK) { break; } #endif From 2b92f57cac456a8c28fe4a0711eb74887395cac3 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 29 Jun 2026 11:23:25 +0200 Subject: [PATCH 492/818] [3.15] GH-151672: `__lazy_import__` always resolves to the module being imported (GH-151827) (#152534) GH-151672: `__lazy_import__` always resolves to the module being imported (GH-151827) (cherry picked from commit 2d0003c0b28dca86197f4b74810966856a27dc60) Co-authored-by: Brandt Bucher <brandt@python.org> --- Lib/test/test_lazy_import/__init__.py | 25 +++++++++++++++++++ ...-06-20-10-01-26.gh-issue-151672.K-w7j0.rst | 3 +++ Python/import.c | 23 +++++++++++------ 3 files changed, 43 insertions(+), 8 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-20-10-01-26.gh-issue-151672.K-w7j0.rst diff --git a/Lib/test/test_lazy_import/__init__.py b/Lib/test/test_lazy_import/__init__.py index 2c9dd0627f697c..417eab84c1088d 100644 --- a/Lib/test/test_lazy_import/__init__.py +++ b/Lib/test/test_lazy_import/__init__.py @@ -572,6 +572,31 @@ def test_dunder_lazy_import_used(self): import test.test_lazy_import.data.dunder_lazy_import_used self.assertIn("test.test_lazy_import.data.basic2", sys.modules) + @support.requires_subprocess() + def test_dunder_lazy_import_fromlist_resolves_to_module(self): + for fromlist in ["basic2", ("basic2",)]: + with self.subTest(fromlist=fromlist): + code = textwrap.dedent(f""" + import sys + import types + + lazy = __lazy_import__("test.test_lazy_import.data", fromlist={fromlist!r}) + + def check(): + lazy_obj = globals()["lazy"] + assert type(lazy_obj) is types.LazyImportType, lazy_obj + assert "test.test_lazy_import.data.basic2" not in sys.modules + + resolved = lazy_obj.resolve() + assert type(resolved) is types.ModuleType, resolved + assert "test.test_lazy_import.data.basic2" in sys.modules + assert resolved.__name__ == "test.test_lazy_import.data" + assert resolved.basic2.x == 42 + + check() + """) + assert_python_ok("-c", code) + def test_dunder_lazy_import_invalid_arguments(self): """__lazy_import__ should reject invalid arguments.""" for invalid_name in (b"", 123, None): diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-20-10-01-26.gh-issue-151672.K-w7j0.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-20-10-01-26.gh-issue-151672.K-w7j0.rst new file mode 100644 index 00000000000000..4f4823df0b2101 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-20-10-01-26.gh-issue-151672.K-w7j0.rst @@ -0,0 +1,3 @@ +Fix an inconsistency where calling ``__lazy_import__`` with a string +``fromlist`` would return a :class:`types.LazyImportType` that resolves to +the named member, rather than the module being imported. diff --git a/Python/import.c b/Python/import.c index 63021208a23d3b..2c975295f9b5d3 100644 --- a/Python/import.c +++ b/Python/import.c @@ -4536,7 +4536,7 @@ _PyImport_LazyImportModuleLevelObject(PyThreadState *tstate, } if (fromlist == NULL) { assert(!PyErr_Occurred()); - fromlist = Py_NewRef(Py_None); + fromlist = Py_None; } PyObject *args[] = {modname, abs_name, fromlist}; PyObject *res = PyObject_Vectorcall(filter, args, 3, NULL); @@ -4565,8 +4565,19 @@ _PyImport_LazyImportModuleLevelObject(PyThreadState *tstate, } // here, 'filter' is either NULL or is equivalent to a borrowed reference + if (fromlist && PyUnicode_Check(fromlist)) { + fromlist = PyTuple_Pack(1, fromlist); + if (fromlist == NULL) { + Py_DECREF(abs_name); + return NULL; + } + } + else { + Py_XINCREF(fromlist); + } PyObject *res = _PyLazyImport_New(frame, builtins, abs_name, fromlist); if (res == NULL) { + Py_XDECREF(fromlist); Py_DECREF(abs_name); return NULL; } @@ -4577,13 +4588,7 @@ _PyImport_LazyImportModuleLevelObject(PyThreadState *tstate, goto error; } - if (fromlist && PyUnicode_Check(fromlist)) { - if (register_from_lazy_on_parent(tstate, abs_name, fromlist) < 0) { - goto error; - } - } - else if (fromlist && PyTuple_Check(fromlist) && - PyTuple_GET_SIZE(fromlist)) { + if (fromlist && PyTuple_Check(fromlist) && PyTuple_GET_SIZE(fromlist)) { for (Py_ssize_t i = 0; i < PyTuple_GET_SIZE(fromlist); i++) { if (register_from_lazy_on_parent(tstate, abs_name, PyTuple_GET_ITEM(fromlist, i)) < 0) @@ -4596,9 +4601,11 @@ _PyImport_LazyImportModuleLevelObject(PyThreadState *tstate, goto error; } + Py_XDECREF(fromlist); Py_DECREF(abs_name); return res; error: + Py_XDECREF(fromlist); Py_DECREF(abs_name); Py_DECREF(res); return NULL; From 1db0c662460152384d5d0d1e04b6c4238c35becb Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 29 Jun 2026 11:35:46 +0200 Subject: [PATCH 493/818] [3.15] gh-148909: Fix broken author attribution URL in 'The Python 2.3 Method Resolution Order' doc (GH-149092) (#152571) (cherry picked from commit 7aae0e58b7c02cefd3e13b0d1b65b4ef5cb2b57e) Co-authored-by: Ivy Xu <fakeshadow1337@gmail.com> --- Doc/howto/mro.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/howto/mro.rst b/Doc/howto/mro.rst index 0872bedcd3a2d3..72cc311e30d669 100644 --- a/Doc/howto/mro.rst +++ b/Doc/howto/mro.rst @@ -10,7 +10,7 @@ The Python 2.3 Method Resolution Order The Method Resolution Order discussed here was *introduced* in Python 2.3, but it is still used in later versions -- including Python 3. -By `Michele Simionato <https://www.phyast.pitt.edu/~micheles/>`__. +By `Michele Simionato <https://github.com/micheles>`__. :Abstract: From 00a43044d88101b44a67bdef40df14a77838bfbf Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 29 Jun 2026 11:54:27 +0200 Subject: [PATCH 494/818] [3.15] gh-152375: Fix undefined behaviour in the `INSTRUMENTED_JUMP` macro (GH-152376) (#152566) (cherry picked from commit cdec9acd63c33d9b822700de8f63eb94d86e1c93) Co-authored-by: Stan Ulbrych <stan@python.org> --- .../2026-06-27-10-05-12.gh-issue-152375.L-ZBk6.rst | 2 ++ Python/ceval_macros.h | 7 ++++--- 2 files changed, 6 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-27-10-05-12.gh-issue-152375.L-ZBk6.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-27-10-05-12.gh-issue-152375.L-ZBk6.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-27-10-05-12.gh-issue-152375.L-ZBk6.rst new file mode 100644 index 00000000000000..db6ae3060d8328 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-27-10-05-12.gh-issue-152375.L-ZBk6.rst @@ -0,0 +1,2 @@ +Fix undefined behaviour when a :mod:`sys.monitoring` callback raised an +exception while the program was following a branch or loop. diff --git a/Python/ceval_macros.h b/Python/ceval_macros.h index c61690e8bd7240..dcc4f577680dc3 100644 --- a/Python/ceval_macros.h +++ b/Python/ceval_macros.h @@ -388,14 +388,15 @@ static void dtrace_function_return(_PyInterpreterFrame *); // for an exception handler, displaying the traceback, and so on #define INSTRUMENTED_JUMP(src, dest, event) \ do { \ + _Py_CODEUNIT *_dest = (dest); \ if (tstate->tracing) {\ - next_instr = dest; \ + next_instr = _dest; \ } else { \ _PyFrame_SetStackPointer(frame, stack_pointer); \ - next_instr = _Py_call_instrumentation_jump(this_instr, tstate, event, frame, src, dest); \ + next_instr = _Py_call_instrumentation_jump(this_instr, tstate, event, frame, src, _dest); \ stack_pointer = _PyFrame_GetStackPointer(frame); \ if (next_instr == NULL) { \ - next_instr = (dest)+1; \ + next_instr = _dest + 1; \ JUMP_TO_LABEL(error); \ } \ } \ From 11c3a404a6a05157758e4128866dfef60e2b16fa Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 29 Jun 2026 12:04:11 +0200 Subject: [PATCH 495/818] [3.15] gh-71450: Document that Tcl sets the HOME variable on Windows (GH-152568) (GH-152574) Also fix the ntpath.expanduser() docstring, which no longer uses $HOME. (cherry picked from commit 1540584d5d0b6483b78256194825e76d2e52ad21) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --- Doc/library/tkinter.rst | 8 ++++++++ Lib/ntpath.py | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/Doc/library/tkinter.rst b/Doc/library/tkinter.rst index dfade1345ca901..44b3c42a936a39 100644 --- a/Doc/library/tkinter.rst +++ b/Doc/library/tkinter.rst @@ -3298,6 +3298,14 @@ Toplevel widgets profile files is the :envvar:`HOME` environment variable or, if that isn't defined, then :data:`os.curdir`. + .. note:: + + On Windows, creating a Tcl interpreter (by instantiating :class:`Tk` or + calling :func:`Tcl`) sets the :envvar:`HOME` environment variable for + the process, if it is not already set, to ``%HOMEDRIVE%%HOMEPATH%`` (or + :envvar:`USERPROFILE`, or ``c:\``). This is done by Tcl and can affect + other code that reads :envvar:`HOME`. + .. attribute:: tk The Tk application object created by instantiating :class:`Tk`. This diff --git a/Lib/ntpath.py b/Lib/ntpath.py index 811e796f7766e9..b3c23f0abc2d88 100644 --- a/Lib/ntpath.py +++ b/Lib/ntpath.py @@ -345,7 +345,7 @@ def _isreservedname(name): def expanduser(path): """Expand ~ and ~user constructs. - If user or $HOME is unknown, do nothing.""" + If user or home directory is unknown, do nothing.""" path = os.fspath(path) if isinstance(path, bytes): seps = b'\\/' From 1507ea1e8f0a0a2038d272dc57a6b03a0691c880 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 29 Jun 2026 12:04:51 +0200 Subject: [PATCH 496/818] [3.15] gh-152359: Update numbers.rst to reference numeric-hash docs (GH-152549) (#152579) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gh-152359: Update numbers.rst to reference numeric-hash docs (GH-152549) (cherry picked from commit 8ec36f14a552136d54072e3e5bb595ec1f4f0b5f) Co-authored-by: Paper Moon <tangyuan0821@email.cn> Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com> --- Doc/library/numbers.rst | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/Doc/library/numbers.rst b/Doc/library/numbers.rst index 57b35017072c97..0ed24b4e6c5225 100644 --- a/Doc/library/numbers.rst +++ b/Doc/library/numbers.rst @@ -90,20 +90,7 @@ Notes for type implementers Implementers should be careful to make equal numbers equal and hash them to the same values. This may be subtle if there are two different -extensions of the real numbers. For example, :class:`fractions.Fraction` -implements :func:`hash` as follows:: - - def __hash__(self): - if self.denominator == 1: - # Get integers right. - return hash(self.numerator) - # Expensive check, but definitely correct. - if self == float(self): - return hash(float(self)) - else: - # Use tuple's hash to avoid a high collision rate on - # simple fractions. - return hash((self.numerator, self.denominator)) +extensions of the real numbers. See also :ref:`numeric-hash`. Adding More Numeric ABCs From bbc7e9b32321c52159462ab5be0048bbe82312d6 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 29 Jun 2026 13:40:49 +0200 Subject: [PATCH 497/818] [3.15] gh-133031: Support non-ASCII characters in curses.textpad.Textbox (GH-152451) (GH-152467) Textbox mangled non-ASCII characters of an 8-bit locale encoding: it masked reads with curses.ascii.ascii(), which clears the 8th bit, and tested input with curses.ascii.isprint(), which rejects bytes above 127. Decode cells and input bytes with the window's encoding instead. Cells are read with instr() and the lower-right cell is written as text, since inch() and insch() with an int byte mishandle a non-ASCII character on a wide build. This uses only the byte-oriented curses API, so it works without wide-character support. (cherry picked from commit c253f0c14b046cf79881d0602620a3b2a15c2316) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --- Lib/curses/textpad.py | 44 ++++++++++-- Lib/test/test_curses.py | 67 +++++++++++++++++++ ...-06-27-12-30-00.gh-issue-133031.Na8Bit.rst | 3 + 3 files changed, 107 insertions(+), 7 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-06-27-12-30-00.gh-issue-133031.Na8Bit.rst diff --git a/Lib/curses/textpad.py b/Lib/curses/textpad.py index 57b2f4a523c95b..c58a7174d194cf 100644 --- a/Lib/curses/textpad.py +++ b/Lib/curses/textpad.py @@ -56,13 +56,42 @@ def _update_max_yx(self): self.maxy = maxy - 1 self.maxx = maxx - 1 + def _decode(self, ch): + # The text of a chtype cell or input byte, decoded with the window's + # encoding. A_CHARTEXT keeps the character byte, dropping the attributes. + return bytes([ch & curses.A_CHARTEXT]).decode(self.win.encoding, 'replace') + + def _char_at(self, *yx): + # The text of the cell at the given position (default: the cursor). + # instr() re-encodes it to the window's encoding; inch() cannot + # represent a non-ASCII 8-bit-locale character on a wide build. + return self.win.instr(*yx, 1).decode(self.win.encoding, 'replace') + + def _cell_at(self, *yx): + # The cell at the given position (default: the cursor) as a chtype + # addch() can write back with its rendition. inch() mangles a non-ASCII + # character on a wide build, so take the byte from instr() and the + # attributes from inch(). + return self.win.instr(*yx, 1)[0] | self.win.inch(*yx) & curses.A_ATTRIBUTES + + def _isprint(self, cell): + # Whether a chtype cell holds a printable character; _decode() drops the + # attribute bits. + return self._decode(cell).isprintable() + + def _printable_key(self, ch): + # Whether the integer keystroke is a printable character, not a key + # code. 0..255 are character bytes (decoded with the window's encoding); + # larger values are function and navigation keys. + return ch <= 0xff and self._decode(ch).isprintable() + def _end_of_line(self, y): """Go to the location of the first blank on the given line, returning the index of the last non-blank character.""" self._update_max_yx() last = self.maxx while True: - if curses.ascii.ascii(self.win.inch(y, last)) != curses.ascii.SP: + if self._char_at(y, last) != ' ': last = min(self.maxx, last+1) break elif last == 0: @@ -76,15 +105,16 @@ def _insert_printable_char(self, ch): backyx = None while True: if self.insert_mode: - oldch = self.win.inch() + oldch = self._cell_at() if y >= self.maxy and x >= self.maxx: # Use insch() in the lower-right cell: addch() there would move # the cursor out of the window, raising an error and scrolling - # a scrollable window. - self.win.insch(ch) + # a scrollable window. Pass it as text: insch() does not decode + # an int byte through the locale on a wide build. + self.win.insch(self._decode(ch), ch & curses.A_ATTRIBUTES) break self.win.addch(ch) - if not self.insert_mode or not curses.ascii.isprint(oldch): + if not self.insert_mode or not self._isprint(oldch): break ch = oldch (y, x) = self.win.getyx() @@ -100,7 +130,7 @@ def do_command(self, ch): self._update_max_yx() (y, x) = self.win.getyx() self.lastcmd = ch - if curses.ascii.isprint(ch): + if self._printable_key(ch): self._insert_printable_char(ch) elif ch == curses.ascii.SOH: # ^a self.win.move(y, 0) @@ -174,7 +204,7 @@ def gather(self): for x in range(self.maxx+1): if self.stripspaces and x > stop: break - result = result + chr(curses.ascii.ascii(self.win.inch(y, x))) + result = result + self._char_at(y, x) if self.maxy > 0: result = result + "\n" return result diff --git a/Lib/test/test_curses.py b/Lib/test/test_curses.py index 15511c2fe6d039..737735fbcc0032 100644 --- a/Lib/test/test_curses.py +++ b/Lib/test/test_curses.py @@ -1534,6 +1534,68 @@ def test_textbox_fill_last_cell_scrollok(self): self._type(box, 'def') self.assertEqual(box.gather(), 'abc\ndef\n') + def test_textbox_8bit(self): + # A character of an 8-bit locale encoding is entered and read back + # through the byte API. The byte path also runs on a wide build, so the + # test is not skipped there. Run the suite under an 8-bit locale + # (ISO-8859-1, ISO-8859-15 or KOI8-U) to reach the non-ASCII cases; each + # string is used only if the encoding maps it to single bytes. 'abc' is + # ASCII, 'café' is common to the Latin encodings, and the rest are + # distinctive (byte 0xA4 is '¤'/'€'/'є' in ISO-8859-1/-15/KOI8-U). + encoding = self.stdscr.encoding + for text in ['abc', 'café', 'naïve ¤¦', 'café €Šž', 'дякую єі']: + try: + data = text.encode(encoding) + except UnicodeEncodeError: + continue + if len(data) != len(text): + continue # a multibyte encoding is not the 8-bit byte path + with self.subTest(text=text): + box, win = self._make_textbox(1, 16) + for byte in data: + box.do_command(byte) + self.assertEqual(box.gather(), text + ' ') + + def test_textbox_8bit_insert(self): + # Insert mode shifts the rest of the line right by reading each cell back + # and rewriting it; a non-ASCII 8-bit-locale character must survive the + # shift, even on a wide build where inch() mangles it. See + # test_textbox_8bit for the character choices. + encoding = self.stdscr.encoding + for ch in ['é', '¤', '€', 'є']: + try: + data = ch.encode(encoding) + except UnicodeEncodeError: + continue + if len(data) != 1: + continue + with self.subTest(ch=ch): + box, win = self._make_textbox(1, 10, insert_mode=True) + for byte in ('a' + ch + 'c').encode(encoding): + box.do_command(byte) + win.move(0, 1) + box.do_command(ord('b')) # insert 'b', shifting ch and 'c' right + self.assertEqual(box.gather(), 'ab' + ch + 'c ') + + def test_textbox_8bit_fill_last_cell(self): + # A non-ASCII 8-bit-locale character must survive being written to the + # lower-right cell, which uses insch() rather than addch(). See + # test_textbox_8bit for the character choices. + encoding = self.stdscr.encoding + for ch in ['é', '¤', '€', 'є']: + try: + data = ch.encode(encoding) + except UnicodeEncodeError: + continue + if len(data) != 1: + continue + with self.subTest(ch=ch): + text = 'ab' + ch # the last character fills the corner + box, win = self._make_textbox(1, len(text), stripspaces=0) + for byte in text.encode(encoding): + box.do_command(byte) + self.assertEqual(box.gather(), text) + def test_textbox_movement(self): box, win = self._make_textbox(3, 10) self._type(box, 'abc') @@ -1889,6 +1951,11 @@ def setUp(self): self.mock_win = MagicMock(spec=curses.window) self.mock_win.getyx.return_value = (1, 1) self.mock_win.getmaxyx.return_value = (10, 20) + self.mock_win.encoding = 'utf-8' + # A non-blank cell so that _end_of_line() reports a full line: instr() + # backs the text reads, inch() the insert-mode shift. + self.mock_win.instr.return_value = b'x' + self.mock_win.inch.return_value = ord('x') self.textbox = curses.textpad.Textbox(self.mock_win) def test_init(self): diff --git a/Misc/NEWS.d/next/Library/2026-06-27-12-30-00.gh-issue-133031.Na8Bit.rst b/Misc/NEWS.d/next/Library/2026-06-27-12-30-00.gh-issue-133031.Na8Bit.rst new file mode 100644 index 00000000000000..96e9efe20e42f0 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-27-12-30-00.gh-issue-133031.Na8Bit.rst @@ -0,0 +1,3 @@ +:class:`curses.textpad.Textbox` now enters and reads back the non-ASCII +characters of an 8-bit locale encoding, instead of mangling them with a 7-bit +mask. From f4c2316428d1d8d3901dafbb41df95306850f468 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 29 Jun 2026 15:56:05 +0200 Subject: [PATCH 498/818] [3.15] gh-151096: Fix test_embed with split exec prefix (GH-151288) (#152590) gh-151096: Fix test_embed with split exec prefix (GH-151288) (cherry picked from commit b19839b40c771904b87ea35127f9fa1b8058597e) Co-authored-by: Harjoth Khara <harjoth.khara@gmail.com> --- Lib/test/test_embed.py | 8 +++++--- .../Tests/2026-06-16-05-11-38.gh-issue-151096.Kq3Lp9.rst | 2 ++ 2 files changed, 7 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Tests/2026-06-16-05-11-38.gh-issue-151096.Kq3Lp9.rst diff --git a/Lib/test/test_embed.py b/Lib/test/test_embed.py index c5ced3cc6134b9..6a464e6d8f9cac 100644 --- a/Lib/test/test_embed.py +++ b/Lib/test/test_embed.py @@ -1429,7 +1429,7 @@ def module_search_paths(self, prefix=None, exec_prefix=None): if prefix is None: prefix = config['config']['prefix'] if exec_prefix is None: - exec_prefix = config['config']['prefix'] + exec_prefix = config['config']['exec_prefix'] if MS_WINDOWS: return config['config']['module_search_paths'] else: @@ -1578,8 +1578,10 @@ def test_init_is_python_build_with_home(self): expected_paths[1 if MS_WINDOWS else 2] = os.path.normpath( os.path.join(exedir, f'{f.read()}\n$'.splitlines()[0])) if not MS_WINDOWS: - # PREFIX (default) is set when running in build directory - prefix = exec_prefix = sys.prefix + # PREFIX and EXEC_PREFIX (defaults) are set when running in the + # build directory and may differ with --exec-prefix (gh-151096). + prefix = sys.prefix + exec_prefix = sys.exec_prefix # stdlib calculation (/Lib) is not yet supported expected_paths[0] = self.module_search_paths(prefix=prefix)[0] config.update(prefix=prefix, base_prefix=prefix, diff --git a/Misc/NEWS.d/next/Tests/2026-06-16-05-11-38.gh-issue-151096.Kq3Lp9.rst b/Misc/NEWS.d/next/Tests/2026-06-16-05-11-38.gh-issue-151096.Kq3Lp9.rst new file mode 100644 index 00000000000000..3251c6fb094723 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2026-06-16-05-11-38.gh-issue-151096.Kq3Lp9.rst @@ -0,0 +1,2 @@ +Fix ``test_embed`` failing when CPython is configured with a split exec prefix +(``--exec-prefix`` differing from ``--prefix``). From 05c7a7082cab166edbb8f7b51477ecd69983d4c2 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 29 Jun 2026 16:09:17 +0200 Subject: [PATCH 499/818] [3.15] gh-152587: Stop documenting bogus default values in tkinter variable methods (GH-152594) (GH-152596) The name parameter of Misc.wait_variable(), setvar() and getvar() and the value parameter of setvar() should not be optional. Their default values ('PY_VAR' and '1') are not meaningful and should not be advertised. (cherry picked from commit e134a1aa36027fb3c8bd9493028072365b19479b) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --- Doc/library/tkinter.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Doc/library/tkinter.rst b/Doc/library/tkinter.rst index 44b3c42a936a39..4687057788d5c3 100644 --- a/Doc/library/tkinter.rst +++ b/Doc/library/tkinter.rst @@ -1056,11 +1056,11 @@ Base and mixin classes :class:`int`. Raise :exc:`ValueError` if *s* is not a valid integer. - .. method:: getvar(name='PY_VAR') + .. method:: getvar(name) Return the value of the Tcl global variable named *name*. - .. method:: setvar(name='PY_VAR', value='1') + .. method:: setvar(name, value) Set the Tcl global variable named *name* to *value*. @@ -1523,10 +1523,10 @@ Base and mixin classes This updates the display of windows, for example after geometry changes, but does not process events caused by the user. - .. method:: waitvar(name='PY_VAR') + .. method:: waitvar(name) :no-typesetting: - .. method:: wait_variable(name='PY_VAR') + .. method:: wait_variable(name) Wait until the Tcl variable *name* is modified, continuing to process events in the meantime so that the application stays responsive. From 2a4ffa6f2128308ba5ba81a7c8912fb781a271e0 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka <storchaka@gmail.com> Date: Mon, 29 Jun 2026 17:20:14 +0300 Subject: [PATCH 500/818] [3.15] gh-152502: Detect optional curses functions with configure probes (GH-152504) (GH-152589) set_escdelay(), set_tabsize() and the ESCDELAY and TABSIZE variables were gated only by the ncurses-specific NCURSES_EXT_FUNCS macro, which excluded them when building against other curses implementations such as NetBSD curses even when they provided them. Detect each with a configure capability probe and gate on HAVE_CURSES_*. (cherry picked from commit 0635e55b47e306aa6cc0610105775849b0699e2c) Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --- ...-06-28-16-17-55.gh-issue-152502.6SNqMg.rst | 5 + Modules/_cursesmodule.c | 16 +- Modules/clinic/_cursesmodule.c.h | 18 +- configure | 238 ++++++++++++++++++ configure.ac | 28 +++ pyconfig.h.in | 12 + 6 files changed, 302 insertions(+), 15 deletions(-) create mode 100644 Misc/NEWS.d/next/Build/2026-06-28-16-17-55.gh-issue-152502.6SNqMg.rst diff --git a/Misc/NEWS.d/next/Build/2026-06-28-16-17-55.gh-issue-152502.6SNqMg.rst b/Misc/NEWS.d/next/Build/2026-06-28-16-17-55.gh-issue-152502.6SNqMg.rst new file mode 100644 index 00000000000000..cc0fabed10f126 --- /dev/null +++ b/Misc/NEWS.d/next/Build/2026-06-28-16-17-55.gh-issue-152502.6SNqMg.rst @@ -0,0 +1,5 @@ +The :mod:`curses` module now detects ``set_escdelay()``, ``set_tabsize()`` and +the ``ESCDELAY`` and ``TABSIZE`` variables with :program:`configure` capability +probes instead of the ncurses-specific ``NCURSES_EXT_FUNCS`` macro, so they are +exposed when building against other curses implementations such as NetBSD curses +that provide them. diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index b7195264c7f090..f474174ef7c9dd 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -4027,9 +4027,7 @@ _curses_setupterm_impl(PyObject *module, const char *term, int fd) Py_RETURN_NONE; } -#if defined(NCURSES_EXT_FUNCS) && NCURSES_EXT_FUNCS >= 20081102 -// https://invisible-island.net/ncurses/NEWS.html#index-t20080119 - +#ifdef HAVE_CURSES_ESCDELAY /*[clinic input] _curses.get_escdelay @@ -4046,6 +4044,9 @@ _curses_get_escdelay_impl(PyObject *module) { return PyLong_FromLong(ESCDELAY); } +#endif /* HAVE_CURSES_ESCDELAY */ + +#ifdef HAVE_CURSES_SET_ESCDELAY /*[clinic input] _curses.set_escdelay ms: int @@ -4070,7 +4071,9 @@ _curses_set_escdelay_impl(PyObject *module, int ms) return curses_check_err(module, set_escdelay(ms), "set_escdelay", NULL); } +#endif /* HAVE_CURSES_SET_ESCDELAY */ +#ifdef HAVE_CURSES_TABSIZE /*[clinic input] _curses.get_tabsize @@ -4086,6 +4089,9 @@ _curses_get_tabsize_impl(PyObject *module) { return PyLong_FromLong(TABSIZE); } +#endif /* HAVE_CURSES_TABSIZE */ + +#ifdef HAVE_CURSES_SET_TABSIZE /*[clinic input] _curses.set_tabsize size: int @@ -4109,7 +4115,7 @@ _curses_set_tabsize_impl(PyObject *module, int size) return curses_check_err(module, set_tabsize(size), "set_tabsize", NULL); } -#endif +#endif /* HAVE_CURSES_SET_TABSIZE */ /*[clinic input] _curses.intrflush @@ -5372,10 +5378,8 @@ static PyMethodDef cursesmodule_methods[] = { _CURSES_RESIZETERM_METHODDEF _CURSES_RESIZE_TERM_METHODDEF _CURSES_SAVETTY_METHODDEF -#if defined(NCURSES_EXT_FUNCS) && NCURSES_EXT_FUNCS >= 20081102 _CURSES_GET_ESCDELAY_METHODDEF _CURSES_SET_ESCDELAY_METHODDEF -#endif _CURSES_GET_TABSIZE_METHODDEF _CURSES_SET_TABSIZE_METHODDEF _CURSES_SETSYX_METHODDEF diff --git a/Modules/clinic/_cursesmodule.c.h b/Modules/clinic/_cursesmodule.c.h index cab9b068a561da..9235586587e876 100644 --- a/Modules/clinic/_cursesmodule.c.h +++ b/Modules/clinic/_cursesmodule.c.h @@ -2792,7 +2792,7 @@ _curses_setupterm(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyO return return_value; } -#if (defined(NCURSES_EXT_FUNCS) && NCURSES_EXT_FUNCS >= 20081102) +#if defined(HAVE_CURSES_ESCDELAY) PyDoc_STRVAR(_curses_get_escdelay__doc__, "get_escdelay($module, /)\n" @@ -2816,9 +2816,9 @@ _curses_get_escdelay(PyObject *module, PyObject *Py_UNUSED(ignored)) return _curses_get_escdelay_impl(module); } -#endif /* (defined(NCURSES_EXT_FUNCS) && NCURSES_EXT_FUNCS >= 20081102) */ +#endif /* defined(HAVE_CURSES_ESCDELAY) */ -#if (defined(NCURSES_EXT_FUNCS) && NCURSES_EXT_FUNCS >= 20081102) +#if defined(HAVE_CURSES_SET_ESCDELAY) PyDoc_STRVAR(_curses_set_escdelay__doc__, "set_escdelay($module, ms, /)\n" @@ -2855,9 +2855,9 @@ _curses_set_escdelay(PyObject *module, PyObject *arg) return return_value; } -#endif /* (defined(NCURSES_EXT_FUNCS) && NCURSES_EXT_FUNCS >= 20081102) */ +#endif /* defined(HAVE_CURSES_SET_ESCDELAY) */ -#if (defined(NCURSES_EXT_FUNCS) && NCURSES_EXT_FUNCS >= 20081102) +#if defined(HAVE_CURSES_TABSIZE) PyDoc_STRVAR(_curses_get_tabsize__doc__, "get_tabsize($module, /)\n" @@ -2880,9 +2880,9 @@ _curses_get_tabsize(PyObject *module, PyObject *Py_UNUSED(ignored)) return _curses_get_tabsize_impl(module); } -#endif /* (defined(NCURSES_EXT_FUNCS) && NCURSES_EXT_FUNCS >= 20081102) */ +#endif /* defined(HAVE_CURSES_TABSIZE) */ -#if (defined(NCURSES_EXT_FUNCS) && NCURSES_EXT_FUNCS >= 20081102) +#if defined(HAVE_CURSES_SET_TABSIZE) PyDoc_STRVAR(_curses_set_tabsize__doc__, "set_tabsize($module, size, /)\n" @@ -2918,7 +2918,7 @@ _curses_set_tabsize(PyObject *module, PyObject *arg) return return_value; } -#endif /* (defined(NCURSES_EXT_FUNCS) && NCURSES_EXT_FUNCS >= 20081102) */ +#endif /* defined(HAVE_CURSES_SET_TABSIZE) */ PyDoc_STRVAR(_curses_intrflush__doc__, "intrflush($module, flag, /)\n" @@ -4486,4 +4486,4 @@ _curses_has_extended_color_support(PyObject *module, PyObject *Py_UNUSED(ignored #ifndef _CURSES_ASSUME_DEFAULT_COLORS_METHODDEF #define _CURSES_ASSUME_DEFAULT_COLORS_METHODDEF #endif /* !defined(_CURSES_ASSUME_DEFAULT_COLORS_METHODDEF) */ -/*[clinic end generated code: output=11ab7c93cbc13e75 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=7835b44ce9413f7f input=a9049054013a1b77]*/ diff --git a/configure b/configure index a296f76a030aaa..d17240882ec956 100755 --- a/configure +++ b/configure @@ -29714,6 +29714,8 @@ fi + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for curses function is_pad" >&5 printf %s "checking for curses function is_pad... " >&6; } if test ${ac_cv_lib_curses_is_pad+y} @@ -30372,6 +30374,242 @@ fi + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for curses function set_escdelay" >&5 +printf %s "checking for curses function set_escdelay... " >&6; } +if test ${ac_cv_lib_curses_set_escdelay+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#define NCURSES_OPAQUE 0 +#if defined(HAVE_NCURSESW_NCURSES_H) +# include <ncursesw/ncurses.h> +#elif defined(HAVE_NCURSESW_CURSES_H) +# include <ncursesw/curses.h> +#elif defined(HAVE_NCURSES_NCURSES_H) +# include <ncurses/ncurses.h> +#elif defined(HAVE_NCURSES_CURSES_H) +# include <ncurses/curses.h> +#elif defined(HAVE_NCURSES_H) +# include <ncurses.h> +#elif defined(HAVE_CURSES_H) +# include <curses.h> +#endif + +int +main (void) +{ + + #ifndef set_escdelay + void *x=set_escdelay + #endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_lib_curses_set_escdelay=yes +else case e in #( + e) ac_cv_lib_curses_set_escdelay=no ;; +esac +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_curses_set_escdelay" >&5 +printf "%s\n" "$ac_cv_lib_curses_set_escdelay" >&6; } + if test "x$ac_cv_lib_curses_set_escdelay" = xyes +then : + +printf "%s\n" "#define HAVE_CURSES_SET_ESCDELAY 1" >>confdefs.h + +fi + + + + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for curses function set_tabsize" >&5 +printf %s "checking for curses function set_tabsize... " >&6; } +if test ${ac_cv_lib_curses_set_tabsize+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#define NCURSES_OPAQUE 0 +#if defined(HAVE_NCURSESW_NCURSES_H) +# include <ncursesw/ncurses.h> +#elif defined(HAVE_NCURSESW_CURSES_H) +# include <ncursesw/curses.h> +#elif defined(HAVE_NCURSES_NCURSES_H) +# include <ncurses/ncurses.h> +#elif defined(HAVE_NCURSES_CURSES_H) +# include <ncurses/curses.h> +#elif defined(HAVE_NCURSES_H) +# include <ncurses.h> +#elif defined(HAVE_CURSES_H) +# include <curses.h> +#endif + +int +main (void) +{ + + #ifndef set_tabsize + void *x=set_tabsize + #endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_lib_curses_set_tabsize=yes +else case e in #( + e) ac_cv_lib_curses_set_tabsize=no ;; +esac +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_curses_set_tabsize" >&5 +printf "%s\n" "$ac_cv_lib_curses_set_tabsize" >&6; } + if test "x$ac_cv_lib_curses_set_tabsize" = xyes +then : + +printf "%s\n" "#define HAVE_CURSES_SET_TABSIZE 1" >>confdefs.h + +fi + + + + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for curses variable ESCDELAY" >&5 +printf %s "checking for curses variable ESCDELAY... " >&6; } +if test ${ac_cv_lib_curses_ESCDELAY+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#define NCURSES_OPAQUE 0 +#if defined(HAVE_NCURSESW_NCURSES_H) +# include <ncursesw/ncurses.h> +#elif defined(HAVE_NCURSESW_CURSES_H) +# include <ncursesw/curses.h> +#elif defined(HAVE_NCURSES_NCURSES_H) +# include <ncurses/ncurses.h> +#elif defined(HAVE_NCURSES_CURSES_H) +# include <ncurses/curses.h> +#elif defined(HAVE_NCURSES_H) +# include <ncurses.h> +#elif defined(HAVE_CURSES_H) +# include <curses.h> +#endif + +int +main (void) +{ + + int x = ESCDELAY; (void)x; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_lib_curses_ESCDELAY=yes +else case e in #( + e) ac_cv_lib_curses_ESCDELAY=no ;; +esac +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_curses_ESCDELAY" >&5 +printf "%s\n" "$ac_cv_lib_curses_ESCDELAY" >&6; } + if test "x$ac_cv_lib_curses_ESCDELAY" = xyes +then : + +printf "%s\n" "#define HAVE_CURSES_ESCDELAY 1" >>confdefs.h + +fi + + + + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for curses variable TABSIZE" >&5 +printf %s "checking for curses variable TABSIZE... " >&6; } +if test ${ac_cv_lib_curses_TABSIZE+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#define NCURSES_OPAQUE 0 +#if defined(HAVE_NCURSESW_NCURSES_H) +# include <ncursesw/ncurses.h> +#elif defined(HAVE_NCURSESW_CURSES_H) +# include <ncursesw/curses.h> +#elif defined(HAVE_NCURSES_NCURSES_H) +# include <ncurses/ncurses.h> +#elif defined(HAVE_NCURSES_CURSES_H) +# include <ncurses/curses.h> +#elif defined(HAVE_NCURSES_H) +# include <ncurses.h> +#elif defined(HAVE_CURSES_H) +# include <curses.h> +#endif + +int +main (void) +{ + + int x = TABSIZE; (void)x; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_lib_curses_TABSIZE=yes +else case e in #( + e) ac_cv_lib_curses_TABSIZE=no ;; +esac +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_curses_TABSIZE" >&5 +printf "%s\n" "$ac_cv_lib_curses_TABSIZE" >&6; } + if test "x$ac_cv_lib_curses_TABSIZE" = xyes +then : + +printf "%s\n" "#define HAVE_CURSES_TABSIZE 1" >>confdefs.h + +fi + + + CPPFLAGS=$ac_save_cppflags fi diff --git a/configure.ac b/configure.ac index f7931cfab580b3..0cf3d3f24506fc 100644 --- a/configure.ac +++ b/configure.ac @@ -7248,6 +7248,30 @@ AC_DEFUN([PY_CHECK_CURSES_FUNC], AS_VAR_POPDEF([py_define]) ]) +dnl PY_CHECK_CURSES_VAR(VARIABLE) +dnl Like PY_CHECK_CURSES_FUNC, but for an integer variable (or macro), such as +dnl ESCDELAY, which a function probe cannot detect. +AC_DEFUN([PY_CHECK_CURSES_VAR], +[ AS_VAR_PUSHDEF([py_var], [ac_cv_lib_curses_$1]) + AS_VAR_PUSHDEF([py_define], [HAVE_CURSES_]m4_toupper($1)) + AC_CACHE_CHECK( + [for curses variable $1], + [py_var], + [AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM(_CURSES_INCLUDES, [ + int x = $1; (void)x; + ])], + [AS_VAR_SET([py_var], [yes])], + [AS_VAR_SET([py_var], [no])])] + ) + AS_VAR_IF( + [py_var], + [yes], + [AC_DEFINE([py_define], [1], [Define if you have the '$1' variable.])]) + AS_VAR_POPDEF([py_var]) + AS_VAR_POPDEF([py_define]) +]) + PY_CHECK_CURSES_FUNC([is_pad]) PY_CHECK_CURSES_FUNC([is_term_resized]) PY_CHECK_CURSES_FUNC([resize_term]) @@ -7259,6 +7283,10 @@ PY_CHECK_CURSES_FUNC([filter]) PY_CHECK_CURSES_FUNC([has_key]) PY_CHECK_CURSES_FUNC([typeahead]) PY_CHECK_CURSES_FUNC([use_env]) +PY_CHECK_CURSES_FUNC([set_escdelay]) +PY_CHECK_CURSES_FUNC([set_tabsize]) +PY_CHECK_CURSES_VAR([ESCDELAY]) +PY_CHECK_CURSES_VAR([TABSIZE]) CPPFLAGS=$ac_save_cppflags ])dnl have_curses != no ])dnl save env diff --git a/pyconfig.h.in b/pyconfig.h.in index 318a9e1ba06364..058fc9f0a42f5e 100644 --- a/pyconfig.h.in +++ b/pyconfig.h.in @@ -185,6 +185,9 @@ /* Define if you have the 'ctermid_r' function. */ #undef HAVE_CTERMID_R +/* Define if you have the 'ESCDELAY' variable. */ +#undef HAVE_CURSES_ESCDELAY + /* Define if you have the 'filter' function. */ #undef HAVE_CURSES_FILTER @@ -209,9 +212,18 @@ /* Define if you have the 'resize_term' function. */ #undef HAVE_CURSES_RESIZE_TERM +/* Define if you have the 'set_escdelay' function. */ +#undef HAVE_CURSES_SET_ESCDELAY + +/* Define if you have the 'set_tabsize' function. */ +#undef HAVE_CURSES_SET_TABSIZE + /* Define if you have the 'syncok' function. */ #undef HAVE_CURSES_SYNCOK +/* Define if you have the 'TABSIZE' variable. */ +#undef HAVE_CURSES_TABSIZE + /* Define if you have the 'typeahead' function. */ #undef HAVE_CURSES_TYPEAHEAD From 9bea12aaca4b6950b0ff58a798b66350e72cfdcc Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 29 Jun 2026 16:23:06 +0200 Subject: [PATCH 501/818] [3.15] gh-69134: Harden tkinter GUI tests that depend on a mapped widget (GH-152499) (GH-152516) Add wait_until_mapped() and AbstractTkTest.require_mapped() to test_tkinter.support and use them to guard the assertions that need a widget to be actually mapped (winfo_width(), identify(), coords(), ...). This avoids intermittent failures under window managers that do not map the widget promptly, without skipping the unrelated checks. (cherry picked from commit 0fff6bd86cf0224152c509e295d3cbbd209098f3) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --- Lib/test/test_tkinter/support.py | 41 +++++++++++++++++++++++++++ Lib/test/test_tkinter/test_widgets.py | 28 +++++++++++------- Lib/test/test_ttk/test_extensions.py | 6 ++-- Lib/test/test_ttk/test_widgets.py | 37 +++++++++++++++--------- 4 files changed, 85 insertions(+), 27 deletions(-) diff --git a/Lib/test/test_tkinter/support.py b/Lib/test/test_tkinter/support.py index 7fb0b217fd24ec..df0cca95a33a18 100644 --- a/Lib/test/test_tkinter/support.py +++ b/Lib/test/test_tkinter/support.py @@ -1,4 +1,5 @@ import functools +import time import tkinter import unittest from test import support @@ -45,6 +46,20 @@ def tearDown(self): w.destroy() self.root.withdraw() + def require_mapped(self, widget, timeout=None): + """Realize *widget*, or skip the test if the window manager will + not map it (e.g. a tiling WM or a headless/contended display). + + Use this instead of a bare update() before querying realized + geometry (winfo_width(), identify(), coords(), place_info(), ...). + See gh-69134, gh-74941 and bpo-40722. + """ + if timeout is None: + timeout = support.LOOPBACK_TIMEOUT + if not wait_until_mapped(widget, timeout): + self.skipTest('widget was not mapped by the window manager ' + f'(timed out after {timeout:g}s)') + class AbstractDefaultRootTest: @@ -78,6 +93,32 @@ def destroy_default_root(): tkinter._default_root.destroy() tkinter._default_root = None +def wait_until_mapped(widget, timeout=None): + """Wait until *widget* is actually mapped and laid out by the window + manager, so that realized-geometry queries (winfo_width(), identify(), + coords(), ...) return meaningful values. + + Return True once the widget is mapped with a non-trivial size, or False + if that has not happened within *timeout* seconds (default: + ``support.LOOPBACK_TIMEOUT``). Unlike Misc.wait_visibility(), this + never blocks indefinitely, so it is safe under a window manager that + never maps the window (see gh-69134, gh-74941, bpo-40722). + """ + if timeout is None: + timeout = support.LOOPBACK_TIMEOUT + deadline = time.monotonic() + timeout + widget.update_idletasks() + while True: + widget.update() # drain pending Map/Configure events + if (widget.winfo_ismapped() + and widget.winfo_width() > 1 + and widget.winfo_height() > 1): + return True + if time.monotonic() >= deadline: + return False + time.sleep(0.01) + + def simulate_mouse_click(widget, x, y): """Generate proper events to click at the x, y position (tries to act like an X server).""" diff --git a/Lib/test/test_tkinter/test_widgets.py b/Lib/test/test_tkinter/test_widgets.py index 4b51d219d87e5b..f5481e7712dad4 100644 --- a/Lib/test/test_tkinter/test_widgets.py +++ b/Lib/test/test_tkinter/test_widgets.py @@ -7,6 +7,7 @@ from test.test_tkinter.support import setUpModule # noqa: F401 from test.test_tkinter.support import (requires_tk, tk_version, get_tk_patchlevel, widget_eq, + wait_until_mapped, AbstractDefaultRootTest) from test.test_tkinter.widget_tests import ( @@ -754,10 +755,11 @@ def test_invoke(self): def test_identify(self): widget = self.create() widget.pack() - widget.update_idletasks() - # The empty string is returned for a point over no element. - self.assertIn(widget.identify(5, 5), - ('entry', 'buttonup', 'buttondown', 'none', '')) + # Identifying the element under a point requires the widget to be + # mapped with a real size. + if wait_until_mapped(widget): + self.assertIn(widget.identify(5, 5), + ('entry', 'buttonup', 'buttondown', 'none')) self.assertRaises(TclError, widget.identify, 'a', 'b') def test_scan(self): @@ -2096,9 +2098,11 @@ def test_delta(self): def test_identify(self): sb = self.create() sb.pack(fill='y', expand=True) - sb.update_idletasks() - self.assertIn(sb.identify(5, 5), - ('arrow1', 'arrow2', 'slider', 'trough1', 'trough2', '')) + # Identifying the element under a point requires the widget to be + # mapped with a real size. + if wait_until_mapped(sb): + self.assertIn(sb.identify(5, 5), + ('arrow1', 'arrow2', 'slider', 'trough1', 'trough2')) self.assertRaises(TclError, sb.identify, 'a', 'b') @@ -2218,10 +2222,12 @@ def test_identify(self): p, b, c = self.create2() p.configure(width=200, height=50) p.pack() - p.update() - x, y = p.sash_coord(0) - # A point over the sash reports the sash. - self.assertIn('sash', p.identify(x + 1, y + 5)) + # Locating the sash requires the widget to be mapped with a real + # size; the rest of the checks do not. + if wait_until_mapped(p): + x, y = p.sash_coord(0) + # A point over the sash reports the sash. + self.assertIn('sash', p.identify(x + 1, y + 5)) # A point over a pane reports nothing. self.assertFalse(p.identify(2, 2)) self.assertRaises(TclError, p.identify, 'a', 'b') diff --git a/Lib/test/test_ttk/test_extensions.py b/Lib/test/test_ttk/test_extensions.py index fb6bd24b4b9147..f6ca5e976109fc 100644 --- a/Lib/test/test_ttk/test_extensions.py +++ b/Lib/test/test_ttk/test_extensions.py @@ -109,7 +109,7 @@ def check_positions(scale, scale_pos, label, label_pos): def test_horizontal_range(self): lscale = ttk.LabeledScale(self.root, from_=0, to=10) lscale.pack() - lscale.update() + self.require_mapped(lscale) linfo_1 = lscale.label.place_info() prev_xcoord = lscale.scale.coords()[0] @@ -138,7 +138,7 @@ def test_horizontal_range(self): def test_variable_change(self): x = ttk.LabeledScale(self.root) x.pack() - x.update() + self.require_mapped(x) curr_xcoord = x.scale.coords()[0] newval = x.value + 1 @@ -181,7 +181,7 @@ def test_resize(self): x = ttk.LabeledScale(self.root) x.pack(expand=True, fill='both') gc_collect() # For PyPy or other GCs. - x.update() + self.require_mapped(x) width, height = x.master.winfo_width(), x.master.winfo_height() width_new, height_new = width * 2, height * 2 diff --git a/Lib/test/test_ttk/test_widgets.py b/Lib/test/test_ttk/test_widgets.py index aef15a7137a06e..5c50fb659d47de 100644 --- a/Lib/test/test_ttk/test_widgets.py +++ b/Lib/test/test_ttk/test_widgets.py @@ -8,7 +8,7 @@ from test.test_tkinter.support import setUpModule # noqa: F401 from test.test_tkinter.support import ( AbstractTkTest, requires_tk, tk_version, get_tk_patchlevel, - simulate_mouse_click, AbstractDefaultRootTest) + simulate_mouse_click, wait_until_mapped, AbstractDefaultRootTest) from test.test_tkinter.widget_tests import (add_configure_tests, AbstractWidgetTest, StandardOptionsTests, IntegerSizeTests, PixelSizeTests) @@ -78,11 +78,13 @@ def setUp(self): self.widget.pack() def test_identify(self): - self.widget.update() - self.assertEqual(self.widget.identify( - int(self.widget.winfo_width() / 2), - int(self.widget.winfo_height() / 2) - ), "label") + # Identifying the element under a point requires the widget to be + # mapped with a real size; the rest of the checks do not. + if wait_until_mapped(self.widget): + self.assertEqual(self.widget.identify( + int(self.widget.winfo_width() / 2), + int(self.widget.winfo_height() / 2) + ), "label") self.assertEqual(self.widget.identify(-1, -1), "") self.assertRaises(tkinter.TclError, self.widget.identify, None, 5) @@ -385,9 +387,11 @@ def test_identify(self): self.skipTest('Test does not work on macOS Tk 9.') # https://core.tcl-lang.org/tk/tktview/8b49e9cfa6 self.entry.pack() - self.root.update() - self.assertIn(self.entry.identify(5, 5), self.IDENTIFY_AS) + # Identifying the element under a point requires the widget to be + # mapped with a real size; the rest of the checks do not. + if wait_until_mapped(self.entry): + self.assertIn(self.entry.identify(5, 5), self.IDENTIFY_AS) self.assertEqual(self.entry.identify(-1, -1), "") self.assertRaises(tkinter.TclError, self.entry.identify, None, 5) @@ -506,7 +510,7 @@ def test_virtual_event(self): self.combo.bind('<<ComboboxSelected>>', lambda evt: success.append(True)) self.combo.pack() - self.combo.update() + self.require_mapped(self.combo) height = self.combo.winfo_height() self._show_drop_down_listbox() @@ -525,7 +529,7 @@ def test_configure_postcommand(self): self.combo['postcommand'] = lambda: success.append(True) self.combo.pack() - self.combo.update() + self.require_mapped(self.combo) self._show_drop_down_listbox() self.assertTrue(success) @@ -875,8 +879,10 @@ def test_get(self): else: conv = float - scale_width = self.scale.winfo_width() - self.assertEqual(self.scale.get(scale_width, 0), self.scale['to']) + # Reading the value at the far edge needs the realized width. + if wait_until_mapped(self.scale): + scale_width = self.scale.winfo_width() + self.assertEqual(self.scale.get(scale_width, 0), self.scale['to']) self.assertEqual(conv(self.scale.get(0, 0)), conv(self.scale['from'])) self.assertEqual(self.scale.get(), self.scale['value']) @@ -918,7 +924,10 @@ def test_set(self): # nevertheless, note that the max/min values we can get specifying # x, y coords are the ones according to the current range self.assertEqual(conv(self.scale.get(0, 0)), min) - self.assertEqual(conv(self.scale.get(self.scale.winfo_width(), 0)), max) + # Reading the value at the far edge needs the realized width. + if wait_until_mapped(self.scale): + self.assertEqual( + conv(self.scale.get(self.scale.winfo_width(), 0)), max) self.assertRaises(tkinter.TclError, self.scale.set, None) @@ -1269,6 +1278,7 @@ def create(self, **kwargs): return ttk.Spinbox(self.root, **kwargs) def _click_increment_arrow(self): + self.require_mapped(self.spin) width = self.spin.winfo_width() height = self.spin.winfo_height() x = width - 5 @@ -1279,6 +1289,7 @@ def _click_increment_arrow(self): self.spin.update_idletasks() def _click_decrement_arrow(self): + self.require_mapped(self.spin) width = self.spin.winfo_width() height = self.spin.winfo_height() x = width - 5 From 05cf0072a71790c9229c1fb89914b1a46abccc86 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 29 Jun 2026 18:00:20 +0200 Subject: [PATCH 502/818] [3.15] gh-69134: Wait until mapped in keyboard virtual-event tests (GH-152599) (GH-152605) test_virtual_events and test_selection_event generate key events after focus_force(). On Windows these are only delivered once the toplevel is mapped, so they could be dropped and the test fail. Wait until the widget is mapped, as the other GUI tests already do. (cherry picked from commit be4eebb8386d07f360dd835a0ecb4a1eb6385736) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --- Lib/test/test_tkinter/test_widgets.py | 2 +- Lib/test/test_ttk/test_widgets.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_tkinter/test_widgets.py b/Lib/test/test_tkinter/test_widgets.py index f5481e7712dad4..efd9beed71a88b 100644 --- a/Lib/test/test_tkinter/test_widgets.py +++ b/Lib/test/test_tkinter/test_widgets.py @@ -1934,7 +1934,7 @@ def test_selection_event(self): lb = self.create(selectmode='browse', exportselection=False) lb.insert(0, *('el%d' % i for i in range(5))) lb.pack() - lb.update() + self.require_mapped(lb) events = [] lb.bind('<<ListboxSelect>>', lambda e: events.append(lb.curselection())) lb.focus_force() diff --git a/Lib/test/test_ttk/test_widgets.py b/Lib/test/test_ttk/test_widgets.py index 5c50fb659d47de..5b1000b699e4b0 100644 --- a/Lib/test/test_ttk/test_widgets.py +++ b/Lib/test/test_ttk/test_widgets.py @@ -1977,7 +1977,7 @@ def test_virtual_events(self): self.tv.insert(parent, 'end') item2 = self.tv.insert('', 'end') self.tv.pack() - self.tv.update() + self.require_mapped(self.tv) selects, opens, closes = [], [], [] self.tv.bind('<<TreeviewSelect>>', lambda e: selects.append(self.tv.selection())) From e08e00383ff92566fb0a14bdf620c3f082bd1443 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 29 Jun 2026 18:52:04 +0200 Subject: [PATCH 503/818] [3.15] gh-152228: Fix an assertion failure in `str.replace` under a limited memory case (GH-152229) (#152615) gh-152228: Fix an assertion failure in `str.replace` under a limited memory case (GH-152229) (cherry picked from commit c5043dce1c6743682d93c71e937b95e7d27e0b35) Co-authored-by: sobolevn <mail@sobolevn.me> --- Lib/test/test_str.py | 15 +++++++++++++++ ...6-06-25-21-34-15.gh-issue-152228.a6K14K.rst | 2 ++ Objects/unicodeobject.c | 18 +++++++++--------- 3 files changed, 26 insertions(+), 9 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-25-21-34-15.gh-issue-152228.a6K14K.rst diff --git a/Lib/test/test_str.py b/Lib/test/test_str.py index 4f57499af70f4d..979bfe36fff680 100644 --- a/Lib/test/test_str.py +++ b/Lib/test/test_str.py @@ -607,6 +607,21 @@ def test_replace_id(self): text = 'abc def' self.assertIs(text.replace(pattern, pattern), text) + @support.nomemtest + def test_replace_oom(self): + # https://github.com/python/cpython/issues/152228 + s1 = "轘" * 4 + s2 = "&" + s3 = "&amp;" + assertion = self.assertRaises(MemoryError) + _testcapi.set_nomemory(0, 0) + try: + # No allocations made in the test itself: + with assertion: + s1.replace(s2, s3) # this line used to crash before + finally: + _testcapi.remove_mem_hooks() + def test_repeat_id_preserving(self): a = '123abc1@' b = '456zyx-+' diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-25-21-34-15.gh-issue-152228.a6K14K.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-25-21-34-15.gh-issue-152228.a6K14K.rst new file mode 100644 index 00000000000000..8af7ae0d173913 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-25-21-34-15.gh-issue-152228.a6K14K.rst @@ -0,0 +1,2 @@ +Fix an assertion failure when python is built in a debug mode +that happened in :meth:`str.replace` under a limited memory situation. diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 74d6ba4db9f2b8..18523c2dfde77e 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -10753,9 +10753,9 @@ replace(PyObject *self, PyObject *str1, } done: - assert(srelease == (sbuf != PyUnicode_DATA(self))); - assert(release1 == (buf1 != PyUnicode_DATA(str1))); - assert(release2 == (buf2 != PyUnicode_DATA(str2))); + assert(srelease == (sbuf != NULL && sbuf != PyUnicode_DATA(self))); + assert(release1 == (buf1 != NULL && buf1 != PyUnicode_DATA(str1))); + assert(release2 == (buf2 != NULL && buf2 != PyUnicode_DATA(str2))); if (srelease) PyMem_Free((void *)sbuf); if (release1) @@ -10767,9 +10767,9 @@ replace(PyObject *self, PyObject *str1, nothing: /* nothing to replace; return original string (when possible) */ - assert(srelease == (sbuf != PyUnicode_DATA(self))); - assert(release1 == (buf1 != PyUnicode_DATA(str1))); - assert(release2 == (buf2 != PyUnicode_DATA(str2))); + assert(srelease == (sbuf != NULL && sbuf != PyUnicode_DATA(self))); + assert(release1 == (buf1 != NULL && buf1 != PyUnicode_DATA(str1))); + assert(release2 == (buf2 != NULL && buf2 != PyUnicode_DATA(str2))); if (srelease) PyMem_Free((void *)sbuf); if (release1) @@ -10779,9 +10779,9 @@ replace(PyObject *self, PyObject *str1, return unicode_result_unchanged(self); error: - assert(srelease == (sbuf != PyUnicode_DATA(self))); - assert(release1 == (buf1 != PyUnicode_DATA(str1))); - assert(release2 == (buf2 != PyUnicode_DATA(str2))); + assert(srelease == (sbuf != NULL && sbuf != PyUnicode_DATA(self))); + assert(release1 == (buf1 != NULL && buf1 != PyUnicode_DATA(str1))); + assert(release2 == (buf2 != NULL && buf2 != PyUnicode_DATA(str2))); if (srelease) PyMem_Free((void *)sbuf); if (release1) From 7b57e8d51446297b8c7c482d224bc5f1938e4301 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 29 Jun 2026 21:10:59 +0200 Subject: [PATCH 504/818] [3.15] gh-151987: Pass `filter_function` to `TarFile._extract_one()` during `.extract()` (GH-151988) (#152608) (cherry picked from commit 7ccdbaba2c54250a70d7f25632152df7655a5e0a) Co-authored-by: Petr Viktorin <encukou@gmail.com> Co-authored-by: Seth Michael Larson <seth@python.org> --- Lib/tarfile.py | 3 +- Lib/test/test_tarfile.py | 92 +++++++++++++++++++ ...-06-23-14-19-30.gh-issue-151987.8mNIMf.rst | 2 + 3 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Security/2026-06-23-14-19-30.gh-issue-151987.8mNIMf.rst diff --git a/Lib/tarfile.py b/Lib/tarfile.py index e4b4b24ba9b640..8c058357f114ad 100644 --- a/Lib/tarfile.py +++ b/Lib/tarfile.py @@ -2554,7 +2554,8 @@ def extract(self, member, path="", set_attrs=True, *, numeric_owner=False, tarinfo, unfiltered = self._get_extract_tarinfo( member, filter_function, path) if tarinfo is not None: - self._extract_one(tarinfo, path, set_attrs, numeric_owner) + self._extract_one(tarinfo, path, set_attrs, numeric_owner, + filter_function=filter_function) def _get_extract_tarinfo(self, member, filter_function, path): """Get (filtered, unfiltered) TarInfos from *member* diff --git a/Lib/test/test_tarfile.py b/Lib/test/test_tarfile.py index 585365353069ea..9615547fc22dfa 100644 --- a/Lib/test/test_tarfile.py +++ b/Lib/test/test_tarfile.py @@ -4510,6 +4510,98 @@ def test_chmod_outside_dir(self): st_mode = cc.outerdir.stat().st_mode self.assertNotEqual(st_mode & 0o777, 0o777) + @symlink_test + @unittest.skipUnless(hasattr(os, 'chown'), "missing os.chown") + @unittest.skipUnless(hasattr(os, 'lchown'), "missing os.lchown") + @unittest.skipUnless(hasattr(os, 'geteuid'), "missing os.geteuid") + @support.subTests('link_type', (tarfile.SYMTYPE, tarfile.LNKTYPE)) + def test_chown_links_on_extract(self, link_type): + with ArchiveMaker() as arc: + arc.add("test.txt", + uid=1337, gid=1337, uname="", gname="", mode='-rwxr-xr-x') + arc.add("link", + type=link_type, + linkname='test.txt', + uid=1337, gid=1337, uname="", gname="", mode='-rwxr-xr-x') + + with ( + os_helper.temp_dir() as tmpdir, + arc.open() as tar, + unittest.mock.patch("os.chown") as mock_chown, + unittest.mock.patch("os.lchown") as mock_lchown, + unittest.mock.patch("os.geteuid") as mock_geteuid, + ): + # Set UID to 0 so chown() is attempted. + mock_geteuid.return_value = 0 + tar.extract("link", path=tmpdir, filter='data') + extract_path = os.path.join(tmpdir, "link") + + if link_type == tarfile.SYMTYPE: + mock_chown.assert_not_called() + mock_lchown.assert_called_once_with(extract_path, -1, -1) + else: + mock_chown.assert_has_calls([ + unittest.mock.call(extract_path, -1, -1), + unittest.mock.call(extract_path, -1, -1) + ]) + mock_lchown.assert_not_called() + + @symlink_test + @unittest.skipUnless(hasattr(os, 'chown'), "missing os.chown") + @unittest.skipUnless(hasattr(os, 'lchown'), "missing os.lchown") + @unittest.skipUnless(hasattr(os, 'geteuid'), "missing os.geteuid") + @support.subTests('link_type', (tarfile.SYMTYPE, tarfile.LNKTYPE)) + def test_chown_links_on_extractall(self, link_type): + with ArchiveMaker() as arc: + arc.add("test.txt", + uid=1337, gid=1337, uname="", gname="", mode='-rwxr-xr-x') + arc.add("link", + type=link_type, + linkname='test.txt', + uid=1337, gid=1337, uname="", gname="", mode='-rwxr-xr-x') + + with ( + os_helper.temp_dir() as tmpdir, + arc.open() as tar, + unittest.mock.patch("os.chown") as mock_chown, + unittest.mock.patch("os.lchown") as mock_lchown, + unittest.mock.patch("os.geteuid") as mock_geteuid, + ): + # Set UID to 0 so chown() is attempted. + mock_geteuid.return_value = 0 + tar.extractall(path=tmpdir, filter='data') + extract_link_path = os.path.join(tmpdir, "link") + extract_file_path = os.path.join(tmpdir, "test.txt") + + if link_type == tarfile.SYMTYPE: + mock_chown.assert_called_once_with(extract_file_path, -1, -1) + mock_lchown.assert_called_once_with(extract_link_path, -1, -1) + else: + mock_chown.assert_has_calls([ + unittest.mock.call(extract_file_path, -1, -1), + unittest.mock.call(extract_link_path, -1, -1) + ]) + mock_lchown.assert_not_called() + + def test_extract_filters_target(self): + # Test that when extract() falls back to extracting (rather than + # linking) a hardlink target, it filters the target. + with ArchiveMaker() as arc: + arc.add("target") + arc.add("link", hardlink_to="target") + def testing_filter(member, path): + if member.name == 'target': + # target: set read-only + return member.replace(mode=stat.S_IRUSR) + # link: don't overwrite the mode + return member.replace(mode=None) + tempdir = pathlib.Path(TEMPDIR) / 'extract' + with os_helper.temp_dir(tempdir), arc.open() as tar: + tar.extract("link", path=tempdir, filter=testing_filter) + path = tempdir / 'link' + if os_helper.can_chmod(): + self.assertFalse(path.stat().st_mode & stat.S_IWUSR) + def test_link_fallback_normalizes(self): # Make sure hardlink fallbacks work for non-normalized paths for all # filters diff --git a/Misc/NEWS.d/next/Security/2026-06-23-14-19-30.gh-issue-151987.8mNIMf.rst b/Misc/NEWS.d/next/Security/2026-06-23-14-19-30.gh-issue-151987.8mNIMf.rst new file mode 100644 index 00000000000000..9eea7b32c4d2b4 --- /dev/null +++ b/Misc/NEWS.d/next/Security/2026-06-23-14-19-30.gh-issue-151987.8mNIMf.rst @@ -0,0 +1,2 @@ +The :meth:`tarfile.TarFile.extract` method now applies the given filter when +it extracts a link target from the archive as a fallback. From 93c71c7a980007f7e4f645832311ad20e9943503 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 29 Jun 2026 22:03:01 +0200 Subject: [PATCH 505/818] [3.15] gh-103878: Document that the cancelled file dialog value is only falsy (GH-152429) (GH-152629) Its exact type (empty string, tuple, list or None) varies between platforms and Tk versions, so advise testing the result for truth. (cherry picked from commit 9dd3340a623093b5d0ff054d5d42c370bb09221c) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --- Doc/library/dialog.rst | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Doc/library/dialog.rst b/Doc/library/dialog.rst index 402cfcfe75369f..384a1eacc2d7cc 100644 --- a/Doc/library/dialog.rst +++ b/Doc/library/dialog.rst @@ -131,7 +131,10 @@ listed below: The below functions when called create a modal, native look-and-feel dialog, wait for the user's selection, and return it. The exact return value depends on the function (see below); when the dialog is -cancelled it is an empty string, an empty tuple, an empty list or ``None``. +cancelled it is an empty string, an empty tuple or ``None``. +The precise type of this empty value may vary between platforms and Tk +versions, so test the result for truth rather than comparing it with a +specific value. .. function:: askopenfile(mode="r", **options) askopenfiles(mode="r", **options) @@ -140,7 +143,7 @@ cancelled it is an empty string, an empty tuple, an empty list or ``None``. :func:`askopenfile` returns the opened file object, or ``None`` if the dialog is cancelled. :func:`askopenfiles` returns a list of the opened file objects, or an empty - list if cancelled. + tuple if cancelled. The files are opened in mode *mode* (read-only ``'r'`` by default). .. function:: asksaveasfile(mode="w", **options) From 0b273d8480ed7606f2928db33833c44673a4ad1c Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 29 Jun 2026 22:20:08 +0200 Subject: [PATCH 506/818] [3.15] gh-152492 Allow `OrderedDict.update` to work with `frozendict` (GH-152494) (#152630) gh-152492 Allow `OrderedDict.update` to work with `frozendict` (GH-152494) (cherry picked from commit 0a29d8408cfdd9a66f2b65745a3ae1cda022775c) Co-authored-by: da-woods <dw-git@d-woods.co.uk> Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com> Co-authored-by: sobolevn <mail@sobolevn.me> --- Lib/test/test_ordered_dict.py | 7 ++++++- .../2026-06-28-14-31-03.gh-issue-152492._09Zee.rst | 1 + Objects/odictobject.c | 4 ++-- 3 files changed, 9 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-28-14-31-03.gh-issue-152492._09Zee.rst diff --git a/Lib/test/test_ordered_dict.py b/Lib/test/test_ordered_dict.py index 84bb3fdfbaaa6e..ac24110cf63e82 100644 --- a/Lib/test/test_ordered_dict.py +++ b/Lib/test/test_ordered_dict.py @@ -74,6 +74,9 @@ def test_update(self): od.update(dict(pairs)) self.assertEqual(sorted(od.items()), pairs) # dict input od = OrderedDict() + od.update(frozendict(pairs)) + self.assertEqual(sorted(od.items()), pairs) # frozendict input + od = OrderedDict() od.update(**dict(pairs)) self.assertEqual(sorted(od.items()), pairs) # kwds input od = OrderedDict() @@ -288,9 +291,11 @@ def test_equality(self): pairs = pairs[2:] + pairs[:2] od2 = OrderedDict(pairs) self.assertNotEqual(od1, od2) # different order implies inequality - # comparison to regular dict is not order sensitive + # comparison to regular (frozen)dict is not order sensitive self.assertEqual(od1, dict(od2)) self.assertEqual(dict(od2), od1) + self.assertEqual(od1, frozendict(od2)) + self.assertEqual(frozendict(od1), od2) # different length implied inequality self.assertNotEqual(od1, OrderedDict(pairs[:-1])) diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-28-14-31-03.gh-issue-152492._09Zee.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-28-14-31-03.gh-issue-152492._09Zee.rst new file mode 100644 index 00000000000000..16cb5a205c908a --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-28-14-31-03.gh-issue-152492._09Zee.rst @@ -0,0 +1 @@ +:type:`collections.OrderedDict` ``update`` method can now accept :type:`frozendict` as an argument. diff --git a/Objects/odictobject.c b/Objects/odictobject.c index 33914cdffb1dcc..6f10c4863856d9 100644 --- a/Objects/odictobject.c +++ b/Objects/odictobject.c @@ -1503,7 +1503,7 @@ odict_tp_clear(PyObject *op) static PyObject * odict_richcompare_lock_held(PyObject *v, PyObject *w, int op) { - if (!PyODict_Check(v) || !PyDict_Check(w)) { + if (!PyODict_Check(v) || !PyAnyDict_Check(w)) { Py_RETURN_NOTIMPLEMENTED; } @@ -2369,7 +2369,7 @@ mutablemapping_update(PyObject *self, PyObject *args, PyObject *kwargs) } /* now handle kwargs */ - assert(kwargs == NULL || PyDict_Check(kwargs)); + assert(kwargs == NULL || PyAnyDict_Check(kwargs)); if (kwargs != NULL && PyDict_GET_SIZE(kwargs)) { PyObject *items = PyDict_Items(kwargs); if (items == NULL) From ac207265bdbcf7d507d2c9831aa54eda0fe9bb61 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 30 Jun 2026 02:12:59 +0200 Subject: [PATCH 507/818] [3.15] gh-146219: Document reusing a thread state across repeated foreign-thread calls (GH-146221) (#152644) gh-146219: Document reusing a thread state across repeated foreign-thread calls (GH-146221) * Document reusing a thread state across repeated foreign-thread calls Add a subsection under "Non-Python created threads" explaining the performance cost of creating/destroying a PyThreadState on every Ensure/Release cycle and showing how to keep one alive for the thread's lifetime instead. * add a comma --------- (cherry picked from commit 5717518fb3ed6f34716683e08ec372267d871d21) Co-authored-by: Gregory P. Smith <68491+gpshead@users.noreply.github.com> Co-authored-by: Peter Bierma <zintensitydev@gmail.com> --- Doc/c-api/threads.rst | 55 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/Doc/c-api/threads.rst b/Doc/c-api/threads.rst index 508a4d71ecdf96..bec6c1f6045f02 100644 --- a/Doc/c-api/threads.rst +++ b/Doc/c-api/threads.rst @@ -242,6 +242,61 @@ a thread state that was previously attached for the current thread. .. seealso:: :pep:`788` +.. _c-api-reuse-thread-state: + +Reusing a thread state across repeated calls +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Creating and destroying a :c:type:`PyThreadState` is not free, and is more +expensive on a :term:`free-threaded build`. A foreign thread that calls into +the interpreter many times -- for example, a worker thread in a native thread +pool -- should avoid creating a fresh thread state on every entry and +destroying it on every exit. Instead, set up one thread state when the thread +starts (or lazily on its first call into Python), attach and detach it around +each call, and tear it down once when the thread exits. + +Manage the thread state explicitly with :c:func:`PyThreadState_New`, attaching +and detaching it with :c:func:`PyEval_RestoreThread` and +:c:func:`PyEval_SaveThread`. This happens in three distinct phases, at +different points in the thread's life. + +When the thread starts, create one thread state for it. ``interp`` is the +target interpreter, captured by the code that created this thread while it held +an attached thread state (for example via :c:func:`PyInterpreterState_Get`):: + + PyThreadState *tstate = PyThreadState_New(interp); + +Then, on each call into Python -- which may happen many times over the thread's +life -- attach the thread state, make the Python C API calls that require it, +and detach again so the thread does not hold the GIL while off doing non-Python +work:: + + PyEval_RestoreThread(tstate); + result = CallSomeFunction(); /* your Python C API calls go here */ + PyEval_SaveThread(); + +When the thread is finished calling into Python, destroy the thread state once:: + + PyEval_RestoreThread(tstate); + PyThreadState_Clear(tstate); + PyThreadState_DeleteCurrent(); + +The general-purpose entry points for calling in from a foreign thread -- +:c:func:`PyThreadState_Ensure` and the older :c:func:`PyGILState_Ensure` -- do +*not* guarantee a persistent thread state: their thread-state lifetime is +deliberately implementation-defined, so a matched acquire/release pair may +create and destroy a thread state each time. Use :c:func:`PyThreadState_New`, +as shown here, whenever you specifically want to reuse one thread state across +calls. + +The code that created the foreign thread must arrange for the shutdown sequence +to run before the thread exits, and before :c:func:`Py_FinalizeEx` is called. +If interpreter finalization begins first, the shutdown +:c:func:`PyEval_RestoreThread` call will hang the thread rather than return (see +:ref:`cautions-regarding-runtime-finalization`). If the thread exits without +running the shutdown sequence, the thread state is leaked for the remainder of +the process. + .. _c-api-attach-detach: Attaching/detaching thread states From 108a2adbc7a98e6adf4cef6ef70e8b7bca328e32 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 30 Jun 2026 08:34:26 +0200 Subject: [PATCH 508/818] [3.15] Use tkinter wrapper methods instead of raw Tcl calls in turtle and IDLE (GH-152414) (GH-152648) Use tkinter wrapper methods instead of raw Tcl calls in turtle and IDLE (GH-152414) * turtle: wm_attributes(topmost=...); * idlelib.macosx: winfo_server(); * idlelib tests: after_info(). (cherry picked from commit fc866dc84ec430ab22d60609520f7ab27267baef) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --- Lib/idlelib/idle_test/template.py | 2 +- Lib/idlelib/idle_test/test_codecontext.py | 4 ++-- Lib/idlelib/idle_test/test_colorizer.py | 10 +++++----- Lib/idlelib/idle_test/test_editor.py | 6 +++--- Lib/idlelib/idle_test/test_filelist.py | 2 +- Lib/idlelib/idle_test/test_iomenu.py | 2 +- Lib/idlelib/idle_test/test_multicall.py | 2 +- Lib/idlelib/idle_test/test_pyshell.py | 2 +- Lib/idlelib/idle_test/test_runscript.py | 2 +- Lib/idlelib/idle_test/test_stackviewer.py | 2 +- Lib/idlelib/idle_test/test_window.py | 2 +- Lib/idlelib/idle_test/test_zoomheight.py | 2 +- Lib/idlelib/idle_test/test_zzdummy.py | 2 +- Lib/idlelib/idle_test/test_zzdummy_user.py | 2 +- Lib/idlelib/macosx.py | 2 +- Lib/turtle.py | 4 ++-- 16 files changed, 24 insertions(+), 24 deletions(-) diff --git a/Lib/idlelib/idle_test/template.py b/Lib/idlelib/idle_test/template.py index 725a55b9c47230..69a2af22efa149 100644 --- a/Lib/idlelib/idle_test/template.py +++ b/Lib/idlelib/idle_test/template.py @@ -17,7 +17,7 @@ def setUpClass(cls): @classmethod def tearDownClass(cls): cls.root.update_idletasks() -## for id in cls.root.tk.call('after', 'info'): +## for id in cls.root.after_info(): ## cls.root.after_cancel(id) # Need for EditorWindow. cls.root.destroy() del cls.root diff --git a/Lib/idlelib/idle_test/test_codecontext.py b/Lib/idlelib/idle_test/test_codecontext.py index 6969ad73b01a81..3f070da022384e 100644 --- a/Lib/idlelib/idle_test/test_codecontext.py +++ b/Lib/idlelib/idle_test/test_codecontext.py @@ -127,7 +127,7 @@ def test_del_with_timer(self): timer = self.cc.t1 = self.text.after(10000, lambda: None) self.cc.__del__() with self.assertRaises(TclError) as cm: - self.root.tk.call('after', 'info', timer) + self.root.after_info(timer) self.assertIn("doesn't exist", str(cm.exception)) def test_reload(self): @@ -151,7 +151,7 @@ def test_toggle_code_context_event(self): eq(cc.context['bg'], self.highlight_cfg['background']) eq(cc.context.get('1.0', 'end-1c'), '') eq(cc.editwin.label, 'Hide Code Context') - eq(self.root.tk.call('after', 'info', self.cc.t1)[1], 'timer') + eq(self.root.after_info(self.cc.t1)[1], 'timer') # Toggle off. toggle() diff --git a/Lib/idlelib/idle_test/test_colorizer.py b/Lib/idlelib/idle_test/test_colorizer.py index fb6ee825086750..4d9e6bd887c5b8 100644 --- a/Lib/idlelib/idle_test/test_colorizer.py +++ b/Lib/idlelib/idle_test/test_colorizer.py @@ -260,7 +260,7 @@ def test_notify_range(self): # Colorizing already scheduled. save_id = color.after_id - eq(self.root.tk.call('after', 'info', save_id)[1], 'timer') + eq(self.root.after_info(save_id)[1], 'timer') self.assertFalse(color.colorizing) self.assertFalse(color.stop_colorizing) self.assertTrue(color.allow_colorizing) @@ -277,7 +277,7 @@ def test_notify_range(self): color.notify_range('1.0', '1.0+3c') self.assertTrue(color.stop_colorizing) self.assertIsNotNone(color.after_id) - eq(self.root.tk.call('after', 'info', color.after_id)[1], 'timer') + eq(self.root.after_info(color.after_id)[1], 'timer') # New event scheduled. self.assertNotEqual(color.after_id, save_id) @@ -297,7 +297,7 @@ def test_toggle_colorize_event(self): self.assertFalse(color.colorizing) self.assertFalse(color.stop_colorizing) self.assertTrue(color.allow_colorizing) - eq(self.root.tk.call('after', 'info', color.after_id)[1], 'timer') + eq(self.root.after_info(color.after_id)[1], 'timer') # Toggle colorizing off. color.toggle_colorize_event() @@ -324,7 +324,7 @@ def test_toggle_colorize_event(self): # Toggle on while colorizing not in progress. color.colorizing = False color.toggle_colorize_event() - eq(self.root.tk.call('after', 'info', color.after_id)[1], 'timer') + eq(self.root.after_info(color.after_id)[1], 'timer') self.assertFalse(color.colorizing) self.assertTrue(color.stop_colorizing) self.assertTrue(color.allow_colorizing) @@ -363,7 +363,7 @@ def test_recolorize(self, mock_recmain): mock_recmain.assert_called() eq(mock_recmain.call_count, 1) # Rescheduled when TODO tag still exists. - eq(self.root.tk.call('after', 'info', color.after_id)[1], 'timer') + eq(self.root.after_info(color.after_id)[1], 'timer') # No changes to text, so no scheduling added. text.tag_remove('TODO', '1.0', 'end') diff --git a/Lib/idlelib/idle_test/test_editor.py b/Lib/idlelib/idle_test/test_editor.py index 0dfe2f3c58befa..e28ee549f180aa 100644 --- a/Lib/idlelib/idle_test/test_editor.py +++ b/Lib/idlelib/idle_test/test_editor.py @@ -20,7 +20,7 @@ def setUpClass(cls): @classmethod def tearDownClass(cls): cls.root.update_idletasks() - for id in cls.root.tk.call('after', 'info'): + for id in cls.root.after_info(): cls.root.after_cancel(id) cls.root.destroy() del cls.root @@ -114,7 +114,7 @@ def tearDownClass(cls): cls.window._close() del cls.window cls.root.update_idletasks() - for id in cls.root.tk.call('after', 'info'): + for id in cls.root.after_info(): cls.root.after_cancel(id) cls.root.destroy() del cls.root @@ -225,7 +225,7 @@ def tearDownClass(cls): cls.window._close() del cls.window cls.root.update_idletasks() - for id in cls.root.tk.call('after', 'info'): + for id in cls.root.after_info(): cls.root.after_cancel(id) cls.root.destroy() del cls.root diff --git a/Lib/idlelib/idle_test/test_filelist.py b/Lib/idlelib/idle_test/test_filelist.py index 731f1975e50e23..e22cc3eced3082 100644 --- a/Lib/idlelib/idle_test/test_filelist.py +++ b/Lib/idlelib/idle_test/test_filelist.py @@ -16,7 +16,7 @@ def setUpClass(cls): @classmethod def tearDownClass(cls): cls.root.update_idletasks() - for id in cls.root.tk.call('after', 'info'): + for id in cls.root.after_info(): cls.root.after_cancel(id) cls.root.destroy() del cls.root diff --git a/Lib/idlelib/idle_test/test_iomenu.py b/Lib/idlelib/idle_test/test_iomenu.py index 80f72bdfe5ff0e..90a23620354f31 100644 --- a/Lib/idlelib/idle_test/test_iomenu.py +++ b/Lib/idlelib/idle_test/test_iomenu.py @@ -30,7 +30,7 @@ def tearDownClass(cls): cls.editwin._close() del cls.editwin cls.root.update_idletasks() - for id in cls.root.tk.call('after', 'info'): + for id in cls.root.after_info(): cls.root.after_cancel(id) # Need for EditorWindow. cls.root.destroy() del cls.root diff --git a/Lib/idlelib/idle_test/test_multicall.py b/Lib/idlelib/idle_test/test_multicall.py index 67f28db6b0875c..7d73761cfdfee8 100644 --- a/Lib/idlelib/idle_test/test_multicall.py +++ b/Lib/idlelib/idle_test/test_multicall.py @@ -19,7 +19,7 @@ def setUpClass(cls): def tearDownClass(cls): del cls.mc cls.root.update_idletasks() -## for id in cls.root.tk.call('after', 'info'): +## for id in cls.root.after_info(): ## cls.root.after_cancel(id) # Need for EditorWindow. cls.root.destroy() del cls.root diff --git a/Lib/idlelib/idle_test/test_pyshell.py b/Lib/idlelib/idle_test/test_pyshell.py index 706703965bffd6..51f7691eefe9d5 100644 --- a/Lib/idlelib/idle_test/test_pyshell.py +++ b/Lib/idlelib/idle_test/test_pyshell.py @@ -40,7 +40,7 @@ def setUpClass(cls): @classmethod def tearDownClass(cls): #cls.root.update_idletasks() -## for id in cls.root.tk.call('after', 'info'): +## for id in cls.root.after_info(): ## cls.root.after_cancel(id) # Need for EditorWindow. cls.root.destroy() del cls.root diff --git a/Lib/idlelib/idle_test/test_runscript.py b/Lib/idlelib/idle_test/test_runscript.py index 5fc60185a663e8..63086bfa4a404e 100644 --- a/Lib/idlelib/idle_test/test_runscript.py +++ b/Lib/idlelib/idle_test/test_runscript.py @@ -18,7 +18,7 @@ def setUpClass(cls): @classmethod def tearDownClass(cls): cls.root.update_idletasks() - for id in cls.root.tk.call('after', 'info'): + for id in cls.root.after_info(): cls.root.after_cancel(id) # Need for EditorWindow. cls.root.destroy() del cls.root diff --git a/Lib/idlelib/idle_test/test_stackviewer.py b/Lib/idlelib/idle_test/test_stackviewer.py index 55f510382bf4c3..2434d38e4ffe83 100644 --- a/Lib/idlelib/idle_test/test_stackviewer.py +++ b/Lib/idlelib/idle_test/test_stackviewer.py @@ -21,7 +21,7 @@ def setUpClass(cls): def tearDownClass(cls): cls.root.update_idletasks() -## for id in cls.root.tk.call('after', 'info'): +## for id in cls.root.after_info(): ## cls.root.after_cancel(id) # Need for EditorWindow. cls.root.destroy() del cls.root diff --git a/Lib/idlelib/idle_test/test_window.py b/Lib/idlelib/idle_test/test_window.py index 5a2645b9cc27dc..9b56d321a407d6 100644 --- a/Lib/idlelib/idle_test/test_window.py +++ b/Lib/idlelib/idle_test/test_window.py @@ -29,7 +29,7 @@ def setUpClass(cls): def tearDownClass(cls): window.registry = window.WindowList() cls.root.update_idletasks() -## for id in cls.root.tk.call('after', 'info'): +## for id in cls.root.after_info(): ## cls.root.after_cancel(id) # Need for EditorWindow. cls.root.destroy() del cls.root diff --git a/Lib/idlelib/idle_test/test_zoomheight.py b/Lib/idlelib/idle_test/test_zoomheight.py index aa5bdfb4fbd4c6..3b97c34d4ab29d 100644 --- a/Lib/idlelib/idle_test/test_zoomheight.py +++ b/Lib/idlelib/idle_test/test_zoomheight.py @@ -21,7 +21,7 @@ def setUpClass(cls): def tearDownClass(cls): cls.editwin._close() cls.root.update_idletasks() - for id in cls.root.tk.call('after', 'info'): + for id in cls.root.after_info(): cls.root.after_cancel(id) # Need for EditorWindow. cls.root.destroy() del cls.root diff --git a/Lib/idlelib/idle_test/test_zzdummy.py b/Lib/idlelib/idle_test/test_zzdummy.py index 14c343cf9b3087..c8e7dd6941b589 100644 --- a/Lib/idlelib/idle_test/test_zzdummy.py +++ b/Lib/idlelib/idle_test/test_zzdummy.py @@ -135,7 +135,7 @@ def tearDownClass(cls): zzdummy.idleConf.userCfg = usercfg del cls.editor, cls.text cls.root.update_idletasks() - for id in cls.root.tk.call('after', 'info'): + for id in cls.root.after_info(): cls.root.after_cancel(id) # Need for EditorWindow. cls.root.destroy() del cls.root diff --git a/Lib/idlelib/idle_test/test_zzdummy_user.py b/Lib/idlelib/idle_test/test_zzdummy_user.py index 1d3f2ac3096fb0..a3476bf52bc588 100644 --- a/Lib/idlelib/idle_test/test_zzdummy_user.py +++ b/Lib/idlelib/idle_test/test_zzdummy_user.py @@ -68,7 +68,7 @@ def tearDownClass(cls): zzdummy.idleConf.userCfg = real_usercfg del cls.editor, cls.text cls.root.update_idletasks() - for id in cls.root.tk.call('after', 'info'): + for id in cls.root.after_info(): cls.root.after_cancel(id) # Need for EditorWindow. cls.root.destroy() del cls.root diff --git a/Lib/idlelib/macosx.py b/Lib/idlelib/macosx.py index 332952f4572cbd..428e49f3eb7d8e 100644 --- a/Lib/idlelib/macosx.py +++ b/Lib/idlelib/macosx.py @@ -39,7 +39,7 @@ def _init_tk_type(): _tk_type = "xquartz" elif 'aqua' not in ws: _tk_type = "other" - elif 'AppKit' in root.tk.call('winfo', 'server', '.'): + elif 'AppKit' in root.winfo_server(): _tk_type = "cocoa" else: _tk_type = "carbon" diff --git a/Lib/turtle.py b/Lib/turtle.py index b52d681b3af1c3..ae5be9fe7039d5 100644 --- a/Lib/turtle.py +++ b/Lib/turtle.py @@ -989,8 +989,8 @@ def __init__(self, cv, mode=_CFG["mode"], # the Turtle window will show behind the Terminal window when you # start the demo from the command line. rootwindow = cv.winfo_toplevel() - rootwindow.call('wm', 'attributes', '.', '-topmost', '1') - rootwindow.call('wm', 'attributes', '.', '-topmost', '0') + rootwindow.wm_attributes(topmost=True) + rootwindow.wm_attributes(topmost=False) def clear(self): """Delete all drawings and all turtles from the TurtleScreen. From ad55e47d6d8d58205ee80011c3cb7bc675f22d69 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 30 Jun 2026 10:11:09 +0200 Subject: [PATCH 509/818] [3.15] gh-149689: add missing error checks in Parser/action_helpers.c (GH-149710) (#152640) --- ...-05-11-15-58-23.gh-issue-149689.9Ht49z.rst | 2 + Parser/action_helpers.c | 54 ++++++++++++++----- 2 files changed, 43 insertions(+), 13 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-05-11-15-58-23.gh-issue-149689.9Ht49z.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-11-15-58-23.gh-issue-149689.9Ht49z.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-11-15-58-23.gh-issue-149689.9Ht49z.rst new file mode 100644 index 00000000000000..aa672760730bd4 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-11-15-58-23.gh-issue-149689.9Ht49z.rst @@ -0,0 +1,2 @@ +Fix missing error propagation in parser action helpers when memory allocation +fails. Patch by Thomas Kowalski. diff --git a/Parser/action_helpers.c b/Parser/action_helpers.c index c74eb34deb7c35..381c173589904b 100644 --- a/Parser/action_helpers.c +++ b/Parser/action_helpers.c @@ -254,7 +254,11 @@ _set_seq_context(Parser *p, asdl_expr_seq *seq, expr_context_ty ctx) } for (Py_ssize_t i = 0; i < len; i++) { expr_ty e = asdl_seq_GET(seq, i); - asdl_seq_SET(new_seq, i, _PyPegen_set_expr_context(p, e, ctx)); + expr_ty new_e = _PyPegen_set_expr_context(p, e, ctx); + if (!new_e) { + return NULL; + } + asdl_seq_SET(new_seq, i, new_e); } return new_seq; } @@ -268,19 +272,21 @@ _set_name_context(Parser *p, expr_ty e, expr_context_ty ctx) static expr_ty _set_tuple_context(Parser *p, expr_ty e, expr_context_ty ctx) { - return _PyAST_Tuple( - _set_seq_context(p, e->v.Tuple.elts, ctx), - ctx, - EXTRA_EXPR(e, e)); + asdl_expr_seq *seq = _set_seq_context(p, e->v.Tuple.elts, ctx); + if (!seq && PyErr_Occurred()) { + return NULL; + } + return _PyAST_Tuple(seq, ctx, EXTRA_EXPR(e, e)); } static expr_ty _set_list_context(Parser *p, expr_ty e, expr_context_ty ctx) { - return _PyAST_List( - _set_seq_context(p, e->v.List.elts, ctx), - ctx, - EXTRA_EXPR(e, e)); + asdl_expr_seq *seq = _set_seq_context(p, e->v.List.elts, ctx); + if (!seq && PyErr_Occurred()) { + return NULL; + } + return _PyAST_List(seq, ctx, EXTRA_EXPR(e, e)); } static expr_ty @@ -300,8 +306,11 @@ _set_attribute_context(Parser *p, expr_ty e, expr_context_ty ctx) static expr_ty _set_starred_context(Parser *p, expr_ty e, expr_context_ty ctx) { - return _PyAST_Starred(_PyPegen_set_expr_context(p, e->v.Starred.value, ctx), - ctx, EXTRA_EXPR(e, e)); + expr_ty inner = _PyPegen_set_expr_context(p, e->v.Starred.value, ctx); + if (!inner) { + return NULL; + } + return _PyAST_Starred(inner, ctx, EXTRA_EXPR(e, e)); } /* Creates an `expr_ty` equivalent to `expr` but with `ctx` as context */ @@ -1168,7 +1177,14 @@ expr_ty _PyPegen_collect_call_seqs(Parser *p, asdl_expr_seq *a, asdl_seq *b, } asdl_expr_seq *starreds = _PyPegen_seq_extract_starred_exprs(p, b); + if (!starreds && PyErr_Occurred()) { + return NULL; + } + asdl_keyword_seq *keywords = _PyPegen_seq_delete_starred_exprs(p, b); + if (!keywords && PyErr_Occurred()) { + return NULL; + } if (starreds) { total_len += asdl_seq_LEN(starreds); @@ -1580,7 +1596,7 @@ expr_ty _PyPegen_interpolation(Parser *p, expr_ty expression, Token *debug, Resu end_col_offset, arena ); - if (!debug) { + if (!interpolation || !debug) { return interpolation; } @@ -1591,6 +1607,9 @@ expr_ty _PyPegen_interpolation(Parser *p, expr_ty expression, Token *debug, Resu } asdl_expr_seq *values = _Py_asdl_expr_seq_new(2, arena); + if (!values) { + return NULL; + } asdl_seq_SET(values, 0, debug_text); asdl_seq_SET(values, 1, interpolation); return _PyAST_JoinedStr(values, lineno, col_offset, debug_end_line, debug_end_offset, p->arena); @@ -1607,7 +1626,7 @@ expr_ty _PyPegen_formatted_value(Parser *p, expr_ty expression, Token *debug, Re end_col_offset, arena ); - if (!debug) { + if (!formatted_value || !debug) { return formatted_value; } @@ -1637,6 +1656,9 @@ expr_ty _PyPegen_formatted_value(Parser *p, expr_ty expression, Token *debug, Re } asdl_expr_seq *values = _Py_asdl_expr_seq_new(2, arena); + if (!values) { + return NULL; + } asdl_seq_SET(values, 0, debug_text); asdl_seq_SET(values, 1, formatted_value); return _PyAST_JoinedStr(values, lineno, col_offset, debug_end_line, debug_end_offset, p->arena); @@ -1904,6 +1926,9 @@ _build_concatenated_joined_str(Parser *p, asdl_expr_seq *strings, { asdl_expr_seq *values = _build_concatenated_str(p, strings, lineno, col_offset, end_lineno, end_col_offset, arena); + if (!values) { + return NULL; + } return _PyAST_JoinedStr(values, lineno, col_offset, end_lineno, end_col_offset, p->arena); } @@ -1914,6 +1939,9 @@ _PyPegen_concatenate_tstrings(Parser *p, asdl_expr_seq *strings, { asdl_expr_seq *values = _build_concatenated_str(p, strings, lineno, col_offset, end_lineno, end_col_offset, arena); + if (!values) { + return NULL; + } return _PyAST_TemplateStr(values, lineno, col_offset, end_lineno, end_col_offset, arena); } From 59616023b19a722b756f27f31af82f63f7e449d5 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 30 Jun 2026 10:57:58 +0200 Subject: [PATCH 510/818] [3.15] gh-152248: Reject a POSIX TZ abbreviation with non-ASCII-letters in pure-Python `zoneinfo` (GH-152249) (#152650) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (cherry picked from commit 449122ed0dbdb6a545af4927c59f4c80ee15c515) Co-authored-by: tonghuaroot (童话) <tonghuaroot@gmail.com> Co-authored-by: Stan Ulbrych <stan@python.org> --- Lib/test/test_zoneinfo/test_zoneinfo.py | 20 +++++++++++++++++-- Lib/zoneinfo/_zoneinfo.py | 4 ++-- ...-06-26-13-39-11.gh-issue-152248.N2Rmaf.rst | 3 +++ Modules/_zoneinfo.c | 3 +++ 4 files changed, 26 insertions(+), 4 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-06-26-13-39-11.gh-issue-152248.N2Rmaf.rst diff --git a/Lib/test/test_zoneinfo/test_zoneinfo.py b/Lib/test/test_zoneinfo/test_zoneinfo.py index cf3f82db75b0b6..813b56501308f9 100644 --- a/Lib/test/test_zoneinfo/test_zoneinfo.py +++ b/Lib/test/test_zoneinfo/test_zoneinfo.py @@ -1009,14 +1009,14 @@ def populate_tzstr_header(cls): cls._tzif_header = bytes(out) - def zone_from_tzstr(self, tzstr): + def zone_from_tzstr(self, tzstr, encoding="ascii"): """Creates a zoneinfo file following a POSIX rule.""" zonefile = io.BytesIO(self._tzif_header) zonefile.seek(0, 2) # Write the footer zonefile.write(b"\x0A") - zonefile.write(tzstr.encode("ascii")) + zonefile.write(tzstr.encode(encoding)) zonefile.write(b"\x0A") zonefile.seek(0) @@ -1150,6 +1150,13 @@ def test_invalid_tzstr(self): "+11", # Unquoted alphanumeric "GMT,M3.2.0/2,M11.1.0/3", # Transition rule but no DST "GMT0+11,M3.2.0/2,M11.1.0/3", # Unquoted alphanumeric in DST + # Unquoted abbreviation with embedded or leading whitespace + "AB C3", + " A B 3", + "AAA4BB B,J60/2,J300/2", # Embedded whitespace in DST + # Empty quoted abbreviation + "<>5", + "AAA4<>,M3.2.0/2,M11.1.0/3", "PST8PDT,M3.2.0/2", # Only one transition rule # Invalid offset hours "AAA168", @@ -1232,6 +1239,15 @@ def test_invalid_tzstr(self): with self.assertRaisesRegex(ValueError, tzstr_regex): self.zone_from_tzstr(invalid_tzstr) + def test_invalid_tzstr_non_ascii_abbr(self): + tzstr = "ABÀC3" + if self.module is py_zoneinfo: + expected = re.escape(tzstr) + else: + expected = re.escape(repr(tzstr.encode("utf-8"))) + with self.assertRaisesRegex(ValueError, expected): + self.zone_from_tzstr(tzstr, encoding="utf-8") + @classmethod def _populate_test_cases(cls): # This method uses a somewhat unusual style in that it populates the diff --git a/Lib/zoneinfo/_zoneinfo.py b/Lib/zoneinfo/_zoneinfo.py index 52832f600c3044..90cf2bbf8f5d0d 100644 --- a/Lib/zoneinfo/_zoneinfo.py +++ b/Lib/zoneinfo/_zoneinfo.py @@ -640,11 +640,11 @@ def _parse_tz_str(tz_str): parser_re = re.compile( r""" - (?P<std>[^<0-9:.+-]+|<[a-zA-Z0-9+-]+>) + (?P<std>[a-zA-Z]+|<[a-zA-Z0-9+-]+>) (?: (?P<stdoff>[+-]?\d{1,3}(?::\d{2}(?::\d{2})?)?) (?: - (?P<dst>[^0-9:.+-]+|<[a-zA-Z0-9+-]+>) + (?P<dst>[a-zA-Z]+|<[a-zA-Z0-9+-]+>) (?P<dstoff>[+-]?\d{1,3}(?::\d{2}(?::\d{2})?)?)? )? # dst )? # stdoff diff --git a/Misc/NEWS.d/next/Library/2026-06-26-13-39-11.gh-issue-152248.N2Rmaf.rst b/Misc/NEWS.d/next/Library/2026-06-26-13-39-11.gh-issue-152248.N2Rmaf.rst new file mode 100644 index 00000000000000..8921ad17349e97 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-26-13-39-11.gh-issue-152248.N2Rmaf.rst @@ -0,0 +1,3 @@ +Make the C and pure-Python :mod:`zoneinfo` parsers validate POSIX TZ +abbreviations consistently, rejecting unquoted abbreviations with non-letter +characters and empty quoted abbreviations. Patch by tonghuaroot. diff --git a/Modules/_zoneinfo.c b/Modules/_zoneinfo.c index eaffd020ed97c0..2a7ac4498261e0 100644 --- a/Modules/_zoneinfo.c +++ b/Modules/_zoneinfo.c @@ -1762,6 +1762,9 @@ parse_abbr(const char **p, PyObject **abbr) ptr++; } str_end = ptr; + if (str_end == str_start) { + return -1; + } ptr++; } else { From 3b1f6eef837c2e4ab364aed12f23bbc12b513a6d Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 30 Jun 2026 11:16:59 +0200 Subject: [PATCH 511/818] [3.15] gh-133510: Add links to more info for the match statement in FAQ anwser (GH-133511) (#152656) (cherry picked from commit 77181570da2d6d8f7bfca39f438ef0a893a30567) Co-authored-by: xzkdeng <xzkdeng@gmail.com> Co-authored-by: sobolevn <mail@sobolevn.me> Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Co-authored-by: Stan Ulbrych <89152624+StanFromIreland@users.noreply.github.com> Co-authored-by: Stan Ulbrych <stan@python.org> --- Doc/faq/design.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Doc/faq/design.rst b/Doc/faq/design.rst index ac0aa81e56bb07..c914089e9806ec 100644 --- a/Doc/faq/design.rst +++ b/Doc/faq/design.rst @@ -263,6 +263,8 @@ In general, structured switch statements execute one block of code when an expression has a particular value or set of values. Since Python 3.10 one can easily match literal values, or constants within a namespace, with a ``match ... case`` statement. +See :ref:`the specification <match>` and :ref:`the tutorial <tut-match>` +for more information about :keyword:`match` statements. An older alternative is a sequence of ``if... elif... elif... else``. For cases where you need to choose from a very large number of possibilities, From 86a836aab198e9cf1f3ddd618046024fe882a07f Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 30 Jun 2026 12:14:56 +0200 Subject: [PATCH 512/818] [3.15] gh-50966: Fix unbounded recursion in turtle drag handlers (GH-152626) (GH-152657) TurtleScreenBase._update() redraws with cv.update(), which also reprocesses input events, so a handler that moves the turtle (such as screen.ondrag(turtle.goto)) reenters _update() for every queued event until the interpreter crashes. A reentrant _update() now only flushes drawing with update_idletasks(). (cherry picked from commit 6f103fab178c07cbb5f701b8ad97e275b6eb6c4c) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --- Lib/test/test_turtle.py | 22 +++++++++++++++++++ Lib/turtle.py | 12 +++++++++- ...6-06-29-22-16-57.gh-issue-50966.Tq5mLp.rst | 3 +++ 3 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2026-06-29-22-16-57.gh-issue-50966.Tq5mLp.rst diff --git a/Lib/test/test_turtle.py b/Lib/test/test_turtle.py index 12d2eed874148c..c49ce9cdb6f6d9 100644 --- a/Lib/test/test_turtle.py +++ b/Lib/test/test_turtle.py @@ -577,6 +577,28 @@ def test_no_animation_calls_update_at_exit(self): s.update.assert_not_called() s.update.assert_called_once() + def test_update_is_not_reentrant(self): + # ondrag(goto) reenters _update() while cv.update() processes events; + # without a guard this recurses without bound (gh-50966). + s = turtle.TurtleScreen(cv=unittest.mock.MagicMock()) + depth = max_depth = 0 + + def reenter(): + nonlocal depth, max_depth + depth += 1 + max_depth = max(max_depth, depth) + if depth < 50: + s._update() # as an event handler would + depth -= 1 + + s.cv.update.reset_mock() # ignore calls made during construction + s.cv.update.side_effect = reenter + s._update() + # cv.update() runs once; reentrant calls only flush idle tasks. + self.assertEqual(s.cv.update.call_count, 1) + self.assertEqual(max_depth, 1) + self.assertTrue(s.cv.update_idletasks.called) + class TestTurtle(unittest.TestCase): def setUp(self): diff --git a/Lib/turtle.py b/Lib/turtle.py index ae5be9fe7039d5..af2c7448a0af17 100644 --- a/Lib/turtle.py +++ b/Lib/turtle.py @@ -486,6 +486,7 @@ def __init__(self, cv): self.canvwidth = w self.canvheight = h self.xscale = self.yscale = 1.0 + self._updating = False def _createpoly(self): """Create an invisible polygon item on canvas self.cv) @@ -555,7 +556,16 @@ def _delete(self, item): def _update(self): """Redraw graphics items on canvas """ - self.cv.update() + if self._updating: + # Reentrant call (e.g. a drag handler moving the turtle, + # gh-50966): flush drawing without reprocessing input. + self.cv.update_idletasks() + return + self._updating = True + try: + self.cv.update() + finally: + self._updating = False def _delay(self, delay): """Delay subsequent canvas actions for delay ms.""" diff --git a/Misc/NEWS.d/next/Library/2026-06-29-22-16-57.gh-issue-50966.Tq5mLp.rst b/Misc/NEWS.d/next/Library/2026-06-29-22-16-57.gh-issue-50966.Tq5mLp.rst new file mode 100644 index 00000000000000..96a0938c02d226 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-29-22-16-57.gh-issue-50966.Tq5mLp.rst @@ -0,0 +1,3 @@ +Fix unbounded recursion in :mod:`turtle` when a mouse event handler that moves +the turtle is reentered while the screen is being redrawn, for example with +``screen.ondrag(turtle.goto)``. This could previously crash the interpreter. From 3e286f7384c7f08183bd6f76d2adb85e1484cc0b Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 30 Jun 2026 12:16:15 +0200 Subject: [PATCH 513/818] [3.15] Don't require the `_test{internal}capi` modules in `test_monitoring.py` (GH-152311) (#152660) (cherry picked from commit 189ab8388762c8102b2d72ad3a1a921f7f2aef10) Co-authored-by: Shahar Naveh <50263213+ShaharNaveh@users.noreply.github.com> Co-authored-by: Stan Ulbrych <stan@python.org> --- Lib/test/test_monitoring.py | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/Lib/test/test_monitoring.py b/Lib/test/test_monitoring.py index b8861d09e1564b..5c2d69934b02ea 100644 --- a/Lib/test/test_monitoring.py +++ b/Lib/test/test_monitoring.py @@ -14,9 +14,6 @@ import test.support from test.support import import_helper, requires_specialization, script_helper -_testcapi = import_helper.import_module("_testcapi") -_testinternalcapi = import_helper.import_module("_testinternalcapi") - PAIR = (0,1) def f1(): @@ -867,6 +864,8 @@ def test_implicit_stop_iteration(self): This test checks that both paths record an equivalent event. """ + _testinternalcapi = import_helper.import_module("_testinternalcapi") + def gen(): yield 1 return 2 @@ -1034,6 +1033,8 @@ def func(): @requires_specialization def test_no_unwind_for_shim_frame(self): + _testinternalcapi = import_helper.import_module("_testinternalcapi") + class ValueErrorRaiser: def __init__(self): raise ValueError() @@ -2455,6 +2456,7 @@ def run(): sys.monitoring.set_events(TEST_TOOL, 0) def test_108390(self): + _testinternalcapi = import_helper.import_module("_testinternalcapi") class Foo: def __init__(self, set_event): @@ -2546,6 +2548,8 @@ def test_func(x): class TestTier2Optimizer(CheckEvents): def test_monitoring_already_opimized_loop(self): + _testinternalcapi = import_helper.import_module("_testinternalcapi") + def test_func(recorder): set_events = sys.monitoring.set_events line = E.LINE @@ -2582,18 +2586,20 @@ class TestCApiEventGeneration(MonitoringTestBase, unittest.TestCase): class Scope: def __init__(self, *args): + self._testcapi = import_helper.import_module("_testcapi") self.args = args def __enter__(self): - _testcapi.monitoring_enter_scope(*self.args) + self._testcapi.monitoring_enter_scope(*self.args) def __exit__(self, *args): - _testcapi.monitoring_exit_scope() + self._testcapi.monitoring_exit_scope() def setUp(self): super(TestCApiEventGeneration, self).setUp() - capi = _testcapi + self._testcapi = import_helper.import_module("_testcapi") + capi = self._testcapi self.codelike = capi.CodeLike(2) @@ -2662,7 +2668,7 @@ def __call__(self, *args): def test_fire_event(self): for expected, event, function, *args in self.cases: offset = 0 - self.codelike = _testcapi.CodeLike(1) + self.codelike = self._testcapi.CodeLike(1) with self.subTest(function.__name__): args_ = (self.codelike, offset) + tuple(args) self.check_event_count(event, function, args_, expected) @@ -2673,7 +2679,7 @@ def test_missing_exception(self): continue assert args and isinstance(args[-1], BaseException) offset = 0 - self.codelike = _testcapi.CodeLike(1) + self.codelike = self._testcapi.CodeLike(1) with self.subTest(function.__name__): args_ = (self.codelike, offset) + tuple(args[:-1]) + (None,) evt = int(math.log2(event)) @@ -2683,7 +2689,7 @@ def test_missing_exception(self): def test_fire_event_failing_callback(self): for expected, event, function, *args in self.cases: offset = 0 - self.codelike = _testcapi.CodeLike(1) + self.codelike = self._testcapi.CodeLike(1) with self.subTest(function.__name__): args_ = (self.codelike, offset) + tuple(args) exc = OSError(42) @@ -2733,12 +2739,14 @@ def check_disable(self, event, func, args, expected): def test_disable_event(self): for expected, event, function, *args in self.cases: offset = 0 - self.codelike = _testcapi.CodeLike(2) + self.codelike = self._testcapi.CodeLike(2) with self.subTest(function.__name__): args_ = (self.codelike, 0) + tuple(args) self.check_disable(event, function, args_, expected) def test_enter_scope_two_events(self): + _testcapi = self._testcapi + try: yield_counter = CounterWithDisable() unwind_counter = CounterWithDisable() From 0d76fdb0647dbcb11ef6129289eec4ba9784c5d0 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 30 Jun 2026 13:24:17 +0200 Subject: [PATCH 514/818] [3.15] gh-152635: Raise MemoryError when the lock allocation fails in `_interpchannels.create()` (GH-152642) (#152671) gh-152635: Raise MemoryError when the lock allocation fails in `_interpchannels.create()` (GH-152642) Previously, an allocation failure when creating the lock for a channel in `_interpchannels` would trigger an assert. Caused by `handle_channel_error` being passed an error code of -1 which is only allowed if an exception has been set. (in this case, no exception was set) `channelsmod_create` now forwards the error code from `channel_create` which `handle_channel_error` already handled. (cherry picked from commit b383aa6e1a8ea53fdeed88c71fbc34d8b2d1fde9) Co-authored-by: Steve Stagg <stestagg@gmail.com> Co-authored-by: sobolevn <mail@sobolevn.me> --- .../2026-06-29-23-29-14.gh-issue-152635.O21J0O.rst | 2 ++ Modules/_interpchannelsmodule.c | 11 ++++------- 2 files changed, 6 insertions(+), 7 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-29-23-29-14.gh-issue-152635.O21J0O.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-29-23-29-14.gh-issue-152635.O21J0O.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-29-23-29-14.gh-issue-152635.O21J0O.rst new file mode 100644 index 00000000000000..dadb25fc7c4477 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-29-23-29-14.gh-issue-152635.O21J0O.rst @@ -0,0 +1,2 @@ +Fix a crash caused when running out of memory creating a +:mod:`!_interpchannels` channel. Now a :exc:`MemoryError` is correctly raised. diff --git a/Modules/_interpchannelsmodule.c b/Modules/_interpchannelsmodule.c index 05957081079d4a..358d51cf13f1af 100644 --- a/Modules/_interpchannelsmodule.c +++ b/Modules/_interpchannelsmodule.c @@ -354,7 +354,7 @@ clear_module_state(module_state *state) #define ERR_CHANNEL_INTERP_CLOSED -4 #define ERR_CHANNEL_EMPTY -5 #define ERR_CHANNEL_NOT_EMPTY -6 -#define ERR_CHANNEL_MUTEX_INIT -7 +#define ERR_CHANNEL_MUTEX_INIT -7 // currently unused #define ERR_CHANNELS_MUTEX_INIT -8 #define ERR_NO_NEXT_CHANNEL_ID -9 #define ERR_CHANNEL_CLOSED_WAITING -10 @@ -427,10 +427,6 @@ handle_channel_error(int err, PyObject *mod, int64_t cid) "if not empty (try force=True)", cid); } - else if (err == ERR_CHANNEL_MUTEX_INIT) { - PyErr_SetString(state->ChannelError, - "can't initialize mutex for new channel"); - } else if (err == ERR_CHANNELS_MUTEX_INIT) { PyErr_SetString(state->ChannelError, "can't initialize mutex for channel management"); @@ -1744,7 +1740,8 @@ channel_create(_channels *channels, struct _channeldefaults defaults) { PyThread_type_lock mutex = PyThread_allocate_lock(); if (mutex == NULL) { - return ERR_CHANNEL_MUTEX_INIT; + PyErr_NoMemory(); + return -1; } _channel_state *chan = _channel_new(mutex, defaults); if (chan == NULL) { @@ -2938,7 +2935,7 @@ channelsmod_create(PyObject *self, PyObject *args, PyObject *kwds) int64_t cid = channel_create(&_globals.channels, defaults); if (cid < 0) { - (void)handle_channel_error(-1, self, cid); + (void)handle_channel_error(cid, self, cid); return NULL; } module_state *state = get_module_state(self); From eebdbfdec524df8a6f42aed51fc52461b9ed49c2 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 30 Jun 2026 13:25:27 +0200 Subject: [PATCH 515/818] [3.15] gh-151029: Fix `test_remote_exec_deleted_static_executable` on static installed builds (GH-152653) (#152670) (cherry picked from commit 03efeef226b774f937056e95e0cdb8f7d37c6532) Co-authored-by: Stan Ulbrych <stan@python.org> --- Lib/test/test_sys.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index 049b36a82c8226..84bc428e196c3e 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -2292,8 +2292,8 @@ def test_remote_exec_deleted_libpython(self): def test_remote_exec_deleted_static_executable(self): """Test remote exec when the target static executable was deleted.""" build_dir = sysconfig.get_config_var('abs_builddir') - srcdir = sysconfig.get_config_var('srcdir') - if not build_dir or not srcdir: + stdlib_dir = os.path.dirname(os.path.abspath(os.__file__)) + if not build_dir or not os.path.isdir(stdlib_dir): self.skipTest('cannot determine build-tree locations') pybuilddir_txt = os.path.join(build_dir, 'pybuilddir.txt') @@ -2310,8 +2310,7 @@ def test_remote_exec_deleted_static_executable(self): copied_build_dir = os.path.join(copied_root, 'build') copied_pybuilddir = os.path.join(copied_build_dir, pybuilddir) os.makedirs(os.path.dirname(copied_pybuilddir)) - os.symlink(os.path.join(srcdir, 'Lib'), - os.path.join(copied_root, 'Lib')) + os.symlink(stdlib_dir, os.path.join(copied_root, 'Lib')) os.symlink(source_ext_dir, copied_pybuilddir) shutil.copy2(pybuilddir_txt, os.path.join(copied_build_dir, 'pybuilddir.txt')) From 0f3e91b1f87697fe143032577f3e2f0f964fe672 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 30 Jun 2026 13:56:43 +0200 Subject: [PATCH 516/818] [3.15] gh-151126: Fix a possible crash during the startup with no memory under `Py_STACKREF_DEBUG` (GH-152478) (#152677) gh-151126: Fix a possible crash during the startup with no memory under `Py_STACKREF_DEBUG` (GH-152478) (cherry picked from commit ecdef1773006529b0fea6639d0effeecbb41679c) Co-authored-by: sobolevn <mail@sobolevn.me> --- Python/pystate.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Python/pystate.c b/Python/pystate.c index b0c924adbe0fc2..8349df1b573952 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -655,6 +655,9 @@ init_interpreter(PyInterpreterState *interp, NULL, &alloc ); + if (interp->open_stackrefs_table == NULL) { + return _PyStatus_NO_MEMORY(); + } # ifdef Py_STACKREF_CLOSE_DEBUG interp->closed_stackrefs_table = _Py_hashtable_new_full( _Py_hashtable_hash_ptr, @@ -663,6 +666,9 @@ init_interpreter(PyInterpreterState *interp, NULL, &alloc ); + if (interp->closed_stackrefs_table == NULL) { + return _PyStatus_NO_MEMORY(); + } # endif _Py_stackref_associate(interp, Py_None, PyStackRef_None); _Py_stackref_associate(interp, Py_False, PyStackRef_False); From e9d064f395199a6e8509ff73b5111cff055e22d8 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 30 Jun 2026 17:47:12 +0200 Subject: [PATCH 517/818] [3.15] gh-152680: Detect container/VM in test.pythoninfo (GH-152668) (#152699) gh-152680: Detect container/VM in test.pythoninfo (GH-152668) On Apple, log the hardware model as "system.hardware". * Log the "CI", "IMAGE_OS_VERSION" and "container" environment variables. * Add run_command() and first_line() functions. (cherry picked from commit f1c536372199cfb9c2e7b360b7bf04208c9eee82) Co-authored-by: Victor Stinner <vstinner@python.org> --- Lib/test/pythoninfo.py | 175 +++++++++++++++++++++++++++-------------- 1 file changed, 116 insertions(+), 59 deletions(-) diff --git a/Lib/test/pythoninfo.py b/Lib/test/pythoninfo.py index a2767f3975bed2..d7fd98a8d4311d 100644 --- a/Lib/test/pythoninfo.py +++ b/Lib/test/pythoninfo.py @@ -9,6 +9,9 @@ MS_WINDOWS = (sys.platform == "win32") +APPLE = (sys.platform in ("darwin", "ios", "tvos", "watchos")) + +COMMAND_TIMEOUT = 60.0 def normalize_text(text): @@ -19,6 +22,16 @@ def normalize_text(text): return text.strip() +def first_line(text): + # Get the first line. Return text unchanged if it's empty. + lines = text.splitlines() + if lines: + return lines[0] + else: + # text is an empty string + return text + + def read_first_line(filename): # Get the first line of a text file and strip trailing spaces try: @@ -293,9 +306,11 @@ def format_groups(groups): "BUILDPYTHON", "CC", "CFLAGS", + "CI", "COLUMNS", "COMPUTERNAME", "COMSPEC", + "CONTAINER", "CPP", "CPPFLAGS", "DISPLAY", @@ -310,6 +325,7 @@ def format_groups(groups): "HOMEDRIVE", "HOMEPATH", "IDLESTARTUP", + "IMAGE_OS_VERSION", "IPHONEOS_DEPLOYMENT_TARGET", "LANG", "LDFLAGS", @@ -434,24 +450,47 @@ def format_attr(attr, value): info_add('readline.library', 'GNU readline') -def collect_gdb(info_add): +def run_command(cmd, check=True, **kwargs): import subprocess + timeout = COMMAND_TIMEOUT + cmd_str = ' '.join(cmd) try: - proc = subprocess.Popen(["gdb", "-nx", "--version"], + proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - universal_newlines=True) - version = proc.communicate()[0] - if proc.returncode: - # ignore gdb failure: test_gdb will log the error - return - except OSError: - return + stderr=subprocess.DEVNULL, + text=True, + **kwargs) + with proc: + try: + stdout = proc.communicate(timeout=timeout)[0] + except: + proc.kill() + proc.communicate() + raise - # Only keep the first line - version = version.splitlines()[0] - info_add('gdb_version', version) + if check and proc.returncode: + print(f"Command {cmd_str} failed with exit code {proc.returncode}") + return '' + + # Strip trailing spaces and newlines + stdout = stdout.rstrip() + return stdout + except FileNotFoundError: + return '' + except OSError as exc: + print(f"Command {cmd_str} failed with: {exc!r}") + return '' + except subprocess.TimeoutExpired: + print(f"Command {cmd_str}: timeout!") + return '' + + +def collect_gdb(info_add): + version = run_command(["gdb", "-nx", "--version"]) + if version: + # Only keep the first line + info_add('gdb_version', first_line(version)) def collect_tkinter(info_add): @@ -847,7 +886,6 @@ def collect_support_threading_helper(info_add): def collect_cc(info_add): - import subprocess import sysconfig CC = sysconfig.get_config_var('CC') @@ -860,23 +898,17 @@ def collect_cc(info_add): except ImportError: args = CC.split() args.append('--version') - try: - proc = subprocess.Popen(args, - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT, - universal_newlines=True) - except OSError: + + stdout = run_command(args) + if not stdout: # Cannot run the compiler, for example when Python has been # cross-compiled and installed on the target platform where the # compiler is missing. - return - - stdout = proc.communicate()[0] - if proc.returncode: + # # CC --version failed: ignore error return - text = stdout.splitlines()[0] + text = first_line(stdout) text = normalize_text(text) info_add('CC.version', text) @@ -978,21 +1010,11 @@ def collect_windows(info_add): call_func(info_add, 'windows.oem_code_page', _winapi, 'GetOEMCP') # windows.version_caption: "wmic os get Caption,Version /value" command - import subprocess - try: - # When wmic.exe output is redirected to a pipe, - # it uses the OEM code page - proc = subprocess.Popen(["wmic", "os", "get", "Caption,Version", "/value"], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - encoding="oem", - text=True) - output, stderr = proc.communicate() - if proc.returncode: - output = "" - except OSError: - pass - else: + output = run_command(["wmic", "os", "get", "Caption,Version", "/value"], + # When wmic.exe output is redirected to a pipe, + # it uses the OEM code page + encoding="oem") + if output: for line in output.splitlines(): line = line.strip() if line.startswith('Caption='): @@ -1005,23 +1027,11 @@ def collect_windows(info_add): info_add('windows.version', line) # windows.ver: "ver" command - try: - proc = subprocess.Popen(["ver"], shell=True, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - text=True) - output = proc.communicate()[0] - if proc.returncode == 0xc0000142: - return - if proc.returncode: - output = "" - except OSError: - return - else: - output = output.strip() - line = output.splitlines()[0] - if line: - info_add('windows.ver', line) + output = run_command(["ver"], shell=True) + # "ver" output starts with an empty line: remove it + output = output.strip() + if output: + info_add('windows.ver', first_line(output)) # windows.developer_mode: get AllowDevelopmentWithoutDevLicense registry value = winreg_query(r"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows" @@ -1132,7 +1142,45 @@ def get_machine_id(): return None -def collect_linux(info_add): +def detect_virt(): + # Run systemd-detect-virt command + virt = run_command(["systemd-detect-virt"], check=False) + if virt and virt != "none": + return virt + + # Check if the process in running in a container + import os.path + if os.path.exists('/.dockerenv'): + return 'docker' + if os.path.exists('/run/.containerenv'): + return 'podman' + + container = read_first_line('/run/systemd/container') + if container: + return container + + if APPLE: + hv_vmm_present = run_command(['sysctl', '-n', 'kern.hv_vmm_present']) + if hv_vmm_present == '1': + return 'run in a VM (kern.hv_vmm_present is 1)' + + # Other ways to check if running in a container: + # * Parse /proc/1/mounts or /proc/1/mountinfo (check "/" filesystem). + # * Parse /proc/1/cgroup. + # * Parse the first line of /proc/1/sched (check process name is different + # than "init" and "systemd"). + # * Check / inode. + # * On systems using SELinux (Fedora/CentOS/RHEL), check for "container_t" + # label, for example of /proc/1/attr/current. + # * Check for "container" variable in /proc/1/environ + # (only root can read this file). + # * Check for "container" environment variable. + # * Set a specific env var when creating the container image. + # * Run virt-what, need to install the script, and must be run as root. + # * Check for "GITHUB_ACTIONS" environmant variable (GitHub Action). + + +def collect_system(info_add): boot_id = read_first_line("/proc/sys/kernel/random/boot_id") if boot_id: info_add('system.boot_id', boot_id) @@ -1152,6 +1200,15 @@ def collect_linux(info_add): uptime = f'{uptime} sec' info_add('system.uptime', uptime) + virt = detect_virt() + if virt: + info_add('system.virt', virt) + + if APPLE: + hardware = run_command(['sysctl', '-n', 'hw.model']) + if hardware: + info_add('system.hardware', hardware) + def collect_info(info): error = False @@ -1194,7 +1251,7 @@ def collect_info(info): collect_zlib, collect_zstd, collect_libregrtest_utils, - collect_linux, + collect_system, # Collecting from tests should be last as they have side effects. collect_test_socket, From 83391ceff61bdc5d0ba994cdae23f1406885825c Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka <storchaka@gmail.com> Date: Tue, 30 Jun 2026 23:59:28 +0300 Subject: [PATCH 518/818] [3.15] gh-152502: Detect the curses mouse interface portably (GH-152705) (GH-152707) The mouse interface (getmouse(), the BUTTON* constants, ...) was gated on the ncurses-specific NCURSES_MOUSE_VERSION macro, so it was dropped on other curses implementations that provide it, such as NetBSD curses and PDCurses. Gate it instead on a configure capability probe or the PDCURSES macro. Probe for getmouse() with its X/Open getmouse(MEVENT *) signature, since PDCurses declares an incompatible getmouse(void) unless built for the ncurses mouse API, which PDC_NCMOUSE now always selects. (cherry picked from commit 7bbea4f4868ef89b07b986d7a0d4b585e8271f27) Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --- Include/py_curses.h | 7 +++ ...-06-30-21-40-00.gh-issue-152502.Kq3Vn7.rst | 5 ++ Modules/_cursesmodule.c | 10 ++-- Modules/clinic/_cursesmodule.c.h | 22 ++++---- configure | 51 +++++++++++++++++++ configure.ac | 12 +++++ pyconfig.h.in | 3 ++ 7 files changed, 94 insertions(+), 16 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-06-30-21-40-00.gh-issue-152502.Kq3Vn7.rst diff --git a/Include/py_curses.h b/Include/py_curses.h index 0948aabedd4993..1127f1ea263e40 100644 --- a/Include/py_curses.h +++ b/Include/py_curses.h @@ -36,6 +36,13 @@ #define NCURSES_OPAQUE 0 #endif +/* PDCurses exposes its ncurses-compatible mouse API, the one this module uses, + only when this is defined before the curses header is included below. + Ignored by other curses implementations. */ +#ifndef PDC_NCMOUSE +# define PDC_NCMOUSE +#endif + #if defined(HAVE_NCURSESW_NCURSES_H) # include <ncursesw/ncurses.h> #elif defined(HAVE_NCURSESW_CURSES_H) diff --git a/Misc/NEWS.d/next/Library/2026-06-30-21-40-00.gh-issue-152502.Kq3Vn7.rst b/Misc/NEWS.d/next/Library/2026-06-30-21-40-00.gh-issue-152502.Kq3Vn7.rst new file mode 100644 index 00000000000000..815bc47966c40c --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-30-21-40-00.gh-issue-152502.Kq3Vn7.rst @@ -0,0 +1,5 @@ +Detect the :mod:`curses` mouse interface (:func:`~curses.getmouse`, the +``BUTTON*`` constants, and others) with a configure capability probe or library +macros instead of gating it on ncurses-specific macros. It is now also +available with other curses implementations that provide it, such as NetBSD +curses and PDCurses (the latter underpins ``windows-curses``). diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index f474174ef7c9dd..dd5af63fcc8a46 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -1681,7 +1681,7 @@ _curses_window_echochar_impl(PyCursesWindowObject *self, PyObject *ch, return curses_window_check_err(self, rtn, funcname, "echochar"); } -#ifdef NCURSES_MOUSE_VERSION +#if defined(HAVE_CURSES_GETMOUSE) || defined(PDCURSES) /*[clinic input] @permit_long_summary _curses.window.enclose @@ -3532,7 +3532,7 @@ _curses_getsyx_impl(PyObject *module) } #endif -#ifdef NCURSES_MOUSE_VERSION +#if defined(HAVE_CURSES_GETMOUSE) || defined(PDCURSES) /*[clinic input] _curses.getmouse @@ -4253,7 +4253,7 @@ _curses_meta_impl(PyObject *module, int yes) return curses_check_err(module, meta(stdscr, yes), "meta", NULL); } -#ifdef NCURSES_MOUSE_VERSION +#if defined(HAVE_CURSES_GETMOUSE) || defined(PDCURSES) /*[clinic input] _curses.mouseinterval @@ -5685,7 +5685,7 @@ cursesmodule_exec(PyObject *module) SetDictInt("COLOR_CYAN", COLOR_CYAN); SetDictInt("COLOR_WHITE", COLOR_WHITE); -#ifdef NCURSES_MOUSE_VERSION +#if defined(HAVE_CURSES_GETMOUSE) || defined(PDCURSES) /* Mouse-related constants */ SetDictInt("BUTTON1_PRESSED", BUTTON1_PRESSED); SetDictInt("BUTTON1_RELEASED", BUTTON1_RELEASED); @@ -5711,7 +5711,7 @@ cursesmodule_exec(PyObject *module) SetDictInt("BUTTON4_DOUBLE_CLICKED", BUTTON4_DOUBLE_CLICKED); SetDictInt("BUTTON4_TRIPLE_CLICKED", BUTTON4_TRIPLE_CLICKED); -#if NCURSES_MOUSE_VERSION > 1 +#ifdef BUTTON5_PRESSED SetDictInt("BUTTON5_PRESSED", BUTTON5_PRESSED); SetDictInt("BUTTON5_RELEASED", BUTTON5_RELEASED); SetDictInt("BUTTON5_CLICKED", BUTTON5_CLICKED); diff --git a/Modules/clinic/_cursesmodule.c.h b/Modules/clinic/_cursesmodule.c.h index 9235586587e876..0d2237241260eb 100644 --- a/Modules/clinic/_cursesmodule.c.h +++ b/Modules/clinic/_cursesmodule.c.h @@ -683,7 +683,7 @@ _curses_window_echochar(PyObject *self, PyObject *const *args, Py_ssize_t nargs) return return_value; } -#if defined(NCURSES_MOUSE_VERSION) +#if (defined(HAVE_CURSES_GETMOUSE) || defined(PDCURSES)) PyDoc_STRVAR(_curses_window_enclose__doc__, "enclose($self, y, x, /)\n" @@ -726,7 +726,7 @@ _curses_window_enclose(PyObject *self, PyObject *const *args, Py_ssize_t nargs) return return_value; } -#endif /* defined(NCURSES_MOUSE_VERSION) */ +#endif /* (defined(HAVE_CURSES_GETMOUSE) || defined(PDCURSES)) */ PyDoc_STRVAR(_curses_window_getbkgd__doc__, "getbkgd($self, /)\n" @@ -2307,7 +2307,7 @@ _curses_getsyx(PyObject *module, PyObject *Py_UNUSED(ignored)) #endif /* defined(getsyx) */ -#if defined(NCURSES_MOUSE_VERSION) +#if (defined(HAVE_CURSES_GETMOUSE) || defined(PDCURSES)) PyDoc_STRVAR(_curses_getmouse__doc__, "getmouse($module, /)\n" @@ -2330,9 +2330,9 @@ _curses_getmouse(PyObject *module, PyObject *Py_UNUSED(ignored)) return _curses_getmouse_impl(module); } -#endif /* defined(NCURSES_MOUSE_VERSION) */ +#endif /* (defined(HAVE_CURSES_GETMOUSE) || defined(PDCURSES)) */ -#if defined(NCURSES_MOUSE_VERSION) +#if (defined(HAVE_CURSES_GETMOUSE) || defined(PDCURSES)) PyDoc_STRVAR(_curses_ungetmouse__doc__, "ungetmouse($module, id, x, y, z, bstate, /)\n" @@ -2419,7 +2419,7 @@ _curses_ungetmouse(PyObject *module, PyObject *const *args, Py_ssize_t nargs) return return_value; } -#endif /* defined(NCURSES_MOUSE_VERSION) */ +#endif /* (defined(HAVE_CURSES_GETMOUSE) || defined(PDCURSES)) */ PyDoc_STRVAR(_curses_getwin__doc__, "getwin($module, file, /)\n" @@ -3116,7 +3116,7 @@ _curses_meta(PyObject *module, PyObject *arg) return return_value; } -#if defined(NCURSES_MOUSE_VERSION) +#if (defined(HAVE_CURSES_GETMOUSE) || defined(PDCURSES)) PyDoc_STRVAR(_curses_mouseinterval__doc__, "mouseinterval($module, interval, /)\n" @@ -3153,9 +3153,9 @@ _curses_mouseinterval(PyObject *module, PyObject *arg) return return_value; } -#endif /* defined(NCURSES_MOUSE_VERSION) */ +#endif /* (defined(HAVE_CURSES_GETMOUSE) || defined(PDCURSES)) */ -#if defined(NCURSES_MOUSE_VERSION) +#if (defined(HAVE_CURSES_GETMOUSE) || defined(PDCURSES)) PyDoc_STRVAR(_curses_mousemask__doc__, "mousemask($module, newmask, /)\n" @@ -3206,7 +3206,7 @@ _curses_mousemask(PyObject *module, PyObject *arg) return return_value; } -#endif /* defined(NCURSES_MOUSE_VERSION) */ +#endif /* (defined(HAVE_CURSES_GETMOUSE) || defined(PDCURSES)) */ PyDoc_STRVAR(_curses_napms__doc__, "napms($module, ms, /)\n" @@ -4486,4 +4486,4 @@ _curses_has_extended_color_support(PyObject *module, PyObject *Py_UNUSED(ignored #ifndef _CURSES_ASSUME_DEFAULT_COLORS_METHODDEF #define _CURSES_ASSUME_DEFAULT_COLORS_METHODDEF #endif /* !defined(_CURSES_ASSUME_DEFAULT_COLORS_METHODDEF) */ -/*[clinic end generated code: output=7835b44ce9413f7f input=a9049054013a1b77]*/ +/*[clinic end generated code: output=c1b7520d331d3d61 input=a9049054013a1b77]*/ diff --git a/configure b/configure index d17240882ec956..b24bb35148beee 100755 --- a/configure +++ b/configure @@ -30610,6 +30610,57 @@ fi + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ncurses-style curses function getmouse" >&5 +printf %s "checking for ncurses-style curses function getmouse... " >&6; } +if test ${ac_cv_lib_curses_getmouse+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#define NCURSES_OPAQUE 0 +#if defined(HAVE_NCURSESW_NCURSES_H) +# include <ncursesw/ncurses.h> +#elif defined(HAVE_NCURSESW_CURSES_H) +# include <ncursesw/curses.h> +#elif defined(HAVE_NCURSES_NCURSES_H) +# include <ncurses/ncurses.h> +#elif defined(HAVE_NCURSES_CURSES_H) +# include <ncurses/curses.h> +#elif defined(HAVE_NCURSES_H) +# include <ncurses.h> +#elif defined(HAVE_CURSES_H) +# include <curses.h> +#endif + +int +main (void) +{ +MEVENT event; (void)getmouse(&event); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_lib_curses_getmouse=yes +else case e in #( + e) ac_cv_lib_curses_getmouse=no ;; +esac +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_curses_getmouse" >&5 +printf "%s\n" "$ac_cv_lib_curses_getmouse" >&6; } +if test "x$ac_cv_lib_curses_getmouse" = xyes +then : + +printf "%s\n" "#define HAVE_CURSES_GETMOUSE 1" >>confdefs.h + +fi CPPFLAGS=$ac_save_cppflags fi diff --git a/configure.ac b/configure.ac index 0cf3d3f24506fc..09a985dc9ce0d7 100644 --- a/configure.ac +++ b/configure.ac @@ -7287,6 +7287,18 @@ PY_CHECK_CURSES_FUNC([set_escdelay]) PY_CHECK_CURSES_FUNC([set_tabsize]) PY_CHECK_CURSES_VAR([ESCDELAY]) PY_CHECK_CURSES_VAR([TABSIZE]) + +dnl Probe for the X/Open getmouse(MEVENT *) signature specifically: PDCurses +dnl declares an incompatible getmouse(void) unless built for the ncurses mouse API. +AC_CACHE_CHECK([for ncurses-style curses function getmouse], + [ac_cv_lib_curses_getmouse], + [AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM(_CURSES_INCLUDES, [MEVENT event; (void)getmouse(&event);])], + [ac_cv_lib_curses_getmouse=yes], + [ac_cv_lib_curses_getmouse=no])]) +AS_VAR_IF([ac_cv_lib_curses_getmouse], [yes], + [AC_DEFINE([HAVE_CURSES_GETMOUSE], [1], + [Define if you have the 'getmouse' function with the X/Open signature.])]) CPPFLAGS=$ac_save_cppflags ])dnl have_curses != no ])dnl save env diff --git a/pyconfig.h.in b/pyconfig.h.in index 058fc9f0a42f5e..618e62bea0c26c 100644 --- a/pyconfig.h.in +++ b/pyconfig.h.in @@ -191,6 +191,9 @@ /* Define if you have the 'filter' function. */ #undef HAVE_CURSES_FILTER +/* Define if you have the 'getmouse' function with the X/Open signature. */ +#undef HAVE_CURSES_GETMOUSE + /* Define to 1 if you have the <curses.h> header file. */ #undef HAVE_CURSES_H From 81bfc9cc8613c7beacc335416940d9426b1e7f4e Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 1 Jul 2026 05:29:26 +0200 Subject: [PATCH 519/818] [3.15] gh-152711: Add pythoninfo-build command to Platforms/Android (GH-152713) (#152725) Add a pythoninfo-build command to Platforms/Android to display build info of the build Python. The command runs "make pythoninfo". ci and build commands now also run pythoninfo-build (cherry picked from commit fdcee4f5bd8d0dd852518ec9f092ac35ce9fd5d8) Co-authored-by: Victor Stinner <vstinner@python.org> --- Platforms/Android/__main__.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Platforms/Android/__main__.py b/Platforms/Android/__main__.py index 063e1f31603144..78f94b317ab047 100755 --- a/Platforms/Android/__main__.py +++ b/Platforms/Android/__main__.py @@ -207,6 +207,11 @@ def make_build_python(context): run(["make", "-j", str(os.cpu_count())]) +def pythoninfo_build_python(context): + os.chdir(subdir("build")) + run(["make", "pythoninfo"]) + + # To create new builds of these dependencies, usually all that's necessary is to # push a tag to the cpython-android-source-deps repository, and GitHub Actions # will do the rest. @@ -308,6 +313,7 @@ def build_targets(context): if context.target in {"all", "build"}: configure_build_python(context) make_build_python(context) + pythoninfo_build_python(context) for host in HOSTS: if context.target in {"all", "hosts", host}: @@ -819,6 +825,7 @@ def ci(context): for step in [ configure_build_python, make_build_python, + pythoninfo_build_python, configure_host_python, make_host_python, package, @@ -903,6 +910,8 @@ def add_parser(*args, **kwargs): "configure-build", help="Run `configure` for the build Python") add_parser( "make-build", help="Run `make` for the build Python") + add_parser( + "pythoninfo-build", help="Display build info of the build Python") configure_host = add_parser( "configure-host", help="Run `configure` for Android") make_host = add_parser( @@ -1019,6 +1028,7 @@ def main(): dispatch = { "configure-build": configure_build_python, "make-build": make_build_python, + "pythoninfo-build": pythoninfo_build_python, "configure-host": configure_host_python, "make-host": make_host_python, "build": build_targets, From fc8d7edd56951e7b015d6d6d33a80639196c1197 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 1 Jul 2026 05:29:44 +0200 Subject: [PATCH 520/818] [3.15] gh-152715: Add pythoninfo-build command to Platforms/Apple (GH-152716) (#152723) Add a pythoninfo-build command to Platforms/Apple to display build info of the build Python. The command runs "make pythoninfo". The "ci" and "build" commands now also run "pythoninfo-build". (cherry picked from commit 746c535a8e4cbf32af3d3ceba204c01d91614217) Co-authored-by: Victor Stinner <vstinner@python.org> --- Platforms/Apple/__main__.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/Platforms/Apple/__main__.py b/Platforms/Apple/__main__.py index 9f2d2afb0aa0f6..b294d2720a80df 100644 --- a/Platforms/Apple/__main__.py +++ b/Platforms/Apple/__main__.py @@ -272,6 +272,15 @@ def make_build_python(context: argparse.Namespace) -> None: run(["make", "-j", str(os.cpu_count())]) +def pythoninfo_build_python(context: argparse.Namespace) -> None: + """The implementation of the "pythoninfo-build" command.""" + with ( + group("Display build info of the build Python"), + cwd(subdir("build")), + ): + run(["make", "pythoninfo"]) + + def apple_target(host: str) -> str: """Return the Apple platform identifier for a given host triple.""" for _, platform_slices in HOSTS.items(): @@ -754,6 +763,7 @@ def build(context: argparse.Namespace, host: str | None = None) -> None: for step in [ configure_build_python, make_build_python, + pythoninfo_build_python, ]: step(context) @@ -909,6 +919,9 @@ def parse_args() -> argparse.Namespace: make_build = subcommands.add_parser( "make-build", help="Run `make` for the build Python" ) + pythoninfo_build = subcommands.add_parser( + "pythoninfo-build", help="Display build info of the build Python" + ) configure_host = subcommands.add_parser( "configure-host", help="Run `configure` for a specific platform and target", @@ -967,6 +980,7 @@ def parse_args() -> argparse.Namespace: clean, configure_build, make_build, + pythoninfo_build, configure_host, make_host, build, @@ -1078,6 +1092,7 @@ def signal_handler(*args): "clean": clean, "configure-build": configure_build_python, "make-build": make_build_python, + "pythoninfo-build": pythoninfo_build_python, "configure-host": configure_host_python, "make-host": make_host_python, "package": package, From 4bacb0ccef0e9908bec3ea6f391e7ffa4ff03c17 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 1 Jul 2026 07:57:17 +0200 Subject: [PATCH 521/818] [3.15] gh-151626: Fix tests that fail when PYTHONPYCACHEPREFIX is set (GH-151952) (#152736) gh-151626: Fix tests that fail when PYTHONPYCACHEPREFIX is set (GH-151952) Fix tests in test_compileall, test_import, test_importlib, test_py_compile, and test_inspect to neutralize PYTHONPYCACHEPREFIX (cherry picked from commit 564c58c718bc3de9cf3d9bc20cdc06317411c1cd) Co-authored-by: Jiucheng(Oliver) <git.jiucheng@gmail.com> --- Lib/test/test_compileall.py | 65 +++++++++++++------ Lib/test/test_import/__init__.py | 6 ++ Lib/test/test_importlib/test_util.py | 11 ++++ Lib/test/test_inspect/test_inspect.py | 23 ++++++- Lib/test/test_py_compile.py | 41 +++++++----- ...-06-22-19-45-00.gh-issue-151626.K9pZ2x.rst | 5 ++ 6 files changed, 112 insertions(+), 39 deletions(-) create mode 100644 Misc/NEWS.d/next/Tests/2026-06-22-19-45-00.gh-issue-151626.K9pZ2x.rst diff --git a/Lib/test/test_compileall.py b/Lib/test/test_compileall.py index b2150b621516ba..95dcb4ef9fdc20 100644 --- a/Lib/test/test_compileall.py +++ b/Lib/test/test_compileall.py @@ -554,6 +554,24 @@ def temporary_pycache_prefix(self): finally: sys.pycache_prefix = old_prefix + @contextlib.contextmanager + def no_pycache_prefix(self): + """Ignore any ambient pycache prefix for the duration of the test. + + Some tests assume bytecode is written next to the source in a + __pycache__ directory. When the test suite is run with + PYTHONPYCACHEPREFIX set, neutralize it both in this process (used by + cache_from_source) and in any spawned subprocesses. + """ + old_prefix = sys.pycache_prefix + sys.pycache_prefix = None + try: + with os_helper.EnvironmentVarGuard() as env: + env.unset('PYTHONPYCACHEPREFIX') + yield + finally: + sys.pycache_prefix = old_prefix + def _get_run_args(self, args): return [*support.optim_args_from_interpreter_flags(), '-S', '-m', 'compileall', @@ -650,15 +668,16 @@ def test_legacy_paths(self): def test_multiple_runs(self): # Bug 8527 reported that multiple calls produced empty # __pycache__/__pycache__ directories. - self.assertRunOK('-q', self.pkgdir) - # Verify the __pycache__ directory contents. - self.assertTrue(os.path.exists(self.pkgdir_cachedir)) - cachecachedir = os.path.join(self.pkgdir_cachedir, '__pycache__') - self.assertFalse(os.path.exists(cachecachedir)) - # Call compileall again. - self.assertRunOK('-q', self.pkgdir) - self.assertTrue(os.path.exists(self.pkgdir_cachedir)) - self.assertFalse(os.path.exists(cachecachedir)) + with self.no_pycache_prefix(): + self.assertRunOK('-q', self.pkgdir) + # Verify the __pycache__ directory contents. + self.assertTrue(os.path.exists(self.pkgdir_cachedir)) + cachecachedir = os.path.join(self.pkgdir_cachedir, '__pycache__') + self.assertFalse(os.path.exists(cachecachedir)) + # Call compileall again. + self.assertRunOK('-q', self.pkgdir) + self.assertTrue(os.path.exists(self.pkgdir_cachedir)) + self.assertFalse(os.path.exists(cachecachedir)) @without_source_date_epoch # timestamp invalidation test def test_force(self): @@ -731,10 +750,13 @@ def test_symlink_loop(self): script_helper.make_pkg(pkg) os.symlink('.', os.path.join(pkg, 'evil')) os.symlink('.', os.path.join(pkg, 'evil2')) - self.assertRunOK('-q', self.pkgdir) - self.assertCompiled(os.path.join( - self.pkgdir, 'spam', 'evil', 'evil2', '__init__.py' - )) + # This relies on the __pycache__ layout (shared across the symlinked + # paths), so neutralize any ambient PYTHONPYCACHEPREFIX. + with self.no_pycache_prefix(): + self.assertRunOK('-q', self.pkgdir) + self.assertCompiled(os.path.join( + self.pkgdir, 'spam', 'evil', 'evil2', '__init__.py' + )) def test_quiet(self): noisy = self.assertRunOK(self.pkgdir) @@ -821,13 +843,16 @@ def test_include_on_stdin(self): f2 = script_helper.make_script(self.pkgdir, 'f2', '') f3 = script_helper.make_script(self.pkgdir, 'f3', '') f4 = script_helper.make_script(self.pkgdir, 'f4', '') - p = script_helper.spawn_python(*(self._get_run_args(()) + ['-i', '-'])) - p.stdin.write((f3+os.linesep).encode('ascii')) - script_helper.kill_python(p) - self.assertNotCompiled(f1) - self.assertNotCompiled(f2) - self.assertCompiled(f3) - self.assertNotCompiled(f4) + # spawn_python() runs with -E, ignoring PYTHONPYCACHEPREFIX, so make + # cache_from_source() in this process agree by neutralizing it too. + with self.no_pycache_prefix(): + p = script_helper.spawn_python(*(self._get_run_args(()) + ['-i', '-'])) + p.stdin.write((f3+os.linesep).encode('ascii')) + script_helper.kill_python(p) + self.assertNotCompiled(f1) + self.assertNotCompiled(f2) + self.assertCompiled(f3) + self.assertNotCompiled(f4) def test_compiles_as_much_as_possible(self): bingfn = script_helper.make_script(self.pkgdir, 'bing', 'syntax(error') diff --git a/Lib/test/test_import/__init__.py b/Lib/test/test_import/__init__.py index 9f3df8010d3233..9f6dec7d1c5802 100644 --- a/Lib/test/test_import/__init__.py +++ b/Lib/test/test_import/__init__.py @@ -1669,6 +1669,11 @@ def _clean(self): unlink(self.source) def setUp(self): + # These tests assume bytecode is written next to the source in a + # local __pycache__ directory, so neutralize any pycache prefix (e.g. + # when the test suite is run with PYTHONPYCACHEPREFIX set). + self._orig_pycache_prefix = sys.pycache_prefix + sys.pycache_prefix = None self.source = TESTFN + '.py' self._clean() with open(self.source, 'w', encoding='utf-8') as fp: @@ -1680,6 +1685,7 @@ def tearDown(self): assert sys.path[0] == os.curdir, 'Unexpected sys.path[0]' del sys.path[0] self._clean() + sys.pycache_prefix = self._orig_pycache_prefix @skip_if_dont_write_bytecode def test_import_pyc_path(self): diff --git a/Lib/test/test_importlib/test_util.py b/Lib/test/test_importlib/test_util.py index a926a7a4d408af..8ec2dcd69e58b6 100644 --- a/Lib/test/test_importlib/test_util.py +++ b/Lib/test/test_importlib/test_util.py @@ -328,6 +328,17 @@ class PEP3147Tests: tag = sys.implementation.cache_tag + def setUp(self): + # Most of these tests assume the default (unset) pycache prefix, so + # clear it for the duration of the test (e.g. when the test suite is + # run with PYTHONPYCACHEPREFIX set). Tests that need a specific prefix + # set their own via util.temporary_pycache_prefix(). + self._orig_pycache_prefix = sys.pycache_prefix + sys.pycache_prefix = None + + def tearDown(self): + sys.pycache_prefix = self._orig_pycache_prefix + @unittest.skipIf(sys.implementation.cache_tag is None, 'requires sys.implementation.cache_tag not be None') def test_cache_from_source(self): diff --git a/Lib/test/test_inspect/test_inspect.py b/Lib/test/test_inspect/test_inspect.py index 7351f97fd9a4b5..1dcbadfb589ebf 100644 --- a/Lib/test/test_inspect/test_inspect.py +++ b/Lib/test/test_inspect/test_inspect.py @@ -7,6 +7,7 @@ import functools import gc import importlib +import importlib.util import inspect import io import linecache @@ -6519,6 +6520,19 @@ class TestModuleCLI(unittest.TestCase): NO_SOURCE_ERROR = "No source code available for defining module" NO_SOURCE_TARGET_ERROR = "Failed to retrieve source code for given target" + @staticmethod + def _expected_cached(module): + # assert_python_ok() runs the subprocess in isolated mode (-I), which + # ignores PYTHONPYCACHEPREFIX, so compute the expected cached path the + # same way (i.e. without any pycache prefix) to stay independent of the + # environment the test suite is run in. Modules without a cached path + # (e.g. frozen modules such as ntpath/importlib.machinery on Windows) + # report None, so preserve that. + if module.__spec__.cached is None: + return None + with support.swap_attr(sys, 'pycache_prefix', None): + return importlib.util.cache_from_source(module.__spec__.origin) + def test_only_source(self): module = importlib.import_module('unittest') rc, out, err = assert_python_ok('-m', 'inspect', @@ -6576,12 +6590,13 @@ def test_details_option_with_package(self): args = support.optim_args_from_interpreter_flags() rc, out, err = assert_python_ok(*args, '-m', 'inspect', module_name, '--details') + cached = self._expected_cached(module) # Full rendering check on the expected output expected_lines = [ f"Target: {module.__name__}", # No aliasing f"Origin: {module.__spec__.origin}", f"Source: {module.__file__}", - f"Cached: {module.__spec__.cached}", # None is still displayed + f"Cached: {cached}", # None is still displayed f"Loader: {_clean_object_ids(repr(module.__spec__.loader))}", f"Submodule search paths: {module.__path__}", "", @@ -6619,13 +6634,14 @@ def test_details_option_with_data_target(self): args = support.optim_args_from_interpreter_flags() rc, out, err = assert_python_ok(*args, '-m', 'inspect', cli_target, '--details') + cached = self._expected_cached(module) # Full rendering check on the expected output # The error is only informational when reading source details expected_lines = [ f"Target: {cli_target}", # No aliasing f"Origin: {module.__spec__.origin}", f"Source: {module.__file__}", - f"Cached: {module.__spec__.cached}", # None is still displayed + f"Cached: {cached}", # None is still displayed self.NO_SOURCE_TARGET_ERROR, "", ] @@ -6644,12 +6660,13 @@ def test_details_option_with_aliased_target(self): args = support.optim_args_from_interpreter_flags() rc, out, err = assert_python_ok(*args, '-m', 'inspect', cli_target, '--details') + cached = self._expected_cached(module) # Full rendering check on the expected output expected_lines = [ f'Target: {defining_target} (looked up as "{cli_target}")', f"Origin: {module.__spec__.origin}", f"Source: {module.__file__}", - f"Cached: {module.__spec__.cached}", # None is still displayed + f"Cached: {cached}", # None is still displayed f"Line: {inspect.findsource(target)[1]}", "", ] diff --git a/Lib/test/test_py_compile.py b/Lib/test/test_py_compile.py index da2d630d7ace7b..d8acd1f04356e7 100644 --- a/Lib/test/test_py_compile.py +++ b/Lib/test/test_py_compile.py @@ -186,21 +186,24 @@ def test_source_date_epoch(self): def test_double_dot_no_clobber(self): # http://bugs.python.org/issue22966 # py_compile foo.bar.py -> __pycache__/foo.cpython-34.pyc - weird_path = os.path.join(self.directory, 'foo.bar.py') - cache_path = importlib.util.cache_from_source(weird_path) - pyc_path = weird_path + 'c' - head, tail = os.path.split(cache_path) - penultimate_tail = os.path.basename(head) - self.assertEqual( - os.path.join(penultimate_tail, tail), - os.path.join( - '__pycache__', - 'foo.bar.{}.pyc'.format(sys.implementation.cache_tag))) - with open(weird_path, 'w') as file: - file.write('x = 123\n') - py_compile.compile(weird_path) - self.assertTrue(os.path.exists(cache_path)) - self.assertFalse(os.path.exists(pyc_path)) + # This test asserts the default __pycache__ layout, so neutralize any + # pycache prefix (e.g. when run with PYTHONPYCACHEPREFIX set). + with support.swap_attr(sys, 'pycache_prefix', None): + weird_path = os.path.join(self.directory, 'foo.bar.py') + cache_path = importlib.util.cache_from_source(weird_path) + pyc_path = weird_path + 'c' + head, tail = os.path.split(cache_path) + penultimate_tail = os.path.basename(head) + self.assertEqual( + os.path.join(penultimate_tail, tail), + os.path.join( + '__pycache__', + 'foo.bar.{}.pyc'.format(sys.implementation.cache_tag))) + with open(weird_path, 'w') as file: + file.write('x = 123\n') + py_compile.compile(weird_path) + self.assertTrue(os.path.exists(cache_path)) + self.assertFalse(os.path.exists(pyc_path)) @unittest.skipIf(sys.implementation.cache_tag is None, 'requires sys.implementation.cache_tag is not None') @@ -307,7 +310,13 @@ def test_with_files(self): self.assertEqual(rc, 0) self.assertEqual(stdout, b'') self.assertEqual(stderr, b'') - self.assertTrue(os.path.exists(self.cache_path)) + # pycompilecmd() runs the interpreter in isolated mode (-I), which + # ignores PYTHONPYCACHEPREFIX, so the bytecode is written next to the + # source. Compute the expected cache path the same way. + with support.swap_attr(sys, 'pycache_prefix', None): + cache_path = importlib.util.cache_from_source( + self.source_path, optimization='' if __debug__ else 1) + self.assertTrue(os.path.exists(cache_path)) def test_bad_syntax(self): bad_syntax = os.path.join(os.path.dirname(__file__), diff --git a/Misc/NEWS.d/next/Tests/2026-06-22-19-45-00.gh-issue-151626.K9pZ2x.rst b/Misc/NEWS.d/next/Tests/2026-06-22-19-45-00.gh-issue-151626.K9pZ2x.rst new file mode 100644 index 00000000000000..9858415018ae1b --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2026-06-22-19-45-00.gh-issue-151626.K9pZ2x.rst @@ -0,0 +1,5 @@ +Fix several tests in ``test.test_inspect``, ``test.test_import``, +``test.test_importlib``, ``test.test_py_compile`` and +``test.test_compileall`` that failed when the test suite was run with +:envvar:`PYTHONPYCACHEPREFIX` set. These tests now neutralize the pycache +prefix where they assume the default ``__pycache__`` bytecode layout. From f663e54dc402d304771be75eac41d5c44a73065b Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 1 Jul 2026 08:08:44 +0200 Subject: [PATCH 522/818] [3.15] gh-152728: IDLE - move 3 toplevel fix_xyz functions to idlelb.util (GH-152729) (#152730) gh-152728: IDLE - move 3 toplevel fix_xyz functions to idlelb.util (GH-152729) IDLE - move 3 toplevel fix_xyz functions to idlelb.util Move idlelib functions run.fix_scaling, editor.fixwordbreaks (as fix_word_breaks). All are used in at least 3 modules. (cherry picked from commit 53ca52ddb0c2725a1c34e4eb2245339cd3dcaa84) Co-authored-by: Terry Jan Reedy <tjreedy@udel.edu> --- Lib/idlelib/News3.txt | 3 ++ Lib/idlelib/editor.py | 17 +++------- Lib/idlelib/filelist.py | 6 ++-- Lib/idlelib/idle_test/test_editmenu.py | 4 +-- Lib/idlelib/idle_test/test_sidebar.py | 7 ++-- Lib/idlelib/pyshell.py | 22 ++++--------- Lib/idlelib/run.py | 13 ++------ Lib/idlelib/util.py | 33 +++++++++++++++++++ ...-07-01-00-15-58.gh-issue-152728.yxIhMN.rst | 2 ++ 9 files changed, 58 insertions(+), 49 deletions(-) create mode 100644 Misc/NEWS.d/next/IDLE/2026-07-01-00-15-58.gh-issue-152728.yxIhMN.rst diff --git a/Lib/idlelib/News3.txt b/Lib/idlelib/News3.txt index 97becb858fea33..dc18b6e07eb364 100644 --- a/Lib/idlelib/News3.txt +++ b/Lib/idlelib/News3.txt @@ -4,6 +4,9 @@ Released on 2026-10-01 ========================= +gh-152728: Move functions run.fix_scaling, editor.fixwordbreaks (as fix_word_breaks) +and pyshell.fix_x11_paste to module util. Patch by Terry J. Reedy. + gh-85320: IDLE now reads and writes its configuration files and the breakpoints file using UTF-8 instead of the locale encoding. Files with non-ASCII characters and non-UTF-8 encoding may need diff --git a/Lib/idlelib/editor.py b/Lib/idlelib/editor.py index 239bf5af470567..a040d791bdeb52 100644 --- a/Lib/idlelib/editor.py +++ b/Lib/idlelib/editor.py @@ -1704,19 +1704,10 @@ def get_accelerator(keydefs, eventname): return s -def fixwordbreaks(root): - # On Windows, tcl/tk breaks 'words' only on spaces, as in Command Prompt. - # We want Motif style everywhere. See #21474, msg218992 and followup. - tk = root.tk - tk.call('tcl_wordBreakAfter', 'a b', 0) # make sure word.tcl is loaded - tk.call('set', 'tcl_wordchars', r'\w') - tk.call('set', 'tcl_nonwordchars', r'\W') - - -def _editor_window(parent): # htest # - # error if close master window first - timer event, after script - root = parent - fixwordbreaks(root) +def _editor_window(root): # htest # + # Error if close master window first - timer event, after script + from util import fix_word_breaks + fix_word_breaks(root) if sys.argv[1:]: filename = sys.argv[1] else: diff --git a/Lib/idlelib/filelist.py b/Lib/idlelib/filelist.py index e27e5d32a0ff63..384908f911f515 100644 --- a/Lib/idlelib/filelist.py +++ b/Lib/idlelib/filelist.py @@ -112,12 +112,12 @@ def canonize(self, filename): def _test(): # TODO check and convert to htest + # Maybe redundant with test_filelist.FileListTest.test_new_empty. from tkinter import Tk - from idlelib.editor import fixwordbreaks - from idlelib.run import fix_scaling + from idlelib.util import fix_scaling, fix_word_breaks root = Tk() fix_scaling(root) - fixwordbreaks(root) + fix_word_breaks(root) root.withdraw() flist = FileList(root) flist.new() diff --git a/Lib/idlelib/idle_test/test_editmenu.py b/Lib/idlelib/idle_test/test_editmenu.py index 17478473a3d1b2..0d1eb9054918da 100644 --- a/Lib/idlelib/idle_test/test_editmenu.py +++ b/Lib/idlelib/idle_test/test_editmenu.py @@ -7,7 +7,7 @@ import tkinter as tk from tkinter import ttk import unittest -from idlelib import pyshell +from idlelib.util import fix_x11_paste class PasteTest(unittest.TestCase): '''Test pasting into widgets that allow pasting. @@ -18,7 +18,7 @@ class PasteTest(unittest.TestCase): def setUpClass(cls): cls.root = root = tk.Tk() cls.root.withdraw() - pyshell.fix_x11_paste(root) + fix_x11_paste(root) cls.text = tk.Text(root) cls.entry = tk.Entry(root) cls.tentry = ttk.Entry(root) diff --git a/Lib/idlelib/idle_test/test_sidebar.py b/Lib/idlelib/idle_test/test_sidebar.py index 4157a4b4dcdd2a..dc3431d8d8ef88 100644 --- a/Lib/idlelib/idle_test/test_sidebar.py +++ b/Lib/idlelib/idle_test/test_sidebar.py @@ -11,11 +11,10 @@ from idlelib.idle_test.tkinter_testing_utils import run_in_tk_mainloop from idlelib.delegator import Delegator -from idlelib.editor import fixwordbreaks from idlelib.percolator import Percolator import idlelib.pyshell -from idlelib.pyshell import fix_x11_paste, PyShell, PyShellFileList -from idlelib.run import fix_scaling +from idlelib.pyshell import PyShell, PyShellFileList +from idlelib.util import fix_scaling, fix_word_breaks, fix_x11_paste import idlelib.sidebar from idlelib.sidebar import get_end_linenumber, get_lineno @@ -403,7 +402,7 @@ def setUpClass(cls): root.withdraw() fix_scaling(root) - fixwordbreaks(root) + fix_word_breaks(root) fix_x11_paste(root) cls.flist = flist = PyShellFileList(root) diff --git a/Lib/idlelib/pyshell.py b/Lib/idlelib/pyshell.py index b1662491935e4a..439f98170292b0 100755 --- a/Lib/idlelib/pyshell.py +++ b/Lib/idlelib/pyshell.py @@ -36,13 +36,14 @@ from idlelib.delegator import Delegator from idlelib import debugger from idlelib import debugger_r -from idlelib.editor import EditorWindow, fixwordbreaks +from idlelib.editor import EditorWindow from idlelib.filelist import FileList from idlelib.outwin import OutputWindow from idlelib import replace from idlelib import rpc from idlelib.run import idle_formatwarning, StdInputFile, StdOutputFile from idlelib.undo import UndoDelegator +from idlelib.util import fix_word_breaks # Default for testing; defaults to True in main() for running. use_subprocess = False @@ -881,9 +882,9 @@ def __init__(self, flist=None): if ms[2][0] != "shell": ms.insert(2, ("shell", "She_ll")) self.interp = ModifiedInterpreter(self) - if flist is None: + if flist is None: # TODO possible? root and flist in main. root = Tk() - fixwordbreaks(root) + fix_word_breaks(root) root.withdraw() flist = PyShellFileList(root) @@ -1452,17 +1453,6 @@ def on_squeezed_expand(self, index, text, tags): self.shell_sidebar.update_sidebar() -def fix_x11_paste(root): - "Make paste replace selection on x11. See issue #5124." - if root._windowingsystem == 'x11': - for cls in 'Text', 'Entry', 'Spinbox': - root.bind_class( - cls, - '<<Paste>>', - 'catch {%W delete sel.first sel.last}\n' + - root.bind_class(cls, '<<Paste>>')) - - usage_msg = """\ USAGE: idle [-deins] [-t title] [file]* @@ -1522,6 +1512,7 @@ def main(): from platform import system from idlelib import testing # bool value from idlelib import macosx + from idlelib.util import fix_scaling, fix_x11_paste global flist, root, use_subprocess @@ -1607,7 +1598,6 @@ def main(): NoDefaultRoot() root = Tk(className="Idle") root.withdraw() - from idlelib.run import fix_scaling fix_scaling(root) # set application icon @@ -1629,7 +1619,7 @@ def main(): root.wm_iconphoto(True, *icons) # start editor and/or shell windows: - fixwordbreaks(root) + fix_word_breaks(root) fix_x11_paste(root) flist = PyShellFileList(root) macosx.setupApp(root, flist) diff --git a/Lib/idlelib/run.py b/Lib/idlelib/run.py index e1c40fee8f4805..f5564ccf90f7f4 100644 --- a/Lib/idlelib/run.py +++ b/Lib/idlelib/run.py @@ -25,6 +25,7 @@ from idlelib import iomenu # encoding from idlelib import rpc # multiple objects from idlelib import stackviewer # StackTreeItem +from idlelib import util # fix_scaling import __main__ import tkinter # Use tcl and, if startup fails, messagebox. @@ -216,7 +217,7 @@ def show_socket_error(err, address): import tkinter from tkinter.messagebox import showerror root = tkinter.Tk() - fix_scaling(root) + util.fix_scaling(root) root.withdraw() showerror( "Subprocess Connection Error", @@ -389,16 +390,6 @@ def exit(): sys.exit(0) -def fix_scaling(root): - """Scale fonts on HiDPI displays.""" - import tkinter.font - scaling = float(root.tk.call('tk', 'scaling')) - if scaling > 1.4: - for name in tkinter.font.names(root): - font = tkinter.font.Font(root=root, name=name, exists=True) - size = int(font['size']) - if size < 0: - font['size'] = round(-0.75*size) def fixdoc(fun, text): diff --git a/Lib/idlelib/util.py b/Lib/idlelib/util.py index e05604ab4853f6..bf88c905e1d177 100644 --- a/Lib/idlelib/util.py +++ b/Lib/idlelib/util.py @@ -19,6 +19,20 @@ py_extensions = ('.py', '.pyw', '.pyi') +# fix_x functions seem only needed once per process. + +def fix_scaling(root): # Called in filelist _test, pyshell, and run. + """Scale fonts on HiDPI displays, once per process.""" + import tkinter.font + scaling = float(root.tk.call('tk', 'scaling')) + if scaling > 1.4: + for name in tkinter.font.names(root): + font = tkinter.font.Font(root=root, name=name, exists=True) + size = int(font['size']) + if size < 0: + font['size'] = round(-0.75*size) + + # Fix for HiDPI screens on Windows. CALL BEFORE ANY TK OPERATIONS! # URL for arguments for the ...Awareness call below. # https://msdn.microsoft.com/en-us/library/windows/desktop/dn280512(v=vs.85).aspx @@ -31,6 +45,25 @@ def fix_win_hidpi(): # Called in pyshell and turtledemo. except (ImportError, AttributeError, OSError): pass +def fix_word_breaks(root): # Called in editor htest, filelist _test, pyshell. + # On Windows, tcl/tk breaks 'words' only on spaces, as in Command Prompt. + # We want Motif style everywhere. See #21474, msg218992 and followup. + tk = root.tk + tk.call('tcl_wordBreakAfter', 'a b', 0) # make sure word.tcl is loaded + tk.call('set', 'tcl_wordchars', r'\w') + tk.call('set', 'tcl_nonwordchars', r'\W') + + +def fix_x11_paste(root): + "Make paste replace selection on x11. See issue #5124." + if root._windowingsystem == 'x11': + for cls in 'Text', 'Entry', 'Spinbox': + root.bind_class( + cls, + '<<Paste>>', + 'catch {%W delete sel.first sel.last}\n' + + root.bind_class(cls, '<<Paste>>')) + if __name__ == '__main__': from unittest import main diff --git a/Misc/NEWS.d/next/IDLE/2026-07-01-00-15-58.gh-issue-152728.yxIhMN.rst b/Misc/NEWS.d/next/IDLE/2026-07-01-00-15-58.gh-issue-152728.yxIhMN.rst new file mode 100644 index 00000000000000..d73512a615c189 --- /dev/null +++ b/Misc/NEWS.d/next/IDLE/2026-07-01-00-15-58.gh-issue-152728.yxIhMN.rst @@ -0,0 +1,2 @@ +Move functions run.fix_scaling, editor.fixwordbreaks (as fix_word_breaks) +and pyshell.fix_x11_paste to idlelib.util. From 63da6c86eb7e10b04ce39d3dff70e77a1ace4255 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 1 Jul 2026 12:23:08 +0200 Subject: [PATCH 523/818] [3.15] gh-152157: Reject empty fractions in `_datetime.{date}time.fromisoformat` (GH-152161) (#152761) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (cherry picked from commit 112c69a0514902af2d2f7d0503de6690ca59a10f) Co-authored-by: tonghuaroot (童话) <tonghuaroot@gmail.com> Co-authored-by: Stan Ulbrych <stan@python.org> --- Lib/test/datetimetester.py | 8 +++++++ ...-06-25-07-08-17.gh-issue-152157.dt5Ef0.rst | 3 +++ Modules/_datetimemodule.c | 21 ++++++++++++------- 3 files changed, 24 insertions(+), 8 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-06-25-07-08-17.gh-issue-152157.dt5Ef0.rst diff --git a/Lib/test/datetimetester.py b/Lib/test/datetimetester.py index 192b22ff754003..c11e9c068bed3b 100644 --- a/Lib/test/datetimetester.py +++ b/Lib/test/datetimetester.py @@ -3758,6 +3758,10 @@ def test_fromisoformat_fails_datetime(self): '2009-04-19T12:30:45-00:90:00', # Time zone field out from range '2009-04-19T12:30:45-00:00:90', # Time zone field out from range '2020-2020', # Ambiguous 9-char date portion + '2009-04-19T12:30:45.+05:00', # Empty fraction before offset + '2009-04-19T12:30:45.-05:00', # Empty fraction before offset + '2009-04-19T12:30:45.Z', # Empty fraction before Z + '2009-04-19T12:30:45,+05:00', # Empty fraction (comma) before offset ] for bad_str in bad_strs: @@ -5034,6 +5038,10 @@ def test_fromisoformat_fails(self): '24:01:00.000000', # Has non-zero minutes on 24:00 '12:30:45+00:90:00', # Time zone field out from range '12:30:45+00:00:90', # Time zone field out from range + '12:30:45.+05:00', # Empty fraction before offset + '12:30:45.-05:00', # Empty fraction before offset + '12:30:45.Z', # Empty fraction before Z + '12:30:45,+05:00', # Empty fraction (comma) before offset ] for bad_str in bad_strs: diff --git a/Misc/NEWS.d/next/Library/2026-06-25-07-08-17.gh-issue-152157.dt5Ef0.rst b/Misc/NEWS.d/next/Library/2026-06-25-07-08-17.gh-issue-152157.dt5Ef0.rst new file mode 100644 index 00000000000000..00e83b4af6be7a --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-25-07-08-17.gh-issue-152157.dt5Ef0.rst @@ -0,0 +1,3 @@ +The C implementations of :meth:`~datetime.datetime.fromisoformat` and :meth:`~datetime.time.fromisoformat` +now reject a decimal separator that is not followed by any +fractional digit before a timezone designator. diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index d52969bef0070f..d218c989891c1b 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -1034,7 +1034,16 @@ parse_hh_mm_ss_ff(const char *tstr, const char *tstr_end, int *hour, has_separator = (c == ':'); } - if (p >= p_end) { + if (c == '.' || c == ',') { + if (i < 2) { + return -3; // Decimal mark on hour or minute + } + if (p >= p_end) { + return -3; // Decimal mark not followed by any digit + } + break; + } + else if (p >= p_end) { return c != '\0'; } else if (has_separator && (c == ':')) { @@ -1043,14 +1052,10 @@ parse_hh_mm_ss_ff(const char *tstr, const char *tstr_end, int *hour, } continue; } - else if (c == '.' || c == ',') { - if (i < 2) { - return -3; // Decimal mark on hour or minute - } - break; - } else if (!has_separator) { + else if (!has_separator) { --p; - } else { + } + else { return -4; // Malformed time separator } } From f7c26ed02f3af169dfc28503d5da3f2e67b71fb0 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 1 Jul 2026 17:44:06 +0200 Subject: [PATCH 524/818] [3.15] gh-66331: Set correct WM_CLASS on X11 for IDLE windows (GH-152733) (#152794) gh-66331: Set correct WM_CLASS on X11 for IDLE windows (GH-152733) Set the WM_CLASS of IDLE's long-lived windows (window-list windows and the stack viewers) to "Idle" instead of the default "Toplevel", so that window managers group and label them correctly. (cherry picked from commit 4e16b8d4eef162082c3d409f171802ceccb36521) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> --- Lib/idlelib/idle_test/test_stackviewer.py | 2 ++ Lib/idlelib/idle_test/test_window.py | 5 +++++ Lib/idlelib/pyshell.py | 2 +- Lib/idlelib/stackviewer.py | 2 +- Lib/idlelib/window.py | 4 ++++ .../next/IDLE/2026-07-01-00-00-00.gh-issue-66331.wMcLaS.rst | 3 +++ 6 files changed, 16 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/IDLE/2026-07-01-00-00-00.gh-issue-66331.wMcLaS.rst diff --git a/Lib/idlelib/idle_test/test_stackviewer.py b/Lib/idlelib/idle_test/test_stackviewer.py index 2434d38e4ffe83..341f158031d5f4 100644 --- a/Lib/idlelib/idle_test/test_stackviewer.py +++ b/Lib/idlelib/idle_test/test_stackviewer.py @@ -35,6 +35,8 @@ def test_init(self): isi(stackviewer.sc, ScrolledCanvas) isi(stackviewer.item, stackviewer.StackTreeItem) isi(stackviewer.node, TreeNode) + top = stackviewer.sc.frame.winfo_toplevel() + self.assertEqual(top.winfo_class(), 'Idle') if __name__ == '__main__': diff --git a/Lib/idlelib/idle_test/test_window.py b/Lib/idlelib/idle_test/test_window.py index 9b56d321a407d6..d8a77817205dc3 100644 --- a/Lib/idlelib/idle_test/test_window.py +++ b/Lib/idlelib/idle_test/test_window.py @@ -39,6 +39,11 @@ def test_init(self): win = window.ListedToplevel(self.root) self.assertIn(win, window.registry) self.assertEqual(win.focused_widget, win) + self.assertEqual(win.winfo_class(), 'Idle') + + def test_init_class_override(self): + win = window.ListedToplevel(self.root, class_='Other') + self.assertEqual(win.winfo_class(), 'Other') if __name__ == '__main__': diff --git a/Lib/idlelib/pyshell.py b/Lib/idlelib/pyshell.py index 439f98170292b0..f117f0bfb52f2a 100755 --- a/Lib/idlelib/pyshell.py +++ b/Lib/idlelib/pyshell.py @@ -644,7 +644,7 @@ def remote_stack_viewer(self): return item = debugobj_r.StubObjectTreeItem(self.rpcclt, oid) from idlelib.tree import ScrolledCanvas, TreeNode - top = Toplevel(self.tkconsole.root) + top = Toplevel(self.tkconsole.root, class_='Idle') theme = idleConf.CurrentTheme() background = idleConf.GetHighlight(theme, 'normal')['background'] sc = ScrolledCanvas(top, bg=background, highlightthickness=0) diff --git a/Lib/idlelib/stackviewer.py b/Lib/idlelib/stackviewer.py index 95042d4debdc03..268e2f1daeb98c 100644 --- a/Lib/idlelib/stackviewer.py +++ b/Lib/idlelib/stackviewer.py @@ -11,7 +11,7 @@ def StackBrowser(root, exc, flist=None, top=None): global sc, item, node # For testing. if top is None: - top = tk.Toplevel(root) + top = tk.Toplevel(root, class_='Idle') sc = ScrolledCanvas(top, bg="white", highlightthickness=0) sc.frame.pack(expand=1, fill="both") item = StackTreeItem(exc, flist) diff --git a/Lib/idlelib/window.py b/Lib/idlelib/window.py index 460d5b67948dde..a41d69927dcdd5 100644 --- a/Lib/idlelib/window.py +++ b/Lib/idlelib/window.py @@ -61,6 +61,10 @@ def call_callbacks(self): class ListedToplevel(Toplevel): def __init__(self, master, **kw): + # Set the WM_CLASS property so that X11 window managers group and + # label IDLE's windows under 'Idle' instead of the default + # 'Toplevel' (gh-66331). It matches the class name passed to Tk(). + kw.setdefault('class_', 'Idle') Toplevel.__init__(self, master, kw) registry.add(self) self.focused_widget = self diff --git a/Misc/NEWS.d/next/IDLE/2026-07-01-00-00-00.gh-issue-66331.wMcLaS.rst b/Misc/NEWS.d/next/IDLE/2026-07-01-00-00-00.gh-issue-66331.wMcLaS.rst new file mode 100644 index 00000000000000..e00e7c7d8fdc65 --- /dev/null +++ b/Misc/NEWS.d/next/IDLE/2026-07-01-00-00-00.gh-issue-66331.wMcLaS.rst @@ -0,0 +1,3 @@ +Set the ``WM_CLASS`` window property of IDLE's windows to ``Idle`` on X11, +so that window managers group and label them correctly instead of using the +default ``Toplevel``. From ad5e591974b2978c57fa9be53f9baec2f7fc9b54 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 1 Jul 2026 18:05:39 +0200 Subject: [PATCH 525/818] [3.15] Fix copy paste error with Py_mod_state_traverse (GH-152776) (#152777) (cherry picked from commit b52bc564513d720fb0c6470871c1f5c24c7ce1d8) Co-authored-by: Petr Viktorin <encukou@gmail.com> Co-authored-by: hydrogen-mvm <hydrogen-mvm@users.noreply.github.com> --- Doc/c-api/module.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/c-api/module.rst b/Doc/c-api/module.rst index 9f68abba66bc5d..8e805b284e0ea4 100644 --- a/Doc/c-api/module.rst +++ b/Doc/c-api/module.rst @@ -488,7 +488,7 @@ defining the module state. .. versionadded:: 3.15 - Use :c:member:`PyModuleDef.m_size` instead to support previous versions. + Use :c:member:`PyModuleDef.m_traverse` instead to support previous versions. .. c:macro:: Py_mod_state_clear From 5de11c6eba3147ddc68e8e7000d05c03fa12f852 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 1 Jul 2026 18:22:25 +0200 Subject: [PATCH 526/818] [3.15] gh-71956: Fix IDLE Replace All searching up without wrap around (GH-152737) (#152799) gh-71956: Fix IDLE Replace All searching up without wrap around (GH-152737) When the search direction is "Up" and "Wrap around" is off, Replace All replaced only the first match above the current position (and all matches below it). It now replaces all matches from the start of the text down to the current position, consistently with the "Up" direction. (cherry picked from commit ef27e5b310feebb6068f9e798eee7069e1966fc9) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> --- Lib/idlelib/idle_test/test_replace.py | 86 +++++++++++++++++-- Lib/idlelib/replace.py | 29 +++++-- ...6-07-01-12-00-00.gh-issue-71956.rPlAlL.rst | 3 + 3 files changed, 105 insertions(+), 13 deletions(-) create mode 100644 Misc/NEWS.d/next/IDLE/2026-07-01-12-00-00.gh-issue-71956.rPlAlL.rst diff --git a/Lib/idlelib/idle_test/test_replace.py b/Lib/idlelib/idle_test/test_replace.py index 6c07389b29ad45..5342a3856ef65d 100644 --- a/Lib/idlelib/idle_test/test_replace.py +++ b/Lib/idlelib/idle_test/test_replace.py @@ -246,32 +246,108 @@ def test_replace_backwards(self): equal(text.get('1.2', '1.5'), 'was') def test_replace_all(self): + # The default mode, forward with wrap around, replaces every + # match, both below and above the current position. + equal = self.assertEqual text = self.text pv = self.engine.patvar rv = self.dialog.replvar replace_all = self.dialog.replace_all - text.insert('insert', '\n') - text.insert('insert', text.get('1.0', 'end')*100) - pv.set('is') - rv.set('was') + text.delete('1.0', 'end') + text.insert('1.0', 'a\na\na\n') + text.mark_set('insert', '2.1') + pv.set('a') + rv.set('b') replace_all() - self.assertNotIn('is', text.get('1.0', 'end')) + equal(text.get('1.0', '3.end'), 'b\nb\nb') # Wrapped around. + # An empty regular expression is reported as an error. self.engine.revar.set(True) pv.set('') replace_all() self.assertIn('error', showerror.title) self.assertIn('Empty', showerror.message) + # An invalid replacement expression is reported as an error, + # and nothing is replaced. + text.delete('1.0', 'end') + text.insert('1.0', 'asT') pv.set('[s][T]') rv.set('\\') replace_all() + self.assertIn('error', showerror.title) + self.assertIn('Invalid Replace Expression', showerror.message) + equal(text.get('1.0', '1.end'), 'asT') + # A pattern that is not present replaces nothing. self.engine.revar.set(False) + text.delete('1.0', 'end') + text.insert('1.0', 'unchanged') pv.set('text which is not present') rv.set('foobar') replace_all() + equal(text.get('1.0', '1.end'), 'unchanged') + + def test_replace_all_backwards_no_wrap(self): + # gh-71956: 'up' without wrap replaces all matches from the start + # of the text down to the current position, not just one up. + equal = self.assertEqual + text = self.text + pv = self.engine.patvar + rv = self.dialog.replvar + replace_all = self.dialog.replace_all + self.engine.backvar.set(True) + self.engine.wrapvar.set(False) + + text.delete('1.0', 'end') + text.insert('1.0', 'a\na\na\n') + text.mark_set('insert', '2.1') + pv.set('a') + rv.set('b') + replace_all() + equal(text.get('1.0', '1.end'), 'b') # Above the cursor. + equal(text.get('2.0', '2.end'), 'b') # At the cursor. + equal(text.get('3.0', '3.end'), 'a') # Below the cursor, untouched. + + def test_replace_all_forwards_no_wrap(self): + # 'down' without wrap replaces all matches from the current + # position to the end of the text, and none before it. + equal = self.assertEqual + text = self.text + pv = self.engine.patvar + rv = self.dialog.replvar + replace_all = self.dialog.replace_all + self.engine.backvar.set(False) + self.engine.wrapvar.set(False) + + text.delete('1.0', 'end') + text.insert('1.0', 'a\na\na\n') + text.mark_set('insert', '2.1') + pv.set('a') + rv.set('b') + replace_all() + equal(text.get('1.0', '1.end'), 'a') # Before the cursor, untouched. + equal(text.get('2.0', '2.end'), 'a') # Before the cursor, untouched. + equal(text.get('3.0', '3.end'), 'b') # After the cursor. + + def test_replace_all_backwards_wrap(self): + # With wrap around, an 'up' search also replaces every match. + equal = self.assertEqual + text = self.text + pv = self.engine.patvar + rv = self.dialog.replvar + replace_all = self.dialog.replace_all + self.engine.backvar.set(True) + self.engine.wrapvar.set(True) + + text.delete('1.0', 'end') + text.insert('1.0', 'a\na\na\n') + text.mark_set('insert', '2.1') + pv.set('a') + rv.set('b') + replace_all() + equal(text.get('1.0', '3.end'), 'b\nb\nb') def test_default_command(self): text = self.text diff --git a/Lib/idlelib/replace.py b/Lib/idlelib/replace.py index 3716d841568d30..93d4f1c0c6c573 100644 --- a/Lib/idlelib/replace.py +++ b/Lib/idlelib/replace.py @@ -122,12 +122,13 @@ def _replace_expand(self, m, repl): def replace_all(self, event=None): """Handle the Replace All button. - Search text for occurrences of the Find value and replace - each of them. The 'wrap around' value controls the start - point for searching. If wrap isn't set, then the searching - starts at the first occurrence after the current selection; - if wrap is set, the replacement starts at the first line. - The replacement is always done top-to-bottom in the text. + Search text for occurrences of the Find value and replace each + of them. The 'wrap around' and direction values control which + occurrences are replaced. With wrap around, every occurrence is + replaced. Without it, a forward search replaces occurrences from + the current position to the end of the text, and a backward search + replaces occurrences from the beginning of the text to the current + position. The replacement is always done top-to-bottom. """ prog = self.engine.getprog() if not prog: @@ -142,9 +143,18 @@ def replace_all(self, event=None): text.tag_remove("hit", "1.0", "end") line = res[0] col = res[1].start() + # For a backward search without wrap, replace top-to-bottom from + # the start of the text down to the first match at or above the + # current position (gh-71956). A mark tracks that stop point. + stop = None if self.engine.iswrap(): line = 1 col = 0 + elif self.engine.isback(): + stop = "replace_all_stop" + text.mark_set(stop, "%d.%d" % (line, res[1].end())) + line = 1 + col = 0 ok = True first = last = None # XXX ought to replace circular instead of top-to-bottom when wrapping @@ -152,12 +162,13 @@ def replace_all(self, event=None): while res := self.engine.search_forward( text, prog, line, col, wrap=False, ok=ok): line, m = res - chars = text.get("%d.0" % line, "%d.0" % (line+1)) + i, j = m.span() + if stop is not None and text.compare("%d.%d" % (line, i), ">=", stop): + break orig = m.group() new = self._replace_expand(m, repl) if new is None: break - i, j = m.span() first = "%d.%d" % (line, i) last = "%d.%d" % (line, j) if new == orig: @@ -170,6 +181,8 @@ def replace_all(self, event=None): text.insert(first, new, self.insert_tags) col = i + len(new) ok = False + if stop is not None: + text.mark_unset(stop) text.undo_block_stop() if first and last: self.show_hit(first, last) diff --git a/Misc/NEWS.d/next/IDLE/2026-07-01-12-00-00.gh-issue-71956.rPlAlL.rst b/Misc/NEWS.d/next/IDLE/2026-07-01-12-00-00.gh-issue-71956.rPlAlL.rst new file mode 100644 index 00000000000000..1a92ed4cd389cf --- /dev/null +++ b/Misc/NEWS.d/next/IDLE/2026-07-01-12-00-00.gh-issue-71956.rPlAlL.rst @@ -0,0 +1,3 @@ +Fix Replace All in the IDLE editor's Replace dialog when the search +direction is "Up" and "Wrap around" is off: it now replaces all matches +above the current position instead of only the first one. From c2d275202830651e91c779c66213bd5ed4610144 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 1 Jul 2026 18:49:12 +0200 Subject: [PATCH 527/818] [3.15] gh-89360: Fix ValueError in IDLE MultiCall event_delete (GH-152738) (#152802) gh-89360: Fix ValueError in IDLE MultiCall event_delete (GH-152738) Deleting a key binding for a sequence not bound to the virtual event no longer raises a ValueError; the discrepancy is now ignored. (cherry picked from commit ea7619faeacf310ba1b2ef41ad07966ce2aae11f) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> --- Lib/idlelib/idle_test/test_multicall.py | 16 ++++++++++++++++ Lib/idlelib/multicall.py | 3 ++- ...2026-07-01-14-00-00.gh-issue-89360.mUlTiC.rst | 3 +++ 3 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/IDLE/2026-07-01-14-00-00.gh-issue-89360.mUlTiC.rst diff --git a/Lib/idlelib/idle_test/test_multicall.py b/Lib/idlelib/idle_test/test_multicall.py index 7d73761cfdfee8..fcce2030579f4b 100644 --- a/Lib/idlelib/idle_test/test_multicall.py +++ b/Lib/idlelib/idle_test/test_multicall.py @@ -43,6 +43,22 @@ def test_yview(self): mctext = self.mc(self.root) self.assertIs(mctext.yview.__func__, Text.yview) + def test_event_delete_unbound_sequence(self): + # gh-89360: deleting a sequence that was not added to a virtual + # event is ignored instead of raising ValueError. + mctext = self.mc(self.root) + mctext.event_add('<<tester>>', '<Control-Key-a>') + info = mctext.event_info('<<tester>>') + self.assertEqual(len(info), 1) + + # A different sequence, never added: a no-op, not an error. + mctext.event_delete('<<tester>>', '<Control-Key-b>') + self.assertEqual(mctext.event_info('<<tester>>'), info) + + # The added sequence can still be deleted normally. + mctext.event_delete('<<tester>>', '<Control-Key-a>') + self.assertNotIn(info[0], mctext.event_info('<<tester>>')) + if __name__ == '__main__': unittest.main(verbosity=2) diff --git a/Lib/idlelib/multicall.py b/Lib/idlelib/multicall.py index 41f81813113062..95f4fee7fbe740 100644 --- a/Lib/idlelib/multicall.py +++ b/Lib/idlelib/multicall.py @@ -386,10 +386,11 @@ def event_delete(self, virtual, *sequences): if triplet is None: #print("Tkinter event_delete: %s" % seq, file=sys.__stderr__) widget.event_delete(self, virtual, seq) - else: + elif triplet in triplets: if func is not None: self.__binders[triplet[1]].unbind(triplet, func) triplets.remove(triplet) + # Else the sequence is not bound; ignore it (gh-89360). def event_info(self, virtual=None): if virtual is None or virtual not in self.__eventinfo: diff --git a/Misc/NEWS.d/next/IDLE/2026-07-01-14-00-00.gh-issue-89360.mUlTiC.rst b/Misc/NEWS.d/next/IDLE/2026-07-01-14-00-00.gh-issue-89360.mUlTiC.rst new file mode 100644 index 00000000000000..9e3023f8228233 --- /dev/null +++ b/Misc/NEWS.d/next/IDLE/2026-07-01-14-00-00.gh-issue-89360.mUlTiC.rst @@ -0,0 +1,3 @@ +Fix a rare crash in the IDLE editor when the completion window is closed: +deleting a key binding for a sequence that is not bound to the virtual +event is now ignored instead of raising a ``ValueError``. From 6aa89d98e3049fc67b10070fa84e5ef4bb4a01f5 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 1 Jul 2026 19:03:14 +0200 Subject: [PATCH 528/818] [3.15] gh-134300: Remove idlelib from the path of the IDLE user process (GH-152739) (#152807) gh-134300: Remove idlelib from the path of the IDLE user process (GH-152739) The idlelib directory ends up on sys.path when idle.py is run as a script, and it was passed to the user process, where it let user code import idlelib submodules as top-level modules, such as "import help". (cherry picked from commit 3f5491a09223f7371b4b4c92225e8dfdf1c989b7) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> --- Lib/idlelib/idle_test/test_pyshell.py | 9 +++++++++ Lib/idlelib/pyshell.py | 12 ++++++++++++ .../2026-07-01-15-00-00.gh-issue-134300.iDlPaT.rst | 3 +++ 3 files changed, 24 insertions(+) create mode 100644 Misc/NEWS.d/next/IDLE/2026-07-01-15-00-00.gh-issue-134300.iDlPaT.rst diff --git a/Lib/idlelib/idle_test/test_pyshell.py b/Lib/idlelib/idle_test/test_pyshell.py index 51f7691eefe9d5..dec81bdbbccd67 100644 --- a/Lib/idlelib/idle_test/test_pyshell.py +++ b/Lib/idlelib/idle_test/test_pyshell.py @@ -2,6 +2,7 @@ # Plus coverage of test_warning. Was 20% with test_openshell. from idlelib import pyshell +import os import unittest from test.support import requires from tkinter import Tk @@ -28,6 +29,14 @@ def test_restart_line_narrow(self): self.assertEqual(pyshell.restart_line(width, ''), expect) self.assertEqual(pyshell.restart_line(taglen+2, ''), expect+' =') + def test_fix_user_path(self): + # gh-134300: the idlelib directory is removed, other entries kept. + eq = self.assertEqual + idlelib_dir = os.path.dirname(os.path.abspath(pyshell.__file__)) + eq(pyshell.fix_user_path(['', '/a', idlelib_dir, '/b']), ['', '/a', '/b']) + eq(pyshell.fix_user_path(['/a', '/b']), ['/a', '/b']) + eq(pyshell.fix_user_path([idlelib_dir]), []) + class PyShellFileListTest(unittest.TestCase): diff --git a/Lib/idlelib/pyshell.py b/Lib/idlelib/pyshell.py index f117f0bfb52f2a..ef3d014d936ce8 100755 --- a/Lib/idlelib/pyshell.py +++ b/Lib/idlelib/pyshell.py @@ -408,6 +408,17 @@ def restart_line(width, filename): # See bpo-38141. return tag[:-2] # Remove ' ='. +def fix_user_path(path): + """Return path without the idlelib directory (gh-134300). + + That directory is on sys.path when idle.py is run as a script. + Otherwise user code could import idlelib submodules as top-level + modules, such as "import help". + """ + idlelib_dir = os.path.dirname(os.path.abspath(__file__)) + return [p for p in path if p != idlelib_dir] + + class ModifiedInterpreter(InteractiveInterpreter): def __init__(self, tkconsole): @@ -568,6 +579,7 @@ def transfer_path(self, with_cwd=False): path.extend(sys.path) else: path = sys.path + path = fix_user_path(path) # gh-134300 self.runcommand("""if 1: import sys as _sys diff --git a/Misc/NEWS.d/next/IDLE/2026-07-01-15-00-00.gh-issue-134300.iDlPaT.rst b/Misc/NEWS.d/next/IDLE/2026-07-01-15-00-00.gh-issue-134300.iDlPaT.rst new file mode 100644 index 00000000000000..791acbbed62aaf --- /dev/null +++ b/Misc/NEWS.d/next/IDLE/2026-07-01-15-00-00.gh-issue-134300.iDlPaT.rst @@ -0,0 +1,3 @@ +Do not add the ``idlelib`` directory to the path of the IDLE user process. +User code run in IDLE can no longer import ``idlelib`` submodules as +top-level modules, such as ``import help``. From c86035cf88ffd3db6f815cafe347477da2912afd Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 1 Jul 2026 19:35:41 +0200 Subject: [PATCH 529/818] [3.15] gh-80504: Always show the full search path in IDLE Find in Files (GH-152740) (#152810) gh-80504: Always show the full search path in IDLE Find in Files (GH-152740) The "In files:" field of the Find in Files dialog now always contains a full directory path, so the grep output shows which directory was searched. (cherry picked from commit f21f338f1f88352d50362271a7f38c01745a65da) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> --- Lib/idlelib/grep.py | 20 ++++++++++++++----- Lib/idlelib/idle_test/test_grep.py | 19 ++++++++++++++++++ ...026-07-01-16-00-00.gh-issue-80504.gReP.rst | 3 +++ 3 files changed, 37 insertions(+), 5 deletions(-) create mode 100644 Misc/NEWS.d/next/IDLE/2026-07-01-16-00-00.gh-issue-80504.gReP.rst diff --git a/Lib/idlelib/grep.py b/Lib/idlelib/grep.py index 42048ff2395fe1..5d604faec23f32 100644 --- a/Lib/idlelib/grep.py +++ b/Lib/idlelib/grep.py @@ -40,6 +40,20 @@ def grep(text, io=None, flist=None): dialog.open(text, searchphrase, io) +def default_glob(path): + """Return the initial "In files:" pattern for a file path (gh-80504). + + Always include a full directory so that grep output shows which + directory was searched. + """ + dir, base = os.path.split(path) + dir = os.path.abspath(dir) # An empty dir becomes the current directory. + head, tail = os.path.splitext(base) + if not tail: + tail = ".py" + return os.path.join(dir, "*" + tail) + + def walk_error(msg): "Handle os.walk error." print(msg) @@ -103,11 +117,7 @@ def open(self, text, searchphrase, io=None): path = io.filename or "" else: path = "" - dir, base = os.path.split(path) - head, tail = os.path.splitext(base) - if not tail: - tail = ".py" - self.globvar.set(os.path.join(dir, "*" + tail)) + self.globvar.set(default_glob(path)) def create_entries(self): "Create base entry widgets and add widget for search path." diff --git a/Lib/idlelib/idle_test/test_grep.py b/Lib/idlelib/idle_test/test_grep.py index d67dba76911fcf..94f217effb656e 100644 --- a/Lib/idlelib/idle_test/test_grep.py +++ b/Lib/idlelib/idle_test/test_grep.py @@ -37,6 +37,25 @@ def close(self): # gui method _grep = Dummy_grep() +class DefaultGlobTest(unittest.TestCase): + + def test_no_path(self): + # gh-80504: an unsaved editor or the Shell has no path, so the + # pattern uses the current directory, not just '*.py'. + self.assertEqual(grep.default_glob(''), + os.path.join(os.getcwd(), '*.py')) + + def test_full_path(self): + path = os.path.join(os.path.abspath(os.sep), 'ab', 'foo.py') + self.assertEqual(grep.default_glob(path), + os.path.join(os.path.dirname(path), '*.py')) + + def test_other_extension(self): + path = os.path.join(os.path.abspath(os.sep), 'ab', 'foo.txt') + self.assertEqual(grep.default_glob(path), + os.path.join(os.path.dirname(path), '*.txt')) + + class FindfilesTest(unittest.TestCase): @classmethod diff --git a/Misc/NEWS.d/next/IDLE/2026-07-01-16-00-00.gh-issue-80504.gReP.rst b/Misc/NEWS.d/next/IDLE/2026-07-01-16-00-00.gh-issue-80504.gReP.rst new file mode 100644 index 00000000000000..93adb33202a41c --- /dev/null +++ b/Misc/NEWS.d/next/IDLE/2026-07-01-16-00-00.gh-issue-80504.gReP.rst @@ -0,0 +1,3 @@ +The "In files:" field of IDLE's Find in Files dialog now always contains a +full directory path, even for an unsaved editor or the Shell. This shows +in the grep output which directory was searched. From 6bbc28bc9c50ef81cb83d859f3b483e1b6928943 Mon Sep 17 00:00:00 2001 From: Stan Ulbrych <stan@python.org> Date: Wed, 1 Jul 2026 21:20:27 +0200 Subject: [PATCH 530/818] [3.15] gh-151040: Fix `test_c_stack_unwind` on RISC-V (GH-152370) (#152819) (cherry picked from commit 1b0c05f14807a43d070127b3d8eac1af8de27f28) Co-authored-by: Ivy Xu <fakeshadow1337@gmail.com> --- Modules/_testinternalcapi.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Modules/_testinternalcapi.c b/Modules/_testinternalcapi.c index 92a49d003ca735..344d663624b270 100644 --- a/Modules/_testinternalcapi.c +++ b/Modules/_testinternalcapi.c @@ -98,6 +98,11 @@ static const uintptr_t min_frame_pointer_addr = 0x1000; // https://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi-1.9.html#STACK # define FRAME_POINTER_NEXT_OFFSET 0 # define FRAME_POINTER_RETURN_OFFSET 2 +#elif defined(__riscv) +// RISC-V saves the return address at fp[-1], and the previous frame pointer at fp[-2]. +// See: https://riscv-non-isa.github.io/riscv-elf-psabi-doc/#_frame_pointer_convention +# define FRAME_POINTER_NEXT_OFFSET -2 +# define FRAME_POINTER_RETURN_OFFSET -1 #else # define FRAME_POINTER_NEXT_OFFSET 0 # define FRAME_POINTER_RETURN_OFFSET 1 From 392f1cc0792583b6aff25d9fdba84cf5da655011 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 1 Jul 2026 23:03:58 +0200 Subject: [PATCH 531/818] [3.15] gh-65339: Save IDLE Shell and Output windows as text by default (GH-152742) (#152821) gh-65339: Save IDLE Shell and Output windows as text by default (GH-152742) Their content is not Python source, so the Save As dialog now lists text files first and defaults to a ".txt" extension. (cherry picked from commit efcfb1a4e0f4d0d0e33aefccd8373e116e98e3de) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> --- Lib/idlelib/idle_test/test_outwin.py | 7 +++++++ Lib/idlelib/iomenu.py | 9 +++++++++ Lib/idlelib/outwin.py | 4 ++++ .../IDLE/2026-07-01-17-00-00.gh-issue-65339.oUtTxt.rst | 3 +++ 4 files changed, 23 insertions(+) create mode 100644 Misc/NEWS.d/next/IDLE/2026-07-01-17-00-00.gh-issue-65339.oUtTxt.rst diff --git a/Lib/idlelib/idle_test/test_outwin.py b/Lib/idlelib/idle_test/test_outwin.py index 0f13363f84f361..00a7432b908873 100644 --- a/Lib/idlelib/idle_test/test_outwin.py +++ b/Lib/idlelib/idle_test/test_outwin.py @@ -41,6 +41,13 @@ def test_ispythonsource(self): self.assertFalse(w.ispythonsource('test.txt')) self.assertFalse(w.ispythonsource(__file__)) + def test_save_defaults_to_text(self): + # gh-65339: output is saved as text, not Python source. + io = self.window.io + self.assertEqual(io.defaultextension, '.txt') + # Text files are offered before Python files. + self.assertEqual(io.filetypes[0][0], 'Text files') + def test_window_title(self): self.assertEqual(self.window.top.title(), 'Output' + ' (%s)' % platform.python_version()) diff --git a/Lib/idlelib/iomenu.py b/Lib/idlelib/iomenu.py index fc502f7fde1780..9560aaa2da0c42 100644 --- a/Lib/idlelib/iomenu.py +++ b/Lib/idlelib/iomenu.py @@ -384,7 +384,16 @@ def print_window(self, event): ("All files", "*"), ) + # Output windows (Shell, Output) are not Python source, so they list + # text files first and default to ".txt" (gh-65339). + text_filetypes = ( + ("Text files", "*.txt", "TEXT"), + ("Python files", py_extensions, "TEXT"), + ("All files", "*"), + ) + defaultextension = '.py' if sys.platform == 'darwin' else '' + text_defaultextension = '.txt' def askopenfile(self): dir, base = self.defaultfilename("open") diff --git a/Lib/idlelib/outwin.py b/Lib/idlelib/outwin.py index 8baa657550de94..f7e92bb8ac0c77 100644 --- a/Lib/idlelib/outwin.py +++ b/Lib/idlelib/outwin.py @@ -78,6 +78,10 @@ class OutputWindow(EditorWindow): def __init__(self, *args): EditorWindow.__init__(self, *args) self.text.bind("<<goto-file-line>>", self.goto_file_line) + # Output is not Python source, so save it as text by default + # (gh-65339). + self.io.filetypes = self.io.text_filetypes + self.io.defaultextension = self.io.text_defaultextension # Customize EditorWindow def ispythonsource(self, filename): diff --git a/Misc/NEWS.d/next/IDLE/2026-07-01-17-00-00.gh-issue-65339.oUtTxt.rst b/Misc/NEWS.d/next/IDLE/2026-07-01-17-00-00.gh-issue-65339.oUtTxt.rst new file mode 100644 index 00000000000000..a8b216e86dc8d7 --- /dev/null +++ b/Misc/NEWS.d/next/IDLE/2026-07-01-17-00-00.gh-issue-65339.oUtTxt.rst @@ -0,0 +1,3 @@ +Saving the IDLE Shell or an Output window now defaults to a ``.txt`` +extension and lists text files before Python files, since their content is +not Python source. From 758a9c389a9b3b961372392ab02a303de308b97a Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 2 Jul 2026 00:27:52 +0200 Subject: [PATCH 532/818] [3.15] gh-75595: Do not save a blank int entry in IDLE Settings (GH-152743) (#152827) gh-75595: Do not save a blank int entry in IDLE Settings (GH-152743) gh-83653: Do not save a blank int entry in IDLE Settings Blanking an integer entry wrote an empty string to the config file, which caused an "invalid int value" warning when it was read back. (cherry picked from commit 3428762f33c6c064998f5b0c385cdfd0f0c2e198) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Cheryl Sabella <cheryl.sabella@gmail.com> --- Lib/idlelib/configdialog.py | 6 +++++- Lib/idlelib/idle_test/test_configdialog.py | 11 +++++++++++ .../2026-07-01-18-00-00.gh-issue-83653.cFgInt.rst | 3 +++ 3 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/IDLE/2026-07-01-18-00-00.gh-issue-83653.cFgInt.rst diff --git a/Lib/idlelib/configdialog.py b/Lib/idlelib/configdialog.py index 10bd3c23450821..4c94d9be69e95e 100644 --- a/Lib/idlelib/configdialog.py +++ b/Lib/idlelib/configdialog.py @@ -2265,7 +2265,11 @@ def make_callback(var, config): "Return default callback function to add values to changes instance." def default_callback(*params): "Add config values to changes instance." - changes.add_option(*config, var.get()) + value = var.get() + # A blanked int entry is an empty string; do not save it as an + # invalid config value (gh-83653). + if value != '': + changes.add_option(*config, value) return default_callback def attach(self): diff --git a/Lib/idlelib/idle_test/test_configdialog.py b/Lib/idlelib/idle_test/test_configdialog.py index 2773ed7ce614b5..c68fd304ea4235 100644 --- a/Lib/idlelib/idle_test/test_configdialog.py +++ b/Lib/idlelib/idle_test/test_configdialog.py @@ -1544,6 +1544,17 @@ def test_make_callback(self): self.assertEqual(changes['main']['section']['option'], '42') changes.clear() + # gh-83653: a blank int entry is not saved as bad config data. + sv = StringVar(root) + cb = self.tracers.make_callback(sv, ('main', 'section', 'option')) + sv.set('') + cb() + self.assertNotIn('section', changes['main']) + sv.set('5') + cb() + self.assertEqual(changes['main']['section']['option'], '5') + changes.clear() + def test_attach_detach(self): tr = self.tracers iv = tr.add(self.iv, self.var_changed_increment) diff --git a/Misc/NEWS.d/next/IDLE/2026-07-01-18-00-00.gh-issue-83653.cFgInt.rst b/Misc/NEWS.d/next/IDLE/2026-07-01-18-00-00.gh-issue-83653.cFgInt.rst new file mode 100644 index 00000000000000..5812b2dd977f6a --- /dev/null +++ b/Misc/NEWS.d/next/IDLE/2026-07-01-18-00-00.gh-issue-83653.cFgInt.rst @@ -0,0 +1,3 @@ +Blanking an integer entry in IDLE's Settings dialog, such as "Auto squeeze +min lines", no longer saves an empty string as an invalid configuration +value. From 75fb03330e8ad6be68fe6c594331592f5bdf3082 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 2 Jul 2026 01:30:08 +0200 Subject: [PATCH 533/818] [3.15] gh-82183: Do not restart the busy IDLE shell when running without restart (GH-152745) (#152832) gh-82183: Do not restart the busy IDLE shell when running without restart (GH-152745) "Run... Customized" with "Restart shell" unchecked restarted the shell anyway when it was busy executing code, killing any pending input. It now reports that the shell is executing just once, not twice, and does not run. (cherry picked from commit be449b1c6ad739a40a7da35a81317bb49f1f54ff) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> --- Lib/idlelib/idle_test/test_runscript.py | 21 +++++++++++++++++++ Lib/idlelib/runscript.py | 4 ++++ ...6-07-01-19-00-00.gh-issue-82183.rNsTrt.rst | 3 +++ 3 files changed, 28 insertions(+) create mode 100644 Misc/NEWS.d/next/IDLE/2026-07-01-19-00-00.gh-issue-82183.rNsTrt.rst diff --git a/Lib/idlelib/idle_test/test_runscript.py b/Lib/idlelib/idle_test/test_runscript.py index 63086bfa4a404e..1e47f402d504f9 100644 --- a/Lib/idlelib/idle_test/test_runscript.py +++ b/Lib/idlelib/idle_test/test_runscript.py @@ -2,6 +2,7 @@ from idlelib import runscript import unittest +from unittest import mock from test.support import requires from tkinter import Tk from idlelib.editor import EditorWindow @@ -28,6 +29,26 @@ def test_init(self): sb = runscript.ScriptBinding(ew) ew._close() + def test_run_module_event_shell_busy_no_restart(self): + # gh-82183: running without restarting the busy shell aborts. + ew = EditorWindow(root=self.root) + sb = runscript.ScriptBinding(ew) + sb.getfilename = mock.Mock(return_value='test.py') + sb.checksyntax = mock.Mock(return_value='code') + sb.tabnanny = mock.Mock(return_value=True) + sb.shell = shell = mock.Mock() + shell.executing = True + interp = shell.interp + with mock.patch.object(runscript, 'CustomRun') as customrun: + # Restart shell unchecked. + customrun.return_value.result = (['arg'], False) + result = sb.run_module_event(None, customize=True) + self.assertEqual(result, 'break') + interp.display_executing_dialog.assert_called_once() + interp.restart_subprocess.assert_not_called() + interp.runcode.assert_not_called() + ew._close() + if __name__ == '__main__': unittest.main(verbosity=2) diff --git a/Lib/idlelib/runscript.py b/Lib/idlelib/runscript.py index 55712e904603f8..cd52d206c9ca0f 100644 --- a/Lib/idlelib/runscript.py +++ b/Lib/idlelib/runscript.py @@ -139,6 +139,10 @@ def run_module_event(self, event, *, customize=False): return 'break' self.cli_args, restart = run_args if customize else ([], True) interp = self.shell.interp + if self.shell.executing and not restart: + # Cannot run without restarting the busy shell (gh-82183). + interp.display_executing_dialog() + return 'break' if pyshell.use_subprocess and restart: interp.restart_subprocess( with_cwd=False, filename=filename) diff --git a/Misc/NEWS.d/next/IDLE/2026-07-01-19-00-00.gh-issue-82183.rNsTrt.rst b/Misc/NEWS.d/next/IDLE/2026-07-01-19-00-00.gh-issue-82183.rNsTrt.rst new file mode 100644 index 00000000000000..2af412f5200d0d --- /dev/null +++ b/Misc/NEWS.d/next/IDLE/2026-07-01-19-00-00.gh-issue-82183.rNsTrt.rst @@ -0,0 +1,3 @@ +When the shell is busy running code, using "Run... Customized" with "Restart +shell" unchecked now reports that the shell is executing instead of +restarting it anyway. From 7d8b0b3a81df388274402d4172e89f97e2ed0146 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 2 Jul 2026 05:20:31 +0200 Subject: [PATCH 534/818] [3.15] gh-135142: update idlelib News3.txt for 9 issues (GH-152839) (#152842) gh-135142: update idlelib News3.txt for 9 issues (GH-152839) 13 posted 2026 June 30 for various issues. Edited one other by me. (cherry picked from commit 384abb71445a5a37dfb4dbc5e3020ea6c0c307f7) Co-authored-by: Terry Jan Reedy <tjreedy@udel.edu> --- Lib/idlelib/News3.txt | 41 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/Lib/idlelib/News3.txt b/Lib/idlelib/News3.txt index dc18b6e07eb364..bcbd7fa542a02a 100644 --- a/Lib/idlelib/News3.txt +++ b/Lib/idlelib/News3.txt @@ -4,8 +4,45 @@ Released on 2026-10-01 ========================= -gh-152728: Move functions run.fix_scaling, editor.fixwordbreaks (as fix_word_breaks) -and pyshell.fix_x11_paste to module util. Patch by Terry J. Reedy. +gh-152745: When "Run... Customized" with "Restart shell" unchecked +while Shell is running code, including waiting for an input('prompt:') +response, just report that the shell is executing instead of +reporting twice and restarting anyway. Patch by Serhiy Storchaka. + +gh-152743: When an integer entry in IDLE's Settings dialog, such as +"Auto squeeze min lines", is deleted, do not save '', which is an +invalid configuration value. Patch by Serhiy Storchaka. + +gh-152742: MakeChange the default extension when saving a Shell or +Output window '.txt' and list text files before Python files. Their +content is not Python source. Patch by Serhiy Storchaka and Claude Code. + +gh-152740: Fill the "In files:" field of IDLE's Find in Files dialog +with a full directory path, even for an unsaved editor or the Shell. +In the grep output whow which directory was searched. Patch by Serhiy +Storchaka and Claude Code. + +gh-152739: Omit the idlelib directory from the path of the IDLE user +process. User code imports such as `import help' can no longer import +an idlelib submodule (here idlelib.help) instead of the intended +top-level module. Patch by Serhiy Storchaka and Claude Code. + +gh-152738: Fix a rare crash in the IDLE editor when the completion +window is closed: deleting a key binding for a sequence that is not +bound to the virtual event is now ignored instead of raising a +ValueError. Patch by Serhiy Storchaka and Claude Code. + +gh-152737: Fix Replace All in the IDLE editor's Replace dialog when the +search direction is "Up" and "Wrap around" is off: it now replaces all +matches above the current position instead of only the first one. +Patch by Serhiy Storchaka and Claude Code. + +gh-152733: For X11 window managers, set toplevel window classes to +"Idle". Patch by Serhiy Storchaka and Claude Code. + +gh-152728: Move functions run.fix_scaling, editor.fixwordbreaks +(as 'fix_word_breaks') and pyshell.fix_x11_paste to module util. +Patch by Terry J. Reedy. gh-85320: IDLE now reads and writes its configuration files and the breakpoints file using UTF-8 instead of the locale encoding. From 58d92ac773a30cf4670e9931d67f04ef0d06d50e Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 2 Jul 2026 09:26:50 +0200 Subject: [PATCH 535/818] [3.15] gh-79964: Clarify the imaplib fetch example in the docs (GH-152780) (GH-152859) A FETCH response may contain additional or unsolicited data, so the message is not always data[0][1]. (cherry picked from commit 50ae0be74988564fb09746a49eb4b8f8e740f3c3) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --- Doc/library/imaplib.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Doc/library/imaplib.rst b/Doc/library/imaplib.rst index b002f4978123e6..cf475734636a20 100644 --- a/Doc/library/imaplib.rst +++ b/Doc/library/imaplib.rst @@ -725,3 +725,10 @@ retrieves and prints all messages:: M.close() M.logout() +.. note:: + + A ``FETCH`` response may contain additional or unsolicited data + (see :rfc:`3501`, section 7.4.2), + so production code should inspect the whole response + rather than rely on ``data[0][1]``. + From 0ab38f48089896dad6a5ca5009883f40da63cb38 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 2 Jul 2026 09:28:02 +0200 Subject: [PATCH 536/818] [3.15] gh-72507: Document that imaplib does not verify TLS certificates by default (GH-152778) (GH-152862) IMAP4_SSL() and IMAP4.starttls() do not verify the server certificate or hostname unless a suitable ssl_context is passed. (cherry picked from commit f3bf8abb8c0f4cb20bed3dc7d98eca4a2d668709) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --- Doc/library/imaplib.rst | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Doc/library/imaplib.rst b/Doc/library/imaplib.rst index cf475734636a20..e175dcccaf652e 100644 --- a/Doc/library/imaplib.rst +++ b/Doc/library/imaplib.rst @@ -89,6 +89,13 @@ There's also a subclass for secure connections: (potentially long-lived) structure. Please read :ref:`ssl-security` for best practices. + .. note:: + + With the default *ssl_context*, the connection is encrypted but the + server certificate and hostname are not verified. + To verify them, pass a context created by + :func:`ssl.create_default_context`. + The optional *timeout* parameter specifies a timeout in seconds for the connection attempt. If timeout is not given or is ``None``, the global default socket timeout is used. @@ -581,6 +588,13 @@ An :class:`IMAP4` instance has the following methods: encryption on the IMAP connection. Please read :ref:`ssl-security` for best practices. + .. note:: + + With the default *ssl_context*, the connection is encrypted but the + server certificate and hostname are not verified. + To verify them, pass a context created by + :func:`ssl.create_default_context`. + .. versionadded:: 3.2 .. versionchanged:: 3.4 From f4b3dd560012658deac4f74ea778ee8563cbe181 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 2 Jul 2026 09:40:43 +0200 Subject: [PATCH 537/818] [3.15] gh-63121: Refresh imaplib capabilities on state changes (GH-152752) (GH-152854) imaplib fetched the server capabilities only once, at connection time. They are now also refreshed after a successful LOGIN or AUTHENTICATE, from the CAPABILITY response the server sent or, if it sent none, by querying it. This lets methods such as enable() see capabilities added after login, for example ENABLE on Gmail (gh-103451). Capabilities advertised in the server greeting are now used too, saving a redundant CAPABILITY command. (cherry picked from commit c89b72abed7393d9d428f1e336e3aa02e7ef6ce8) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --- Lib/imaplib.py | 13 +++- Lib/test/test_imaplib.py | 69 ++++++++++++++++++- ...6-07-01-10-30-00.gh-issue-63121.Rm4tZp.rst | 7 ++ 3 files changed, 87 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-07-01-10-30-00.gh-issue-63121.Rm4tZp.rst diff --git a/Lib/imaplib.py b/Lib/imaplib.py index 497b5a60cecb08..26773fb0ee083b 100644 --- a/Lib/imaplib.py +++ b/Lib/imaplib.py @@ -255,7 +255,7 @@ def _connect(self): else: raise self.error(self.welcome) - self._get_capabilities() + self._refresh_capabilities() if __debug__: if self.debug >= 3: self._mesg('CAPABILITIES: %r' % (self.capabilities,)) @@ -533,6 +533,7 @@ def authenticate(self, mechanism, authobject): if typ != 'OK': raise self.error(dat[-1].decode('utf-8', 'replace')) self.state = 'AUTH' + self._refresh_capabilities() return typ, dat @@ -714,6 +715,7 @@ def login(self, user, password): if typ != 'OK': raise self.error(dat[-1].decode('UTF-8', 'replace')) self.state = 'AUTH' + self._refresh_capabilities() return typ, dat @@ -1201,6 +1203,15 @@ def _get_capabilities(self): self.capabilities = tuple(dat.split()) + def _refresh_capabilities(self): + # Use a CAPABILITY response sent by the server, or ask for it. + if 'CAPABILITY' in self.untagged_responses: + dat = self.untagged_responses.pop('CAPABILITY')[-1] + self.capabilities = tuple(str(dat, self._encoding).upper().split()) + else: + self._get_capabilities() + + def _get_response(self, start_timeout=False): # Read response and store. diff --git a/Lib/test/test_imaplib.py b/Lib/test/test_imaplib.py index fb256fb7cbcd34..fa23d09806e6fb 100644 --- a/Lib/test/test_imaplib.py +++ b/Lib/test/test_imaplib.py @@ -136,9 +136,11 @@ def _send_textline(self, message): def _send_tagged(self, tag, code, message): self._send_textline(' '.join((tag, code, message))) + welcome = '* OK IMAP4rev1' + def handle(self): # Send a welcome message. - self._send_textline('* OK IMAP4rev1') + self._send_textline(self.welcome) while 1: # Gather up input until we receive a line terminator or we timeout. # Accumulate read(1) because it's simpler to handle the differences @@ -634,6 +636,71 @@ def test_login(self): self.assertEqual(data[0], b'LOGIN completed') self.assertEqual(client.state, 'AUTH') + def test_login_capabilities(self): + # A server may advertise new capabilities after login (as an + # untagged CAPABILITY response); imaplib must refresh its cached + # capability list (gh-63121, gh-103451). + class CapabilityLoginHandler(SimpleIMAPHandler): + def cmd_LOGIN(self, tag, args): + self.server.logged = args[0] + self._send_textline('* CAPABILITY IMAP4rev1 ENABLE UTF8=ACCEPT') + self._send_tagged(tag, 'OK', 'LOGIN completed') + def cmd_ENABLE(self, tag, args): + self._send_tagged(tag, 'OK', 'ENABLE completed') + + client, _ = self._setup(CapabilityLoginHandler) + self.assertNotIn('ENABLE', client.capabilities) + client.login('user', 'pass') + self.assertIn('ENABLE', client.capabilities) + self.assertIn('UTF8=ACCEPT', client.capabilities) + typ, _ = client.enable('UTF8=ACCEPT') + self.assertEqual(typ, 'OK') + + def test_authenticate_capabilities(self): + # Capabilities are also refreshed after AUTHENTICATE, here from a + # CAPABILITY response code in the tagged OK response. + class CapabilityAuthHandler(SimpleIMAPHandler): + def cmd_AUTHENTICATE(self, tag, args): + self._send_textline('+') + self.server.response = yield + self._send_tagged( + tag, 'OK', + '[CAPABILITY IMAP4rev1 ENABLE] AUTHENTICATE completed') + + client, _ = self._setup(CapabilityAuthHandler) + self.assertNotIn('ENABLE', client.capabilities) + client.authenticate('MYAUTH', lambda x: b'fake') + self.assertIn('ENABLE', client.capabilities) + + def test_greeting_capabilities(self): + # Capabilities advertised in the greeting are used directly, + # without sending a separate CAPABILITY command. + class GreetingHandler(SimpleIMAPHandler): + welcome = '* OK [CAPABILITY IMAP4rev1 ENABLE] Server ready' + def cmd_CAPABILITY(self, tag, args): + self.server.capability_queried = True + super().cmd_CAPABILITY(tag, args) + + client, server = self._setup(GreetingHandler) + self.assertEqual(client.capabilities, ('IMAP4REV1', 'ENABLE')) + self.assertFalse(getattr(server, 'capability_queried', False)) + + def test_login_requery_capabilities(self): + # If the server does not advertise capabilities after login, + # imaplib re-queries them (as it does after STARTTLS), so a + # capability that becomes available only after authentication is + # still recognized (gh-63121). + class RequeryHandler(SimpleIMAPHandler): + def cmd_CAPABILITY(self, tag, args): + caps = 'IMAP4rev1 ENABLE' if self.server.logged else 'IMAP4rev1' + self._send_textline('* CAPABILITY ' + caps) + self._send_tagged(tag, 'OK', 'CAPABILITY completed') + + client, _ = self._setup(RequeryHandler) + self.assertNotIn('ENABLE', client.capabilities) + client.login('user', 'pass') + self.assertIn('ENABLE', client.capabilities) + def test_logout(self): client, _ = self._setup(SimpleIMAPHandler) typ, data = client.login('user', 'pass') diff --git a/Misc/NEWS.d/next/Library/2026-07-01-10-30-00.gh-issue-63121.Rm4tZp.rst b/Misc/NEWS.d/next/Library/2026-07-01-10-30-00.gh-issue-63121.Rm4tZp.rst new file mode 100644 index 00000000000000..a63b164ad7a627 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-01-10-30-00.gh-issue-63121.Rm4tZp.rst @@ -0,0 +1,7 @@ +:mod:`imaplib` now refreshes the cached capability list after a successful +:meth:`~imaplib.IMAP4.login` or :meth:`~imaplib.IMAP4.authenticate`, using +the ``CAPABILITY`` response sent by the server or, if none was sent, by +querying it, so that capabilities that become available only after +authentication (such as ``ENABLE`` on Gmail) are recognized. Capabilities +advertised in the server greeting are now also used, avoiding a redundant +``CAPABILITY`` command. From 6a1a23f2e79617e5d7ef3ce141105f9f9fc50b10 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 2 Jul 2026 09:46:30 +0200 Subject: [PATCH 538/818] [3.15] gh-108280: Give a meaningful error for an invalid imaplib greeting (GH-152768) (GH-152856) Connecting to a server that does not send a valid IMAP4 greeting, such as a POP3 server answering on the IMAP port, failed with the unhelpful "imaplib.IMAP4.error: None". A meaningful message is now raised instead. (cherry picked from commit 262b6a0df5a325e788928ab0cd514fa4786571b4) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --- Lib/imaplib.py | 6 +++- Lib/test/test_imaplib.py | 33 +++++++++++++++++++ ...-07-01-12-00-00.gh-issue-108280.Nq8vTr.rst | 4 +++ 3 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2026-07-01-12-00-00.gh-issue-108280.Nq8vTr.rst diff --git a/Lib/imaplib.py b/Lib/imaplib.py index 26773fb0ee083b..ca2ae40726b2d1 100644 --- a/Lib/imaplib.py +++ b/Lib/imaplib.py @@ -253,7 +253,11 @@ def _connect(self): elif 'OK' in self.untagged_responses: self.state = 'NONAUTH' else: - raise self.error(self.welcome) + # A continuation ('+') greeting is returned as None; report its + # raw line, still held by the last match (gh-108280). + greeting = (self.welcome or self.mo.string).decode( + self._encoding, 'replace') + raise self.error('invalid greeting: ' + greeting) self._refresh_capabilities() if __debug__: diff --git a/Lib/test/test_imaplib.py b/Lib/test/test_imaplib.py index fa23d09806e6fb..67bf47ad41a1ac 100644 --- a/Lib/test/test_imaplib.py +++ b/Lib/test/test_imaplib.py @@ -331,6 +331,39 @@ def handle(self): self.assertRaises(imaplib.IMAP4.abort, self.imap_class, *server.server_address) + def test_invalid_greeting(self): + # An invalid greeting, e.g. from a POP3 server on the IMAP port, + # must not fail with "error: None" but report the server's line + # (gh-108280). + class Pop3Handler(socketserver.StreamRequestHandler): + def handle(self): + self.wfile.write(b'+OK POP3 server ready\r\n') + _, server = self._setup(Pop3Handler, connect=False) + with self.assertRaisesRegex(imaplib.IMAP4.error, + r'invalid greeting: \+OK POP3 server ready'): + self.imap_class(*server.server_address) + + def test_invalid_greeting_untagged(self): + # An untagged greeting that is neither OK nor PREAUTH (e.g. BYE) + # is reported as is (gh-108280). + class ByeHandler(socketserver.StreamRequestHandler): + def handle(self): + self.wfile.write(b'* BYE Server unavailable\r\n') + _, server = self._setup(ByeHandler, connect=False) + with self.assertRaisesRegex(imaplib.IMAP4.error, + r'invalid greeting: \* BYE Server unavailable'): + self.imap_class(*server.server_address) + + def test_invalid_greeting_bare_continuation(self): + # A bare continuation greeting is still reported (gh-108280). + class BareHandler(socketserver.StreamRequestHandler): + def handle(self): + self.wfile.write(b'+\r\n') + _, server = self._setup(BareHandler, connect=False) + with self.assertRaisesRegex(imaplib.IMAP4.error, + r'invalid greeting: \+'): + self.imap_class(*server.server_address) + def test_line_termination(self): class BadNewlineHandler(SimpleIMAPHandler): def cmd_CAPABILITY(self, tag, args): diff --git a/Misc/NEWS.d/next/Library/2026-07-01-12-00-00.gh-issue-108280.Nq8vTr.rst b/Misc/NEWS.d/next/Library/2026-07-01-12-00-00.gh-issue-108280.Nq8vTr.rst new file mode 100644 index 00000000000000..487c9da67f1832 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-01-12-00-00.gh-issue-108280.Nq8vTr.rst @@ -0,0 +1,4 @@ +Connecting :mod:`imaplib` to a server that does not send a valid IMAP4 +greeting (for example a POP3 server answering on the IMAP port) now raises +an error reporting the server's response instead of +``imaplib.IMAP4.error: None``. From c5b0c81c52f1a1580113519fb17c25dee9caf433 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 2 Jul 2026 10:07:57 +0200 Subject: [PATCH 539/818] [3.15] gh-144473: Add "steal" term to glossary; clarify "stealing" on error (GH-144502) (GH-152771) With one exception, all "stealing" functions also steal on error, but it makes sense to note this in each case. (cherry picked from commit 34503f39532279efb12653754bb3a7e535fb66cc) Co-authored-by: Petr Viktorin <encukou@gmail.com> Co-authored-by: Peter Bierma <zintensitydev@gmail.com> --- Doc/c-api/bytes.rst | 9 +++++---- Doc/c-api/dict.rst | 4 ++-- Doc/c-api/exceptions.rst | 15 +++++++++------ Doc/c-api/gen.rst | 13 +++++++------ Doc/c-api/intro.rst | 9 ++++++--- Doc/c-api/list.rst | 8 +++++--- Doc/c-api/module.rst | 8 ++++---- Doc/c-api/sequence.rst | 2 +- Doc/c-api/threads.rst | 2 +- Doc/c-api/tuple.rst | 9 +++++---- Doc/c-api/unicode.rst | 3 ++- Doc/glossary.rst | 8 ++++++++ 12 files changed, 55 insertions(+), 35 deletions(-) diff --git a/Doc/c-api/bytes.rst b/Doc/c-api/bytes.rst index fa77d3d38ff89f..ff68ecafcda4d0 100644 --- a/Doc/c-api/bytes.rst +++ b/Doc/c-api/bytes.rst @@ -184,10 +184,11 @@ called with a non-bytes parameter. .. c:function:: void PyBytes_Concat(PyObject **bytes, PyObject *newpart) Create a new bytes object in *\*bytes* containing the contents of *newpart* - appended to *bytes*; the caller will own the new reference. The reference to - the old value of *bytes* will be stolen. If the new object cannot be - created, the old reference to *bytes* will still be discarded and the value - of *\*bytes* will be set to ``NULL``; the appropriate exception will be set. + appended to *bytes*; the caller will own the new reference. + The reference to the old value of *bytes* will be ":term:`stolen <steal>`". + If the new object cannot be created, the old reference to *bytes* will still + be "stolen", the value of *\*bytes* will be set to ``NULL``, and + the appropriate exception will be set. .. note:: If *newpart* implements the buffer protocol, then the buffer diff --git a/Doc/c-api/dict.rst b/Doc/c-api/dict.rst index 556113a97bf772..87d09ad2412e40 100644 --- a/Doc/c-api/dict.rst +++ b/Doc/c-api/dict.rst @@ -107,8 +107,8 @@ Dictionary objects Insert *val* into the dictionary *p* with a key of *key*. *key* must be :term:`hashable`; if it isn't, :exc:`TypeError` will be raised. Return - ``0`` on success or ``-1`` on failure. This function *does not* steal a - reference to *val*. + ``0`` on success or ``-1`` on failure. + This function *does not* ":term:`steal`" a reference to *val*. .. note:: diff --git a/Doc/c-api/exceptions.rst b/Doc/c-api/exceptions.rst index f3f408c400bed0..312095ad85f8b6 100644 --- a/Doc/c-api/exceptions.rst +++ b/Doc/c-api/exceptions.rst @@ -503,7 +503,8 @@ Querying the error indicator .. warning:: - This call steals a reference to *exc*, which must be a valid exception. + This call ":term:`steals <steal>`" a reference to *exc*, + which must be a valid exception. .. versionadded:: 3.12 @@ -641,7 +642,8 @@ Querying the error indicator Set the exception info, as known from ``sys.exc_info()``. This refers to an exception that was *already caught*, not to an exception that was - freshly raised. This function steals the references of the arguments. + freshly raised. This function ":term:`steals <steal>`" the references + of the arguments. To clear the exception state, pass ``NULL`` for all three arguments. This function is kept for backwards compatibility. Prefer using :c:func:`PyErr_SetHandledException`. @@ -658,8 +660,8 @@ Querying the error indicator .. versionchanged:: 3.11 The ``type`` and ``traceback`` arguments are no longer used and can be NULL. The interpreter now derives them from the exception - instance (the ``value`` argument). The function still steals - references of all three arguments. + instance (the ``value`` argument). The function still + ":term:`steals <steal>`" references of all three arguments. Signal Handling @@ -869,7 +871,7 @@ Exception Objects Set the context associated with the exception to *ctx*. Use ``NULL`` to clear it. There is no type check to make sure that *ctx* is an exception instance. - This steals a reference to *ctx*. + This ":term:`steals <steal>`" a reference to *ctx*. .. c:function:: PyObject* PyException_GetCause(PyObject *ex) @@ -884,7 +886,8 @@ Exception Objects Set the cause associated with the exception to *cause*. Use ``NULL`` to clear it. There is no type check to make sure that *cause* is either an exception - instance or ``None``. This steals a reference to *cause*. + instance or ``None``. + This ":term:`steals <steal>`" a reference to *cause*. The :attr:`~BaseException.__suppress_context__` attribute is implicitly set to ``True`` by this function. diff --git a/Doc/c-api/gen.rst b/Doc/c-api/gen.rst index ed121726b89620..8648d529170c82 100644 --- a/Doc/c-api/gen.rst +++ b/Doc/c-api/gen.rst @@ -35,15 +35,15 @@ than explicitly calling :c:func:`PyGen_New` or :c:func:`PyGen_NewWithQualName`. .. c:function:: PyObject* PyGen_New(PyFrameObject *frame) Create and return a new generator object based on the *frame* object. - A reference to *frame* is stolen by this function. The argument must not be - ``NULL``. + A reference to *frame* is ":term:`stolen <steal>`" by this function (even + on error). The argument must not be ``NULL``. .. c:function:: PyObject* PyGen_NewWithQualName(PyFrameObject *frame, PyObject *name, PyObject *qualname) Create and return a new generator object based on the *frame* object, with ``__name__`` and ``__qualname__`` set to *name* and *qualname*. - A reference to *frame* is stolen by this function. The *frame* argument - must not be ``NULL``. + A reference to *frame* is ":term:`stolen <steal>`" by this function (even + on error). The *frame* argument must not be ``NULL``. .. c:function:: PyCodeObject* PyGen_GetCode(PyGenObject *gen) @@ -68,8 +68,9 @@ Asynchronous Generator Objects .. c:function:: PyObject *PyAsyncGen_New(PyFrameObject *frame, PyObject *name, PyObject *qualname) Create a new asynchronous generator wrapping *frame*, with ``__name__`` and - ``__qualname__`` set to *name* and *qualname*. *frame* is stolen by this - function and must not be ``NULL``. + ``__qualname__`` set to *name* and *qualname*. + *frame* is ":term:`stolen <steal>`" by this function (even on error) and + must not be ``NULL``. On success, this function returns a :term:`strong reference` to the new asynchronous generator. On failure, this function returns ``NULL`` diff --git a/Doc/c-api/intro.rst b/Doc/c-api/intro.rst index 500f2818e2e40a..4c0c9af45e8360 100644 --- a/Doc/c-api/intro.rst +++ b/Doc/c-api/intro.rst @@ -737,9 +737,12 @@ the caller is said to *borrow* the reference. Nothing needs to be done for a Conversely, when a calling function passes in a reference to an object, there are two possibilities: the function *steals* a reference to the object, or it -does not. *Stealing a reference* means that when you pass a reference to a -function, that function assumes that it now owns that reference, and you are not -responsible for it any longer. +does not. + +*Stealing a reference* means that when you pass a reference to a +function, that function assumes that it now owns that reference. +Since the new owner can use :c:func:`!Py_DECREF` at its discretion, +you (the caller) must not use that reference after the call. .. index:: single: PyList_SetItem (C function) diff --git a/Doc/c-api/list.rst b/Doc/c-api/list.rst index 8f560699d355e4..21769c4c5c869c 100644 --- a/Doc/c-api/list.rst +++ b/Doc/c-api/list.rst @@ -102,8 +102,10 @@ List Objects .. note:: - This function "steals" a reference to *item* and discards a reference to - an item already in the list at the affected position. + This function ":term:`steals <steal>`" a reference to *item*, + even on error. + On success, it discards a reference to an item already in the list + at the affected position (unless it was ``NULL``). .. c:function:: void PyList_SET_ITEM(PyObject *list, Py_ssize_t i, PyObject *o) @@ -117,7 +119,7 @@ List Objects .. note:: - This macro "steals" a reference to *item*, and, unlike + This macro ":term:`steals <steal>`" a reference to *item*, and, unlike :c:func:`PyList_SetItem`, does *not* discard a reference to any item that is being replaced; any reference in *list* at position *i* will be leaked. diff --git a/Doc/c-api/module.rst b/Doc/c-api/module.rst index 8e805b284e0ea4..31df4451f15e66 100644 --- a/Doc/c-api/module.rst +++ b/Doc/c-api/module.rst @@ -974,8 +974,8 @@ or code that creates modules dynamically. .. c:function:: int PyModule_Add(PyObject *module, const char *name, PyObject *value) - Similar to :c:func:`PyModule_AddObjectRef`, but "steals" a reference - to *value*. + Similar to :c:func:`PyModule_AddObjectRef`, but ":term:`steals <steal>`" + a reference to *value* (even on error). It can be called with a result of function that returns a new reference without bothering to check its result or even saving it to a variable. @@ -990,8 +990,8 @@ or code that creates modules dynamically. .. c:function:: int PyModule_AddObject(PyObject *module, const char *name, PyObject *value) - Similar to :c:func:`PyModule_AddObjectRef`, but steals a reference to - *value* on success (if it returns ``0``). + Similar to :c:func:`PyModule_AddObjectRef`, but :term:`steals <steal>` + a reference to *value* on success (if it returns ``0``). The new :c:func:`PyModule_Add` or :c:func:`PyModule_AddObjectRef` functions are recommended, since it is diff --git a/Doc/c-api/sequence.rst b/Doc/c-api/sequence.rst index 6bae8f25ad75d1..90490cf6749b59 100644 --- a/Doc/c-api/sequence.rst +++ b/Doc/c-api/sequence.rst @@ -67,7 +67,7 @@ Sequence Protocol Assign object *v* to the *i*\ th element of *o*. Raise an exception and return ``-1`` on failure; return ``0`` on success. This is the equivalent of the Python statement ``o[i] = v``. This function *does - not* steal a reference to *v*. + not* ":term:`steal`" a reference to *v*. If *v* is ``NULL``, the element is deleted, but this feature is deprecated in favour of using :c:func:`PySequence_DelItem`. diff --git a/Doc/c-api/threads.rst b/Doc/c-api/threads.rst index bec6c1f6045f02..3bd18da72c78ed 100644 --- a/Doc/c-api/threads.rst +++ b/Doc/c-api/threads.rst @@ -924,7 +924,7 @@ pointer and a void pointer argument. To prevent naive misuse, you must write your own C extension to call this. This function must be called with an :term:`attached thread state`. - This function does not steal any references to *exc*. + This function does not :term:`steal` any references to *exc*. This function does not necessarily interrupt system calls such as :py:func:`~time.sleep`. diff --git a/Doc/c-api/tuple.rst b/Doc/c-api/tuple.rst index ba4c6b93de4c11..e8be4762dc33a1 100644 --- a/Doc/c-api/tuple.rst +++ b/Doc/c-api/tuple.rst @@ -104,8 +104,9 @@ Tuple Objects .. note:: - This function "steals" a reference to *o* and discards a reference to - an item already in the tuple at the affected position. + This function ":term:`steals <steal>`" a reference to *o* and discards + a reference to an item already in the tuple at the affected position + (unless it was NULL). .. c:function:: void PyTuple_SET_ITEM(PyObject *p, Py_ssize_t pos, PyObject *o) @@ -118,7 +119,7 @@ Tuple Objects .. note:: - This function "steals" a reference to *o*, and, unlike + This function ":term:`steals <steal>`" a reference to *o*, and, unlike :c:func:`PyTuple_SetItem`, does *not* discard a reference to any item that is being replaced; any reference in the tuple at position *pos* will be leaked. @@ -263,7 +264,7 @@ type. .. note:: - This function "steals" a reference to *o*. + This function ":term:`steals <steal>`" a reference to *o*. .. c:function:: void PyStructSequence_SET_ITEM(PyObject *p, Py_ssize_t *pos, PyObject *o) diff --git a/Doc/c-api/unicode.rst b/Doc/c-api/unicode.rst index 401c99ebeb0fec..aa411db484e430 100644 --- a/Doc/c-api/unicode.rst +++ b/Doc/c-api/unicode.rst @@ -676,7 +676,8 @@ APIs: 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. + :c:func:`!PyUnicode_Append` releases (":term:`steals <steal>`") + this reference. On error, set *\*p_left* to ``NULL`` and set an exception. diff --git a/Doc/glossary.rst b/Doc/glossary.rst index 7b74651fda1fe5..515fa77dd038df 100644 --- a/Doc/glossary.rst +++ b/Doc/glossary.rst @@ -1515,6 +1515,14 @@ Glossary stdlib An abbreviation of :term:`standard library`. + steal + In Python's C API, "*stealing*" an argument means that ownership of the + argument is transferred to the called function. + The caller must not use that reference after the call. + Generally, functions that "steal" an argument do so even if they fail. + + See :ref:`api-refcountdetails` for a full explanation. + strong reference In Python's C API, a strong reference is a reference to an object which is owned by the code holding the reference. The strong From c2cb9bdcdc905a0859a9c456dcff548909b101d0 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 2 Jul 2026 10:20:14 +0200 Subject: [PATCH 540/818] [3.15] gh-152569: Fix asyncio.wait leaking tasks via await-graph on long-lived futures (GH-152585) (#152868) gh-152569: Fix asyncio.wait leaking tasks via await-graph on long-lived futures (GH-152585) (cherry picked from commit f8514dccaca4acb84ba02188c3e433a9d6989c13) Co-authored-by: Simon Knott <info@simonknott.de> --- Lib/asyncio/tasks.py | 1 + Lib/test/test_asyncio/test_tasks.py | 13 +++++++++++++ .../2026-06-29-09-45-00.gh-issue-152569.Kf7Lq2.rst | 3 +++ 3 files changed, 17 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2026-06-29-09-45-00.gh-issue-152569.Kf7Lq2.rst diff --git a/Lib/asyncio/tasks.py b/Lib/asyncio/tasks.py index 14d3c1ceb58cac..9d20930dc300c6 100644 --- a/Lib/asyncio/tasks.py +++ b/Lib/asyncio/tasks.py @@ -524,6 +524,7 @@ def _on_completion(f): timeout_handle.cancel() for f in fs: f.remove_done_callback(_on_completion) + futures.future_discard_from_awaited_by(f, cur_task) done, pending = set(), set() for f in fs: diff --git a/Lib/test/test_asyncio/test_tasks.py b/Lib/test/test_asyncio/test_tasks.py index dc179acd86e8a6..fa7e21c3536582 100644 --- a/Lib/test/test_asyncio/test_tasks.py +++ b/Lib/test/test_asyncio/test_tasks.py @@ -1218,6 +1218,19 @@ def gen(): loop.advance_time(10) loop.run_until_complete(asyncio.wait([a, b])) + def test_wait_discards_awaited_by_for_pending(self): + # gh-152569: wait() must remove itself from the await-graph of every + # future once it returns, including futures that never resolved. + async def coro(): + immortal = self.loop.create_future() + done = self.new_task(self.loop, asyncio.sleep(0)) + await asyncio.wait({done, immortal}, + return_when=asyncio.FIRST_COMPLETED) + self.assertFalse(immortal._asyncio_awaited_by) + immortal.cancel() + + self.loop.run_until_complete(self.new_task(self.loop, coro())) + def test_wait_really_done(self): # there is possibility that some tasks in the pending list # became done but their callbacks haven't all been called yet diff --git a/Misc/NEWS.d/next/Library/2026-06-29-09-45-00.gh-issue-152569.Kf7Lq2.rst b/Misc/NEWS.d/next/Library/2026-06-29-09-45-00.gh-issue-152569.Kf7Lq2.rst new file mode 100644 index 00000000000000..fb7e32a5260b39 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-29-09-45-00.gh-issue-152569.Kf7Lq2.rst @@ -0,0 +1,3 @@ +Fix :func:`asyncio.wait` leaking waiting tasks via the await-graph when racing a +future that never resolves. The waiting task is now discarded from every future's +``awaited_by`` set once :func:`~asyncio.wait` returns, even for pending futures. From d13f5b27c8e1af059304c857986eec91de9146c8 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 2 Jul 2026 10:23:23 +0200 Subject: [PATCH 541/818] [3.15] gh-151763: Fix OOM-0013 crash when the parser or compiler fails to allocate (GH-151968) (#152836) --- .../2026-06-23-12-03-55.gh-issue-151763.K7QfWG.rst | 3 +++ Parser/pegen.c | 14 +++++++++++++- Python/compile.c | 1 + 3 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-23-12-03-55.gh-issue-151763.K7QfWG.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-23-12-03-55.gh-issue-151763.K7QfWG.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-23-12-03-55.gh-issue-151763.K7QfWG.rst new file mode 100644 index 00000000000000..64d0146cb09101 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-23-12-03-55.gh-issue-151763.K7QfWG.rst @@ -0,0 +1,3 @@ +Fix a potential crash in :func:`compile`, :func:`exec`, :func:`eval` and +:func:`ast.parse` when an allocation fails: the parser or compiler could +return without setting an exception. diff --git a/Parser/pegen.c b/Parser/pegen.c index bb222b50fc095f..165dcb9f995095 100644 --- a/Parser/pegen.c +++ b/Parser/pegen.c @@ -940,6 +940,11 @@ _PyPegen_run_parser(Parser *p) { void *res = _PyPegen_parse(p); assert(p->level == 0); + if (res != NULL && PyErr_Occurred()) { + // Discard a result returned with an exception still pending + // (e.g. a MemoryError from a recovered-from allocation failure). + return NULL; + } if (res == NULL) { if ((p->flags & PyPARSE_ALLOW_INCOMPLETE_INPUT) && _is_end_of_source(p)) { PyErr_Clear(); @@ -995,7 +1000,10 @@ _PyPegen_run_parser_from_file_pointer(FILE *fp, int start_rule, PyObject *filena if (tok == NULL) { if (PyErr_Occurred()) { _PyTokenizer_raise_init_error(filename_ob); - return NULL; + } + else { + // The only silent tokenizer init failure is a failed allocation. + PyErr_NoMemory(); } return NULL; } @@ -1054,6 +1062,10 @@ _PyPegen_run_parser_from_string(const char *str, int start_rule, PyObject *filen if (PyErr_Occurred()) { _PyTokenizer_raise_init_error(filename_ob); } + else { + // The only silent tokenizer init failure is a failed allocation. + PyErr_NoMemory(); + } return NULL; } // This transfers the ownership to the tokenizer diff --git a/Python/compile.c b/Python/compile.c index e223ef42a42e22..f2c1de5e0c07c6 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -174,6 +174,7 @@ new_compiler(mod_ty mod, PyObject *filename, PyCompilerFlags *pflags, { compiler *c = PyMem_Calloc(1, sizeof(compiler)); if (c == NULL) { + PyErr_NoMemory(); return NULL; } if (compiler_setup(c, mod, filename, pflags, optimize, arena, module) < 0) { From ad6b3590cff0011d521a7fb14cbd04f78763903b Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 2 Jul 2026 12:40:07 +0200 Subject: [PATCH 542/818] [3.15] gh-66335: Add tests for imaplib command methods (GH-152872) (GH-152873) Add coverage tests for the IMAP4 command methods and their UID variants (SELECT, CREATE, COPY, STORE, FETCH, SEARCH, SORT, THREAD, DELETE, RENAME, SUBSCRIBE, UNSUBSCRIBE, LIST, STATUS, the ACL and quota commands, ANNOTATION, PROXYAUTH and ENABLE), plus test helpers (splitargs, parse_sequence_set, make_simple_handler) and per-command argument capture in the test server. (cherry picked from commit a50b089b7c46e3068d9177b5f18ac767a31a18cd) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --- Lib/test/test_imaplib.py | 672 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 660 insertions(+), 12 deletions(-) diff --git a/Lib/test/test_imaplib.py b/Lib/test/test_imaplib.py index 67bf47ad41a1ac..e797a625014603 100644 --- a/Lib/test/test_imaplib.py +++ b/Lib/test/test_imaplib.py @@ -26,6 +26,68 @@ CERTFILE = os.path.join(os.path.dirname(__file__) or os.curdir, "certdata", "keycert3.pem") CAFILE = os.path.join(os.path.dirname(__file__) or os.curdir, "certdata", "pycacert.pem") +_quoted_string = re.compile(r'"(?:[^"\\]|\\.)*"') + + +def splitargs(line): + # Split a command line into IMAP arguments: quoted strings, balanced + # (possibly nested) parenthesized lists, and bare atoms. + args = [] + i, n = 0, len(line) + while i < n: + if line[i] == ' ': + i += 1 + continue + start = i + depth = 0 + while i < n and (depth or line[i] != ' '): + c = line[i] + if c == '"': + i = _quoted_string.match(line, i).end() + continue + elif c == '(': + depth += 1 + elif c == ')': + depth -= 1 + i += 1 + args.append(line[start:i]) + return args + + +def parse_seq_number(s, maxmsg): + if s == '*': + return maxmsg + return int(s) + + +def parse_sequence_set(arg, maxmsg): + for s in arg.split(','): + if ':' in s: + lo, hi = s.split(':') + lo = parse_seq_number(lo, maxmsg) + hi = parse_seq_number(hi, maxmsg) + yield from range(min(lo, hi), max(lo, hi) + 1) + else: + yield parse_seq_number(s, maxmsg) + + +def make_simple_handler(command, untagged_response=(), + completed=None): + if completed is None: + completed = f'{command} completed' + def cmd(self, tag, args): + for msg in untagged_response: + self._send_textline(msg) + self._send_tagged(tag, 'OK', completed) + cmd.__name__ = 'cmd_' + command + class Handler(SimpleIMAPHandler): + pass + Handler.__name__ = command.title() + 'Handler' + setattr(Handler, cmd.__name__, cmd) + Handler.__qualname__ = Handler.__name__ + cmd.__qualname__ = Handler.__qualname__ + '.' + cmd.__name__ + return Handler + class TestImaplib(unittest.TestCase): @@ -119,7 +181,7 @@ class SimpleIMAPHandler(socketserver.StreamRequestHandler): def setup(self): super().setup() - self.server.is_selected = False + self.server.is_selected = None self.server.logged = None def _send(self, message): @@ -167,10 +229,11 @@ def handle(self): except StopIteration: self.continuation = None continue - splitline = line.decode('ASCII').split() + splitline = splitargs(line.decode().removesuffix('\r\n')) tag = splitline[0] cmd = splitline[1] args = splitline[2:] + self.server.args = args if hasattr(self, 'cmd_' + cmd): continuation = getattr(self, 'cmd_' + cmd)(tag, args) @@ -197,13 +260,18 @@ def cmd_LOGIN(self, tag, args): self._send_tagged(tag, 'OK', 'LOGIN completed') def cmd_SELECT(self, tag, args): - self.server.is_selected = True + self.server.is_selected = args self._send_line(b'* 2 EXISTS') self._send_tagged(tag, 'OK', '[READ-WRITE] SELECT completed.') + def cmd_EXAMINE(self, tag, args): + self.server.is_selected = args + self._send_line(b'* 2 EXISTS') + self._send_tagged(tag, 'OK', '[READ-ONLY] EXAMINE completed.') + def cmd_UNSELECT(self, tag, args): - if self.server.is_selected: - self.server.is_selected = False + if self.server.is_selected is not None: + self.server.is_selected = None self._send_tagged(tag, 'OK', 'Returned to authenticated state. (Success)') else: self._send_tagged(tag, 'BAD', 'No mailbox selected') @@ -745,18 +813,20 @@ def test_logout(self): self.assertEqual(client.state, 'LOGOUT') def test_lsub(self): - class LsubCmd(SimpleIMAPHandler): - def cmd_LSUB(self, tag, args): - self._send_textline('* LSUB () "." directoryA') - return self._send_tagged(tag, 'OK', 'LSUB completed') - client, _ = self._setup(LsubCmd) + client, server = self._setup(make_simple_handler('LSUB', + ['* LSUB () "." directoryA', '* LSUB () "." directoryB'])) client.login('user', 'pass') typ, data = client.lsub() self.assertEqual(typ, 'OK') - self.assertEqual(data[0], b'() "." directoryA') + self.assertEqual(data, [b'() "." directoryA', b'() "." directoryB']) + self.assertEqual(server.args, ['""', '*']) + + typ, data = client.lsub('~/Mail/', '%') + self.assertEqual(typ, 'OK') + self.assertEqual(server.args, ['~/Mail/', '%']) def test_unselect(self): - client, _ = self._setup(SimpleIMAPHandler) + client, server = self._setup(SimpleIMAPHandler) client.login('user', 'pass') typ, data = client.select() self.assertEqual(typ, 'OK') @@ -766,6 +836,584 @@ def test_unselect(self): self.assertEqual(typ, 'OK') self.assertEqual(data[0], b'Returned to authenticated state. (Success)') self.assertEqual(client.state, 'AUTH') + self.assertIsNone(server.is_selected) + + def test_enable(self): + class EnableHandler(SimpleIMAPHandler): + capabilities = 'IMAP4rev1 ID LITERAL+ ENABLE X-GOOD-IDEA' + def cmd_ENABLE(self, tag, args): + capabilities = self.capabilities.split() + for arg in args: + if arg in capabilities: + self._send_textline('* ENABLED ' + arg) + self._send_tagged(tag, 'OK', 'foo') + + client, server = self._setup(EnableHandler) + client.login('user', 'pass') + code, data = client.enable('CONDSTORE X-GOOD-IDEA') + self.assertEqual(code, 'OK') + self.assertEqual(data, [b'foo']) + self.assertEqual(server.args, ['CONDSTORE', 'X-GOOD-IDEA']) + + def test_select(self): + client, server = self._setup(SimpleIMAPHandler) + client.login('user', 'pass') + typ, data = client.select() + self.assertEqual(typ, 'OK') + self.assertEqual(data[0], b'2') + self.assertEqual(server.is_selected, ['INBOX']) + + typ, data = client.select('Archive') + self.assertEqual(typ, 'OK') + self.assertEqual(server.is_selected, ['Archive']) + + # readonly=True issues EXAMINE instead of SELECT + # (there is no separate examine() method). + typ, data = client.select(readonly=True) + self.assertEqual(typ, 'OK') + self.assertEqual(data[0], b'2') + self.assertEqual(server.is_selected, ['INBOX']) + self.assertTrue(client.is_readonly) + + def test_expunge(self): + client, server = self._setup(make_simple_handler('EXPUNGE', + ['* 3 EXPUNGE', '* 3 EXPUNGE', '* 5 EXPUNGE', '* 8 EXPUNGE'])) + client.login('user', 'pass') + client.select() + typ, data = client.expunge() + self.assertEqual(typ, 'OK') + self.assertEqual(data, [b'3', b'3', b'5', b'8']) + + def test_close(self): + client, server = self._setup(make_simple_handler('CLOSE')) + client.login('user', 'pass') + client.select() + typ, data = client.close() + self.assertEqual(typ, 'OK') + self.assertEqual(client.state, 'AUTH') + + def test_check(self): + client, server = self._setup(make_simple_handler('CHECK')) + client.login('user', 'pass') + client.select() + typ, data = client.check() + self.assertEqual(typ, 'OK') + + def test_noop(self): + client, server = self._setup(make_simple_handler('NOOP', + ['* 4 EXISTS'])) + client.login('user', 'pass') + typ, data = client.noop() + self.assertEqual(typ, 'OK') + # NOOP is used to pick up server-pushed untagged responses. + self.assertEqual(client.untagged_responses['EXISTS'], [b'4']) + + def test_namespace(self): + client, server = self._setup(make_simple_handler('NAMESPACE', + ['* NAMESPACE (("" "/")) NIL NIL'])) + client.login('user', 'pass') + typ, data = client.namespace() + self.assertEqual(typ, 'OK') + self.assertEqual(data[0], b'(("" "/")) NIL NIL') + + def test_capability(self): + client, server = self._setup(make_simple_handler('CAPABILITY', + ['* CAPABILITY IMAP4rev1 IDLE NAMESPACE'])) + client.login('user', 'pass') + typ, data = client.capability() + self.assertEqual(typ, 'OK') + self.assertEqual(data, [b'IMAP4rev1 IDLE NAMESPACE']) + + def test_recent(self): + # recent() prods the server with NOOP if no RECENT was seen yet. + client, server = self._setup(make_simple_handler('NOOP', + ['* 5 RECENT'])) + client.login('user', 'pass') + typ, data = client.recent() + self.assertEqual(typ, 'OK') + self.assertEqual(data, [b'5']) + + def test_response(self): + client, server = self._setup(SimpleIMAPHandler) + client.login('user', 'pass') + client.select() # the handler answers with '* 2 EXISTS' + typ, data = client.response('EXISTS') + self.assertEqual(typ, 'EXISTS') + self.assertEqual(data, [b'2']) + # The value is cleared once read. + typ, data = client.response('EXISTS') + self.assertEqual(data, [None]) + + def test_create(self): + client, server = self._setup(make_simple_handler('CREATE')) + client.login('user', 'pass') + typ, data = client.create('owatagusiam/') + self.assertEqual(typ, 'OK') + self.assertEqual(data, [b'CREATE completed']) + self.assertEqual(server.args, ['owatagusiam/']) + + typ, data = client.create('owatagusiam/blurdybloop') + self.assertEqual(typ, 'OK') + self.assertEqual(data, [b'CREATE completed']) + self.assertEqual(server.args, ['owatagusiam/blurdybloop']) + + def test_copy(self): + client, server = self._setup(make_simple_handler('COPY')) + client.login('user', 'pass') + client.select() + typ, data = client.copy('2:4', 'MEETING') + self.assertEqual(typ, 'OK') + self.assertEqual(data, [b'COPY completed']) + self.assertEqual(server.args, ['2:4', 'MEETING']) + + def test_uid_copy(self): + client, server = self._setup(make_simple_handler('UID', + completed='UID COPY completed')) + client.login('user', 'pass') + client.select() + typ, data = client.uid('copy', '4827313:4828442', 'MEETING') + self.assertEqual(typ, 'OK') + self.assertEqual(data, [None]) + self.assertEqual(server.args, ['COPY', '4827313:4828442', 'MEETING']) + + def test_store(self): + client, server = self._setup(make_simple_handler('STORE', [ + r'* 2 FETCH (FLAGS (\Deleted \Seen))', + r'* 3 FETCH (FLAGS (\Deleted))', + r'* 4 FETCH (FLAGS (\Deleted \Flagged \Seen))', + ])) + client.login('user', 'pass') + client.select() + typ, data = client.store('2:4', '+FLAGS', r'(\Deleted)') + self.assertEqual(typ, 'OK') + self.assertEqual(data, [ + br'2 (FLAGS (\Deleted \Seen))', + br'3 (FLAGS (\Deleted))', + br'4 (FLAGS (\Deleted \Flagged \Seen))', + ]) + self.assertEqual(server.args, ['2:4', '+FLAGS', r'(\Deleted)']) + + typ, data = client.store('2:4', '+FLAGS', r'\Deleted') + self.assertEqual(typ, 'OK') + self.assertEqual(server.args, ['2:4', '+FLAGS', r'(\Deleted)']) + + def test_uid_store(self): + client, server = self._setup(make_simple_handler('UID', [ + r'* 23 FETCH (FLAGS (\Deleted \Seen) UID 4827313)', + r'* 24 FETCH (FLAGS (\Deleted) UID 4827943)', + r'* 25 FETCH (FLAGS (\Deleted \Flagged \Seen) UID 4828442)', + ], 'UID STORE completed')) + client.login('user', 'pass') + client.select() + typ, data = client.uid('store', '4827313:4828442', '+FLAGS', r'(\Deleted)') + self.assertEqual(typ, 'OK') + self.assertEqual(data, [ + br'23 (FLAGS (\Deleted \Seen) UID 4827313)', + br'24 (FLAGS (\Deleted) UID 4827943)', + br'25 (FLAGS (\Deleted \Flagged \Seen) UID 4828442)', + ]) + self.assertEqual(server.args, ['STORE', '4827313:4828442', '+FLAGS', r'(\Deleted)']) + + def test_fetch(self): + # The handler expands the requested sequence set and answers for + # exactly those messages, so the test exercises the round trip of + # the message set, not just a canned reply. + class FetchHandler(SimpleIMAPHandler): + messages = 4 + def cmd_SELECT(self, tag, args): + self.server.is_selected = args + self._send_line(b'* %d EXISTS' % self.messages) + self._send_tagged(tag, 'OK', '[READ-WRITE] SELECT completed.') + def cmd_FETCH(self, tag, args): + for n in parse_sequence_set(args[0], self.messages): + self._send_textline(r'* %d FETCH (FLAGS (\Seen))' % n) + self._send_tagged(tag, 'OK', 'FETCH completed') + + client, server = self._setup(FetchHandler) + client.login('user', 'pass') + client.select() + typ, data = client.fetch('2:4', '(FLAGS)') + self.assertEqual(typ, 'OK') + self.assertEqual(data, [ + br'2 (FLAGS (\Seen))', + br'3 (FLAGS (\Seen))', + br'4 (FLAGS (\Seen))', + ]) + self.assertEqual(server.args, ['2:4', '(FLAGS)']) + + # A comma-separated set with an open range up to '*'. + typ, data = client.fetch('1,3:*', '(FLAGS)') + self.assertEqual(typ, 'OK') + self.assertEqual(data, [ + br'1 (FLAGS (\Seen))', + br'3 (FLAGS (\Seen))', + br'4 (FLAGS (\Seen))', + ]) + self.assertEqual(server.args, ['1,3:*', '(FLAGS)']) + + # An item with nested parentheses is sent (and parsed) as a + # single argument. + typ, data = client.fetch('1', '(BODY[HEADER.FIELDS (DATE FROM)])') + self.assertEqual(typ, 'OK') + self.assertEqual(data, [br'1 (FLAGS (\Seen))']) + self.assertEqual(server.args, ['1', '(BODY[HEADER.FIELDS (DATE FROM)])']) + + def test_uid_fetch(self): + client, server = self._setup(make_simple_handler('UID', [ + r'* 23 FETCH (FLAGS (\Seen) UID 4827313)', + r'* 24 FETCH (FLAGS (\Seen) UID 4827943)', + r'* 25 FETCH (FLAGS (\Seen) UID 4828442)', + ], 'UID FETCH completed')) + client.login('user', 'pass') + client.select() + typ, data = client.uid('fetch', '4827313:4828442', '(FLAGS)') + self.assertEqual(typ, 'OK') + self.assertEqual(data, [ + br'23 (FLAGS (\Seen) UID 4827313)', + br'24 (FLAGS (\Seen) UID 4827943)', + br'25 (FLAGS (\Seen) UID 4828442)', + ]) + self.assertEqual(server.args, ['FETCH', '4827313:4828442', '(FLAGS)']) + + def test_partial(self): + client, server = self._setup(make_simple_handler('PARTIAL', + ['* 1 FETCH (RFC822.TEXT<0.10> "0123456789")'])) + client.login('user', 'pass') + client.select() + typ, data = client.partial('1', 'RFC822.TEXT', '0', '10') + self.assertEqual(typ, 'OK') + self.assertEqual(data, [b'1 (RFC822.TEXT<0.10> "0123456789")']) + self.assertEqual(server.args, ['1', 'RFC822.TEXT', '0', '10']) + + def test_search(self): + response = [] + client, server = self._setup(make_simple_handler('SEARCH', response)) + client.login('user', 'pass') + client.select() + response[:] = ['* SEARCH 2 84 882'] + typ, data = client.search(None, 'FLAGGED', 'SINCE', '1-Feb-1994', 'NOT', 'FROM', '"Smith"') + self.assertEqual(typ, 'OK') + self.assertEqual(data, [b'2 84 882']) + self.assertEqual(server.args, ['FLAGGED', 'SINCE', '1-Feb-1994', 'NOT', 'FROM', '"Smith"']) + + response[:] = ['* SEARCH'] + typ, data = client.search(None, 'TEXT', '"string not in mailbox"') + self.assertEqual(typ, 'OK') + self.assertEqual(data, [b'']) + self.assertEqual(server.args, ['TEXT', '"string not in mailbox"']) + + response[:] = ['* SEARCH 43'] + typ, data = client.search('UTF-8', 'TEXT', 'XXXXXX') + self.assertEqual(typ, 'OK') + self.assertEqual(data, [b'43']) + self.assertEqual(server.args, ['CHARSET', 'UTF-8', 'TEXT', 'XXXXXX']) + + def test_uid_search(self): + response = [] + client, server = self._setup(make_simple_handler('UID', response, + 'UID SEARCH completed')) + client.login('user', 'pass') + client.select() + response[:] = ['* SEARCH 2 84 882'] + typ, data = client.uid('SEARCH', 'FLAGGED', 'SINCE', '1-Feb-1994', 'NOT', 'FROM', '"Smith"') + self.assertEqual(typ, 'OK') + self.assertEqual(data, [b'2 84 882']) + self.assertEqual(server.args, ['SEARCH', 'FLAGGED', 'SINCE', '1-Feb-1994', 'NOT', 'FROM', '"Smith"']) + + response[:] = ['* SEARCH'] + typ, data = client.uid('SEARCH', 'TEXT', '"string not in mailbox"') + self.assertEqual(typ, 'OK') + self.assertEqual(data, [b'']) + self.assertEqual(server.args, ['SEARCH', 'TEXT', '"string not in mailbox"']) + + response[:] = ['* SEARCH 43'] + typ, data = client.uid('SEARCH', 'CHARSET', 'UTF-8', 'TEXT', 'XXXXXX') + self.assertEqual(typ, 'OK') + self.assertEqual(data, [b'43']) + self.assertEqual(server.args, ['SEARCH', 'CHARSET', 'UTF-8', 'TEXT', 'XXXXXX']) + + typ, data = client.uid('SEARCH', 'CHARSET', '"NF_Z_62-010_(1973)"', 'TEXT', 'XXXXXX') + self.assertEqual(typ, 'OK') + self.assertEqual(server.args, ['SEARCH', 'CHARSET', '"NF_Z_62-010_(1973)"', 'TEXT', 'XXXXXX']) + + def test_sort(self): + response = [] + client, server = self._setup(make_simple_handler('SORT', response)) + client.login('user', 'pass') + client.select() + response[:] = ['* SORT 2 84 882'] + typ, data = client.sort('(SUBJECT)', 'UTF-8', 'SINCE', '1-Feb-1994') + self.assertEqual(typ, 'OK') + self.assertEqual(data, [br'2 84 882']) + self.assertEqual(server.args, ['(SUBJECT)', 'UTF-8', 'SINCE', '1-Feb-1994']) + + response[:] = ['* SORT 5 3 4 1 2'] + typ, data = client.sort('(SUBJECT REVERSE DATE)', 'UTF-8', 'ALL') + self.assertEqual(typ, 'OK') + self.assertEqual(data, [br'5 3 4 1 2']) + self.assertEqual(server.args, ['(SUBJECT REVERSE DATE)', 'UTF-8', 'ALL']) + + response[:] = ['* SORT'] + typ, data = client.sort('(SUBJECT)', 'US-ASCII', 'TEXT', '"not in mailbox"') + self.assertEqual(typ, 'OK') + self.assertEqual(data, [br'']) + self.assertEqual(server.args, ['(SUBJECT)', 'US-ASCII', 'TEXT', '"not in mailbox"']) + + def test_uid_sort(self): + response = [] + client, server = self._setup(make_simple_handler('UID', response, + 'UID SORT completed')) + client.login('user', 'pass') + client.select() + response[:] = ['* SORT 2 84 882'] + typ, data = client.uid('sort', '(SUBJECT)', 'UTF-8', 'SINCE', '1-Feb-1994') + self.assertEqual(typ, 'OK') + self.assertEqual(data, [br'2 84 882']) + self.assertEqual(server.args, ['SORT', '(SUBJECT)', 'UTF-8', 'SINCE', '1-Feb-1994']) + + response[:] = ['* SORT 5 3 4 1 2'] + typ, data = client.uid('sort', '(SUBJECT REVERSE DATE)', 'UTF-8', 'ALL') + self.assertEqual(typ, 'OK') + self.assertEqual(data, [br'5 3 4 1 2']) + self.assertEqual(server.args, ['SORT', '(SUBJECT REVERSE DATE)', 'UTF-8', 'ALL']) + + response[:] = ['* SORT'] + typ, data = client.uid('sort', '(SUBJECT)', 'US-ASCII', 'TEXT', '"not in mailbox"') + self.assertEqual(typ, 'OK') + self.assertEqual(data, [br'']) + self.assertEqual(server.args, ['SORT', '(SUBJECT)', 'US-ASCII', 'TEXT', '"not in mailbox"']) + + def test_thread(self): + response = [] + client, server = self._setup(make_simple_handler('THREAD', response)) + client.login('user', 'pass') + client.select() + response[:] = [ + '* THREAD (166)(167)(168)(169)(172)(170)(171)' + '(173)(174 (175)(176)(178)(181)(180))(179)(177 ' + '(183)(182)(188)(184)(185)(186)(187)(189))(190)' + '(191)(192)(193)(194 195)(196 (197)(198))(199)' + '(200 202)(201)(203)(204)(205)(206 207)(208)'] + typ, data = client.thread('ORDEREDSUBJECT', 'UTF-8', 'SINCE', '5-MAR-2000') + self.assertEqual(typ, 'OK') + self.assertEqual(data, [ + b'(166)(167)(168)(169)(172)(170)(171)' + b'(173)(174 (175)(176)(178)(181)(180))(179)(177 ' + b'(183)(182)(188)(184)(185)(186)(187)(189))(190)' + b'(191)(192)(193)(194 195)(196 (197)(198))(199)' + b'(200 202)(201)(203)(204)(205)(206 207)(208)']) + self.assertEqual(server.args, ['ORDEREDSUBJECT', 'UTF-8', 'SINCE', '5-MAR-2000']) + + response[:] = [ + '* THREAD (166)(167)(168)(169)(172)((170)(179))' + '(171)(173)((174)(175)(176)(178)(181)(180))' + '((177)(183)(182)(188 (184)(189))(185 186)(187))' + '(190)(191)(192)(193)((194)(195 196))(197 198)' + '(199)(200 202)(201)(203)(204)(205 206 207)(208)'] + typ, data = client.thread('ORDEREDSUBJECT', 'US-ASCII', 'TEXT', '"gewp"') + self.assertEqual(typ, 'OK') + self.assertEqual(data, [ + b'(166)(167)(168)(169)(172)((170)(179))' + b'(171)(173)((174)(175)(176)(178)(181)(180))' + b'((177)(183)(182)(188 (184)(189))(185 186)(187))' + b'(190)(191)(192)(193)((194)(195 196))(197 198)' + b'(199)(200 202)(201)(203)(204)(205 206 207)(208)']) + self.assertEqual(server.args, ['ORDEREDSUBJECT', 'US-ASCII', 'TEXT', '"gewp"']) + + def test_uid_thread(self): + response = [] + client, server = self._setup(make_simple_handler('UID', response, + 'UID THREAD completed')) + client.login('user', 'pass') + client.select() + response[:] = [ + '* THREAD (166)(167)(168)(169)(172)(170)(171)' + '(173)(174 (175)(176)(178)(181)(180))(179)(177 ' + '(183)(182)(188)(184)(185)(186)(187)(189))(190)' + '(191)(192)(193)(194 195)(196 (197)(198))(199)' + '(200 202)(201)(203)(204)(205)(206 207)(208)'] + typ, data = client.uid('THREAD', 'ORDEREDSUBJECT', 'UTF-8', 'SINCE', '5-MAR-2000') + self.assertEqual(typ, 'OK') + self.assertEqual(data, [ + b'(166)(167)(168)(169)(172)(170)(171)' + b'(173)(174 (175)(176)(178)(181)(180))(179)(177 ' + b'(183)(182)(188)(184)(185)(186)(187)(189))(190)' + b'(191)(192)(193)(194 195)(196 (197)(198))(199)' + b'(200 202)(201)(203)(204)(205)(206 207)(208)']) + self.assertEqual(server.args, ['THREAD', 'ORDEREDSUBJECT', 'UTF-8', 'SINCE', '5-MAR-2000']) + + response[:] = [ + '* THREAD (166)(167)(168)(169)(172)((170)(179))' + '(171)(173)((174)(175)(176)(178)(181)(180))' + '((177)(183)(182)(188 (184)(189))(185 186)(187))' + '(190)(191)(192)(193)((194)(195 196))(197 198)' + '(199)(200 202)(201)(203)(204)(205 206 207)(208)'] + typ, data = client.uid('THREAD', 'ORDEREDSUBJECT', 'US-ASCII', 'TEXT', '"gewp"') + self.assertEqual(typ, 'OK') + self.assertEqual(data, [ + b'(166)(167)(168)(169)(172)((170)(179))' + b'(171)(173)((174)(175)(176)(178)(181)(180))' + b'((177)(183)(182)(188 (184)(189))(185 186)(187))' + b'(190)(191)(192)(193)((194)(195 196))(197 198)' + b'(199)(200 202)(201)(203)(204)(205 206 207)(208)']) + self.assertEqual(server.args, ['THREAD', 'ORDEREDSUBJECT', 'US-ASCII', 'TEXT', '"gewp"']) + + def test_delete(self): + client, server = self._setup(make_simple_handler('DELETE')) + client.login('user', 'pass') + typ, data = client.delete('blurdybloop') + self.assertEqual(typ, 'OK') + self.assertEqual(data, [b'DELETE completed']) + self.assertEqual(server.args, ['blurdybloop']) + + typ, data = client.delete('foo/bar') + self.assertEqual(typ, 'OK') + self.assertEqual(server.args, ['foo/bar']) + + def test_rename(self): + client, server = self._setup(make_simple_handler('RENAME')) + client.login('user', 'pass') + typ, data = client.rename('blurdybloop', 'sarasoop') + self.assertEqual(typ, 'OK') + self.assertEqual(data, [b'RENAME completed']) + self.assertEqual(server.args, ['blurdybloop', 'sarasoop']) + + def test_subscribe(self): + client, server = self._setup(make_simple_handler('SUBSCRIBE')) + client.login('user', 'pass') + typ, data = client.subscribe('#news.comp.mail.mime') + self.assertEqual(typ, 'OK') + self.assertEqual(data, [b'SUBSCRIBE completed']) + self.assertEqual(server.args, ['#news.comp.mail.mime']) + + def test_unsubscribe(self): + client, server = self._setup(make_simple_handler('UNSUBSCRIBE')) + client.login('user', 'pass') + typ, data = client.unsubscribe('#news.comp.mail.mime') + self.assertEqual(typ, 'OK') + self.assertEqual(data, [b'UNSUBSCRIBE completed']) + self.assertEqual(server.args, ['#news.comp.mail.mime']) + + def test_list(self): + client, server = self._setup(make_simple_handler('LIST', + [r'* LIST (\Noselect) "/" ""', + r'* LIST (\Unmarked) "/" "~/Mail/foo"'])) + client.login('user', 'pass') + typ, data = client.list() + self.assertEqual(typ, 'OK') + self.assertEqual(data, [br'(\Noselect) "/" ""', + br'(\Unmarked) "/" "~/Mail/foo"']) + self.assertEqual(server.args, ['""', '*']) + + typ, data = client.list('~/Mail/', '%') + self.assertEqual(typ, 'OK') + self.assertEqual(server.args, ['~/Mail/', '%']) + + def test_status(self): + client, server = self._setup(make_simple_handler('STATUS', + ['* STATUS blurdybloop (MESSAGES 231 UIDNEXT 44292)'])) + client.login('user', 'pass') + typ, data = client.status('blurdybloop', '(UIDNEXT MESSAGES)') + self.assertEqual(typ, 'OK') + self.assertEqual(data, [b'blurdybloop (MESSAGES 231 UIDNEXT 44292)']) + self.assertEqual(server.args, ['blurdybloop', '(UIDNEXT MESSAGES)']) + + def test_getacl(self): + client, server = self._setup(make_simple_handler('GETACL', + ['* ACL INBOX Fred rwipslxetad'])) + client.login('user', 'pass') + typ, data = client.getacl('INBOX') + self.assertEqual(typ, 'OK') + self.assertEqual(data, [b'INBOX Fred rwipslxetad']) + self.assertEqual(server.args, ['INBOX']) + + def test_setacl(self): + client, server = self._setup(make_simple_handler('SETACL')) + client.login('user', 'pass') + typ, data = client.setacl('INBOX', 'Fred', 'rwipslxetad') + self.assertEqual(typ, 'OK') + self.assertEqual(data, [b'SETACL completed']) + self.assertEqual(server.args, ['INBOX', 'Fred', 'rwipslxetad']) + + def test_deleteacl(self): + client, server = self._setup(make_simple_handler('DELETEACL')) + client.login('user', 'pass') + typ, data = client.deleteacl('INBOX', 'Fred') + self.assertEqual(typ, 'OK') + self.assertEqual(data, [b'DELETEACL completed']) + self.assertEqual(server.args, ['INBOX', 'Fred']) + + def test_myrights(self): + client, server = self._setup(make_simple_handler('MYRIGHTS', + ['* MYRIGHTS INBOX rwiptsldaex'])) + client.login('user', 'pass') + typ, data = client.myrights('INBOX') + self.assertEqual(typ, 'OK') + self.assertEqual(data, [b'INBOX rwiptsldaex']) + self.assertEqual(server.args, ['INBOX']) + + def test_getquota(self): + client, server = self._setup(make_simple_handler('GETQUOTA', + ['* QUOTA "" (STORAGE 10 512)'])) + client.login('user', 'pass') + typ, data = client.getquota('#news') + self.assertEqual(typ, 'OK') + self.assertEqual(data, [b'"" (STORAGE 10 512)']) + self.assertEqual(server.args, ['#news']) + + def test_getquotaroot(self): + client, server = self._setup(make_simple_handler('GETQUOTAROOT', + ['* QUOTAROOT INBOX ""', '* QUOTA "" (STORAGE 10 512)'])) + client.login('user', 'pass') + typ, data = client.getquotaroot('INBOX') + self.assertEqual(typ, 'OK') + self.assertEqual(data, [[b'INBOX ""'], [b'"" (STORAGE 10 512)']]) + self.assertEqual(server.args, ['INBOX']) + + def test_setquota(self): + client, server = self._setup(make_simple_handler('SETQUOTA', + ['* QUOTA "" (STORAGE 512)'])) + client.login('user', 'pass') + typ, data = client.setquota('#news', '(STORAGE 512)') + self.assertEqual(typ, 'OK') + self.assertEqual(data, [b'"" (STORAGE 512)']) + self.assertEqual(server.args, ['#news', '(STORAGE 512)']) + + def test_getannotation(self): + client, server = self._setup(make_simple_handler('GETANNOTATION', + ['* ANNOTATION INBOX "/comment" ("value.shared" "Hello")'])) + client.login('user', 'pass') + typ, data = client.getannotation('INBOX', '/comment', 'value.shared') + self.assertEqual(typ, 'OK') + self.assertEqual(data, [b'INBOX "/comment" ("value.shared" "Hello")']) + self.assertEqual(server.args, ['INBOX', '/comment', 'value.shared']) + + def test_setannotation(self): + client, server = self._setup(make_simple_handler('SETANNOTATION')) + client.login('user', 'pass') + typ, data = client.setannotation('INBOX', '/comment', + '("value.shared" "My comment")') + self.assertEqual(typ, 'OK') + self.assertEqual(server.args, + ['INBOX', '/comment', '("value.shared" "My comment")']) + + def test_proxyauth(self): + client, server = self._setup(make_simple_handler('PROXYAUTH')) + client.login('user', 'pass') + typ, data = client.proxyauth('user') + self.assertEqual(typ, 'OK') + self.assertEqual(data, [b'PROXYAUTH completed']) + self.assertEqual(server.args, ['user']) + + def test_xatom(self): + client, server = self._setup(make_simple_handler('MYCOMMAND', + completed='MYCOMMAND completed')) + client.login('user', 'pass') + self.addCleanup(imaplib.Commands.pop, 'MYCOMMAND', None) + typ, data = client.xatom('MYCOMMAND', 'arg1', 'arg2') + self.assertEqual(typ, 'OK') + self.assertEqual(data, [b'MYCOMMAND completed']) + self.assertEqual(server.args, ['arg1', 'arg2']) def test_control_characters(self): client, _ = self._setup(SimpleIMAPHandler) From 6759fd82117a50c40a0911189eda1c8dfa93ad03 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka <storchaka@gmail.com> Date: Thu, 2 Jul 2026 14:57:58 +0300 Subject: [PATCH 543/818] [3.15] gh-49680: Test imaplib.IMAP4.append line-ending normalization (GH-152877) gh-49680: Test imaplib.IMAP4.append line-ending normalization (cherry picked from commit ddb6539c4976b18895bb5c5cd37d197c60fb459d) Co-authored-by: harjoth <harjoth.khara@gmail.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --- Lib/test/test_imaplib.py | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/Lib/test/test_imaplib.py b/Lib/test/test_imaplib.py index e797a625014603..cb62aef1ff52d4 100644 --- a/Lib/test/test_imaplib.py +++ b/Lib/test/test_imaplib.py @@ -9,6 +9,7 @@ import calendar import threading import re +import select import socket from test.support import verbose, run_with_tz, run_with_locale, cpython_only @@ -89,6 +90,18 @@ class Handler(SimpleIMAPHandler): return Handler +def _read_literal(handler, marker): + # Read one literal, a raw octet sequence, by its count from the marker + # ('{N}', or '(~{N}' in UTF8 mode). + size = int(re.search(r'\{(\d+)\}', marker).group(1)) + # The client must wait for the continuation, so nothing should be readable. + if select.select([handler.connection], [], [], 0)[0]: + raise AssertionError('client sent the literal before the ' + 'continuation request') + handler._send_textline('+') + return handler.rfile.read(size) + + class TestImaplib(unittest.TestCase): def test_Internaldate2tuple(self): @@ -474,10 +487,8 @@ def cmd_AUTHENTICATE(self, tag, args): self.server.response = yield self._send_tagged(tag, 'OK', 'FAKEAUTH successful') def cmd_APPEND(self, tag, args): - self._send_textline('+') self.server.response = args - literal = yield - self.server.response.append(literal) + self.server.response.append(_read_literal(self, args[-1])) literal = yield self.server.response.append(literal) self._send_tagged(tag, 'OK', 'okay') @@ -737,6 +748,19 @@ def test_login(self): self.assertEqual(data[0], b'LOGIN completed') self.assertEqual(client.state, 'AUTH') + def test_append_line_endings(self): + # append() normalizes bare CR and LF in the message to CRLF. + class AppendHandler(SimpleIMAPHandler): + def cmd_APPEND(self, tag, args): + self.server.response = _read_literal(self, args[-1]) + yield # read the trailer line + self._send_tagged(tag, 'OK', 'APPEND completed') + client, server = self._setup(AppendHandler) + client.login('user', 'pass') + message = b'a\rb\nc\r\nd' + client.append('INBOX', None, None, message) + self.assertEqual(server.response, b'a\r\nb\r\nc\r\nd') + def test_login_capabilities(self): # A server may advertise new capabilities after login (as an # untagged CAPABILITY response); imaplib must refresh its cached @@ -1673,10 +1697,8 @@ def test_enable_UTF8_True_append(self): class UTF8AppendServer(self.UTF8Server): def cmd_APPEND(self, tag, args): - self._send_textline('+') self.server.response = args - literal = yield - self.server.response.append(literal) + self.server.response.append(_read_literal(self, args[-1])) literal = yield self.server.response.append(literal) self._send_tagged(tag, 'OK', 'okay') From d8493ae633de28f68978becca14224154ffc7e9c Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 2 Jul 2026 15:20:55 +0200 Subject: [PATCH 544/818] [3.15] gh-150069: Test frozen dataclass and properties interaction (GH-150070) (#152882) gh-150069: Test frozen dataclass and properties interaction (GH-150070) (cherry picked from commit 753f82db2fed38bf725ded2b333ea3749c81fe82) Co-authored-by: sobolevn <mail@sobolevn.me> --- Lib/test/test_dataclasses/__init__.py | 84 ++++++++++++++++++++++++++- 1 file changed, 82 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_dataclasses/__init__.py b/Lib/test/test_dataclasses/__init__.py index cede6671da1475..17dee87599135b 100644 --- a/Lib/test/test_dataclasses/__init__.py +++ b/Lib/test/test_dataclasses/__init__.py @@ -3377,6 +3377,47 @@ def test_non_frozen_normal_derived(self): class D: x: int y: int = 10 + z: int = 1 + + @property + def readonly(self) -> int: + return self.x + + @property + def prop(self) -> int: + return self.z + + @prop.setter + def prop(self, val: int) -> None: + object.__setattr__(self, 'z', val) + + @prop.deleter + def prop(self) -> None: + object.__setattr__(self, 'z', 0) + + d = D(5) + self.assertEqual(d.x, 5) + self.assertEqual(d.y, 10) + self.assertEqual(d.z, 1) + self.assertEqual(d.readonly, 5) + self.assertEqual(d.prop, 1) + + with self.assertRaises(FrozenInstanceError): + d.x = 5 + with self.assertRaises(FrozenInstanceError): + d.readonly = 5 + with self.assertRaises(FrozenInstanceError): + d.z = 5 + with self.assertRaises(FrozenInstanceError): + d.prop = 5 + with self.assertRaises(FrozenInstanceError): + del d.prop + + self.assertEqual(d.x, 5) + self.assertEqual(d.y, 10) + self.assertEqual(d.z, 1) + self.assertEqual(d.readonly, 5) + self.assertEqual(d.prop, 1) class S(D): pass @@ -3384,16 +3425,40 @@ class S(D): s = S(3) self.assertEqual(s.x, 3) self.assertEqual(s.y, 10) + self.assertEqual(s.z, 1) + self.assertEqual(s.readonly, 3) + self.assertEqual(s.prop, 1) + # Can set new attrs: s.cached = True + self.assertTrue(s.cached) + # Can mutate them: + s.cached = False + self.assertFalse(s.cached) + + # Can also change writable properties: + with self.assertRaisesRegex( + AttributeError, + 'object has no setter', + ) as cm: + s.readonly = 5 + self.assertNotIsInstance(cm.exception, FrozenInstanceError) + s.prop = 2 + self.assertEqual(s.x, 3) + self.assertEqual(s.readonly, 3) + self.assertEqual(s.prop, 2) + self.assertEqual(s.z, 2) # But can't change the frozen attributes. with self.assertRaises(FrozenInstanceError): s.x = 5 with self.assertRaises(FrozenInstanceError): s.y = 5 + with self.assertRaises(FrozenInstanceError): + s.z = 5 self.assertEqual(s.x, 3) self.assertEqual(s.y, 10) - self.assertEqual(s.cached, True) + self.assertEqual(s.z, 2) + self.assertIs(s.cached, False) with self.assertRaises(FrozenInstanceError): del s.x @@ -3401,11 +3466,26 @@ class S(D): with self.assertRaises(FrozenInstanceError): del s.y self.assertEqual(s.y, 10) + with self.assertRaisesRegex( + AttributeError, + 'object has no deleter', + ) as cm: + del s.readonly + self.assertNotIsInstance(cm.exception, FrozenInstanceError) + self.assertEqual(s.x, 3) + self.assertEqual(s.readonly, 3) del s.cached self.assertNotHasAttr(s, 'cached') - with self.assertRaises(AttributeError) as cm: + with self.assertRaisesRegex( + AttributeError, + "object has no attribute 'cached'", + ) as cm: del s.cached self.assertNotIsInstance(cm.exception, FrozenInstanceError) + del s.prop + self.assertEqual(s.z, 0) + self.assertEqual(s.prop, 0) + del s.prop def test_non_frozen_normal_derived_from_empty_frozen(self): @dataclass(frozen=True) From 9317d52169d2d845a74a082e2df86ce3978832f3 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 2 Jul 2026 15:25:34 +0200 Subject: [PATCH 545/818] [3.15] gh-88574: Skip a spurious blank line after a literal in imaplib (GH-152751) (GH-152884) Some IMAP servers send an extra blank line after the data of a literal. imaplib mistook it for the response trailer and failed on the next command. Such a blank line is now skipped. (cherry picked from commit 53ff1a28ccfa69925c3c452cfc003970640fa65b) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --- Lib/imaplib.py | 4 ++++ Lib/test/test_imaplib.py | 17 +++++++++++++++++ ...026-07-01-10-00-00.gh-issue-88574.Kz3wQm.rst | 2 ++ 3 files changed, 23 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2026-07-01-10-00-00.gh-issue-88574.Kz3wQm.rst diff --git a/Lib/imaplib.py b/Lib/imaplib.py index ca2ae40726b2d1..e444abb4f1f77c 100644 --- a/Lib/imaplib.py +++ b/Lib/imaplib.py @@ -1295,6 +1295,10 @@ def _get_response(self, start_timeout=False): dat = self._get_line() + # Skip a blank line that some servers send after a literal. + if dat == b'': + dat = self._get_line() + self._append_untagged(typ, dat) # Bracketed response information? diff --git a/Lib/test/test_imaplib.py b/Lib/test/test_imaplib.py index cb62aef1ff52d4..f734ebfaa1a009 100644 --- a/Lib/test/test_imaplib.py +++ b/Lib/test/test_imaplib.py @@ -849,6 +849,23 @@ def test_lsub(self): self.assertEqual(typ, 'OK') self.assertEqual(server.args, ['~/Mail/', '%']) + def test_extra_blank_line_after_literal(self): + # Some buggy servers send an extra blank line after the counted + # literal data. imaplib should skip it instead of failing. + class BlankLineHandler(SimpleIMAPHandler): + def cmd_FETCH(self, tag, args): + self._send(b'* 1 FETCH (BODY[HEADER] {13}\r\n') + self._send(b'Subject: test') # 13-byte literal + self._send(b'\r\n)\r\n') # stray blank line, then ')' + self._send_tagged(tag, 'OK', 'FETCH completed') + client, _ = self._setup(BlankLineHandler) + client.login('user', 'pass') + client.select() + typ, data = client.fetch('1', '(BODY[HEADER])') + self.assertEqual(typ, 'OK') + self.assertEqual(data, [(b'1 (BODY[HEADER] {13}', b'Subject: test'), + b')']) + def test_unselect(self): client, server = self._setup(SimpleIMAPHandler) client.login('user', 'pass') diff --git a/Misc/NEWS.d/next/Library/2026-07-01-10-00-00.gh-issue-88574.Kz3wQm.rst b/Misc/NEWS.d/next/Library/2026-07-01-10-00-00.gh-issue-88574.Kz3wQm.rst new file mode 100644 index 00000000000000..8d95bbbb5a15e4 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-01-10-00-00.gh-issue-88574.Kz3wQm.rst @@ -0,0 +1,2 @@ +:mod:`imaplib` no longer fails when a server sends a spurious blank line +after the counted data of a literal. Such a blank line is now skipped. From a1a9e6f081256b88860b3866f2b19398eca57d99 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 2 Jul 2026 15:27:35 +0200 Subject: [PATCH 546/818] [3.15] gh-152680: Detect virtualization on Windows in pythoninfo (GH-152824) (#152890) gh-152680: Detect virtualization on Windows in pythoninfo (GH-152824) Use WMI to detect virtualization on Windows. Replace wmic command with _wmi module to get the operating system caption and version. The wmic tool is deprecated since January 2024: https://techcommunity.microsoft.com/blog/windows-itpro-blog/wmi-command-line-wmic-utility-deprecation-next-steps/4039242 For example, it's no longer installed in Windows images on GitHub Action. Fix also run_command(): no longer try to spawn a subprocess if the platform doesn't support subprocess. It avoids logging run_command() errors. (cherry picked from commit 4e4869b62fa91e26117b1d9136f60b58c9f505a5) Co-authored-by: Victor Stinner <vstinner@python.org> --- Lib/test/pythoninfo.py | 142 +++++++++++++++++++++++++++++++++++------ 1 file changed, 124 insertions(+), 18 deletions(-) diff --git a/Lib/test/pythoninfo.py b/Lib/test/pythoninfo.py index d7fd98a8d4311d..3227b91bd82a86 100644 --- a/Lib/test/pythoninfo.py +++ b/Lib/test/pythoninfo.py @@ -452,6 +452,12 @@ def format_attr(attr, value): def run_command(cmd, check=True, **kwargs): import subprocess + from test.support import has_subprocess_support + + if not has_subprocess_support: + # subprocess is not supported by the current platform + return '' + timeout = COMMAND_TIMEOUT cmd_str = ' '.join(cmd) @@ -963,6 +969,24 @@ def winreg_query(path): return None +def wmi_query(query): + try: + import _wmi + except ImportError: + return {} + + try: + data = _wmi.exec_query(query) + except OSError: + return {} + + dict_data = {} + for item in data.split("\0"): + key, _, value = item.partition("=") + dict_data[key] = value + return dict_data + + def collect_windows(info_add): if not MS_WINDOWS: # Code specific to Windows @@ -1009,22 +1033,14 @@ def collect_windows(info_add): call_func(info_add, 'windows.ansi_code_page', _winapi, 'GetACP') call_func(info_add, 'windows.oem_code_page', _winapi, 'GetOEMCP') - # windows.version_caption: "wmic os get Caption,Version /value" command - output = run_command(["wmic", "os", "get", "Caption,Version", "/value"], - # When wmic.exe output is redirected to a pipe, - # it uses the OEM code page - encoding="oem") - if output: - for line in output.splitlines(): - line = line.strip() - if line.startswith('Caption='): - line = line.removeprefix('Caption=').strip() - if line: - info_add('windows.version_caption', line) - elif line.startswith('Version='): - line = line.removeprefix('Version=').strip() - if line: - info_add('windows.version', line) + # Get operating system caption and version using WMI + data = wmi_query("SELECT Caption, Version FROM Win32_OperatingSystem") + caption = data.get('Caption', '') + if caption: + info_add('windows.version_caption', caption) + version = data.get('Version', '') + if version: + info_add('windows.version', version) # windows.ver: "ver" command output = run_command(["ver"], shell=True) @@ -1142,7 +1158,97 @@ def get_machine_id(): return None -def detect_virt(): +def detect_virt_windows(info_add): + # On Windows, use WMI to detect the virtualization. + # + # Microsoft Hyper-V: + # - Win32_Bios.Version = 'VRTUAL - 12001807' + # - Win32_Bios.Manufacturer = 'American Megatrends Inc.' + # - Win32_ComputerSystem.Model = 'Virtual Machine' + # - Win32_ComputerSystem.Manufacturer = 'Microsoft Corporation' + # + # VMware: + # - Win32_ComputerSystem.Model = 'VMware' + # - Win32_ComputerSystem.Manufacturer = 'VMWare' (uppercase W in Ware) + # - Win32_Bios.SerialNumber starts with 'VMware-' + # + # QEMU: + # - Win32_ComputerSystem.Manufacturer = 'QEMU' + # - Win32_ComputerSystem.Model = 'Standard PC (Q35 + ICH9, 2009)' + # - Win32_Bios.Version = 'BOCHS - 1' + # - Win32_Bios.Manufacturer = 'EDK II' + # + # Parallels: + # - Win32_Bios.Version = 'PARALLELS' + # + # VirtualBox: + # - Win32_Bios.Version = 'VBOX' + # - Win32_ComputerSystem.Model = 'VirtualBox' + # - Win32_ComputerSystem.Manufacturer = 'innotek GmbH' + # + # Amazon EC2: + # - Win32_Bios.Version = 'AMAZON - 1' + # - Win32_Bios.Manufacturer = 'Amazon EC2' + # - Win32_ComputerSystem.Model = 'm7i.4xlarge' + # - Win32_ComputerSystem.Manufacturer = 'Amazon EC2' + + KNOWN_VIRT = ( + 'Amazon EC2', + 'QEMU', + 'VMware', + 'VirtualBox', + 'Xen', + 'oVirt', + ) + KNOWN_BIOS_VERSIONS = { + 'PARALLELS': 'Parallels', + 'VBOX': 'VirtualBox', + } + + computer = wmi_query('SELECT Model, Manufacturer FROM Win32_ComputerSystem') + computer_model = computer.get('Model', '') + computer_manufacturer = computer.get('Manufacturer', '') + if computer_manufacturer == 'Amazon EC2': + # Log the VM model (ex: 'm7i.4xlarge') + info_add('system.computer.model', computer_model) + return computer_manufacturer + if computer_model in KNOWN_VIRT: + return computer_model + if computer_manufacturer in KNOWN_VIRT: + return computer_manufacturer + + bios = wmi_query('SELECT Version, Manufacturer FROM Win32_Bios') + + bios_version = bios.get('Version', '') + if bios_version in KNOWN_VIRT: + return bios_version + if (bios_version.startswith('VRTUAL - ') + and computer_manufacturer == 'Microsoft Corporation'): + return 'Microsoft Hyper-V' + try: + return KNOWN_BIOS_VERSIONS[bios_version] + except KeyError: + pass + + bios_manufacturer = bios.get('Manufacturer', '') + if bios_manufacturer in KNOWN_VIRT: + return bios_manufacturer + + # Log the values to update the code if a new VM is discovered + if computer_model: + info_add('system.computer.model', computer_model) + if computer_manufacturer: + info_add('system.computer.manufacturer', computer_manufacturer) + if bios_version: + info_add('system.bios.version', bios_version) + if bios_manufacturer: + info_add('system.bios.manufacturer', bios_manufacturer) + + +def detect_virt(info_add): + if MS_WINDOWS: + return detect_virt_windows(info_add) + # Run systemd-detect-virt command virt = run_command(["systemd-detect-virt"], check=False) if virt and virt != "none": @@ -1200,7 +1306,7 @@ def collect_system(info_add): uptime = f'{uptime} sec' info_add('system.uptime', uptime) - virt = detect_virt() + virt = detect_virt(info_add) if virt: info_add('system.virt', virt) From bd86f3cb692840fbe0bfe83fcd1c1f78767294e5 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 2 Jul 2026 16:58:12 +0200 Subject: [PATCH 547/818] [3.15] gh-98894: Check readelf failures in test_dtrace (GH-152345) (#152891) gh-98894: Check readelf failures in test_dtrace (GH-152345) Report readelf command failures directly instead of later failing with missing-probe assertions. (cherry picked from commit d60a6779e8dd5fbf1f2f84b34bb5a20f3e8cd7fd) Co-authored-by: stratakis <cstratak@redhat.com> --- Lib/test/test_dtrace.py | 62 +++++++++++++++++++---------------------- 1 file changed, 29 insertions(+), 33 deletions(-) diff --git a/Lib/test/test_dtrace.py b/Lib/test/test_dtrace.py index 2cfd94239aee24..788d31c60f4d97 100644 --- a/Lib/test/test_dtrace.py +++ b/Lib/test/test_dtrace.py @@ -73,6 +73,33 @@ def kill_process_group(proc): proc.communicate() # Clean up +def run_readelf(cmd): + # Force the C locale to disable localization. + env = dict(os.environ, LC_ALL="C") + try: + proc = subprocess.Popen( + cmd, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True, + env=env, + ) + except OSError: + raise unittest.SkipTest("Couldn't find readelf on the path") + + with proc: + stdout, stderr = proc.communicate() + + if proc.returncode: + raise AssertionError( + f"Command {' '.join(cmd)!r} failed " + f"with exit code {proc.returncode}: " + f"stdout={stdout!r} stderr={stderr!r}" + ) + + return stdout + + class TraceBackend: EXTENSION = None COMMAND = None @@ -408,28 +435,7 @@ def setUpClass(cls): @staticmethod def get_readelf_version(): - try: - cmd = ["readelf", "--version"] - # Force the C locale to disable localization. - env = dict(os.environ, LC_ALL="C") - proc = subprocess.Popen( - cmd, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - universal_newlines=True, - env=env, - ) - with proc: - version, stderr = proc.communicate() - - if proc.returncode: - raise Exception( - f"Command {' '.join(cmd)!r} failed " - f"with exit code {proc.returncode}: " - f"stdout={version!r} stderr={stderr!r}" - ) - except OSError: - raise unittest.SkipTest("Couldn't find readelf on the path") + version = run_readelf(["readelf", "--version"]) # Regex to parse: # 'GNU readelf (GNU Binutils) 2.40.0\n' -> 2.40 @@ -461,17 +467,7 @@ def get_readelf_output(self): binary = libpython_path break - command = ["readelf", "-n", binary] - # Force the C locale to disable localization. - env = dict(os.environ, LC_ALL="C") - stdout, _ = subprocess.Popen( - command, - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT, - universal_newlines=True, - env=env, - ).communicate() - return stdout + return run_readelf(["readelf", "-n", binary]) def test_check_probes(self): readelf_output = self.get_readelf_output() From 46b48ff09ac9b22d558cfd74274da3ca033c9bcd Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka <storchaka@gmail.com> Date: Thu, 2 Jul 2026 18:01:41 +0300 Subject: [PATCH 548/818] [3.15] gh-144067: Document terminal leak when initscr() follows setupterm() (GH-152624) (GH-152894) (cherry picked from commit e471712958515b65b737ac742b294acf7de9220c) Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --- Doc/library/curses.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Doc/library/curses.rst b/Doc/library/curses.rst index 621e3d6ad2043a..f2115a236f2583 100644 --- a/Doc/library/curses.rst +++ b/Doc/library/curses.rst @@ -324,6 +324,8 @@ The module :mod:`!curses` defines the following functions: Initialize the library. Return a :ref:`window <curses-window-objects>` object which represents the whole screen. + See :func:`setupterm` for a caveat about calling it before this function. + .. note:: If there is an error opening the terminal, the underlying curses library may @@ -593,6 +595,13 @@ The module :mod:`!curses` defines the following functions: terminfo database entry could not be read. If the terminal has already been initialized, this function has no effect. + .. note:: + + Calling :func:`initscr` after :func:`setupterm` + leaks the terminal that :func:`setupterm` allocated: + the curses library keeps only a single current terminal + and does not free the previously allocated one. + .. function:: start_color() From 7dd15e4f76bed0af816316ab27d51a859a5b55b5 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 2 Jul 2026 17:29:55 +0200 Subject: [PATCH 549/818] [3.15] gh-86165: Fix Time2Internaldate with datetime timetuple (GH-151844) (GH-152895) (cherry picked from commit 460fe13601d1a71f4700f6685e0f4d01d1ef0d6b) Co-authored-by: Xiao Yuan <yuanx749@gmail.com> --- Lib/imaplib.py | 5 ++--- Lib/test/test_imaplib.py | 9 +++++++++ .../2026-06-21-15-50-24.gh-issue-86165.dyac1G.rst | 3 +++ 3 files changed, 14 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-06-21-15-50-24.gh-issue-86165.dyac1G.rst diff --git a/Lib/imaplib.py b/Lib/imaplib.py index e444abb4f1f77c..eea29d2fef9cc6 100644 --- a/Lib/imaplib.py +++ b/Lib/imaplib.py @@ -1863,9 +1863,8 @@ def Time2Internaldate(date_time): dt = datetime.fromtimestamp(date_time, timezone.utc).astimezone() elif isinstance(date_time, tuple): - try: - gmtoff = date_time.tm_gmtoff - except AttributeError: + gmtoff = getattr(date_time, "tm_gmtoff", None) + if gmtoff is None: if time.daylight: dst = date_time[8] if dst == -1: diff --git a/Lib/test/test_imaplib.py b/Lib/test/test_imaplib.py index f734ebfaa1a009..d02c0498dabd37 100644 --- a/Lib/test/test_imaplib.py +++ b/Lib/test/test_imaplib.py @@ -142,6 +142,15 @@ def test_Time2Internaldate(self): internal = imaplib.Time2Internaldate(t) self.assertEqual(internal, expected) + @run_with_tz('STD-1DST,M3.2.0,M11.1.0') + def test_Time2Internaldate_datetime_timetuple(self): + date_time = datetime.fromtimestamp(2000000000).timetuple() + self.assertIsNone(date_time.tm_gmtoff) + self.assertEqual( + imaplib.Time2Internaldate(date_time), + '"18-May-2033 05:33:20 +0200"', + ) + def test_that_Time2Internaldate_returns_a_result(self): # Without tzset, we can check only that it successfully # produces a result, not the correctness of the result itself, diff --git a/Misc/NEWS.d/next/Library/2026-06-21-15-50-24.gh-issue-86165.dyac1G.rst b/Misc/NEWS.d/next/Library/2026-06-21-15-50-24.gh-issue-86165.dyac1G.rst new file mode 100644 index 00000000000000..0b630e9ae34683 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-21-15-50-24.gh-issue-86165.dyac1G.rst @@ -0,0 +1,3 @@ +Fix :func:`imaplib.Time2Internaldate` to use the local timezone offset for +``time.struct_time`` values with ``tm_gmtoff`` set to ``None``, as returned by +``datetime.datetime.timetuple()``. Contributed by Xiao Yuan. From e0db0e4d3472716149f5861deee6390ac8e9b47f Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 2 Jul 2026 17:37:52 +0200 Subject: [PATCH 550/818] [3.15] gh-98894: Check tracer exit status in test_dtrace (GH-152893) (#152900) gh-98894: Check tracer exit status in test_dtrace (GH-152893) Fail functional dtrace and SystemTap cases directly when the tracer exits non-zero. (cherry picked from commit 311e7e79f4e305f1217ef548a62ea219a47c0d7b) Co-authored-by: stratakis <cstratak@redhat.com> --- Lib/test/test_dtrace.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_dtrace.py b/Lib/test/test_dtrace.py index 788d31c60f4d97..e1662a70b26d3e 100644 --- a/Lib/test/test_dtrace.py +++ b/Lib/test/test_dtrace.py @@ -125,7 +125,8 @@ def generate_trace_command(self, script_file, subcommand=None): command += ["-c", subcommand] return command - def trace(self, script_file, subcommand=None, *, timeout=None): + def trace(self, script_file, subcommand=None, *, timeout=None, + check_returncode=False): command = self.generate_trace_command(script_file, subcommand) proc = create_process_group(command, stdout=subprocess.PIPE, @@ -136,6 +137,11 @@ def trace(self, script_file, subcommand=None, *, timeout=None): except subprocess.TimeoutExpired: kill_process_group(proc) raise + if check_returncode and proc.returncode: + raise AssertionError( + f"Command {' '.join(command)!r} failed " + f"with exit code {proc.returncode}: output={stdout!r}" + ) return stdout def trace_python(self, script_file, python_file, optimize_python=None): @@ -143,7 +149,8 @@ def trace_python(self, script_file, python_file, optimize_python=None): if optimize_python: python_flags.extend(["-O"] * optimize_python) subcommand = " ".join([sys.executable] + python_flags + [python_file]) - return self.trace(script_file, subcommand, timeout=60) + return self.trace(script_file, subcommand, timeout=60, + check_returncode=True) def assert_usable(self): try: From 598856c7e44639b3c46bfffd8958d77d859d2c2c Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 2 Jul 2026 20:31:47 +0200 Subject: [PATCH 551/818] [3.15] gh-152847: Reject POSIX TZ rule with non-digit day-of-year in `_zoneinfo.py` (GH-152848) (#152910) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (cherry picked from commit 31864bd9a683c93bd9b294fb5bcf6857493c15ff) Co-authored-by: tonghuaroot (童话) <tonghuaroot@gmail.com> Co-authored-by: Stan Ulbrych <stan@python.org> --- Lib/test/test_zoneinfo/test_zoneinfo.py | 21 +++++++++++++++++++ Lib/zoneinfo/_zoneinfo.py | 2 ++ ...-07-02-12-00-00.gh-issue-152847.PitKqc.rst | 3 +++ 3 files changed, 26 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2026-07-02-12-00-00.gh-issue-152847.PitKqc.rst diff --git a/Lib/test/test_zoneinfo/test_zoneinfo.py b/Lib/test/test_zoneinfo/test_zoneinfo.py index 813b56501308f9..a10f434eb27590 100644 --- a/Lib/test/test_zoneinfo/test_zoneinfo.py +++ b/Lib/test/test_zoneinfo/test_zoneinfo.py @@ -1111,6 +1111,9 @@ def test_extreme_tzstr(self): "AAA4BBB,J1/2,J1/14", "AAA4BBB,J20/2,J365/2", "AAA4BBB,J365/2,J365/14", + # Leading-zero day-of-year + "AAA4BBB,J001/2,J065/2", + "AAA4BBB,001/2,065/2", # Extreme transition hour "AAA4BBB,J60/167,J300/2", "AAA4BBB,J60/+167,J300/2", @@ -1209,6 +1212,15 @@ def test_invalid_tzstr(self): # Invalid julian offset "AAA4BBB,J0/2,J20/2", "AAA4BBB,J20/2,J366/2", + # gh-152847: non-digit day-of-year + "AAA4BBB,J1_0,J300/2", + "AAA4BBB,J60/2,J30_0/2", + "AAA4BBB,1_0,J300/2", + "AAA4BBB,J+1,J300/2", + "AAA4BBB,J 1,J300/2", + "AAA4BBB, 1,J300/2", + "AAA4BBB,J0001,J300/2", + "AAA4BBB,0001,J300/2", # Invalid transition time "AAA4BBB,J60/2/3,J300/2", "AAA4BBB,J60/2,J300/2/3", @@ -1248,6 +1260,15 @@ def test_invalid_tzstr_non_ascii_abbr(self): with self.assertRaisesRegex(ValueError, expected): self.zone_from_tzstr(tzstr, encoding="utf-8") + def test_invalid_tzstr_non_ascii_dst_date(self): + tzstr = "AAA4BBB,J١,J300/2" + if self.module is py_zoneinfo: + expected = re.escape(tzstr) + else: + expected = re.escape(repr(tzstr.encode("utf-8"))) + with self.assertRaisesRegex(ValueError, expected): + self.zone_from_tzstr(tzstr, encoding="utf-8") + @classmethod def _populate_test_cases(cls): # This method uses a somewhat unusual style in that it populates the diff --git a/Lib/zoneinfo/_zoneinfo.py b/Lib/zoneinfo/_zoneinfo.py index 90cf2bbf8f5d0d..48154775568b6d 100644 --- a/Lib/zoneinfo/_zoneinfo.py +++ b/Lib/zoneinfo/_zoneinfo.py @@ -720,6 +720,8 @@ def _parse_dst_start_end(dststr): else: n_is_julian = False + if re.fullmatch(r"\d{1,3}", date, re.ASCII) is None: + raise ValueError(f"Invalid dst start/end date: {dststr}") doy = int(date) offset = _DayOffset(doy, n_is_julian) diff --git a/Misc/NEWS.d/next/Library/2026-07-02-12-00-00.gh-issue-152847.PitKqc.rst b/Misc/NEWS.d/next/Library/2026-07-02-12-00-00.gh-issue-152847.PitKqc.rst new file mode 100644 index 00000000000000..3f20d78a201e84 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-02-12-00-00.gh-issue-152847.PitKqc.rst @@ -0,0 +1,3 @@ +Reject a POSIX TZ transition rule with non-digit characters in the +day-of-year field in the pure-Python :mod:`zoneinfo` parser. Patch by +tonghuaroot. From 984ebbfeecaa8b614fd81ebac4460e301ffc8f08 Mon Sep 17 00:00:00 2001 From: Terry Jan Reedy <tjreedy@udel.edu> Date: Thu, 2 Jul 2026 17:07:27 -0400 Subject: [PATCH 552/818] [3.15] gh-151428: Remove unused imports in idlelib.idle_test (GH-151478) (#152916) --- Lib/idlelib/idle_test/template.py | 1 - Lib/idlelib/idle_test/test_help.py | 1 - 2 files changed, 2 deletions(-) diff --git a/Lib/idlelib/idle_test/template.py b/Lib/idlelib/idle_test/template.py index 69a2af22efa149..0a4bd8b8e981fc 100644 --- a/Lib/idlelib/idle_test/template.py +++ b/Lib/idlelib/idle_test/template.py @@ -1,6 +1,5 @@ "Test , coverage %." -from idlelib import zzdummy import unittest from test.support import requires from tkinter import Tk diff --git a/Lib/idlelib/idle_test/test_help.py b/Lib/idlelib/idle_test/test_help.py index ebb02b5c0d8356..ebbaceb2eb7bbf 100644 --- a/Lib/idlelib/idle_test/test_help.py +++ b/Lib/idlelib/idle_test/test_help.py @@ -4,7 +4,6 @@ import unittest from test.support import requires requires('gui') -from os.path import abspath, dirname, join from tkinter import Tk From c09f078796c4eb31679b1c5960bfab584277bb09 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 3 Jul 2026 04:56:16 +0200 Subject: [PATCH 553/818] [3.15] gh-152785: Upgrade Java from 17 to 21 in GHA Android (GH-152783) (#152920) Upgrade Java from 17 to 21 in GHA Android, and document the Java version requirement. (cherry picked from commit 0a13efc3fb0bf0896612ed20decce3ce4eb5e05b) Co-authored-by: Victor Stinner <vstinner@python.org> --- .github/workflows/build.yml | 2 +- Platforms/Android/README.md | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 89be2d9c8ed84d..362db498eb6c2c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -401,7 +401,7 @@ jobs: with: persist-credentials: false - name: Build and test - run: python3 Platforms/Android ci --fast-ci ${{ matrix.arch }}-linux-android + run: JAVA_HOME="${JAVA_HOME_21_X64:-$JAVA_HOME_21_arm64}" python3 Platforms/Android ci --fast-ci ${{ matrix.arch }}-linux-android build-ios: name: iOS diff --git a/Platforms/Android/README.md b/Platforms/Android/README.md index d6f95c365c63a0..54b7f1c46a59db 100644 --- a/Platforms/Android/README.md +++ b/Platforms/Android/README.md @@ -30,7 +30,8 @@ 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) +* `java` (or set the `JAVA_HOME` environment variable). + Java versions 17 and 21 are supported. ## Building From c8c08cfe2921f8d78dc49fed48f636f6b809630b Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 3 Jul 2026 08:37:25 +0200 Subject: [PATCH 554/818] [3.15] gh-115634: Fix ProcessPoolExecutor deadlock with max_tasks_per_child (GH-140900) (#152926) gh-115634: Fix ProcessPoolExecutor deadlock with max_tasks_per_child (GH-140900) The idle worker semaphore counts task completions, not idle workers, so it can hold a stale token released by a worker that later exited upon reaching its max_tasks_per_child limit. The worker replacement path consumed such tokens and skipped spawning a replacement, deadlocking the remaining queued tasks once no workers were left. Replace dead workers based on len(self._processes) without consulting the semaphore. The submit() path is unchanged, preserving on-demand spawning and idle worker reuse. Replace the documentation note added in GH-140897 with a versionchanged entry now that the bug is fixed. Based on a fix proposed by Tabrez Mohammed. (cherry picked from commit b706767d8fd7d21afc3f156fb9c173bc99855e0e) Co-authored-by: Gregory P. Smith <68491+gpshead@users.noreply.github.com> --- Doc/library/concurrent.futures.rst | 10 ++--- Lib/concurrent/futures/process.py | 38 +++++++++++++++---- .../test_process_pool.py | 27 +++++++++++++ ...-11-02-05-28-56.gh-issue-115634.JbcNnF.rst | 5 +++ 4 files changed, 68 insertions(+), 12 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2025-11-02-05-28-56.gh-issue-115634.JbcNnF.rst diff --git a/Doc/library/concurrent.futures.rst b/Doc/library/concurrent.futures.rst index a32c3828313454..cadf841b43537e 100644 --- a/Doc/library/concurrent.futures.rst +++ b/Doc/library/concurrent.futures.rst @@ -386,11 +386,6 @@ in a REPL or a lambda should not be expected to work. default in absence of a *mp_context* parameter. This feature is incompatible with the "fork" start method. - .. note:: - Bugs have been reported when using the *max_tasks_per_child* feature that - can result in the :class:`ProcessPoolExecutor` hanging in some - circumstances. Follow its eventual resolution in :gh:`115634`. - .. versionchanged:: 3.3 When one of the worker processes terminates abruptly, a :exc:`~concurrent.futures.process.BrokenProcessPool` error is now raised. @@ -426,6 +421,11 @@ in a REPL or a lambda should not be expected to work. require the *fork* start method for :class:`ProcessPoolExecutor` you must explicitly pass ``mp_context=multiprocessing.get_context("fork")``. + .. versionchanged:: next + Fixed a deadlock (:gh:`115634`) where the executor could hang after + a worker process exited upon reaching its *max_tasks_per_child* + limit while tasks remained queued. + .. method:: terminate_workers() Attempt to terminate all living worker processes immediately by calling diff --git a/Lib/concurrent/futures/process.py b/Lib/concurrent/futures/process.py index 10d4ac89d72571..8f200fc1c82613 100644 --- a/Lib/concurrent/futures/process.py +++ b/Lib/concurrent/futures/process.py @@ -360,7 +360,7 @@ def run(self): if executor := self.executor_reference(): if process_exited: with self.shutdown_lock: - executor._adjust_process_count() + executor._replace_dead_worker() else: executor._idle_worker_semaphore.release() del executor @@ -772,6 +772,30 @@ def _start_executor_manager_thread(self): _threads_wakeups[self._executor_manager_thread] = \ self._executor_manager_thread_wakeup + def _replace_dead_worker(self): + # gh-132969: avoid error when state is reset and executor is still running, + # which will happen when shutdown(wait=False) is called. + if self._processes is None: + return + + # A replacement is pointless when shutting down with nothing left + # to run. Both attributes are read under _shutdown_lock, which + # shutdown() holds while setting _shutdown_thread. + assert self._shutdown_lock.locked() + if self._shutdown_thread and not self._pending_work_items: + return + + # gh-115634: A worker exited after reaching max_tasks_per_child and + # has been removed from self._processes. Do not consult + # _idle_worker_semaphore here: it counts task completions, not idle + # workers, so it can hold a stale token released by the now-dead + # worker. Trusting such a token would leave the pool a worker short, + # deadlocking once all workers reach their task limit. Spawning is + # safe from this (manager) thread despite gh-90622 because + # max_tasks_per_child is rejected for the "fork" start method. + if len(self._processes) < self._max_workers: + self._spawn_process() + def _adjust_process_count(self): # gh-132969: avoid error when state is reset and executor is still running, # which will happen when shutdown(wait=False) is called. @@ -784,12 +808,12 @@ def _adjust_process_count(self): process_count = len(self._processes) if process_count < self._max_workers: - # Assertion disabled as this codepath is also used to replace a - # worker that unexpectedly dies, even when using the 'fork' start - # method. That means there is still a potential deadlock bug. If a - # 'fork' mp_context worker dies, we'll be forking a new one when - # we know a thread is running (self._executor_manager_thread). - #assert self._safe_to_dynamically_spawn_children or not self._executor_manager_thread, 'https://github.com/python/cpython/issues/90622' + # gh-90622: spawning a child via fork while another thread is + # running can deadlock in the child. submit() only calls this + # method when using a non-fork start method. + assert (self._safe_to_dynamically_spawn_children + or not self._executor_manager_thread), ( + 'https://github.com/python/cpython/issues/90622') self._spawn_process() def _launch_processes(self): diff --git a/Lib/test/test_concurrent_futures/test_process_pool.py b/Lib/test/test_concurrent_futures/test_process_pool.py index 56cc38984a2cb3..38e2cb302c6d51 100644 --- a/Lib/test/test_concurrent_futures/test_process_pool.py +++ b/Lib/test/test_concurrent_futures/test_process_pool.py @@ -240,6 +240,33 @@ def test_max_tasks_per_child_defaults_to_spawn_context(self): executor = self.executor_type(1, max_tasks_per_child=3) self.assertEqual(executor._mp_context.get_start_method(), "spawn") + def test_max_tasks_per_child_pending_tasks_gh115634(self): + # gh-115634: A worker exiting at its max_tasks_per_child limit left a + # stale token in the idle worker semaphore, so no replacement worker + # was spawned and the remaining queued tasks deadlocked. Submit more + # tasks than the pool can run at once so a backlog is queued while + # workers hit their task limit. + context = self.get_context() + if context.get_start_method(allow_none=False) == "fork": + raise unittest.SkipTest("Incompatible with the fork start method.") + + for max_workers, max_tasks, num_tasks in [(1, 2, 6), (2, 2, 8)]: + with self.subTest(max_workers=max_workers, max_tasks=max_tasks): + executor = self.executor_type( + max_workers, mp_context=context, + max_tasks_per_child=max_tasks) + try: + futures = [executor.submit(mul, i, 2) + for i in range(num_tasks)] + # If the deadlock regresses, the result() calls time out, + # and the shutdown below hangs until the test timeout. + results = [f.result(timeout=support.SHORT_TIMEOUT) + for f in futures] + self.assertEqual(results, + [i * 2 for i in range(num_tasks)]) + finally: + executor.shutdown(wait=True, cancel_futures=True) + def test_max_tasks_early_shutdown(self): context = self.get_context() if context.get_start_method(allow_none=False) == "fork": diff --git a/Misc/NEWS.d/next/Library/2025-11-02-05-28-56.gh-issue-115634.JbcNnF.rst b/Misc/NEWS.d/next/Library/2025-11-02-05-28-56.gh-issue-115634.JbcNnF.rst new file mode 100644 index 00000000000000..f023ce999c60b7 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-11-02-05-28-56.gh-issue-115634.JbcNnF.rst @@ -0,0 +1,5 @@ +Fix a deadlock in :class:`concurrent.futures.ProcessPoolExecutor` when +using ``max_tasks_per_child``, present since the feature was introduced in +Python 3.11. The executor stopped scheduling queued tasks after a worker +process exited upon reaching its task limit. Based on a fix proposed by +Tabrez Mohammed. From d657028a6e668c9cf04df53f82a57c97f59b7a5d Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 3 Jul 2026 10:55:46 +0200 Subject: [PATCH 555/818] [3.15] gh-152919: Ensure nuget.org source exist before python install (GH-152919) (cherry picked from commit 8c35afa221020f58d7d4f0237a999b2b989410fe) Co-authored-by: Bart van der Braak <bartvdbraak@gmail.com> --- PCbuild/find_python.bat | 3 +++ 1 file changed, 3 insertions(+) diff --git a/PCbuild/find_python.bat b/PCbuild/find_python.bat index 841d83968c60be..deec9541cf0559 100644 --- a/PCbuild/find_python.bat +++ b/PCbuild/find_python.bat @@ -67,6 +67,9 @@ ) ) +@rem ensure nuget.org source exist +@"%_Py_NUGET%" sources add -Name nuget.org -Source https://api.nuget.org/v3/index.json >nul 2>nul + @if not "%_Py_Quiet%"=="1" @echo Installing Python via nuget... @if not "%_Py_Quiet%"=="1" ( @"%_Py_NUGET%" install pythonx86 -ExcludeVersion -OutputDirectory "%_Py_EXTERNALS_DIR%" From 1b89ad7e009c00da78aab3eff73620fafb5b032e Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 3 Jul 2026 11:55:10 +0200 Subject: [PATCH 556/818] [3.15] gh-150641: Fix evaluating forward references in STRING format can 'leak' internal names in `typing` (GH-150648) (#152935) gh-150641: Fix evaluating forward references in STRING format can 'leak' internal names in `typing` (GH-150648) (cherry picked from commit f75028f7ceebee4cbeb46bf040834e2005d57436) Co-authored-by: Ivy Xu <fakeshadow1337@gmail.com> Co-authored-by: Jelle Zijlstra <jelle.zijlstra@gmail.com> --- Lib/test/test_typing.py | 12 ++++++++++++ Lib/typing.py | 2 +- .../2026-05-31-14-39-25.gh-issue-150641.LLIhd1.rst | 2 ++ 3 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2026-05-31-14-39-25.gh-issue-150641.LLIhd1.rst diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 042604ed7c1a42..0c57c83491042d 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -7582,6 +7582,18 @@ def test_with_module(self): typing.evaluate_forward_ref( fwdref_module.fw,) + def test_evaluate_forward_ref_string_format(self): + # Test evaluating forward references in STRING format + # does not 'leak' internal names + # See https://github.com/python/cpython/issues/150641 + + def f(arg: unknown | str | int | list[str] | tuple[int, ...]): ... + + ref = annotationlib.get_annotations(f, format=annotationlib.Format.FORWARDREF)['arg'] + self.assertEqual( + typing.evaluate_forward_ref(ref, format=annotationlib.Format.STRING), + "unknown | str | int | list[str] | tuple[int, ...]", + ) class CollectionsAbcTests(BaseTestCase): diff --git a/Lib/typing.py b/Lib/typing.py index 6011b62cd26944..8b17cbbae2f6ec 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -1032,7 +1032,7 @@ def evaluate_forward_ref( """ if format == annotationlib.Format.STRING: - return forward_ref.__forward_arg__ + return forward_ref.__resolved_str__ if forward_ref.__forward_arg__ in _recursive_guard: return forward_ref diff --git a/Misc/NEWS.d/next/Library/2026-05-31-14-39-25.gh-issue-150641.LLIhd1.rst b/Misc/NEWS.d/next/Library/2026-05-31-14-39-25.gh-issue-150641.LLIhd1.rst new file mode 100644 index 00000000000000..eba899c96fcd26 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-05-31-14-39-25.gh-issue-150641.LLIhd1.rst @@ -0,0 +1,2 @@ +Fix bug where :func:`typing.evaluate_forward_ref` with the ``STRING`` format +could leak internal names used by the annotation machinery. From 2a7eb3d179bbfbd7ba085c8093796bcbc6aea285 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 3 Jul 2026 13:03:07 +0200 Subject: [PATCH 557/818] [3.15] gh-152870: Fix compile error with decimal when EXTRA_FUNCTIONALITY enabled (GH-152871) (#152937) gh-152870: Fix compile error with decimal when EXTRA_FUNCTIONALITY enabled (GH-152871) (cherry picked from commit c4739533f335f9cd4fa71ba6daff2a81751da643) Co-authored-by: Xiaowei Lu <weixlu420302@gmail.com> --- Lib/test/test_decimal.py | 8 ++++++++ .../Build/2026-07-02-16-25-13.gh-issue-152870.oh9eD1.rst | 4 ++++ Modules/_decimal/_decimal.c | 2 +- 3 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Build/2026-07-02-16-25-13.gh-issue-152870.oh9eD1.rst diff --git a/Lib/test/test_decimal.py b/Lib/test/test_decimal.py index fe8c8ce12da0bf..a04ed0c83c07c4 100644 --- a/Lib/test/test_decimal.py +++ b/Lib/test/test_decimal.py @@ -4967,6 +4967,14 @@ def test_c_context(self): self.assertEqual(c._flags, C.DecClamped) self.assertEqual(c._traps, C.DecRounded) + @requires_extra_functionality + def test_c_context_apply(self): + c = C.Context(prec=3) + self.assertEqual(c.apply(C.Decimal('1.23456')), C.Decimal('1.23')) + # A higher precision won't see them as equal. + c = C.Context(prec=5) + self.assertNotEqual(c.apply(C.Decimal('1.23456')), C.Decimal('1.23')) + @requires_extra_functionality def test_constants(self): # Condition flags diff --git a/Misc/NEWS.d/next/Build/2026-07-02-16-25-13.gh-issue-152870.oh9eD1.rst b/Misc/NEWS.d/next/Build/2026-07-02-16-25-13.gh-issue-152870.oh9eD1.rst new file mode 100644 index 00000000000000..eaddd22a60fc09 --- /dev/null +++ b/Misc/NEWS.d/next/Build/2026-07-02-16-25-13.gh-issue-152870.oh9eD1.rst @@ -0,0 +1,4 @@ +Fix a compilation error in the :mod:`decimal` C extension (``_decimal``) when +it is built with ``EXTRA_FUNCTIONALITY``. ``Context.apply()`` called the +internal ``_apply`` helper using its pre-Argument-Clinic signature; the call is +now made through the generated ``_impl`` function. diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index 2760792a3fe18e..7a3240a3636a9c 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -6993,7 +6993,7 @@ _decimal_Context_apply_impl(PyObject *context, PyTypeObject *cls, PyObject *x) /*[clinic end generated code: output=f8a7142d47ad4ff3 input=388e66ca82733516]*/ { - return _decimal_Context__apply(context, x); + return _decimal_Context__apply_impl(context, cls, x); } #endif From fe23abac94840456a07e686512d0d09ed80efd6b Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 3 Jul 2026 13:33:14 +0200 Subject: [PATCH 558/818] [3.15] gh-152903: Change PCWSTR to PWSTR in GetThreadDescription() typedef (GH-152904) (#152943) gh-152903: Change PCWSTR to PWSTR in GetThreadDescription() typedef (GH-152904) Fixes issue GH-152903 (cherry picked from commit ac1acb6d7de2680d1f1f3e4cef7c145083ebba74) Co-authored-by: Carlo Bramini <carlo_bramini@users.sourceforge.net> --- Modules/_threadmodule.c | 2 +- Python/traceback.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Modules/_threadmodule.c b/Modules/_threadmodule.c index 7a34c5a5a0ef6b..7e1884edf5213e 100644 --- a/Modules/_threadmodule.c +++ b/Modules/_threadmodule.c @@ -74,7 +74,7 @@ get_thread_state_by_cls(PyTypeObject *cls) #ifdef MS_WINDOWS -typedef HRESULT (WINAPI *PF_GET_THREAD_DESCRIPTION)(HANDLE, PCWSTR*); +typedef HRESULT (WINAPI *PF_GET_THREAD_DESCRIPTION)(HANDLE, PWSTR*); typedef HRESULT (WINAPI *PF_SET_THREAD_DESCRIPTION)(HANDLE, PCWSTR); static PF_GET_THREAD_DESCRIPTION pGetThreadDescription = NULL; static PF_SET_THREAD_DESCRIPTION pSetThreadDescription = NULL; diff --git a/Python/traceback.c b/Python/traceback.c index 50a79d78d2e10e..5bfa28f9c7dc8b 100644 --- a/Python/traceback.c +++ b/Python/traceback.c @@ -71,7 +71,7 @@ class traceback "PyTracebackObject *" "&PyTraceback_Type" #ifdef MS_WINDOWS -typedef HRESULT (WINAPI *PF_GET_THREAD_DESCRIPTION)(HANDLE, PCWSTR*); +typedef HRESULT (WINAPI *PF_GET_THREAD_DESCRIPTION)(HANDLE, PWSTR*); static PF_GET_THREAD_DESCRIPTION pGetThreadDescription = NULL; #endif From 8ad11e3d96d34b4e6b382074173e437ed99ded95 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 3 Jul 2026 13:40:56 +0200 Subject: [PATCH 559/818] [3.15] gh-152785: Upgrade GCC from 10 to 13 in GHA Address Sanitizer (GH-152782) (#152949) gh-152785: Upgrade GCC from 10 to 13 in GHA Address Sanitizer (GH-152782) Remove the step which installs GCC 10. This step was needed when Ubuntu only had GCC 9. We are now using Ubuntu 24.04 which has GCC 13. (cherry picked from commit 31a0e0968e92c65019e4e0547475904e9b047d4a) Co-authored-by: Victor Stinner <vstinner@python.org> --- .github/workflows/build.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 362db498eb6c2c..f5bec534d80cec 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -566,10 +566,6 @@ jobs: run: echo "::add-matcher::.github/problem-matchers/gcc.json" - name: Install dependencies run: sudo ./.github/workflows/posix-deps-apt.sh - - name: Set up GCC-10 for ASAN - uses: egor-tensin/setup-gcc@a2861a8b8538f49cf2850980acccf6b05a1b2ae4 # v2.0 - with: - version: 10 - name: Configure OpenSSL env vars run: | echo "MULTISSL_DIR=${GITHUB_WORKSPACE}/multissl" >> "$GITHUB_ENV" From f3ef09e976d7a3c0b8f9ae1d2aeafb509b84a38f Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 3 Jul 2026 18:02:22 +0200 Subject: [PATCH 560/818] [3.15] gh-150880: Normalize paths on Windows before appending wildcard (GH-152906) (GH-152963) gh-150880: Normalize paths on Windows before appending wildcard (GH-152906) This ensures that we don't turn a "valid" path with trailing spaces into an invalid path with embedded spaces. (cherry picked from commit 1b4135a2c69f5320dbdcb37dcc295a5fd36580b5) Co-authored-by: Zain Nadeem <zainnadeemzainnadeem80@gmail.com> --- Lib/test/test_os/test_os.py | 24 ++++++ ...-07-02-22-19-53.gh-issue-150880.vPZ7jK.rst | 3 + Modules/posixmodule.c | 80 ++++++++++++------- 3 files changed, 78 insertions(+), 29 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-07-02-22-19-53.gh-issue-150880.vPZ7jK.rst diff --git a/Lib/test/test_os/test_os.py b/Lib/test/test_os/test_os.py index 930a06963ac058..279c9ac804f6be 100644 --- a/Lib/test/test_os/test_os.py +++ b/Lib/test/test_os/test_os.py @@ -5046,6 +5046,30 @@ def test_current_directory(self): finally: os.chdir(old_dir) + @unittest.skipIf(sys.platform != 'win32', "Win32 specific test") + def test_windows_trailing_space_path(self): + import pathlib + + filename = self.create_file("file.txt") + path = self.path + " " + + self.assertTrue(os.path.exists(path)) + os.stat(path) + with open(filename + " ", "rb") as file: + self.assertEqual(file.read(), b"python") + + self.assertEqual(os.listdir(path), ["file.txt"]) + with os.scandir(path) as entries: + self.assertEqual([entry.name for entry in entries], ["file.txt"]) + pathlib_entries = list(pathlib.Path(path).iterdir()) + self.assertEqual([entry.name for entry in pathlib_entries], ["file.txt"]) + del pathlib_entries + + extended_path = "\\\\?\\" + path + self.assertFalse(os.path.exists(extended_path)) + self.assertRaises(FileNotFoundError, os.listdir, extended_path) + self.assertRaises(FileNotFoundError, os.scandir, extended_path) + def test_repr(self): entry = self.create_file_entry() self.assertEqual(repr(entry), "<DirEntry 'file.txt'>") diff --git a/Misc/NEWS.d/next/Library/2026-07-02-22-19-53.gh-issue-150880.vPZ7jK.rst b/Misc/NEWS.d/next/Library/2026-07-02-22-19-53.gh-issue-150880.vPZ7jK.rst new file mode 100644 index 00000000000000..a7bf210f8e1ca9 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-02-22-19-53.gh-issue-150880.vPZ7jK.rst @@ -0,0 +1,3 @@ +Normalize non-extended Windows paths before appending the wildcard used by +``os.listdir()`` and ``os.scandir()``, making paths with trailing spaces +behave consistently with other filesystem APIs. diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 27ee07389f125f..2a25be16e61dc2 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -4905,15 +4905,16 @@ os_link_impl(PyObject *module, path_t *src, path_t *dst, int src_dir_fd, #if defined(MS_WINDOWS) && !defined(HAVE_OPENDIR) +static wchar_t * +join_path_filenameW(const wchar_t *path_wide, const wchar_t *filename, + int normalize); + static PyObject * _listdir_windows_no_opendir(path_t *path, PyObject *list) { PyObject *v; HANDLE hFindFile = INVALID_HANDLE_VALUE; BOOL result, return_bytes; - wchar_t namebuf[MAX_PATH+4]; /* Overallocate for "\*.*" */ - /* only claim to have space for MAX_PATH */ - Py_ssize_t len = Py_ARRAY_LENGTH(namebuf)-4; wchar_t *wnamebuf = NULL; WIN32_FIND_DATAW wFileData; @@ -4921,26 +4922,17 @@ _listdir_windows_no_opendir(path_t *path, PyObject *list) if (!path->wide) { /* Default arg: "." */ po_wchars = L"."; - len = 1; return_bytes = 0; } else { po_wchars = path->wide; - len = wcslen(path->wide); return_bytes = PyBytes_Check(path->object); } - /* The +5 is so we can append "\\*.*\0" */ - wnamebuf = PyMem_New(wchar_t, len + 5); - if (!wnamebuf) { - PyErr_NoMemory(); + + wnamebuf = join_path_filenameW(po_wchars, L"*.*", 1); + if (wnamebuf == NULL) { goto exit; } - wcscpy(wnamebuf, po_wchars); - if (len > 0) { - wchar_t wch = wnamebuf[len-1]; - if (wch != SEP && wch != ALTSEP && wch != L':') - wnamebuf[len++] = SEP; - wcscpy(wnamebuf + len, L"*.*"); - } + if ((list = PyList_New(0)) == NULL) { goto exit; } @@ -16579,13 +16571,19 @@ static PyType_Spec DirEntryType_spec = { #ifdef MS_WINDOWS +static int +is_extended_path(const wchar_t *path) +{ + return wcsncmp(path, L"\\\\?\\", 4) == 0; +} + static wchar_t * -join_path_filenameW(const wchar_t *path_wide, const wchar_t *filename) +join_path_filenameW(const wchar_t *path_wide, const wchar_t *filename, + int normalize) { Py_ssize_t path_len; - Py_ssize_t size; wchar_t *result; - wchar_t ch; + wchar_t *path_allocated = NULL; if (!path_wide) { /* Default arg: "." */ path_wide = L"."; @@ -16595,20 +16593,44 @@ join_path_filenameW(const wchar_t *path_wide, const wchar_t *filename) path_len = wcslen(path_wide); } - /* The +1's are for the path separator and the NUL */ - size = path_len + 1 + wcslen(filename) + 1; + if (path_len == 0) { + result = PyMem_New(wchar_t, 1); + if (result == NULL) { + PyErr_NoMemory(); + return NULL; + } + result[0] = L'\0'; + return result; + } + + if (normalize && !is_extended_path(path_wide)) { + int err = _PyOS_getfullpathname(path_wide, &path_allocated); + if (err < 0) { + PyErr_SetFromWindowsErr(0); + return NULL; + } + if (path_allocated == NULL) { + PyErr_NoMemory(); + return NULL; + } + path_wide = path_allocated; + path_len = wcslen(path_wide); + } + + size_t size = (size_t)path_len + 1 + wcslen(filename) + 1; result = PyMem_New(wchar_t, size); - if (!result) { + if (result == NULL) { + PyMem_RawFree(path_allocated); PyErr_NoMemory(); return NULL; } wcscpy(result, path_wide); - if (path_len > 0) { - ch = result[path_len - 1]; - if (ch != SEP && ch != ALTSEP && ch != L':') - result[path_len++] = SEP; - wcscpy(result + path_len, filename); + wchar_t ch = result[path_len - 1]; + if (ch != SEP && ch != ALTSEP && ch != L':') { + result[path_len++] = SEP; } + wcscpy(result + path_len, filename); + PyMem_RawFree(path_allocated); return result; } @@ -16640,7 +16662,7 @@ DirEntry_from_find_data(PyObject *module, path_t *path, WIN32_FIND_DATAW *dataW) goto error; } - joined_path = join_path_filenameW(path->wide, dataW->cFileName); + joined_path = join_path_filenameW(path->wide, dataW->cFileName, 0); if (!joined_path) goto error; @@ -17076,7 +17098,7 @@ os_scandir_impl(PyObject *module, path_t *path) #ifdef MS_WINDOWS iterator->first_time = 1; - path_strW = join_path_filenameW(iterator->path.wide, L"*.*"); + path_strW = join_path_filenameW(iterator->path.wide, L"*.*", 1); if (!path_strW) goto error; From 138dd26337efd79b3afa84044aa364d8e2c6fe82 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 3 Jul 2026 18:48:51 +0200 Subject: [PATCH 561/818] [3.15] gh-152785: Upgrade LLVM to LLVM 21 in GitHub Action jobs (GH-152781) (#152968) gh-152785: Upgrade LLVM to LLVM 21 in GitHub Action jobs (GH-152781) Upgrade LLVM to LLVM 21 in GitHub Action jobs: * Reusable Sanitizer * Reusable Ubuntu ("Install Clang and BOLT") (cherry picked from commit f5b3eefbdabeedb71f0d69f60a6f8d71dc11873a) Co-authored-by: Victor Stinner <vstinner@python.org> --- .github/workflows/reusable-san.yml | 10 +++++----- .github/workflows/reusable-ubuntu.yml | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/reusable-san.yml b/.github/workflows/reusable-san.yml index ef36447964cf41..aed2776b4bab71 100644 --- a/.github/workflows/reusable-san.yml +++ b/.github/workflows/reusable-san.yml @@ -40,11 +40,11 @@ jobs: # Install clang wget https://apt.llvm.org/llvm.sh chmod +x llvm.sh - sudo ./llvm.sh 20 - sudo update-alternatives --install /usr/bin/clang clang /usr/bin/clang-20 100 - sudo update-alternatives --set clang /usr/bin/clang-20 - sudo update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-20 100 - sudo update-alternatives --set clang++ /usr/bin/clang++-20 + sudo ./llvm.sh 21 + sudo update-alternatives --install /usr/bin/clang clang /usr/bin/clang-21 100 + sudo update-alternatives --set clang /usr/bin/clang-21 + sudo update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-21 100 + sudo update-alternatives --set clang++ /usr/bin/clang++-21 if [ "${SANITIZER}" = "TSan" ]; then # Reduce ASLR to avoid TSan crashing diff --git a/.github/workflows/reusable-ubuntu.yml b/.github/workflows/reusable-ubuntu.yml index f4321cefa1b598..564ad024ec1f8a 100644 --- a/.github/workflows/reusable-ubuntu.yml +++ b/.github/workflows/reusable-ubuntu.yml @@ -49,9 +49,9 @@ jobs: - name: Install Clang and BOLT if: ${{ fromJSON(inputs.bolt-optimizations) }} run: | - sudo bash -c "$(wget -O - https://apt.llvm.org/llvm.sh)" ./llvm.sh 19 - sudo apt-get install --no-install-recommends bolt-19 - echo PATH="$(llvm-config-19 --bindir):$PATH" >> $GITHUB_ENV + sudo bash -c "$(wget -O - https://apt.llvm.org/llvm.sh)" ./llvm.sh 21 + sudo apt-get install --no-install-recommends bolt-21 + echo PATH="$(llvm-config-21 --bindir):$PATH" >> $GITHUB_ENV - name: Configure OpenSSL env vars run: | echo "MULTISSL_DIR=${GITHUB_WORKSPACE}/multissl" >> "$GITHUB_ENV" From ce373b845ce822a413ee8eb9bf161270825b38a2 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 3 Jul 2026 20:14:59 +0200 Subject: [PATCH 562/818] [3.15] gh-152951 - Fix double DECREF when `newblock` fails during deque.extend calls (GH-152961) (#152971) gh-152951 - Fix double DECREF when `newblock` fails during deque.extend calls (GH-152961) (cherry picked from commit a90576d72c8a409f7c3ffcaefafb13945e3405ab) Co-authored-by: Steve Stagg <stestagg@gmail.com> --- .../next/Library/2026-07-03-14-54-33.gh-issue-152951.u8tPCI.rst | 2 ++ Modules/_collectionsmodule.c | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2026-07-03-14-54-33.gh-issue-152951.u8tPCI.rst diff --git a/Misc/NEWS.d/next/Library/2026-07-03-14-54-33.gh-issue-152951.u8tPCI.rst b/Misc/NEWS.d/next/Library/2026-07-03-14-54-33.gh-issue-152951.u8tPCI.rst new file mode 100644 index 00000000000000..c3d56c6d59c91b --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-03-14-54-33.gh-issue-152951.u8tPCI.rst @@ -0,0 +1,2 @@ +:class:`collections.deque` prevent rare crash when calling ``extend`` under +high memory pressure conditions. diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c index 5ca6362406a78b..b0701df26bbd24 100644 --- a/Modules/_collectionsmodule.c +++ b/Modules/_collectionsmodule.c @@ -512,7 +512,6 @@ deque_extend_impl(dequeobject *deque, PyObject *iterable) iternext = *Py_TYPE(it)->tp_iternext; while ((item = iternext(it)) != NULL) { if (deque_append_lock_held(deque, item, maxlen) == -1) { - Py_DECREF(item); Py_DECREF(it); return NULL; } From 8d08232817dfb14e86f26087f6f090da6f48884a Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 3 Jul 2026 23:32:20 +0200 Subject: [PATCH 563/818] [3.15] gh-83386: Enable test_hang_gh83386 for ProcessPoolExecutor (GH-152976) (#152982) gh-83386: Enable test_hang_gh83386 for ProcessPoolExecutor (GH-152976) The hang this test guards against (interpreter exit after shutdown(wait=False) with running futures) was fixed for ProcessPoolExecutor by the executor management rewrite years ago, but the test still skipped it citing the issue. The skip also hid a latent NameError in the subprocess template, which only selects a start method in the process pool variants; rewrite it to use the same mp_context=get_context() shape as the sibling templates. Remove a stale comment claiming ProcessPoolExecutor often hangs with wait=False. (cherry picked from commit 548c7314138b85cab3b945a1ce05440dd836a2ea) Co-authored-by: Gregory P. Smith <68491+gpshead@users.noreply.github.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> --- .../test_concurrent_futures/test_shutdown.py | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/Lib/test/test_concurrent_futures/test_shutdown.py b/Lib/test/test_concurrent_futures/test_shutdown.py index c576df1068ed32..129b5cb5057093 100644 --- a/Lib/test/test_concurrent_futures/test_shutdown.py +++ b/Lib/test/test_concurrent_futures/test_shutdown.py @@ -115,20 +115,21 @@ def test_hang_gh83386(self): See https://github.com/python/cpython/issues/83386. """ - if self.executor_type == futures.ProcessPoolExecutor: - raise unittest.SkipTest( - "Hangs, see https://github.com/python/cpython/issues/83386") - rc, out, err = assert_python_ok('-c', """if True: from concurrent.futures import {executor_type} from test.test_concurrent_futures.test_shutdown import sleep_and_print if __name__ == "__main__": - if {context!r}: multiprocessing.set_start_method({context!r}) - t = {executor_type}(max_workers=3) + context = '{context}' + if context == "": + t = {executor_type}(max_workers=3) + else: + from multiprocessing import get_context + t = {executor_type}(max_workers=3, + mp_context=get_context(context)) t.submit(sleep_and_print, 1.0, "apple") t.shutdown(wait=False) """.format(executor_type=self.executor_type.__name__, - context=getattr(self, 'ctx', None))) + context=getattr(self, 'ctx', ''))) self.assertFalse(err) self.assertEqual(out.strip(), b"apple") @@ -243,8 +244,6 @@ def test_thread_names_default(self): t.join() def test_cancel_futures_wait_false(self): - # Can only be reliably tested for TPE, since PPE often hangs with - # `wait=False` (even without *cancel_futures*). rc, out, err = assert_python_ok('-c', """if True: from concurrent.futures import ThreadPoolExecutor from test.test_concurrent_futures.test_shutdown import sleep_and_print From 2dd5d4e1ec78c56e4ee05a6fc3aa345a76ec457c Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 4 Jul 2026 05:20:49 +0200 Subject: [PATCH 564/818] [3.15] gh-150579: use lazy imports for concurrent.futures (GH-150585) (#152975) gh-150579: use lazy imports for concurrent.futures (GH-150585) This module has a manual lazy import hack using `__getattr__`. Now that lazy imports exist and cannot be disabled, this could use lazy imports instead. Key differences: this will now show up in sys.lazy_modules when accessed. Error messages should be a bit better without the wrapper `__getattr__` involved. That's the only differences I can think of. (cherry picked from commit 423ae0ff36c6485f722e0fe3274124dc3df09862) Signed-off-by: Henry Schreiner <henryfs@princeton.edu> Co-authored-by: Henry Schreiner <henryfs@princeton.edu> Co-authored-by: Gregory P. Smith <greg@krypto.org> --- Lib/concurrent/futures/__init__.py | 22 ++++--------------- ...-03-17-29-34.gh-issue-150579.0tLpQukIU.rst | 2 ++ 2 files changed, 6 insertions(+), 18 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-07-03-17-29-34.gh-issue-150579.0tLpQukIU.rst diff --git a/Lib/concurrent/futures/__init__.py b/Lib/concurrent/futures/__init__.py index d6ac4b3e0b675f..5d53a5ac50931d 100644 --- a/Lib/concurrent/futures/__init__.py +++ b/Lib/concurrent/futures/__init__.py @@ -17,6 +17,9 @@ wait, as_completed) +lazy from .process import ProcessPoolExecutor +lazy from .thread import ThreadPoolExecutor + __all__ = [ 'FIRST_COMPLETED', 'FIRST_EXCEPTION', @@ -40,26 +43,9 @@ _interpreters = None if _interpreters: + lazy from .interpreter import InterpreterPoolExecutor # noqa: F401 __all__.append('InterpreterPoolExecutor') def __dir__(): return __all__ + ['__author__', '__doc__'] - - -def __getattr__(name): - global ProcessPoolExecutor, ThreadPoolExecutor, InterpreterPoolExecutor - - if name == 'ProcessPoolExecutor': - from .process import ProcessPoolExecutor - return ProcessPoolExecutor - - if name == 'ThreadPoolExecutor': - from .thread import ThreadPoolExecutor - return ThreadPoolExecutor - - if _interpreters and name == 'InterpreterPoolExecutor': - from .interpreter import InterpreterPoolExecutor - return InterpreterPoolExecutor - - raise AttributeError(f"module {__name__!r} has no attribute {name!r}") diff --git a/Misc/NEWS.d/next/Library/2026-07-03-17-29-34.gh-issue-150579.0tLpQukIU.rst b/Misc/NEWS.d/next/Library/2026-07-03-17-29-34.gh-issue-150579.0tLpQukIU.rst new file mode 100644 index 00000000000000..7aff384431edc7 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-03-17-29-34.gh-issue-150579.0tLpQukIU.rst @@ -0,0 +1,2 @@ +:mod:`concurrent.futures` now uses lazy imports for its executor submodules +instead of a module ``__getattr__`` hook. From e1320ae4c3c53e09108f2089fecab545def44d23 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 4 Jul 2026 12:41:40 +0200 Subject: [PATCH 565/818] [3.15] gh-152851: fix a crash when copying a BLAKE-2s/2b object (GH-153008) (#153011) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gh-152851: fix a crash when copying a BLAKE-2s/2b object (GH-153008) (cherry picked from commit 5a400ceafbbd4456ac65fbdbcf5d62ce9e8e4f9f) Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com> --- .../Library/2026-07-04-11-14-06.gh-issue-152851.diYvTf.rst | 2 ++ Modules/blake2module.c | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2026-07-04-11-14-06.gh-issue-152851.diYvTf.rst diff --git a/Misc/NEWS.d/next/Library/2026-07-04-11-14-06.gh-issue-152851.diYvTf.rst b/Misc/NEWS.d/next/Library/2026-07-04-11-14-06.gh-issue-152851.diYvTf.rst new file mode 100644 index 00000000000000..aab033ebeed695 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-04-11-14-06.gh-issue-152851.diYvTf.rst @@ -0,0 +1,2 @@ +Prevent a crash when allocation fails while copying a :func:`BLAKE-2s/2b +<hashlib.blake2b>` object. Patch by Bénédikt Tran. diff --git a/Modules/blake2module.c b/Modules/blake2module.c index b71dd20925611e..ac7265bb9d6836 100644 --- a/Modules/blake2module.c +++ b/Modules/blake2module.c @@ -757,6 +757,10 @@ blake2_blake2b_copy_unlocked(Blake2Object *self, Blake2Object *cpy) } \ } while (0) + // Ensure that the implementation type is consistent with the HACL* state. + // See https://github.com/python/cpython/issues/152851 for details. + cpy->impl = self->impl; + switch (self->impl) { #if _Py_HACL_CAN_COMPILE_VEC256 case Blake2b_256: @@ -778,7 +782,6 @@ blake2_blake2b_copy_unlocked(Blake2Object *self, Blake2Object *cpy) Py_UNREACHABLE(); } #undef BLAKE2_COPY - cpy->impl = self->impl; return 0; error: From fdc17cab045c62f956557c28cbe9481610451bfe Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 4 Jul 2026 14:36:03 +0200 Subject: [PATCH 566/818] [3.15] gh-135661: Fix abrupt closing of empty comment in HTMLParser (GH-153007) (GH-153024) An abruptly closed empty comment ("<!-->" or "<!--->") no longer extends up to a later "-->" in the same feed() call. test_htmlparser now also feeds each string source as a single chunk, in addition to one character at a time, to exercise different input buffering. (cherry picked from commit ed370d3337c1ac4f7295b444a4807c0b72287608) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --- Lib/html/parser.py | 6 ++++-- Lib/test/test_htmlparser.py | 10 ++++++++++ .../2026-07-04-13-00-00.gh-issue-135661.CIkADG.rst | 3 +++ 3 files changed, 17 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-07-04-13-00-00.gh-issue-135661.CIkADG.rst diff --git a/Lib/html/parser.py b/Lib/html/parser.py index 80fb8c3f929f6b..38ddf9ef442d36 100644 --- a/Lib/html/parser.py +++ b/Lib/html/parser.py @@ -387,9 +387,11 @@ def parse_html_declaration(self, i): def parse_comment(self, i, report=True): rawdata = self.rawdata assert rawdata.startswith('<!--', i), 'unexpected call to parse_comment()' - match = commentclose.search(rawdata, i+4) + # An empty comment is abruptly closed by the first ">" or "->", + # taking priority over a later "-->" or "--!>" close. + match = commentabruptclose.match(rawdata, i+4) if not match: - match = commentabruptclose.match(rawdata, i+4) + match = commentclose.search(rawdata, i+4) if not match: return -1 if report: diff --git a/Lib/test/test_htmlparser.py b/Lib/test/test_htmlparser.py index e4eff1ea17a670..6b7624f11505d9 100644 --- a/Lib/test/test_htmlparser.py +++ b/Lib/test/test_htmlparser.py @@ -116,6 +116,11 @@ def _run_check(self, source, expected_events, *, collector=None, convert_charrefs=False): if collector is None: collector = self.get_collector(convert_charrefs=convert_charrefs) + if isinstance(source, str): + # Also feed the whole string at once, not just character by + # character (below), to exercise different input buffering. + self._run_check([source], expected_events, + convert_charrefs=convert_charrefs) parser = collector for s in source: parser.feed(s) @@ -593,6 +598,9 @@ def test_comments(self): '<!-- <!-- nested --> -->' '<!--<!-->' '<!--<!--!>' + # abruptly closed empty comment must not swallow later text + '<!-->x-->' + '<!--->y-->' ) expected = [('comment', " I'm a valid comment "), ('comment', 'me too!'), @@ -613,6 +621,8 @@ def test_comments(self): ('comment', ' <!-- nested '), ('data', ' -->'), ('comment', '<!'), ('comment', '<!'), + ('comment', ''), ('data', 'x-->'), + ('comment', ''), ('data', 'y-->'), ] self._run_check(html, expected) diff --git a/Misc/NEWS.d/next/Library/2026-07-04-13-00-00.gh-issue-135661.CIkADG.rst b/Misc/NEWS.d/next/Library/2026-07-04-13-00-00.gh-issue-135661.CIkADG.rst new file mode 100644 index 00000000000000..26a912a6f3a194 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-04-13-00-00.gh-issue-135661.CIkADG.rst @@ -0,0 +1,3 @@ +Fix :class:`html.parser.HTMLParser`: an abruptly closed empty comment +(``<!-->`` or ``<!--->``) no longer extends up to a later ``-->`` in the same +:meth:`~html.parser.HTMLParser.feed` call. From cb0adb0d94764338ae6eedc359fc8312f04f8b69 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 4 Jul 2026 15:49:59 +0200 Subject: [PATCH 567/818] [3.15] gh-152068: Reset PyREPL Colors on prompt finish (GH-152108) (#153029) --- Lib/_pyrepl/render.py | 10 ++++---- Lib/_pyrepl/unix_console.py | 4 ++++ Lib/_pyrepl/windows_console.py | 5 ++++ Lib/test/test_pyrepl/test_unix_console.py | 19 +++++++++++++++ Lib/test/test_pyrepl/test_windows_console.py | 23 +++++++++++++++++++ ...-07-02-19-21-15.gh-issue-152068.ThsmJU.rst | 1 + 6 files changed, 58 insertions(+), 4 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-07-02-19-21-15.gh-issue-152068.ThsmJU.rst diff --git a/Lib/_pyrepl/render.py b/Lib/_pyrepl/render.py index b821f35d850825..b835778e366c53 100644 --- a/Lib/_pyrepl/render.py +++ b/Lib/_pyrepl/render.py @@ -4,8 +4,10 @@ from dataclasses import dataclass, field from typing import Literal, Protocol, Self -from .utils import ANSI_ESCAPE_SEQUENCE, THEME, StyleRef, str_width +from _colorize import ANSIColors + from .types import CursorXY +from .utils import ANSI_ESCAPE_SEQUENCE, THEME, StyleRef, str_width type RenderStyle = StyleRef | str | None type LineUpdateKind = Literal[ @@ -55,7 +57,7 @@ def _style_escape(style: StyleRef) -> str: def _update_terminal_state(state: str, escape: str) -> str: - if escape in {"\x1b[0m", "\x1b[m"}: + if escape in {ANSIColors.RESET, "\x1b[m"}: return "" return state + escape @@ -344,14 +346,14 @@ def render_cells( target_escape += visual_style if target_escape != active_escape: if active_escape: - rendered.append("\x1b[0m") + rendered.append(ANSIColors.RESET) if target_escape: rendered.append(target_escape) active_escape = target_escape rendered.append(cell.text) if active_escape: - rendered.append("\x1b[0m") + rendered.append(ANSIColors.RESET) return "".join(rendered) diff --git a/Lib/_pyrepl/unix_console.py b/Lib/_pyrepl/unix_console.py index 9c4644db53e343..bfefa68e9207d8 100644 --- a/Lib/_pyrepl/unix_console.py +++ b/Lib/_pyrepl/unix_console.py @@ -36,6 +36,8 @@ from fcntl import ioctl from typing import TYPE_CHECKING, cast, overload +from _colorize import ANSIColors + from . import terminfo from .console import Console, Event from .fancy_termios import tcgetattr, tcsetattr, TermState @@ -517,6 +519,7 @@ def restore(self) -> None: Restore the console to the default state """ trace("unix.restore") + self.__write(ANSIColors.RESET) self.__disable_bracketed_paste() self.__maybe_write_code(self._rmkx) self.flushoutput() @@ -654,6 +657,7 @@ def finish(self): while y >= 0 and not rendered_lines[y].text: y -= 1 self.__move(0, min(y, self.height + self.__offset - 1)) + self.__write(ANSIColors.RESET) self.__write("\n\r") self.flushoutput() diff --git a/Lib/_pyrepl/windows_console.py b/Lib/_pyrepl/windows_console.py index c1f9a19545d35f..3768a22ad16f7b 100644 --- a/Lib/_pyrepl/windows_console.py +++ b/Lib/_pyrepl/windows_console.py @@ -39,6 +39,9 @@ ) from ctypes import Structure, POINTER, Union from typing import TYPE_CHECKING + +from _colorize import ANSIColors + from .console import Event, Console from .render import ( EMPTY_RENDER_LINE, @@ -480,6 +483,7 @@ def prepare(self) -> None: def restore(self) -> None: trace("windows.restore") if self.__vt_support: + self.__write(ANSIColors.RESET) # Recover to original mode before running REPL self._disable_bracketed_paste() if not SetConsoleMode(InHandle, self.__original_input_mode): @@ -647,6 +651,7 @@ def finish(self) -> None: while y >= 0 and not rendered_lines[y].text: y -= 1 self._move_relative(0, min(y, self.height + self.__offset - 1)) + self.__write(ANSIColors.RESET) self.__write("\r\n") def flushoutput(self) -> None: diff --git a/Lib/test/test_pyrepl/test_unix_console.py b/Lib/test/test_pyrepl/test_unix_console.py index 71b2e17e334151..2fc8398923cbf3 100644 --- a/Lib/test/test_pyrepl/test_unix_console.py +++ b/Lib/test/test_pyrepl/test_unix_console.py @@ -6,6 +6,7 @@ import threading import unittest from functools import partial +from _colorize import ANSIColors from test.support import force_color, os_helper, force_not_colorized_test_class from test.support import threading_helper @@ -147,6 +148,24 @@ def test_no_newline(self, _os_write): self.assertNotIn(call(ANY, b'\n'), _os_write.mock_calls) con.restore() + def test_reset_on_finish(self, _os_write): + # gh-152068: finish() must emit the ANSI reset sequence so any + # active color does not leak past the prompt. + code = "1" + events = code_to_events(code) + _, con = handle_events_unix_console(events) + con.finish() + _os_write.assert_any_call(ANY, ANSIColors.RESET.encode(con.encoding)) + con.restore() + + def test_reset_on_restore(self, _os_write): + # gh-152068: restore() must emit the ANSI reset sequence. + code = "1" + events = code_to_events(code) + _, con = handle_events_unix_console(events) + con.restore() + _os_write.assert_any_call(ANY, ANSIColors.RESET.encode(con.encoding)) + def test_newline(self, _os_write): code = "\n" events = code_to_events(code) diff --git a/Lib/test/test_pyrepl/test_windows_console.py b/Lib/test/test_pyrepl/test_windows_console.py index 2b6075b3274c05..32c4255aa6b190 100644 --- a/Lib/test/test_pyrepl/test_windows_console.py +++ b/Lib/test/test_pyrepl/test_windows_console.py @@ -6,6 +6,7 @@ import itertools +from _colorize import ANSIColors from functools import partial from test.support import force_not_colorized_test_class from typing import Iterable @@ -380,6 +381,28 @@ def test_multiline_ctrl_z(self): self.assertEqual(reader.cxy, (2, 3)) con.restore() + def test_reset_on_finish(self): + # gh-152068: finish() must emit the ANSI reset sequence so any + # active color does not leak past the prompt. + code = "1" + events = code_to_events(code) + _, con = self.handle_events(events) + con.finish() + con.out.write.assert_any_call(ANSIColors.RESET.encode(con.encoding)) + con.restore() + + def test_reset_on_restore(self): + # gh-152068: restore() must emit the ANSI reset sequence when VT + # support is enabled. + code = "1" + events = code_to_events(code) + _, con = self.handle_events(events) + con._WindowsConsole__vt_support = True + con._WindowsConsole__original_input_mode = 0 + with patch.object(wc, "SetConsoleMode", return_value=1): + con.restore() + con.out.write.assert_any_call(ANSIColors.RESET.encode(con.encoding)) + @patch.object(WindowsConsole, '__init__', _mock_console_init) class WindowsConsoleGetEventTests(TestCase): diff --git a/Misc/NEWS.d/next/Library/2026-07-02-19-21-15.gh-issue-152068.ThsmJU.rst b/Misc/NEWS.d/next/Library/2026-07-02-19-21-15.gh-issue-152068.ThsmJU.rst new file mode 100644 index 00000000000000..9ec8413b4ac424 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-02-19-21-15.gh-issue-152068.ThsmJU.rst @@ -0,0 +1 @@ +Fixes a bug when a line was split (particularly on macOS Terminal.app) in the middle of a colorized keyword, causing the ANSI Color Reset sequence (ESC0m) to not be properly printed, causing the output to be colored when it shouldn't From 960e152bf69d426f4e203cb251d4736f0e44993e Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 4 Jul 2026 17:11:20 +0200 Subject: [PATCH 568/818] [3.15] gh-151945: Fix all reference warnings and various solecisms in the `http.cookiejar` docs (GH-152816) (#153032) (cherry picked from commit 66c76fa6737d497cd3c735f75e67a5ca52eceb15) Co-authored-by: Harjoth Khara <harjoth.khara@gmail.com> Co-authored-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> Co-authored-by: Stan Ulbrych <stan@python.org> --- Doc/library/http.cookiejar.rst | 106 ++++++++++++++++++--------------- Doc/tools/.nitignore | 1 - 2 files changed, 59 insertions(+), 48 deletions(-) diff --git a/Doc/library/http.cookiejar.rst b/Doc/library/http.cookiejar.rst index 5ee783b7fae950..ce65bc961a98a6 100644 --- a/Doc/library/http.cookiejar.rst +++ b/Doc/library/http.cookiejar.rst @@ -26,7 +26,7 @@ introduced with RFC 2965. .. note:: The various named parameters found in :mailheader:`Set-Cookie` and - :mailheader:`Set-Cookie2` headers (eg. ``domain`` and ``expires``) are + :mailheader:`Set-Cookie2` headers (for example, ``domain`` and ``expires``) are conventionally referred to as :dfn:`attributes`. To distinguish them from Python attributes, the documentation for this module uses the term :dfn:`cookie-attribute` instead. @@ -85,7 +85,7 @@ The following classes are provided: Constructor arguments should be passed as keyword arguments only. *blocked_domains* is a sequence of domain names that we never accept cookies - from, nor return cookies to. *allowed_domains* if not :const:`None`, this is a + from, nor return cookies to. *allowed_domains* if not ``None``, this is a sequence of the only domains for which we accept and return cookies. *secure_protocols* is a sequence of protocols for which secure cookies can be added to. By default *https* and *wss* (secure websocket) are considered @@ -93,12 +93,12 @@ The following classes are provided: :class:`CookiePolicy` and :class:`DefaultCookiePolicy` objects. :class:`DefaultCookiePolicy` implements the standard accept / reject rules for - Netscape and :rfc:`2965` cookies. By default, :rfc:`2109` cookies (ie. cookies + Netscape and :rfc:`2965` cookies. By default, :rfc:`2109` cookies (that is, cookies received in a :mailheader:`Set-Cookie` header with a version cookie-attribute of 1) are treated according to the RFC 2965 rules. However, if RFC 2965 handling is turned off or :attr:`rfc2109_as_netscape` is ``True``, RFC 2109 cookies are 'downgraded' by the :class:`CookieJar` instance to Netscape cookies, by - setting the :attr:`version` attribute of the :class:`Cookie` instance to 0. + setting the :attr:`~Cookie.version` attribute of the :class:`Cookie` instance to 0. :class:`DefaultCookiePolicy` also provides some parameters to allow some fine-tuning of policy. @@ -107,7 +107,7 @@ The following classes are provided: This class represents Netscape, :rfc:`2109` and :rfc:`2965` cookies. It is not expected that users of :mod:`!http.cookiejar` construct their own :class:`Cookie` - instances. Instead, if necessary, call :meth:`make_cookies` on a + instances. Instead, if necessary, call :meth:`~CookieJar.make_cookies` on a :class:`CookieJar` instance. @@ -141,7 +141,7 @@ The following classes are provided: .. _cookie-jar-objects: -CookieJar and FileCookieJar Objects +CookieJar and FileCookieJar objects ----------------------------------- :class:`CookieJar` objects support the :term:`iterator` protocol for iterating over @@ -154,20 +154,27 @@ contained :class:`Cookie` objects. Add correct :mailheader:`Cookie` header to *request*. - If policy allows (ie. the :attr:`rfc2965` and :attr:`hide_cookie2` attributes of + If policy allows (that is, the :attr:`~CookiePolicy.rfc2965` and + :attr:`~CookiePolicy.hide_cookie2` attributes of the :class:`CookieJar`'s :class:`CookiePolicy` instance are true and false respectively), the :mailheader:`Cookie2` header is also added when appropriate. The *request* object (usually a :class:`urllib.request.Request` instance) - must support the methods :meth:`get_full_url`, :meth:`has_header`, - :meth:`get_header`, :meth:`header_items`, :meth:`add_unredirected_header` - and the attributes :attr:`host`, :attr:`!type`, :attr:`unverifiable` - and :attr:`origin_req_host` as documented by :mod:`urllib.request`. + must support the methods :meth:`~urllib.request.Request.get_full_url`, + :meth:`~urllib.request.Request.has_header`, + :meth:`~urllib.request.Request.get_header`, + :meth:`~urllib.request.Request.header_items`, + :meth:`~urllib.request.Request.add_unredirected_header` + and the attributes :attr:`~urllib.request.Request.host`, + :attr:`~urllib.request.Request.type`, :attr:`~urllib.request.Request.unverifiable` + and :attr:`~urllib.request.Request.origin_req_host` as documented by + :mod:`urllib.request`. .. versionchanged:: 3.3 - *request* object needs :attr:`origin_req_host` attribute. Dependency on a - deprecated method :meth:`get_origin_req_host` has been removed. + *request* object needs :attr:`~urllib.request.Request.origin_req_host` + attribute. Dependency on a deprecated method + :meth:`!get_origin_req_host` has been removed. .. method:: CookieJar.extract_cookies(response, request) @@ -180,20 +187,24 @@ contained :class:`Cookie` objects. as appropriate (subject to the :meth:`CookiePolicy.set_ok` method's approval). The *response* object (usually the result of a call to - :meth:`urllib.request.urlopen`, or similar) should support an :meth:`info` - method, which returns an :class:`email.message.Message` instance. + :meth:`urllib.request.urlopen`, or similar) should support an + :meth:`~http.client.HTTPResponse.info` method, which returns an + :class:`email.message.Message` instance. The *request* object (usually a :class:`urllib.request.Request` instance) - must support the method :meth:`get_full_url` and the attributes - :attr:`host`, :attr:`unverifiable` and :attr:`origin_req_host`, + must support the method :meth:`~urllib.request.Request.get_full_url` and + the attributes :attr:`~urllib.request.Request.host`, + :attr:`~urllib.request.Request.unverifiable` + and :attr:`~urllib.request.Request.origin_req_host`, as documented by :mod:`urllib.request`. The request is used to set default values for cookie-attributes as well as for checking that the cookie is allowed to be set. .. versionchanged:: 3.3 - *request* object needs :attr:`origin_req_host` attribute. Dependency on a - deprecated method :meth:`get_origin_req_host` has been removed. + *request* object needs :attr:`~urllib.request.Request.origin_req_host` + attribute. Dependency on a deprecated method + :meth:`!get_origin_req_host` has been removed. .. method:: CookieJar.set_policy(policy) @@ -236,13 +247,13 @@ contained :class:`Cookie` objects. Discard all session cookies. - Discards all contained cookies that have a true :attr:`discard` attribute + Discards all contained cookies that have a true :attr:`~Cookie.discard` attribute (usually because they had either no ``max-age`` or ``expires`` cookie-attribute, or an explicit ``discard`` cookie-attribute). For interactive browsers, the end of a session usually corresponds to closing the browser window. - Note that the :meth:`save` method won't save session cookies anyway, unless you - ask otherwise by passing a true *ignore_discard* argument. + Note that the :meth:`~FileCookieJar.save` method won't save session cookies + anyway, unless you ask otherwise by passing a true *ignore_discard* argument. :class:`FileCookieJar` implements the following additional methods: @@ -255,8 +266,9 @@ contained :class:`Cookie` objects. method unimplemented. *filename* is the name of file in which to save cookies. If *filename* is not - specified, :attr:`self.filename` is used (whose default is the value passed to - the constructor, if any); if :attr:`self.filename` is :const:`None`, + specified, :attr:`self.filename <FileCookieJar.filename>` is used (whose + default is the value passed to the constructor, if any); if + :attr:`self.filename <FileCookieJar.filename>` is ``None``, :exc:`ValueError` is raised. *ignore_discard*: save even cookies set to be discarded. *ignore_expires*: save @@ -349,7 +361,7 @@ writing. .. _cookie-policy-objects: -CookiePolicy Objects +CookiePolicy objects -------------------- Objects implementing the :class:`CookiePolicy` interface have the following @@ -433,7 +445,7 @@ setting and receiving any and all cookies (this is unlikely to be useful). .. _default-cookie-policy-objects: -DefaultCookiePolicy Objects +DefaultCookiePolicy objects --------------------------- Implements the standard rules for accepting and returning cookies. @@ -463,10 +475,10 @@ blocking some benign cookies). A domain blocklist and allowlist is provided (both off by default). Only domains not in the blocklist and present in the allowlist (if the allowlist is active) participate in cookie setting and returning. Use the *blocked_domains* -constructor argument, and :meth:`blocked_domains` and -:meth:`set_blocked_domains` methods (and the corresponding argument and methods -for *allowed_domains*). If you set an allowlist, you can turn it off again by -setting it to :const:`None`. +constructor argument, and :meth:`~DefaultCookiePolicy.blocked_domains` and +:meth:`~DefaultCookiePolicy.set_blocked_domains` methods (and the corresponding +argument and methods for *allowed_domains*). If you set an allowlist, you can +turn it off again by setting it to ``None``. Domains in block or allow lists that do not start with a dot must equal the cookie domain to be matched. For example, ``"example.com"`` matches a blocklist @@ -498,12 +510,12 @@ and ``".168.1.2"``, 192.168.1.2 is blocked, but 193.168.1.2 is not. .. method:: DefaultCookiePolicy.allowed_domains() - Return :const:`None`, or the sequence of allowed domains (as a tuple). + Return ``None``, or the sequence of allowed domains (as a tuple). .. method:: DefaultCookiePolicy.set_allowed_domains(allowed_domains) - Set the sequence of allowed domains, or :const:`None`. + Set the sequence of allowed domains, or ``None``. .. method:: DefaultCookiePolicy.is_not_allowed(domain) @@ -519,9 +531,9 @@ all be assigned to. .. attribute:: DefaultCookiePolicy.rfc2109_as_netscape If true, request that the :class:`CookieJar` instance downgrade :rfc:`2109` cookies - (ie. cookies received in a :mailheader:`Set-Cookie` header with a version + (that is, cookies received in a :mailheader:`Set-Cookie` header with a version cookie-attribute of 1) to Netscape cookies by setting the version attribute of - the :class:`Cookie` instance to 0. The default value is :const:`None`, in which + the :class:`Cookie` instance to 0. The default value is ``None``, in which case RFC 2109 cookies are downgraded if and only if :rfc:`2965` handling is turned off. Therefore, RFC 2109 cookies are downgraded by default. @@ -574,7 +586,7 @@ both flags are set). .. attribute:: DefaultCookiePolicy.DomainStrictNoDots - When setting cookies, the 'host prefix' must not contain a dot (eg. + When setting cookies, the 'host prefix' must not contain a dot (for example, ``www.foo.bar.com`` can't set a cookie for ``.bar.com``, because ``www.foo`` contains a dot). @@ -582,7 +594,7 @@ both flags are set). .. attribute:: DefaultCookiePolicy.DomainStrictNonDomain Cookies that did not explicitly specify a ``domain`` cookie-attribute can only - be returned to a domain equal to the domain that set the cookie (eg. + be returned to a domain equal to the domain that set the cookie (for example, ``spam.example.com`` won't be returned cookies from ``example.com`` that had no ``domain`` cookie-attribute). @@ -597,7 +609,7 @@ combinations of the above flags: .. attribute:: DefaultCookiePolicy.DomainLiberal - Equivalent to 0 (ie. all of the above Netscape domain strictness flags switched + Equivalent to 0 (that is, all of the above Netscape domain strictness flags switched off). @@ -606,7 +618,7 @@ combinations of the above flags: Equivalent to ``DomainStrictNoDots|DomainStrictNonDomain``. -Cookie Objects +Cookie objects -------------- :class:`Cookie` instances have Python attributes roughly corresponding to the @@ -624,7 +636,7 @@ internal consistency, so you should know what you're doing if you do that. .. attribute:: Cookie.version - Integer or :const:`None`. Netscape cookies have :attr:`version` 0. :rfc:`2965` and + Integer or ``None``. Netscape cookies have :attr:`version` 0. :rfc:`2965` and :rfc:`2109` cookies have a ``version`` cookie-attribute of 1. However, note that :mod:`!http.cookiejar` may 'downgrade' RFC 2109 cookies to Netscape cookies, in which case :attr:`version` is 0. @@ -637,13 +649,13 @@ internal consistency, so you should know what you're doing if you do that. .. attribute:: Cookie.value - Cookie value (a string), or :const:`None`. + Cookie value (a string), or ``None``. .. attribute:: Cookie.port - String representing a port or a set of ports (eg. '80', or '80,8080'), or - :const:`None`. + String representing a port or a set of ports (for example, '80', or '80,8080'), or + ``None``. .. attribute:: Cookie.domain @@ -653,7 +665,7 @@ internal consistency, so you should know what you're doing if you do that. .. attribute:: Cookie.path - Cookie path (a string, eg. ``'/acme/rocket_launchers'``). + Cookie path (a string, for example, ``'/acme/rocket_launchers'``). .. attribute:: Cookie.secure @@ -663,7 +675,7 @@ internal consistency, so you should know what you're doing if you do that. .. attribute:: Cookie.expires - Integer expiry date in seconds since epoch, or :const:`None`. See also the + Integer expiry date in seconds since epoch, or ``None``. See also the :meth:`is_expired` method. @@ -675,18 +687,18 @@ internal consistency, so you should know what you're doing if you do that. .. attribute:: Cookie.comment String comment from the server explaining the function of this cookie, or - :const:`None`. + ``None``. .. attribute:: Cookie.comment_url URL linking to a comment from the server explaining the function of this cookie, - or :const:`None`. + or ``None``. .. attribute:: Cookie.rfc2109 - ``True`` if this cookie was received as an :rfc:`2109` cookie (ie. the cookie + ``True`` if this cookie was received as an :rfc:`2109` cookie (that is, the cookie arrived in a :mailheader:`Set-Cookie` header, and the value of the Version cookie-attribute in that header was 1). This attribute is provided because :mod:`!http.cookiejar` may 'downgrade' RFC 2109 cookies to Netscape cookies, in diff --git a/Doc/tools/.nitignore b/Doc/tools/.nitignore index 2255c745c00383..7b956f0ef0eb2c 100644 --- a/Doc/tools/.nitignore +++ b/Doc/tools/.nitignore @@ -9,7 +9,6 @@ Doc/library/ast.rst Doc/library/asyncio-extending.rst Doc/library/email.charset.rst Doc/library/email.parser.rst -Doc/library/http.cookiejar.rst Doc/library/http.server.rst Doc/library/importlib.rst Doc/library/logging.config.rst From 9f82c25eca14fe484fc9a2d8662f47174372d6f7 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 4 Jul 2026 21:34:15 +0200 Subject: [PATCH 569/818] [3.15] gh-151378: Fix unbounded memory growth when recording binary and the thread is sleeping (GH-152089) (#153047) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gh-151378: Fix unbounded memory growth when recording binary and the thread is sleeping (GH-152089) (cherry picked from commit 639a5525fb1b54973dcf55a636efc10be4042239) Co-authored-by: Maurycy Pawłowski-Wieroński <maurycy@maurycy.com> --- .../test_binary_format.py | 23 +++++ ...-06-24-16-40-15.gh-issue-151378.iYWa_6.rst | 3 + Modules/_remote_debugging/binary_io.h | 16 +--- Modules/_remote_debugging/binary_io_writer.c | 93 +++++++------------ Modules/_remote_debugging/module.c | 6 +- 5 files changed, 68 insertions(+), 73 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-06-24-16-40-15.gh-issue-151378.iYWa_6.rst diff --git a/Lib/test/test_profiling/test_sampling_profiler/test_binary_format.py b/Lib/test/test_profiling/test_sampling_profiler/test_binary_format.py index 5efc60a9211175..56dac2cf86a764 100644 --- a/Lib/test/test_profiling/test_sampling_profiler/test_binary_format.py +++ b/Lib/test/test_profiling/test_sampling_profiler/test_binary_format.py @@ -932,6 +932,29 @@ def test_writer_total_samples_after_finalize_matches_reader(self): self.assertEqual(writer_collector.total_samples, len(samples)) self.assertEqual(writer_collector.total_samples, replayed) + def test_rle_buffer_flushes_before_finalize(self): + """RLE buffer flushes before the writer is destroyed during finalize().""" + with tempfile.NamedTemporaryFile(suffix=".bin", delete=False) as f: + filename = f.name + self.temp_files.append(filename) + + frame = make_frame("rle_boundary.py", 1, "hot") + sample = [make_interpreter(0, [make_thread(1, [frame])])] + + writer = _remote_debugging.BinaryWriter(filename, 1000, 0, compression=0) + for i in range(10_000): + writer.write_sample(sample, i * 1000) + self.assertGreater(writer.get_stats()["repeat_records"], 0) + + writer.finalize() + + reader_collector = RawCollector() + with BinaryReader(filename) as reader: + replayed = reader.replay_samples(reader_collector) + + self.assertEqual(replayed, 10_000) + self.assertEqual(writer.total_samples, 10_000) + def test_writer_total_samples_after_context_manager_matches_reader(self): """total_samples after `with BinaryWriter(...)` matches the reader's count. diff --git a/Misc/NEWS.d/next/Library/2026-06-24-16-40-15.gh-issue-151378.iYWa_6.rst b/Misc/NEWS.d/next/Library/2026-06-24-16-40-15.gh-issue-151378.iYWa_6.rst new file mode 100644 index 00000000000000..0b3eb860ba8d32 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-24-16-40-15.gh-issue-151378.iYWa_6.rst @@ -0,0 +1,3 @@ +Fix a bug in the binary collector in Tachyon that caused unbounded memory +growth while profiling a thread that stayed asleep. Patch by Maurycy +Pawłowski-Wieroński. diff --git a/Modules/_remote_debugging/binary_io.h b/Modules/_remote_debugging/binary_io.h index d4188335c0b6d0..b8ea9a0e2cc41c 100644 --- a/Modules/_remote_debugging/binary_io.h +++ b/Modules/_remote_debugging/binary_io.h @@ -109,9 +109,6 @@ static_assert(FILE_FOOTER_SIZE == 32, /* Maximum stack depth we'll buffer for delta encoding */ #define MAX_STACK_DEPTH 256 -/* Initial capacity for RLE pending buffer */ -#define INITIAL_RLE_CAPACITY 64 - /* Initial capacities for dynamic arrays - sized to reduce reallocations */ #define INITIAL_STRING_CAPACITY 4096 #define INITIAL_FRAME_CAPACITY 4096 @@ -226,12 +223,6 @@ typedef struct { uint8_t opcode; } FrameKey; -/* Pending RLE sample - buffered for run-length encoding */ -typedef struct { - uint64_t timestamp_delta; - uint8_t status; -} PendingRLESample; - /* Thread entry - tracks per-thread state for delta encoding */ typedef struct { uint64_t thread_id; @@ -244,10 +235,9 @@ typedef struct { size_t prev_stack_capacity; /* RLE pending buffer - samples waiting to be written as a repeat group */ - PendingRLESample *pending_rle; - size_t pending_rle_count; - size_t pending_rle_capacity; - int has_pending_rle; /* Flag: do we have buffered repeats? */ + uint8_t *pending_rle; + size_t pending_rle_bytes; + size_t pending_rle_samples; } ThreadEntry; /* Main binary writer structure */ diff --git a/Modules/_remote_debugging/binary_io_writer.c b/Modules/_remote_debugging/binary_io_writer.c index 341f9f7dc8ac45..5d300103ff16f8 100644 --- a/Modules/_remote_debugging/binary_io_writer.c +++ b/Modules/_remote_debugging/binary_io_writer.c @@ -29,6 +29,10 @@ /* Frame buffer: depth varint (max 2 bytes for 256) + 256 frames * 5 bytes/varint + margin */ #define MAX_FRAME_BUFFER_SIZE ((MAX_STACK_DEPTH * MAX_VARINT_SIZE_U32) + MAX_VARINT_SIZE_U32 + 16) +/* RLE pending buffer (per thread): one entry is a u64 delta varint + status byte */ +#define MAX_RLE_BUF_SIZE (16 * 1024) +#define MAX_RLE_ENTRY_SIZE (MAX_VARINT_SIZE + sizeof(uint8_t)) + /* Helper macro: convert PyLong to int32, using default_val if conversion fails */ #define PYLONG_TO_INT32_OR_DEFAULT(obj, var, default_val) \ do { \ @@ -134,15 +138,6 @@ writer_write_varint_u32(BinaryWriter *writer, uint32_t value) return writer_write_bytes(writer, buf, len); } -/* Encode and write a varint u64 - returns 0 on success, -1 on error */ -static inline int -writer_write_varint_u64(BinaryWriter *writer, uint64_t value) -{ - uint8_t buf[MAX_VARINT_SIZE]; - size_t len = encode_varint_u64(buf, value); - return writer_write_bytes(writer, buf, len); -} - /* ============================================================================ * UTILITY FUNCTIONS @@ -511,7 +506,6 @@ writer_get_or_create_thread_entry(BinaryWriter *writer, uint64_t thread_id, entry->interpreter_id = interpreter_id; entry->prev_timestamp = writer->start_time_us; entry->prev_stack_capacity = MAX_STACK_DEPTH; - entry->pending_rle_capacity = INITIAL_RLE_CAPACITY; entry->prev_stack = PyMem_Calloc(entry->prev_stack_capacity, sizeof(uint32_t)); if (!entry->prev_stack) { @@ -519,13 +513,6 @@ writer_get_or_create_thread_entry(BinaryWriter *writer, uint64_t thread_id, return NULL; } - entry->pending_rle = PyMem_Malloc(entry->pending_rle_capacity * sizeof(PendingRLESample)); - if (!entry->pending_rle) { - PyMem_Free(entry->prev_stack); - PyErr_NoMemory(); - return NULL; - } - writer->thread_count++; if (is_new) { *is_new = 1; @@ -626,14 +613,9 @@ write_sample_header(BinaryWriter *writer, ThreadEntry *entry, uint8_t encoding) static int flush_pending_rle(BinaryWriter *writer, ThreadEntry *entry) { - if (!entry->has_pending_rle || entry->pending_rle_count == 0) { + if (entry->pending_rle_samples == 0) { return 0; } - if (entry->pending_rle_count > UINT32_MAX - writer->total_samples) { - PyErr_SetString(PyExc_OverflowError, - "too many samples for binary format"); - return -1; - } /* Write RLE record: * [thread_id: 8] [interpreter_id: 4] [STACK_REPEAT: 1] [count: varint] @@ -644,27 +626,21 @@ flush_pending_rle(BinaryWriter *writer, ThreadEntry *entry) return -1; } - if (writer_write_varint_u32(writer, (uint32_t)entry->pending_rle_count) < 0) { + if (writer_write_varint_u32(writer, (uint32_t)entry->pending_rle_samples) < 0) { return -1; } - for (size_t i = 0; i < entry->pending_rle_count; i++) { - if (writer_write_varint_u64(writer, entry->pending_rle[i].timestamp_delta) < 0) { - return -1; - } - if (writer_write_bytes(writer, &entry->pending_rle[i].status, 1) < 0) { - return -1; - } - writer->total_samples++; + if (writer_write_bytes(writer, entry->pending_rle, entry->pending_rle_bytes) < 0) { + return -1; } writer->stats.repeat_records++; - writer->stats.repeat_samples += entry->pending_rle_count; + writer->stats.repeat_samples += entry->pending_rle_samples; /* Each RLE sample saves writing the entire stack */ - writer->stats.frames_saved += entry->pending_rle_count * entry->prev_stack_depth; + writer->stats.frames_saved += entry->pending_rle_samples * entry->prev_stack_depth; - entry->pending_rle_count = 0; - entry->has_pending_rle = 0; + entry->pending_rle_bytes = 0; + entry->pending_rle_samples = 0; return 0; } @@ -678,12 +654,6 @@ write_sample_with_encoding(BinaryWriter *writer, ThreadEntry *entry, const uint32_t *frame_indices, size_t stack_depth, size_t shared_count, size_t pop_count, size_t push_count) { - if (writer->total_samples == UINT32_MAX) { - PyErr_SetString(PyExc_OverflowError, - "too many samples for binary format"); - return -1; - } - /* Header: thread_id(8) + interpreter_id(4) + encoding(1) + delta(varint) + status(1) */ uint8_t header_buf[SAMPLE_HEADER_MAX_SIZE]; memcpy(header_buf + SMP_OFF_THREAD_ID, &entry->thread_id, SMP_SIZE_THREAD_ID); @@ -752,7 +722,6 @@ write_sample_with_encoding(BinaryWriter *writer, ThreadEntry *entry, } writer->stats.total_frames_written += frames_written; - writer->total_samples++; return 0; } @@ -955,6 +924,12 @@ static int process_thread_sample(BinaryWriter *writer, PyObject *thread_info, uint32_t interpreter_id, uint64_t timestamp_us) { + if (writer->total_samples >= UINT32_MAX) { + PyErr_SetString(PyExc_OverflowError, + "too many samples for binary format"); + return -1; + } + PyObject *thread_id_obj = PyStructSequence_GET_ITEM(thread_info, 0); PyObject *status_obj = PyStructSequence_GET_ITEM(thread_info, 1); PyObject *frame_list = PyStructSequence_GET_ITEM(thread_info, 2); @@ -1002,20 +977,25 @@ process_thread_sample(BinaryWriter *writer, PyObject *thread_info, * STACK_REPEAT against an empty curr_stack (depth 0). Buffering * it here is correct; the RLE flush path emits it as a normal * STACK_REPEAT record. */ - if (GROW_ARRAY(entry->pending_rle, entry->pending_rle_count, - entry->pending_rle_capacity, PendingRLESample) < 0) { + if (entry->pending_rle == NULL) { + entry->pending_rle = PyMem_Malloc(MAX_RLE_BUF_SIZE); + if (!entry->pending_rle) { + PyErr_NoMemory(); + return -1; + } + } + if (entry->pending_rle_bytes + MAX_RLE_ENTRY_SIZE > MAX_RLE_BUF_SIZE + && flush_pending_rle(writer, entry) < 0) { return -1; } - entry->pending_rle[entry->pending_rle_count].timestamp_delta = delta; - entry->pending_rle[entry->pending_rle_count].status = status; - entry->pending_rle_count++; - entry->has_pending_rle = 1; + entry->pending_rle_bytes += encode_varint_u64( + entry->pending_rle + entry->pending_rle_bytes, delta); + entry->pending_rle[entry->pending_rle_bytes++] = status; + entry->pending_rle_samples++; } else { /* Stack changed - flush any pending RLE first */ - if (entry->has_pending_rle) { - if (flush_pending_rle(writer, entry) < 0) { - return -1; - } + if (flush_pending_rle(writer, entry) < 0) { + return -1; } if (write_sample_with_encoding(writer, entry, delta, status, encoding, @@ -1028,6 +1008,7 @@ process_thread_sample(BinaryWriter *writer, PyObject *thread_info, entry->prev_stack_depth = curr_depth; } + writer->total_samples++; return 0; } @@ -1075,10 +1056,8 @@ int binary_writer_finalize(BinaryWriter *writer) { for (size_t i = 0; i < writer->thread_count; i++) { - if (writer->thread_entries[i].has_pending_rle) { - if (flush_pending_rle(writer, &writer->thread_entries[i]) < 0) { - return -1; - } + if (flush_pending_rle(writer, &writer->thread_entries[i]) < 0) { + return -1; } } diff --git a/Modules/_remote_debugging/module.c b/Modules/_remote_debugging/module.c index 7979cd43c6a127..62d5315f361fa8 100644 --- a/Modules/_remote_debugging/module.c +++ b/Modules/_remote_debugging/module.c @@ -1784,9 +1784,9 @@ _remote_debugging_BinaryWriter_write_sample_impl(BinaryWriterObject *self, /* Finalize the writer, cache total_samples, and destroy it. * * The cache assignment must happen AFTER binary_writer_finalize(): finalize - * flushes pending RLE samples via flush_pending_rle(), which increments - * writer->total_samples for each one. Caching before finalize would lose - * those trailing samples. */ + * flushes pending RLE records and updates the file header before the writer is + * destroyed. Caching before finalize would preserve a count for a file that + * might still fail to finish. */ static int binary_writer_finalize_and_cache(BinaryWriterObject *self) { From 41a2abe06d6e77c1ecbb7cf455a8cff59988debe Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 5 Jul 2026 01:27:41 +0200 Subject: [PATCH 570/818] [3.15] gh-152718: Reject oversized table counts in the profiling binary reader (GH-152719) (#153050) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gh-152718: Reject oversized table counts in the profiling binary reader (GH-152719) (cherry picked from commit 8e580b068500feec5d6cc5e5a3e6072e8996fb25) Co-authored-by: tonghuaroot (童话) <tonghuaroot@gmail.com> --- .../test_binary_format.py | 85 +++++++++++++++++++ ...-07-01-12-00-00.gh-issue-152718.pr0f1l.rst | 2 + Modules/_remote_debugging/binary_io.h | 4 + Modules/_remote_debugging/binary_io_reader.c | 42 +++++++-- 4 files changed, 124 insertions(+), 9 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-07-01-12-00-00.gh-issue-152718.pr0f1l.rst diff --git a/Lib/test/test_profiling/test_sampling_profiler/test_binary_format.py b/Lib/test/test_profiling/test_sampling_profiler/test_binary_format.py index 56dac2cf86a764..5dff58498a4a15 100644 --- a/Lib/test/test_profiling/test_sampling_profiler/test_binary_format.py +++ b/Lib/test/test_profiling/test_sampling_profiler/test_binary_format.py @@ -1003,6 +1003,9 @@ class TestBinaryFormatValidation(BinaryFormatTestBase): HDR_OFF_STR_TABLE = 36 HDR_OFF_FRAME_TABLE = 44 FILE_HEADER_PLACEHOLDER_SIZE = 64 + FILE_FOOTER_SIZE = 32 + FTR_OFF_STRINGS = 0 + FTR_OFF_FRAMES = 4 def test_replay_rejects_more_threads_than_declared(self): """Replay rejects files with more unique threads than the header declares.""" @@ -1064,6 +1067,88 @@ def test_replay_rejects_trailing_partial_sample_header(self): reader.replay_samples(RawCollector()) self.assertEqual(str(cm.exception), "Truncated sample data: 1 trailing bytes") + # Minimum on-disk size of one table entry (see binary_io.h). + MIN_STRING_ENTRY_SIZE = 1 + MIN_FRAME_ENTRY_SIZE = 7 + + def _read_offset(self, filename, hdr_off): + with open(filename, "rb") as raw: + raw.seek(hdr_off) + return struct.unpack("=Q", raw.read(8))[0] + + def _patch_footer_count(self, filename, ftr_off, value): + size = os.path.getsize(filename) + with open(filename, "r+b") as raw: + raw.seek(size - self.FILE_FOOTER_SIZE + ftr_off) + raw.write(struct.pack("=I", value)) + + def test_open_rejects_string_count_larger_than_file(self): + """Open rejects a footer string count larger than the file.""" + samples = [[make_interpreter(0, [ + make_thread(1, [make_frame("s.py", 10, "s")]) + ])]] + filename = self.create_binary_file(samples, compression="none") + size = os.path.getsize(filename) + str_off = self._read_offset(filename, self.HDR_OFF_STR_TABLE) + max_strings = (size - str_off) // self.MIN_STRING_ENTRY_SIZE + self._patch_footer_count(filename, self.FTR_OFF_STRINGS, 0xFFFFFFFF) + + with self.assertRaises(ValueError) as cm: + with BinaryReader(filename): + pass + self.assertEqual( + str(cm.exception), + f"Invalid string count 4294967295 exceeds maximum " + f"possible {max_strings}", + ) + + def test_open_rejects_frame_count_larger_than_file(self): + """Open rejects a footer frame count larger than the file.""" + samples = [[make_interpreter(0, [ + make_thread(1, [make_frame("f.py", 10, "f")]) + ])]] + filename = self.create_binary_file(samples, compression="none") + size = os.path.getsize(filename) + frame_off = self._read_offset(filename, self.HDR_OFF_FRAME_TABLE) + max_frames = (size - frame_off) // self.MIN_FRAME_ENTRY_SIZE + self._patch_footer_count(filename, self.FTR_OFF_FRAMES, 0xFFFFFFFF) + + # On a 32-bit build this count overflows the allocation size, so the + # size_t overflow guard (OverflowError) fires before the count check. + with self.assertRaises((ValueError, OverflowError)) as cm: + with BinaryReader(filename): + pass + if isinstance(cm.exception, ValueError): + self.assertEqual( + str(cm.exception), + f"Invalid frame count 4294967295 exceeds maximum " + f"possible {max_frames}", + ) + + def test_open_accepts_frame_count_at_capacity_boundary(self): + """A frame count at the file-size cap opens; one more is rejected.""" + samples = [[make_interpreter(0, [ + make_thread(1, [make_frame("f.py", 10, "f")]) + ])]] + filename = self.create_binary_file(samples, compression="none") + size = os.path.getsize(filename) + frame_off = self._read_offset(filename, self.HDR_OFF_FRAME_TABLE) + max_frames = (size - frame_off) // self.MIN_FRAME_ENTRY_SIZE + + self._patch_footer_count(filename, self.FTR_OFF_FRAMES, max_frames) + with BinaryReader(filename): + pass + + self._patch_footer_count(filename, self.FTR_OFF_FRAMES, max_frames + 1) + with self.assertRaises(ValueError) as cm: + with BinaryReader(filename): + pass + self.assertEqual( + str(cm.exception), + f"Invalid frame count {max_frames + 1} exceeds maximum " + f"possible {max_frames}", + ) + class TestBinaryEncodings(BinaryFormatTestBase): """Tests specifically targeting different stack encodings.""" diff --git a/Misc/NEWS.d/next/Library/2026-07-01-12-00-00.gh-issue-152718.pr0f1l.rst b/Misc/NEWS.d/next/Library/2026-07-01-12-00-00.gh-issue-152718.pr0f1l.rst new file mode 100644 index 00000000000000..63d9d7f878cb07 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-01-12-00-00.gh-issue-152718.pr0f1l.rst @@ -0,0 +1,2 @@ +Fix unbounded memory allocation in the :mod:`profiling.sampling` binary profile +reader when a file declares more string or frame entries than it contains. diff --git a/Modules/_remote_debugging/binary_io.h b/Modules/_remote_debugging/binary_io.h index b8ea9a0e2cc41c..9696bea1cabd86 100644 --- a/Modules/_remote_debugging/binary_io.h +++ b/Modules/_remote_debugging/binary_io.h @@ -91,6 +91,10 @@ static_assert(SAMPLE_HEADER_FIXED_SIZE == 13, static_assert(FILE_FOOTER_SIZE == 32, "FILE_FOOTER_SIZE must remain 32"); +/* Minimum on-disk bytes of a string (1) and frame (7) table entry. */ +#define MIN_STRING_ENTRY_SIZE 1 +#define MIN_FRAME_ENTRY_SIZE 7 + /* Buffer sizes: 512KB balances syscall amortization against memory use, * and aligns well with filesystem block sizes and zstd dictionary windows */ #define WRITE_BUFFER_SIZE (512 * 1024) diff --git a/Modules/_remote_debugging/binary_io_reader.c b/Modules/_remote_debugging/binary_io_reader.c index ce1c3d232c94e0..73c4f5b6250d89 100644 --- a/Modules/_remote_debugging/binary_io_reader.c +++ b/Modules/_remote_debugging/binary_io_reader.c @@ -237,9 +237,32 @@ reader_decompress_samples(BinaryReader *reader, const uint8_t *data) } #endif +/* Reject a table/run count whose entries cannot fit in the bytes still + * available; a malicious file could otherwise drive a huge allocation. + * Each entry occupies at least min_entry_size bytes. */ +static int +reader_validate_count(const char *what, uint32_t count, + size_t available_bytes, size_t min_entry_size) +{ + size_t max_possible = available_bytes / min_entry_size; + if (count > max_possible) { + PyErr_Format(PyExc_ValueError, + "Invalid %s count %u exceeds maximum possible %zu", + what, count, max_possible); + return -1; + } + return 0; +} + static inline int reader_parse_string_table(BinaryReader *reader, const uint8_t *data, size_t file_size) { + if (reader_validate_count("string", reader->strings_count, + file_size - reader->string_table_offset, + MIN_STRING_ENTRY_SIZE) < 0) { + return -1; + } + reader->strings = PyMem_Calloc(reader->strings_count, sizeof(PyObject *)); if (!reader->strings && reader->strings_count > 0) { PyErr_NoMemory(); @@ -280,6 +303,12 @@ reader_parse_frame_table(BinaryReader *reader, const uint8_t *data, size_t file_ } #endif + if (reader_validate_count("frame", reader->frames_count, + file_size - reader->frame_table_offset, + MIN_FRAME_ENTRY_SIZE) < 0) { + return -1; + } + size_t alloc_size = (size_t)reader->frames_count * sizeof(FrameEntry); reader->frames = PyMem_Malloc(alloc_size); if (!reader->frames && reader->frames_count > 0) { @@ -1053,15 +1082,10 @@ binary_reader_replay(BinaryReader *reader, PyObject *collector, PyObject *progre return -1; } - /* Validate RLE count to prevent DoS from malicious files. - * Each RLE sample needs at least 2 bytes (1 byte min varint + 1 status byte). - * Also reject absurdly large counts that would exhaust memory. */ - size_t remaining_data = reader->sample_data_size - offset; - size_t max_possible_samples = remaining_data / 2; - if (count > max_possible_samples) { - PyErr_Format(PyExc_ValueError, - "Invalid RLE count %u exceeds maximum possible %zu for remaining data", - count, max_possible_samples); + /* Reject a count larger than the remaining bytes can hold; each + * RLE sample needs at least 2 bytes (1-byte min varint + status). */ + if (reader_validate_count("RLE", count, + reader->sample_data_size - offset, 2) < 0) { return -1; } if ((uint64_t)count > (uint64_t)PY_SSIZE_T_MAX - (uint64_t)replayed) { From 7eb476dfbe8a62b02f976ab3211d86e8729c8f91 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 5 Jul 2026 04:28:53 +0200 Subject: [PATCH 571/818] [3.15] Add "new in 3.15" comments to idlelib (GH-153052) (#153054) Add "new in 3.15" comments to idlelib (GH-153052) Lazy keyword added to colorizer and test in PR-GH-142351. Tested NameError hint expanded in PR-GH-144299. (cherry picked from commit 0621639e8fc0084af15550651198c9e221b6619d) Co-authored-by: Terry Jan Reedy <tjreedy@udel.edu> --- Lib/idlelib/colorizer.py | 2 +- Lib/idlelib/idle_test/test_colorizer.py | 2 +- Lib/idlelib/idle_test/test_run.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Lib/idlelib/colorizer.py b/Lib/idlelib/colorizer.py index 6db38de3aa6cb9..ac12d8ace3575f 100644 --- a/Lib/idlelib/colorizer.py +++ b/Lib/idlelib/colorizer.py @@ -42,7 +42,7 @@ def make_pat(): ]) + r"))" ) - lazy_softkw = ( + lazy_softkw = ( # lazy new in 3.15 (+ 2 lines below). r"^[ \t]*" + # at beginning of line + possible indentation r"(?P<LAZY_SOFTKW>lazy)" + r"(?=[ \t]+(?:import|from)\b)" # followed by 'import' or 'from' diff --git a/Lib/idlelib/idle_test/test_colorizer.py b/Lib/idlelib/idle_test/test_colorizer.py index 4d9e6bd887c5b8..8a6ab527f9387f 100644 --- a/Lib/idlelib/idle_test/test_colorizer.py +++ b/Lib/idlelib/idle_test/test_colorizer.py @@ -542,7 +542,7 @@ def test_case_soft_keyword(self): self._assert_highlighting('case _:', {'KEYWORD': [('1.0', '1.4'), ('1.5', '1.6')]}) - def test_lazy_soft_keyword(self): + def test_lazy_soft_keyword(self): # lazy new in 3.15. # lazy followed by import self._assert_highlighting('lazy import foo', {'KEYWORD': [('1.0', '1.4'), diff --git a/Lib/idlelib/idle_test/test_run.py b/Lib/idlelib/idle_test/test_run.py index 57bf5559c0fa88..f35c3168a446fe 100644 --- a/Lib/idlelib/idle_test/test_run.py +++ b/Lib/idlelib/idle_test/test_run.py @@ -44,7 +44,7 @@ def __eq__(self, other): "Or did you forget to import 'abc'?\n"), ('int.reel', AttributeError, "type object 'int' has no attribute 'reel'. " - "Did you mean '.real' instead of '.reel'?\n"), + "Did you mean '.real' instead of '.reel'?\n"), # More in 3.15. ) @force_not_colorized From 2c99ec4388f6bc4e09eb095b3caf2e1b4466c108 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka <storchaka@gmail.com> Date: Sun, 5 Jul 2026 09:55:59 +0300 Subject: [PATCH 572/818] [3.15] gh-40038: Quote imaplib command arguments when necessary (GH-152703) (GH-153066) Argument quoting was inadvertently disabled when imaplib was ported to Python 3 (bpo-1210 commented out the ``_checkquote()`` call, bpo-9638 then removed it), so since Python 3.0 commands failed for arguments containing protocol-sensitive characters, such as a space in a mailbox name. Quoting is restored and reimplemented per the RFC 3501 grammar, so that arguments that need quoting are escaped and quoted, while flags, sequence sets and list wildcards are left intact. For backward compatibility, an argument already enclosed in double quotes is left unchanged, so code that quotes arguments itself keeps working. (cherry picked from commit 600e86490fddf4732e8b993058ca011cc6387464) Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --- Doc/library/imaplib.rst | 7 +- Lib/imaplib.py | 170 ++++++++--- Lib/test/test_imaplib.py | 273 +++++++++++++++++- ...6-06-30-12-00-00.gh-issue-40038.qK7mGv.rst | 6 + 4 files changed, 404 insertions(+), 52 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-06-30-12-00-00.gh-issue-40038.qK7mGv.rst diff --git a/Doc/library/imaplib.rst b/Doc/library/imaplib.rst index e175dcccaf652e..8732aa15d2f1be 100644 --- a/Doc/library/imaplib.rst +++ b/Doc/library/imaplib.rst @@ -186,6 +186,9 @@ enclosed with either parentheses or double quotes) each string is quoted. However, the *password* argument to the ``LOGIN`` command is always quoted. If you want to avoid having an argument string quoted (eg: the *flags* argument to ``STORE``) then enclose the string in parentheses (eg: ``r'(\Deleted)'``). +In general, pass arguments unquoted and let the module quote them as needed. +An argument that is already enclosed in double quotes is left unchanged, +so that code which quotes arguments itself keeps working. Most commands return a tuple: ``(type, [data, ...])`` where *type* is usually ``'OK'`` or ``'NO'``, and *data* is either the text from the command response, @@ -394,7 +397,7 @@ An :class:`IMAP4` instance has the following methods: .. versionadded:: 3.14 -.. method:: IMAP4.list([directory[, pattern]]) +.. method:: IMAP4.list(directory='', pattern='*') List mailbox names in *directory* matching *pattern*. *directory* defaults to the top-level mail folder, and *pattern* defaults to match anything. Returned @@ -424,7 +427,7 @@ An :class:`IMAP4` instance has the following methods: The method no longer ignores silently arbitrary exceptions. -.. method:: IMAP4.lsub(directory='""', pattern='*') +.. method:: IMAP4.lsub(directory='', pattern='*') List subscribed mailbox names in directory matching pattern. *directory* defaults to the top level directory and *pattern* defaults to match any mailbox. diff --git a/Lib/imaplib.py b/Lib/imaplib.py index eea29d2fef9cc6..a46f3d4c466cb1 100644 --- a/Lib/imaplib.py +++ b/Lib/imaplib.py @@ -130,6 +130,9 @@ _Literal = br'.*{(?P<size>\d+)}$' _Untagged_status = br'\* (?P<data>\d+) (?P<type>[A-Z-]+)( (?P<data2>.*))?' _control_chars = re.compile(b'[\x00-\x1F\x7F]') +_non_astring_char = re.compile(br'[(){ \x00-\x1f\x7f-\xff%*\\"]') +_non_list_char = re.compile(br'[(){ \x00-\x1f\x7f-\xff\\"]') +_quoted = re.compile(br'"(?:[^"\\]|\\.)*+"') class IMAP4: @@ -498,8 +501,7 @@ def append(self, mailbox, flags, date_time, message): if not mailbox: mailbox = 'INBOX' if flags: - if (flags[0],flags[-1]) != ('(',')'): - flags = '(%s)' % flags + flags = self._set_quote(flags) else: flags = None if date_time: @@ -508,7 +510,7 @@ def append(self, mailbox, flags, date_time, message): date_time = None literal = MapCRLF.sub(CRLF, message) self.literal = literal - return self._simple_command(name, mailbox, flags, date_time) + return self._simple_command(name, self._astring(mailbox), flags, date_time) def authenticate(self, mechanism, authobject): @@ -533,7 +535,7 @@ def authenticate(self, mechanism, authobject): #if not cap in self.capabilities: # Let the server decide! # raise self.error("Server doesn't allow %s authentication." % mech) self.literal = _Authenticator(authobject).process - typ, dat = self._simple_command('AUTHENTICATE', mech) + typ, dat = self._simple_command('AUTHENTICATE', self._atom(mech)) if typ != 'OK': raise self.error(dat[-1].decode('utf-8', 'replace')) self.state = 'AUTH' @@ -578,7 +580,8 @@ def copy(self, message_set, new_mailbox): (typ, [data]) = <instance>.copy(message_set, new_mailbox) """ - return self._simple_command('COPY', message_set, new_mailbox) + return self._simple_command('COPY', self._sequence_set(message_set), + self._astring(new_mailbox)) def create(self, mailbox): @@ -586,7 +589,7 @@ def create(self, mailbox): (typ, [data]) = <instance>.create(mailbox) """ - return self._simple_command('CREATE', mailbox) + return self._simple_command('CREATE', self._astring(mailbox)) def delete(self, mailbox): @@ -594,14 +597,15 @@ def delete(self, mailbox): (typ, [data]) = <instance>.delete(mailbox) """ - return self._simple_command('DELETE', mailbox) + return self._simple_command('DELETE', self._astring(mailbox)) def deleteacl(self, mailbox, who): """Delete the ACLs (remove any rights) set for who on mailbox. (typ, [data]) = <instance>.deleteacl(mailbox, who) """ - return self._simple_command('DELETEACL', mailbox, who) + return self._simple_command('DELETEACL', self._astring(mailbox), + self._astring(who)) def enable(self, capability): """Send an RFC5161 enable string to the server. @@ -640,7 +644,8 @@ def fetch(self, message_set, message_parts): 'data' are tuples of message part envelope and data. """ name = 'FETCH' - typ, dat = self._simple_command(name, message_set, message_parts) + typ, dat = self._simple_command(name, self._sequence_set(message_set), + self._fetch_parts(message_parts)) return self._untagged_response(typ, dat, name) @@ -649,7 +654,7 @@ def getacl(self, mailbox): (typ, [data]) = <instance>.getacl(mailbox) """ - typ, dat = self._simple_command('GETACL', mailbox) + typ, dat = self._simple_command('GETACL', self._astring(mailbox)) return self._untagged_response(typ, dat, 'ACL') @@ -657,7 +662,8 @@ def getannotation(self, mailbox, entry, attribute): """(typ, [data]) = <instance>.getannotation(mailbox, entry, attribute) Retrieve ANNOTATIONs.""" - typ, dat = self._simple_command('GETANNOTATION', mailbox, entry, attribute) + typ, dat = self._simple_command('GETANNOTATION', self._astring(mailbox), + entry, attribute) return self._untagged_response(typ, dat, 'ANNOTATION') @@ -668,7 +674,7 @@ def getquota(self, root): (typ, [data]) = <instance>.getquota(root) """ - typ, dat = self._simple_command('GETQUOTA', root) + typ, dat = self._simple_command('GETQUOTA', self._astring(root)) return self._untagged_response(typ, dat, 'QUOTA') @@ -677,7 +683,7 @@ def getquotaroot(self, mailbox): (typ, [[QUOTAROOT responses...], [QUOTA responses]]) = <instance>.getquotaroot(mailbox) """ - typ, dat = self._simple_command('GETQUOTAROOT', mailbox) + typ, dat = self._simple_command('GETQUOTAROOT', self._astring(mailbox)) typ, quota = self._untagged_response(typ, dat, 'QUOTA') typ, quotaroot = self._untagged_response(typ, dat, 'QUOTAROOT') return typ, [quotaroot, quota] @@ -696,15 +702,16 @@ def idle(self, duration=None): return Idler(self, duration) - def list(self, directory='""', pattern='*'): + def list(self, directory='', pattern='*'): """List mailbox names in directory matching pattern. - (typ, [data]) = <instance>.list(directory='""', pattern='*') + (typ, [data]) = <instance>.list(directory='', pattern='*') 'data' is list of LIST responses. """ name = 'LIST' - typ, dat = self._simple_command(name, directory, pattern) + typ, dat = self._simple_command(name, self._astring(directory), + self._list_mailbox(pattern)) return self._untagged_response(typ, dat, name) @@ -715,7 +722,8 @@ def login(self, user, password): NB: 'password' will be quoted. """ - typ, dat = self._simple_command('LOGIN', user, self._quote(password)) + typ, dat = self._simple_command('LOGIN', self._astring(user), + self._quote(password)) if typ != 'OK': raise self.error(dat[-1].decode('UTF-8', 'replace')) self.state = 'AUTH' @@ -761,15 +769,16 @@ def logout(self): return typ, dat - def lsub(self, directory='""', pattern='*'): + def lsub(self, directory='', pattern='*'): """List 'subscribed' mailbox names in directory matching pattern. - (typ, [data, ...]) = <instance>.lsub(directory='""', pattern='*') + (typ, [data, ...]) = <instance>.lsub(directory='', pattern='*') 'data' are tuples of message part envelope and data. """ name = 'LSUB' - typ, dat = self._simple_command(name, directory, pattern) + typ, dat = self._simple_command(name, self._astring(directory), + self._list_mailbox(pattern)) return self._untagged_response(typ, dat, name) def myrights(self, mailbox): @@ -777,7 +786,7 @@ def myrights(self, mailbox): (typ, [data]) = <instance>.myrights(mailbox) """ - typ,dat = self._simple_command('MYRIGHTS', mailbox) + typ,dat = self._simple_command('MYRIGHTS', self._astring(mailbox)) return self._untagged_response(typ, dat, 'MYRIGHTS') def namespace(self): @@ -823,7 +832,7 @@ def proxyauth(self, user): """ name = 'PROXYAUTH' - return self._simple_command(name, user) + return self._simple_command(name, self._astring(user)) def rename(self, oldmailbox, newmailbox): @@ -831,7 +840,8 @@ def rename(self, oldmailbox, newmailbox): (typ, [data]) = <instance>.rename(oldmailbox, newmailbox) """ - return self._simple_command('RENAME', oldmailbox, newmailbox) + return self._simple_command('RENAME', self._astring(oldmailbox), + self._astring(newmailbox)) def search(self, charset, *criteria): @@ -843,10 +853,11 @@ def search(self, charset, *criteria): If UTF8 is enabled, charset MUST be None. """ name = 'SEARCH' - if charset: + if charset is not None: if self.utf8_enabled: raise IMAP4.error("Non-None charset not valid in UTF8 mode") - typ, dat = self._simple_command(name, 'CHARSET', charset, *criteria) + typ, dat = self._simple_command(name, + 'CHARSET', self._astring(charset), *criteria) else: typ, dat = self._simple_command(name, *criteria) return self._untagged_response(typ, dat, name) @@ -870,7 +881,7 @@ def select(self, mailbox='INBOX', readonly=False): name = 'EXAMINE' else: name = 'SELECT' - typ, dat = self._simple_command(name, mailbox) + typ, dat = self._simple_command(name, self._astring(mailbox)) if typ != 'OK': self.state = 'AUTH' # Might have been 'SELECTED' return typ, dat @@ -889,14 +900,15 @@ def setacl(self, mailbox, who, what): (typ, [data]) = <instance>.setacl(mailbox, who, what) """ - return self._simple_command('SETACL', mailbox, who, what) + return self._simple_command('SETACL', self._astring(mailbox), + self._astring(who), self._astring(what)) - def setannotation(self, *args): + def setannotation(self, mailbox, *args): """(typ, [data]) = <instance>.setannotation(mailbox[, entry, attribute]+) Set ANNOTATIONs.""" - typ, dat = self._simple_command('SETANNOTATION', *args) + typ, dat = self._simple_command('SETANNOTATION', self._astring(mailbox), *args) return self._untagged_response(typ, dat, 'ANNOTATION') @@ -905,7 +917,8 @@ def setquota(self, root, limits): (typ, [data]) = <instance>.setquota(root, limits) """ - typ, dat = self._simple_command('SETQUOTA', root, limits) + typ, dat = self._simple_command('SETQUOTA', self._astring(root), + self._set_quote(limits)) return self._untagged_response(typ, dat, 'QUOTA') @@ -917,8 +930,9 @@ def sort(self, sort_criteria, charset, *search_criteria): name = 'SORT' #if not name in self.capabilities: # Let the server decide! # raise self.error('unimplemented extension command: %s' % name) - if (sort_criteria[0],sort_criteria[-1]) != ('(',')'): - sort_criteria = '(%s)' % sort_criteria + sort_criteria = self._set_quote(sort_criteria) + if charset is not None: + charset = self._astring(charset) typ, dat = self._simple_command(name, sort_criteria, charset, *search_criteria) return self._untagged_response(typ, dat, name) @@ -955,7 +969,8 @@ def status(self, mailbox, names): name = 'STATUS' #if self.PROTOCOL_VERSION == 'IMAP4': # Let the server decide! # raise self.error('%s unimplemented in IMAP4 (obtain IMAP4rev1 server, or re-code)' % name) - typ, dat = self._simple_command(name, mailbox, names) + typ, dat = self._simple_command(name, self._astring(mailbox), + self._set_quote(names)) return self._untagged_response(typ, dat, name) @@ -964,9 +979,9 @@ def store(self, message_set, command, flags): (typ, [data]) = <instance>.store(message_set, command, flags) """ - if (flags[0],flags[-1]) != ('(',')'): - flags = '(%s)' % flags # Avoid quoting the flags - typ, dat = self._simple_command('STORE', message_set, command, flags) + flags = self._set_quote(flags) + typ, dat = self._simple_command('STORE', self._sequence_set(message_set), + command, flags) return self._untagged_response(typ, dat, 'FETCH') @@ -975,7 +990,7 @@ def subscribe(self, mailbox): (typ, [data]) = <instance>.subscribe(mailbox) """ - return self._simple_command('SUBSCRIBE', mailbox) + return self._simple_command('SUBSCRIBE', self._astring(mailbox)) def thread(self, threading_algorithm, charset, *search_criteria): @@ -984,7 +999,10 @@ def thread(self, threading_algorithm, charset, *search_criteria): (type, [data]) = <instance>.thread(threading_algorithm, charset, search_criteria, ...) """ name = 'THREAD' - typ, dat = self._simple_command(name, threading_algorithm, charset, *search_criteria) + if charset is not None: + charset = self._astring(charset) + typ, dat = self._simple_command(name, self._atom(threading_algorithm), + charset, *search_criteria) return self._untagged_response(typ, dat, name) @@ -1005,7 +1023,31 @@ def uid(self, command, *args): (command, self.state, ', '.join(Commands[command]))) name = 'UID' - typ, dat = self._simple_command(name, command, *args) + if command == 'COPY': + message_set, new_mailbox = args + args = (self._sequence_set(message_set), + self._astring(new_mailbox)) + elif command == 'FETCH': + message_set, message_parts = args + args = (self._sequence_set(message_set), + self._fetch_parts(message_parts)) + elif command == 'STORE': + message_set, op, flags = args + args = (self._sequence_set(message_set), op, + self._set_quote(flags)) + elif command == 'SORT': + sort_criteria, charset, *search_criteria = args + if charset is not None: + charset = self._astring(charset) + args = (self._set_quote(sort_criteria), charset, + *search_criteria) + elif command == 'THREAD': + threading_algorithm, charset, *search_criteria = args + if charset is not None: + charset = self._astring(charset) + args = (self._atom(threading_algorithm), charset, + *search_criteria) + typ, dat = self._simple_command(name, self._atom(command), *args) if command in ('SEARCH', 'SORT', 'THREAD'): name = command else: @@ -1018,7 +1060,7 @@ def unsubscribe(self, mailbox): (typ, [data]) = <instance>.unsubscribe(mailbox) """ - return self._simple_command('UNSUBSCRIBE', mailbox) + return self._simple_command('UNSUBSCRIBE', self._astring(mailbox)) def unselect(self): @@ -1387,13 +1429,53 @@ def _new_tag(self): return tag - def _quote(self, arg): + def _atom(self, arg): + return arg + + def _sequence_set(self, arg): + return arg - arg = arg.replace('\\', '\\\\') - arg = arg.replace('"', '\\"') + def _set_quote(self, arg): + if arg and arg[0] == '(' and arg[-1] == ')': + return arg + return '(' + arg + ')' - return '"' + arg + '"' + def _fetch_parts(self, arg): + # "ALL", "FULL" and "FAST" are macros, not data item names; + # they cannot be enclosed in parentheses. + if arg.upper() in ('ALL', 'FULL', 'FAST'): + return arg + return self._set_quote(arg) + def _quote(self, arg): + if isinstance(arg, str): + arg = bytes(arg, self._encoding) + arg = arg.replace(b'\\', br'\\') + arg = arg.replace(b'"', br'\"') + return b'"' + arg + b'"' + + # For backward compatibility, an argument already enclosed in double + # quotes is left unquoted, so that code which quotes arguments itself + # keeps working. New code should pass arguments unquoted and let the + # module quote them as needed. + + def _astring(self, arg): + if isinstance(arg, str): + arg = bytes(arg, self._encoding) + if _quoted.fullmatch(arg): + return arg + if arg and _non_astring_char.search(arg) is None: + return arg + return self._quote(arg) + + def _list_mailbox(self, arg): + if isinstance(arg, str): + arg = bytes(arg, self._encoding) + if _quoted.fullmatch(arg): + return arg + if arg and _non_list_char.search(arg) is None: + return arg + return self._quote(arg) def _simple_command(self, name, *args): diff --git a/Lib/test/test_imaplib.py b/Lib/test/test_imaplib.py index d02c0498dabd37..091769e98ef523 100644 --- a/Lib/test/test_imaplib.py +++ b/Lib/test/test_imaplib.py @@ -175,6 +175,65 @@ def test_imap4_host_default_value(self): imaplib.IMAP4() self.assertIn(cm.exception.errno, expected_errnos) + def test_astring(self): + m = imaplib.IMAP4.__new__(imaplib.IMAP4) + m._encoding = 'ascii' + # Plain atoms are left unquoted. + self.assertEqual(m._astring('INBOX'), b'INBOX') + self.assertEqual(m._astring(b'INBOX'), b'INBOX') + # Names with protocol-sensitive characters are quoted. + self.assertEqual(m._astring('New folder'), b'"New folder"') + self.assertEqual(m._astring('a"b'), b'"a\\"b"') + self.assertEqual(m._astring('a\\b'), b'"a\\\\b"') + self.assertEqual(m._astring(''), b'""') + self.assertEqual(m._astring('*'), b'"*"') + # A well-formed quoted string is passed through unchanged. + self.assertEqual(m._astring('"New folder"'), b'"New folder"') + self.assertEqual(m._astring('""'), b'""') + # Including a lenient (non-RFC) backslash escape, which the server + # may accept. + self.assertEqual(m._astring('"a\\b"'), b'"a\\b"') + # A string that only looks quoted but is not a single token is + # quoted as data, closing the argument injection vector. + self.assertEqual(m._astring('"a" SELECT evil "'), + b'"\\"a\\" SELECT evil \\""') + self.assertEqual(m._astring('"'), b'"\\""') + # Non-ASCII names are only allowed in a quoted string or a + # literal, never in an atom (RFC 6855). + m._encoding = 'utf-8' + self.assertEqual(m._astring('Entwürfe'), '"Entwürfe"'.encode()) + self.assertEqual(m._astring(b'Entw\xc3\xbcrfe'), b'"Entw\xc3\xbcrfe"') + + def test_astring_idempotent(self): + # Quoting an already quoted argument should not change it, so that + # quoting twice gives the same result as quoting once. + m = imaplib.IMAP4.__new__(imaplib.IMAP4) + m._encoding = 'ascii' + for arg in ['INBOX', 'New folder', 'a"b', 'a\\b', '', '*', '%', + '"New folder"', '""', '"a\\b"', '"a" SELECT evil "', + '"', 'a\tb', 'a\rb', '\x7f', '(a)', b'Entw\xc3\xbcrfe']: + with self.subTest(arg=arg): + once = m._astring(arg) + self.assertEqual(m._astring(once), once) + twice = m._list_mailbox(arg) + self.assertEqual(m._list_mailbox(twice), twice) + + def test_list_mailbox(self): + m = imaplib.IMAP4.__new__(imaplib.IMAP4) + m._encoding = 'ascii' + # Wildcards are not quoted in a list pattern. + self.assertEqual(m._list_mailbox('*'), b'*') + self.assertEqual(m._list_mailbox('%'), b'%') + self.assertEqual(m._list_mailbox('foo/%'), b'foo/%') + # But spaces still require quoting. + self.assertEqual(m._list_mailbox('New folder'), b'"New folder"') + self.assertEqual(m._list_mailbox('"New folder"'), b'"New folder"') + # As do non-ASCII names; wildcards keep their meaning inside a + # quoted string. + m._encoding = 'utf-8' + self.assertEqual(m._list_mailbox('Entwürfe/%'), + '"Entwürfe/%"'.encode()) + if ssl: class SecureTCPServer(socketserver.TCPServer): @@ -278,7 +337,7 @@ def cmd_LOGOUT(self, tag, args): self._send_tagged(tag, 'OK', 'LOGOUT completed') def cmd_LOGIN(self, tag, args): - self.server.logged = args[0] + self.server.logged = args self._send_tagged(tag, 'OK', 'LOGIN completed') def cmd_SELECT(self, tag, args): @@ -509,6 +568,7 @@ def cmd_APPEND(self, tag, args): code, _ = client.enable('UTF8=ACCEPT') self.assertEqual(code, 'OK') self.assertEqual(client._encoding, 'utf-8') + self.assertEqual(server.args, ['UTF8=ACCEPT']) msg_string = 'Subject: üñí©öðé' typ, data = client.append( None, None, None, (msg_string + '\n').encode('utf-8')) @@ -536,6 +596,26 @@ def cmd_AUTHENTICATE(self, tag, args): with self.assertRaisesRegex(imaplib.IMAP4.error, 'charset.*UTF8'): client.search('foo', 'bar') + def test_utf8_mailbox_name(self): + class UTF8Server(SimpleIMAPHandler): + capabilities = 'AUTH ENABLE UTF8=ACCEPT' + def cmd_ENABLE(self, tag, args): + self._send_tagged(tag, 'OK', 'ENABLE successful') + def cmd_AUTHENTICATE(self, tag, args): + self._send_textline('+') + self.server.response = yield + self._send_tagged(tag, 'OK', 'FAKEAUTH successful') + client, server = self._setup(UTF8Server) + typ, _ = client.authenticate('MYAUTH', lambda x: b'fake') + self.assertEqual(typ, 'OK') + typ, _ = client.enable('UTF8=ACCEPT') + self.assertEqual(typ, 'OK') + # A non-ASCII mailbox name is only allowed in a quoted string + # or a literal, never in an atom (RFC 6855). + typ, _ = client.select('Entwürfe') + self.assertEqual(typ, 'OK') + self.assertEqual(server.is_selected, ['"Entwürfe"']) + def test_bad_auth_name(self): class MyServer(SimpleIMAPHandler): def cmd_AUTHENTICATE(self, tag, args): @@ -668,7 +748,7 @@ def test_with_statement(self): _, server = self._setup(SimpleIMAPHandler, connect=False) with self.imap_class(*server.server_address) as imap: imap.login('user', 'pass') - self.assertEqual(server.logged, 'user') + self.assertEqual(server.logged, ['user', '"pass"']) self.assertIsNone(server.logged) def test_with_statement_logout(self): @@ -676,7 +756,7 @@ def test_with_statement_logout(self): _, server = self._setup(SimpleIMAPHandler, connect=False) with self.imap_class(*server.server_address) as imap: imap.login('user', 'pass') - self.assertEqual(server.logged, 'user') + self.assertEqual(server.logged, ['user', '"pass"']) imap.logout() self.assertIsNone(server.logged) self.assertIsNone(server.logged) @@ -751,11 +831,33 @@ def test_idle_delayed_packet(self): self.fail('multi-packet response was corrupted by idle timeout') def test_login(self): - client, _ = self._setup(SimpleIMAPHandler) + client, server = self._setup(SimpleIMAPHandler) typ, data = client.login('user', 'pass') self.assertEqual(typ, 'OK') self.assertEqual(data[0], b'LOGIN completed') self.assertEqual(client.state, 'AUTH') + # The user name is quoted only when necessary, but the password + # is always quoted. + self.assertEqual(server.logged, ['user', '"pass"']) + self.assertRaises(imaplib.IMAP4.error, client.login, 'user', 'pass') + + def test_login_quoted(self): + client, server = self._setup(SimpleIMAPHandler) + typ, data = client.login('us*r', 'p%ss') + self.assertEqual(typ, 'OK') + self.assertEqual(data[0], b'LOGIN completed') + self.assertEqual(client.state, 'AUTH') + self.assertEqual(server.logged, ['"us*r"', '"p%ss"']) + + def test_login_quoted2(self): + # An already quoted user name is passed through unchanged, rather + # than being quoted a second time; the password is always quoted. + client, server = self._setup(SimpleIMAPHandler) + typ, data = client.login('"user"', '"pass"') + self.assertEqual(typ, 'OK') + self.assertEqual(data[0], b'LOGIN completed') + self.assertEqual(client.state, 'AUTH') + self.assertEqual(server.logged, ['"user"', r'"\"pass\""']) def test_append_line_endings(self): # append() normalizes bare CR and LF in the message to CRLF. @@ -770,6 +872,11 @@ def cmd_APPEND(self, tag, args): client.append('INBOX', None, None, message) self.assertEqual(server.response, b'a\r\nb\r\nc\r\nd') + # The mailbox is quoted and the flags are wrapped in parentheses + # when necessary. + client.append('New folder', r'\Seen', None, b'data') + self.assertEqual(server.args, ['"New folder"', r'(\Seen)', '{4}']) + def test_login_capabilities(self): # A server may advertise new capabilities after login (as an # untagged CAPABILITY response); imaplib must refresh its cached @@ -858,6 +965,12 @@ def test_lsub(self): self.assertEqual(typ, 'OK') self.assertEqual(server.args, ['~/Mail/', '%']) + # The directory is quoted when necessary; wildcards in the pattern + # are preserved. + typ, data = client.lsub('New folder', '%') + self.assertEqual(typ, 'OK') + self.assertEqual(server.args, ['"New folder"', '%']) + def test_extra_blank_line_after_literal(self): # Some buggy servers send an extra blank line after the counted # literal data. imaplib should skip it instead of failing. @@ -925,6 +1038,10 @@ def test_select(self): self.assertEqual(server.is_selected, ['INBOX']) self.assertTrue(client.is_readonly) + typ, data = client.select('New folder') + self.assertEqual(typ, 'OK') + self.assertEqual(server.is_selected, ['"New folder"']) + def test_expunge(self): client, server = self._setup(make_simple_handler('EXPUNGE', ['* 3 EXPUNGE', '* 3 EXPUNGE', '* 5 EXPUNGE', '* 8 EXPUNGE'])) @@ -1007,6 +1124,11 @@ def test_create(self): self.assertEqual(data, [b'CREATE completed']) self.assertEqual(server.args, ['owatagusiam/blurdybloop']) + typ, data = client.create('New folder') + self.assertEqual(typ, 'OK') + self.assertEqual(data, [b'CREATE completed']) + self.assertEqual(server.args, ['"New folder"']) + def test_copy(self): client, server = self._setup(make_simple_handler('COPY')) client.login('user', 'pass') @@ -1016,6 +1138,11 @@ def test_copy(self): self.assertEqual(data, [b'COPY completed']) self.assertEqual(server.args, ['2:4', 'MEETING']) + typ, data = client.copy('2:4', 'New folder') + self.assertEqual(typ, 'OK') + self.assertEqual(data, [b'COPY completed']) + self.assertEqual(server.args, ['2:4', '"New folder"']) + def test_uid_copy(self): client, server = self._setup(make_simple_handler('UID', completed='UID COPY completed')) @@ -1026,6 +1153,11 @@ def test_uid_copy(self): self.assertEqual(data, [None]) self.assertEqual(server.args, ['COPY', '4827313:4828442', 'MEETING']) + typ, data = client.uid('copy', '4827313:4828442', 'New folder') + self.assertEqual(typ, 'OK') + self.assertEqual(data, [None]) + self.assertEqual(server.args, ['COPY', '4827313:4828442', '"New folder"']) + def test_store(self): client, server = self._setup(make_simple_handler('STORE', [ r'* 2 FETCH (FLAGS (\Deleted \Seen))', @@ -1064,6 +1196,10 @@ def test_uid_store(self): ]) self.assertEqual(server.args, ['STORE', '4827313:4828442', '+FLAGS', r'(\Deleted)']) + typ, data = client.uid('store', '4827313:4828442', '+FLAGS', r'\Deleted') + self.assertEqual(typ, 'OK') + self.assertEqual(server.args, ['STORE', '4827313:4828442', '+FLAGS', r'(\Deleted)']) + def test_fetch(self): # The handler expands the requested sequence set and answers for # exactly those messages, so the test exercises the round trip of @@ -1108,6 +1244,19 @@ def cmd_FETCH(self, tag, args): self.assertEqual(data, [br'1 (FLAGS (\Seen))']) self.assertEqual(server.args, ['1', '(BODY[HEADER.FIELDS (DATE FROM)])']) + # message_parts is wrapped in parentheses if it is not already. + typ, data = client.fetch('2:4', 'FLAGS') + self.assertEqual(typ, 'OK') + self.assertEqual(server.args, ['2:4', '(FLAGS)']) + + # But the macros are not, as they are not data item names. + typ, data = client.fetch('2:4', 'ALL') + self.assertEqual(typ, 'OK') + self.assertEqual(server.args, ['2:4', 'ALL']) + typ, data = client.fetch('2:4', 'fast') + self.assertEqual(typ, 'OK') + self.assertEqual(server.args, ['2:4', 'fast']) + def test_uid_fetch(self): client, server = self._setup(make_simple_handler('UID', [ r'* 23 FETCH (FLAGS (\Seen) UID 4827313)', @@ -1125,6 +1274,14 @@ def test_uid_fetch(self): ]) self.assertEqual(server.args, ['FETCH', '4827313:4828442', '(FLAGS)']) + typ, data = client.uid('fetch', '4827313:4828442', 'FLAGS') + self.assertEqual(typ, 'OK') + self.assertEqual(server.args, ['FETCH', '4827313:4828442', '(FLAGS)']) + + typ, data = client.uid('fetch', '4827313:4828442', 'ALL') + self.assertEqual(typ, 'OK') + self.assertEqual(server.args, ['FETCH', '4827313:4828442', 'ALL']) + def test_partial(self): client, server = self._setup(make_simple_handler('PARTIAL', ['* 1 FETCH (RFC822.TEXT<0.10> "0123456789")'])) @@ -1158,6 +1315,10 @@ def test_search(self): self.assertEqual(data, [b'43']) self.assertEqual(server.args, ['CHARSET', 'UTF-8', 'TEXT', 'XXXXXX']) + typ, data = client.search('NF_Z_62-010_(1973)', 'TEXT', 'XXXXXX') + self.assertEqual(typ, 'OK') + self.assertEqual(server.args, ['CHARSET', '"NF_Z_62-010_(1973)"', 'TEXT', 'XXXXXX']) + def test_uid_search(self): response = [] client, server = self._setup(make_simple_handler('UID', response, @@ -1209,6 +1370,10 @@ def test_sort(self): self.assertEqual(data, [br'']) self.assertEqual(server.args, ['(SUBJECT)', 'US-ASCII', 'TEXT', '"not in mailbox"']) + typ, data = client.sort('SUBJECT', 'NF_Z_62-010_(1973)', 'TEXT', '"not in mailbox"') + self.assertEqual(typ, 'OK') + self.assertEqual(server.args, ['(SUBJECT)', '"NF_Z_62-010_(1973)"', 'TEXT', '"not in mailbox"']) + def test_uid_sort(self): response = [] client, server = self._setup(make_simple_handler('UID', response, @@ -1233,6 +1398,10 @@ def test_uid_sort(self): self.assertEqual(data, [br'']) self.assertEqual(server.args, ['SORT', '(SUBJECT)', 'US-ASCII', 'TEXT', '"not in mailbox"']) + typ, data = client.uid('sort', 'SUBJECT', 'NF_Z_62-010_(1973)', 'TEXT', '"not in mailbox"') + self.assertEqual(typ, 'OK') + self.assertEqual(server.args, ['SORT', '(SUBJECT)', '"NF_Z_62-010_(1973)"', 'TEXT', '"not in mailbox"']) + def test_thread(self): response = [] client, server = self._setup(make_simple_handler('THREAD', response)) @@ -1270,6 +1439,10 @@ def test_thread(self): b'(199)(200 202)(201)(203)(204)(205 206 207)(208)']) self.assertEqual(server.args, ['ORDEREDSUBJECT', 'US-ASCII', 'TEXT', '"gewp"']) + typ, data = client.thread('ORDEREDSUBJECT', 'NF_Z_62-010_(1973)', 'TEXT', '"gewp"') + self.assertEqual(typ, 'OK') + self.assertEqual(server.args, ['ORDEREDSUBJECT', '"NF_Z_62-010_(1973)"', 'TEXT', '"gewp"']) + def test_uid_thread(self): response = [] client, server = self._setup(make_simple_handler('UID', response, @@ -1308,6 +1481,10 @@ def test_uid_thread(self): b'(199)(200 202)(201)(203)(204)(205 206 207)(208)']) self.assertEqual(server.args, ['THREAD', 'ORDEREDSUBJECT', 'US-ASCII', 'TEXT', '"gewp"']) + typ, data = client.uid('THREAD', 'ORDEREDSUBJECT', 'NF_Z_62-010_(1973)', 'TEXT', '"gewp"') + self.assertEqual(typ, 'OK') + self.assertEqual(server.args, ['THREAD', 'ORDEREDSUBJECT', '"NF_Z_62-010_(1973)"', 'TEXT', '"gewp"']) + def test_delete(self): client, server = self._setup(make_simple_handler('DELETE')) client.login('user', 'pass') @@ -1320,6 +1497,10 @@ def test_delete(self): self.assertEqual(typ, 'OK') self.assertEqual(server.args, ['foo/bar']) + typ, data = client.delete('New folder') + self.assertEqual(typ, 'OK') + self.assertEqual(server.args, ['"New folder"']) + def test_rename(self): client, server = self._setup(make_simple_handler('RENAME')) client.login('user', 'pass') @@ -1328,6 +1509,10 @@ def test_rename(self): self.assertEqual(data, [b'RENAME completed']) self.assertEqual(server.args, ['blurdybloop', 'sarasoop']) + typ, data = client.rename('Old folder', 'New folder') + self.assertEqual(typ, 'OK') + self.assertEqual(server.args, ['"Old folder"', '"New folder"']) + def test_subscribe(self): client, server = self._setup(make_simple_handler('SUBSCRIBE')) client.login('user', 'pass') @@ -1336,6 +1521,10 @@ def test_subscribe(self): self.assertEqual(data, [b'SUBSCRIBE completed']) self.assertEqual(server.args, ['#news.comp.mail.mime']) + typ, data = client.subscribe('New folder') + self.assertEqual(typ, 'OK') + self.assertEqual(server.args, ['"New folder"']) + def test_unsubscribe(self): client, server = self._setup(make_simple_handler('UNSUBSCRIBE')) client.login('user', 'pass') @@ -1344,6 +1533,10 @@ def test_unsubscribe(self): self.assertEqual(data, [b'UNSUBSCRIBE completed']) self.assertEqual(server.args, ['#news.comp.mail.mime']) + typ, data = client.unsubscribe('New folder') + self.assertEqual(typ, 'OK') + self.assertEqual(server.args, ['"New folder"']) + def test_list(self): client, server = self._setup(make_simple_handler('LIST', [r'* LIST (\Noselect) "/" ""', @@ -1359,6 +1552,15 @@ def test_list(self): self.assertEqual(typ, 'OK') self.assertEqual(server.args, ['~/Mail/', '%']) + typ, data = client.list('New folder', '*') + self.assertEqual(typ, 'OK') + self.assertEqual(server.args, ['"New folder"', '*']) + + # A pattern without wildcards is quoted when necessary. + typ, data = client.list('~/Mail/', 'My Folder') + self.assertEqual(typ, 'OK') + self.assertEqual(server.args, ['~/Mail/', '"My Folder"']) + def test_status(self): client, server = self._setup(make_simple_handler('STATUS', ['* STATUS blurdybloop (MESSAGES 231 UIDNEXT 44292)'])) @@ -1368,6 +1570,11 @@ def test_status(self): self.assertEqual(data, [b'blurdybloop (MESSAGES 231 UIDNEXT 44292)']) self.assertEqual(server.args, ['blurdybloop', '(UIDNEXT MESSAGES)']) + # The names argument is wrapped in parentheses if it is not already. + typ, data = client.status('New folder', 'UIDNEXT MESSAGES') + self.assertEqual(typ, 'OK') + self.assertEqual(server.args, ['"New folder"', '(UIDNEXT MESSAGES)']) + def test_getacl(self): client, server = self._setup(make_simple_handler('GETACL', ['* ACL INBOX Fred rwipslxetad'])) @@ -1377,6 +1584,10 @@ def test_getacl(self): self.assertEqual(data, [b'INBOX Fred rwipslxetad']) self.assertEqual(server.args, ['INBOX']) + typ, data = client.getacl('New folder') + self.assertEqual(typ, 'OK') + self.assertEqual(server.args, ['"New folder"']) + def test_setacl(self): client, server = self._setup(make_simple_handler('SETACL')) client.login('user', 'pass') @@ -1385,6 +1596,15 @@ def test_setacl(self): self.assertEqual(data, [b'SETACL completed']) self.assertEqual(server.args, ['INBOX', 'Fred', 'rwipslxetad']) + typ, data = client.setacl('New folder', 'Fred', '+lr') + self.assertEqual(typ, 'OK') + self.assertEqual(server.args, ['"New folder"', 'Fred', '+lr']) + + # The identifier and the rights are quoted when necessary too. + typ, data = client.setacl('INBOX', 'John Doe', 'a b') + self.assertEqual(typ, 'OK') + self.assertEqual(server.args, ['INBOX', '"John Doe"', '"a b"']) + def test_deleteacl(self): client, server = self._setup(make_simple_handler('DELETEACL')) client.login('user', 'pass') @@ -1393,6 +1613,11 @@ def test_deleteacl(self): self.assertEqual(data, [b'DELETEACL completed']) self.assertEqual(server.args, ['INBOX', 'Fred']) + # The identifier is quoted when necessary too. + typ, data = client.deleteacl('New folder', 'John Doe') + self.assertEqual(typ, 'OK') + self.assertEqual(server.args, ['"New folder"', '"John Doe"']) + def test_myrights(self): client, server = self._setup(make_simple_handler('MYRIGHTS', ['* MYRIGHTS INBOX rwiptsldaex'])) @@ -1402,6 +1627,10 @@ def test_myrights(self): self.assertEqual(data, [b'INBOX rwiptsldaex']) self.assertEqual(server.args, ['INBOX']) + typ, data = client.myrights('New folder') + self.assertEqual(typ, 'OK') + self.assertEqual(server.args, ['"New folder"']) + def test_getquota(self): client, server = self._setup(make_simple_handler('GETQUOTA', ['* QUOTA "" (STORAGE 10 512)'])) @@ -1411,6 +1640,10 @@ def test_getquota(self): self.assertEqual(data, [b'"" (STORAGE 10 512)']) self.assertEqual(server.args, ['#news']) + typ, data = client.getquota('') + self.assertEqual(typ, 'OK') + self.assertEqual(server.args, ['""']) + def test_getquotaroot(self): client, server = self._setup(make_simple_handler('GETQUOTAROOT', ['* QUOTAROOT INBOX ""', '* QUOTA "" (STORAGE 10 512)'])) @@ -1420,6 +1653,10 @@ def test_getquotaroot(self): self.assertEqual(data, [[b'INBOX ""'], [b'"" (STORAGE 10 512)']]) self.assertEqual(server.args, ['INBOX']) + typ, data = client.getquotaroot('New folder') + self.assertEqual(typ, 'OK') + self.assertEqual(server.args, ['"New folder"']) + def test_setquota(self): client, server = self._setup(make_simple_handler('SETQUOTA', ['* QUOTA "" (STORAGE 512)'])) @@ -1429,6 +1666,15 @@ def test_setquota(self): self.assertEqual(data, [b'"" (STORAGE 512)']) self.assertEqual(server.args, ['#news', '(STORAGE 512)']) + typ, data = client.setquota('', '(STORAGE 512)') + self.assertEqual(typ, 'OK') + self.assertEqual(server.args, ['""', '(STORAGE 512)']) + + # The limits argument is wrapped in parentheses if it is not already. + typ, data = client.setquota('', 'STORAGE 512') + self.assertEqual(typ, 'OK') + self.assertEqual(server.args, ['""', '(STORAGE 512)']) + def test_getannotation(self): client, server = self._setup(make_simple_handler('GETANNOTATION', ['* ANNOTATION INBOX "/comment" ("value.shared" "Hello")'])) @@ -1438,6 +1684,10 @@ def test_getannotation(self): self.assertEqual(data, [b'INBOX "/comment" ("value.shared" "Hello")']) self.assertEqual(server.args, ['INBOX', '/comment', 'value.shared']) + typ, data = client.getannotation('New folder', '/comment', 'value.shared') + self.assertEqual(typ, 'OK') + self.assertEqual(server.args, ['"New folder"', '/comment', 'value.shared']) + def test_setannotation(self): client, server = self._setup(make_simple_handler('SETANNOTATION')) client.login('user', 'pass') @@ -1447,6 +1697,12 @@ def test_setannotation(self): self.assertEqual(server.args, ['INBOX', '/comment', '("value.shared" "My comment")']) + typ, data = client.setannotation('New folder', '/comment', + '("value.shared" "My comment")') + self.assertEqual(typ, 'OK') + self.assertEqual(server.args, + ['"New folder"', '/comment', '("value.shared" "My comment")']) + def test_proxyauth(self): client, server = self._setup(make_simple_handler('PROXYAUTH')) client.login('user', 'pass') @@ -1455,6 +1711,10 @@ def test_proxyauth(self): self.assertEqual(data, [b'PROXYAUTH completed']) self.assertEqual(server.args, ['user']) + typ, data = client.proxyauth('us er') + self.assertEqual(typ, 'OK') + self.assertEqual(server.args, ['"us er"']) + def test_xatom(self): client, server = self._setup(make_simple_handler('MYCOMMAND', completed='MYCOMMAND completed')) @@ -1738,6 +1998,7 @@ def cmd_APPEND(self, tag, args): code, _ = client.enable('UTF8=ACCEPT') self.assertEqual(code, 'OK') self.assertEqual(client._encoding, 'utf-8') + self.assertEqual(server.args, ['UTF8=ACCEPT']) msg_string = 'Subject: üñí©öðé' typ, data = client.append( None, None, None, (msg_string + '\n').encode('utf-8')) @@ -1893,7 +2154,7 @@ def test_with_statement(self): with self.reaped_server(SimpleIMAPHandler) as server: with self.imap_class(*server.server_address) as imap: imap.login('user', 'pass') - self.assertEqual(server.logged, 'user') + self.assertEqual(server.logged, ['user', '"pass"']) self.assertIsNone(server.logged) @threading_helper.reap_threads @@ -1902,7 +2163,7 @@ def test_with_statement_logout(self): with self.reaped_server(SimpleIMAPHandler) as server: with self.imap_class(*server.server_address) as imap: imap.login('user', 'pass') - self.assertEqual(server.logged, 'user') + self.assertEqual(server.logged, ['user', '"pass"']) imap.logout() self.assertIsNone(server.logged) self.assertIsNone(server.logged) diff --git a/Misc/NEWS.d/next/Library/2026-06-30-12-00-00.gh-issue-40038.qK7mGv.rst b/Misc/NEWS.d/next/Library/2026-06-30-12-00-00.gh-issue-40038.qK7mGv.rst new file mode 100644 index 00000000000000..1f393d23266bce --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-30-12-00-00.gh-issue-40038.qK7mGv.rst @@ -0,0 +1,6 @@ +:mod:`imaplib` now again quotes command arguments when necessary, for +example mailbox names containing a space. Such quoting was inadvertently +disabled when the module was ported to Python 3, and the arguments are now +quoted according to the :rfc:`3501` grammar. For backward compatibility, +an argument already enclosed in double quotes is left unchanged, so code +that quotes arguments itself keeps working. From f09f5dced1ee37aa8b9eb923514e74ba84b56b14 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 5 Jul 2026 10:05:51 +0200 Subject: [PATCH 573/818] [3.15] gh-67512: Document IMAP4.append() flags argument (GH-149907) (GH-153078) (cherry picked from commit 5f8d9d35753e22946880d4fefb123e8234706266) Co-authored-by: Savage Mechanic <savagemechanic@github.com> --- Doc/library/imaplib.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Doc/library/imaplib.rst b/Doc/library/imaplib.rst index 8732aa15d2f1be..38a749b95f3e0e 100644 --- a/Doc/library/imaplib.rst +++ b/Doc/library/imaplib.rst @@ -209,6 +209,11 @@ An :class:`IMAP4` instance has the following methods: Append *message* to named mailbox. + *flags* may be ``None`` or a string of IMAP flag tokens. Multiple + flags are separated by spaces, for example ``r'\Seen \Answered'``. + If *flags* is not already enclosed in parentheses, parentheses are + added automatically. + .. method:: IMAP4.authenticate(mechanism, authobject) From 14568f4acfc56613483b4661ccde3c3e0363ce3c Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 5 Jul 2026 10:23:10 +0200 Subject: [PATCH 574/818] [3.15] gh-151819: Clarify the conditional-pattern email example in re docs (GH-153072) (GH-153073) The example pattern does not fail to match '<user@host.com' outright -- re.search finds 'user@host.com' in it; it only fails to match the whole string. Reword to say so. (cherry picked from commit fe9c7213e6576e27ebff6ef039706cd463593310) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --- Doc/library/re.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Doc/library/re.rst b/Doc/library/re.rst index 4745c1b98a4554..c8375f4d6a0527 100644 --- a/Doc/library/re.rst +++ b/Doc/library/re.rst @@ -509,8 +509,9 @@ The special characters are: *name* exists, and with ``no-pattern`` if it doesn't. ``no-pattern`` is optional and can be omitted. For example, ``(<)?(\w+@\w+(?:\.\w+)+)(?(1)>|$)`` is a poor email matching pattern, which - will match with ``'<user@host.com>'`` as well as ``'user@host.com'``, but - not with ``'<user@host.com'`` nor ``'user@host.com>'``. + matches ``'<user@host.com>'`` as well as ``'user@host.com'``, but does not + match ``'<user@host.com'`` nor ``'user@host.com>'`` in their entirety + (:func:`re.search` finds only ``'user@host.com'`` in the former). .. versionchanged:: 3.12 Group *id* can only contain ASCII digits. From f8d7ae89f99e11982713c7390b3728540c824b86 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 5 Jul 2026 10:26:29 +0200 Subject: [PATCH 575/818] [3.15] Remove PDF images (GH-145977) (#153064) (cherry picked from commit 5616505b443b13d9f5766dedcf6c0b43167705b6) Co-authored-by: Stan Ulbrych <stan@python.org> Co-authored-by: Maciej Olko <maciej.olko@affirm.com> --- Doc/c-api/lifecycle.dot.pdf | Bin 19328 -> 0 bytes Doc/c-api/lifecycle.rst | 11 ++--------- Doc/library/turtle-star.pdf | Bin 4418 -> 0 bytes Doc/library/turtle-star.ps | Bin 13803 -> 0 bytes Doc/library/turtle.rst | 2 +- 5 files changed, 3 insertions(+), 10 deletions(-) delete mode 100644 Doc/c-api/lifecycle.dot.pdf delete mode 100644 Doc/library/turtle-star.pdf delete mode 100644 Doc/library/turtle-star.ps diff --git a/Doc/c-api/lifecycle.dot.pdf b/Doc/c-api/lifecycle.dot.pdf deleted file mode 100644 index ed5b5039c83e2c4a36d77e713c430c8f14901bed..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19328 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 diff --git a/Doc/c-api/lifecycle.rst b/Doc/c-api/lifecycle.rst index 531c4080a0131c..5e3dca29f2ad90 100644 --- a/Doc/c-api/lifecycle.rst +++ b/Doc/c-api/lifecycle.rst @@ -19,7 +19,7 @@ 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 +.. only:: builder_html .. raw:: html @@ -50,20 +50,13 @@ that must be true for *B* to occur after *A*. })(); </script> -.. only:: epub or not (html or latex) +.. only:: not builder_html .. 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 diff --git a/Doc/library/turtle-star.pdf b/Doc/library/turtle-star.pdf deleted file mode 100644 index e354073dd42f5e6ea48118d7e2363247b190528b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4418 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 diff --git a/Doc/library/turtle-star.ps b/Doc/library/turtle-star.ps deleted file mode 100644 index 46362cb9f7c8f52ae8ee352d81db4bd42bfe26a8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13803 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 BwL<^^ diff --git a/Doc/library/turtle.rst b/Doc/library/turtle.rst index 20c659756fe1c1..d7839e2f81172c 100644 --- a/Doc/library/turtle.rst +++ b/Doc/library/turtle.rst @@ -46,7 +46,7 @@ direction it is facing, drawing a line as it moves. Give it the command Turtle can draw intricate shapes using programs that repeat simple moves. - .. image:: turtle-star.* + .. image:: turtle-star.png :align: center In Python, turtle graphics provides a representation of a physical "turtle" From 6416d86afc50ced6cf9b0e1020fe04885eabac87 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 5 Jul 2026 10:40:12 +0200 Subject: [PATCH 576/818] [3.15] gh-66335: Test uppercase IMAP4 command names (GH-152876) (GH-153080) (cherry picked from commit 3cd6b7406442ad976c6651b9fba6f078971cdf10) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Milan Oberkirch <zvyn@oberkirch.org> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --- Lib/test/test_imaplib.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Lib/test/test_imaplib.py b/Lib/test/test_imaplib.py index 091769e98ef523..55e5c9fe3a6ecf 100644 --- a/Lib/test/test_imaplib.py +++ b/Lib/test/test_imaplib.py @@ -1725,6 +1725,16 @@ def test_xatom(self): self.assertEqual(data, [b'MYCOMMAND completed']) self.assertEqual(server.args, ['arg1', 'arg2']) + def test_uppercase_command_names(self): + client, server = self._setup(SimpleIMAPHandler) + client.login('user', 'pass') + self.assertEqual(client.CAPABILITY, client.capability) + self.assertEqual(client.SELECT, client.select) + typ, data = client.CAPABILITY() + self.assertEqual(typ, 'OK') + with self.assertRaises(AttributeError): + client.NONEXISTENT + def test_control_characters(self): client, _ = self._setup(SimpleIMAPHandler) for c0 in support.control_characters_c0(): From e9f92ac0b298292e7ff998e52cb8ccacfb27a0bd Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 5 Jul 2026 10:57:20 +0200 Subject: [PATCH 577/818] [3.15] gh-153030: Fix quadratic complexity in incremental parsing in HTMLParser (GH-153031) (GH-153038) When an unterminated construct (e.g. a tag or comment) spanned many feed() calls, rescanning the growing buffer and concatenating new data onto it were both quadratic. New data is now accumulated in a list and only joined and parsed once enough has piled up. (cherry picked from commit bcf98ddbc40ec9b3ee87da0124a5660b19b7e606) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --- Lib/html/parser.py | 32 +++++++++++++++++-- Lib/test/test_htmlparser.py | 20 ++++++++++++ ...-07-04-17-00-00.gh-issue-153030.RovkP6.rst | 3 ++ 3 files changed, 53 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Security/2026-07-04-17-00-00.gh-issue-153030.RovkP6.rst diff --git a/Lib/html/parser.py b/Lib/html/parser.py index 38ddf9ef442d36..fbe0d3665e073c 100644 --- a/Lib/html/parser.py +++ b/Lib/html/parser.py @@ -157,6 +157,9 @@ def reset(self): self.cdata_elem = None self._support_cdata = True self._escapable = True + self._pending = [] + self._pending_len = 0 + self._parse_threshold = 1 super().reset() def feed(self, data): @@ -165,11 +168,36 @@ def feed(self, data): Call this as often as you want, with as little or as much text as you want (may include '\n'). """ - self.rawdata = self.rawdata + data - self.goahead(0) + # Accumulate new data in a list and only join and parse it once + # enough has piled up. Rescanning an unparsed buffer (e.g. an + # unterminated tag) and concatenating onto it on every call would + # both be quadratic in the input size. + self._pending_len += len(data) + if self._pending_len < self._parse_threshold: + self._pending.append(data) + else: + if not self._pending: + self.rawdata += data + else: + self._pending.append(data) + self.rawdata += ''.join(self._pending) + self._pending.clear() + self._pending_len = 0 + n = len(self.rawdata) + self.goahead(0) + if len(self.rawdata) < n: + # Some data was parsed; resume on the next call. + self._parse_threshold = 1 + else: + # Nothing was parsed; wait until the buffer doubles. + self._parse_threshold = len(self.rawdata) def close(self): """Handle any buffered data.""" + if self._pending: + self.rawdata += ''.join(self._pending) + self._pending.clear() + self._pending_len = 0 self.goahead(1) __starttag_text = None diff --git a/Lib/test/test_htmlparser.py b/Lib/test/test_htmlparser.py index 6b7624f11505d9..3fdaed4ff46b9d 100644 --- a/Lib/test/test_htmlparser.py +++ b/Lib/test/test_htmlparser.py @@ -1041,6 +1041,26 @@ def check(source): check("<![CDATA[" * 9 * n) check("<!doctype" * 35 * n) + @support.requires_resource('cpu') + def test_incremental_no_quadratic_complexity(self): + # An unterminated construct fed in many small chunks used to take + # quadratic time, both to rescan and to concatenate the buffer. + # Now it takes a fraction of a second. + def check(prefix, chunk, suffix): + parser = html.parser.HTMLParser() + parser.feed(prefix) + for _ in range(200_000): + parser.feed(chunk) + parser.feed(suffix) + parser.close() + chunk = "a" * 64 + check("<!--", chunk, "-->") # comment + check("<?", chunk, ">") # processing instruction + check("<!doctype ", chunk, ">") # doctype + check("<![CDATA[", chunk, "]]>") # CDATA section + check("<a href='", chunk, "'>") # start tag + check("<script>", chunk, "</script>") # RAWTEXT element + class AttributesTestCase(TestCaseBase): diff --git a/Misc/NEWS.d/next/Security/2026-07-04-17-00-00.gh-issue-153030.RovkP6.rst b/Misc/NEWS.d/next/Security/2026-07-04-17-00-00.gh-issue-153030.RovkP6.rst new file mode 100644 index 00000000000000..d1d60593f4ba7d --- /dev/null +++ b/Misc/NEWS.d/next/Security/2026-07-04-17-00-00.gh-issue-153030.RovkP6.rst @@ -0,0 +1,3 @@ +Fixed quadratic complexity in incremental parsing of long unterminated +constructs (such as tags or comments) in :class:`html.parser.HTMLParser`, +which could be exploited for a denial of service. From 9b0a97c4c58252d88b1e05a5a7a5ae28f5c7d388 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 5 Jul 2026 11:33:42 +0200 Subject: [PATCH 578/818] [3.15] gh-151945: fix Sphinx reference warnings in `http.server` docs (GH-153084) (#153085) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gh-151945: fix Sphinx reference warnings in `http.server` docs (GH-153084) (cherry picked from commit 9f9787d83462f5b44cb59e3c69e7c1799612a33f) Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com> --- Doc/library/http.server.rst | 48 ++++++++++++++++++++++++++++++++++--- Doc/tools/.nitignore | 1 - 2 files changed, 45 insertions(+), 4 deletions(-) diff --git a/Doc/library/http.server.rst b/Doc/library/http.server.rst index c4b9173f9e34eb..9c2ce2dffb185e 100644 --- a/Doc/library/http.server.rst +++ b/Doc/library/http.server.rst @@ -39,7 +39,17 @@ handler. Code to create and run the server looks like this:: This class builds on the :class:`~socketserver.TCPServer` class by storing the server address as instance variables named :attr:`server_name` and :attr:`server_port`. The server is accessible by the handler, typically - through the handler's :attr:`server` instance variable. + through the handler's :attr:`~socketserver.BaseRequestHandler.server` + instance variable. + + .. attribute:: server_name + + The HTTP server's fully qualified domain name. + + .. attribute:: server_port + + The HTTP server's port number obtained from *server_address*. + .. class:: ThreadingHTTPServer(server_address, RequestHandlerClass) @@ -402,6 +412,14 @@ instantiation, of which this module provides three different variants: .. versionadded:: 3.15 + .. attribute:: index_pages + + Specifies the filenames that are treated as directory index pages. + + Defaults to ``("index.html", "index.htm")``. + + .. versionadded:: 3.12 + .. attribute:: extensions_map A dictionary mapping suffixes into MIME types, contains custom overrides @@ -435,7 +453,7 @@ instantiation, of which this module provides three different variants: path relative to the current working directory. If the request was mapped to a directory, the directory is checked for a - file named ``index.html`` or ``index.htm`` (in that order). If found, the + an index page as specified by :attr:`index_pages`. If found, the file's contents are returned; otherwise a directory listing is generated by calling the :meth:`list_directory` method. This method uses :func:`os.listdir` to scan the directory, and returns a ``404`` error @@ -465,6 +483,30 @@ instantiation, of which this module provides three different variants: .. versionchanged:: 3.7 Support of the ``'If-Modified-Since'`` header. + .. method:: list_directory(path) + + Helper to list the contents of *path* when no index page is present. + + This returns either a :term:`file-like object` (which must be closed + by the caller) or ``None`` to indicate an error, in which case the + caller has nothing further to do. In either case, the headers are sent. + + .. method:: guess_type(path) + + Guess the type of the file at the given *path*. + + This returns a string of the form ``type/subtype``, usable for + a MIME Content-type header. + + The default implementation looks the file's extension up in + :attr:`extensions_map`, falling back to + :func:`mimetypes.guess_file_type` and then to + :attr:`default_content_type`. + + .. versionchanged:: 3.13 + Add :func:`mimetypes.guess_file_type` as a fallback. + + The :class:`SimpleHTTPRequestHandler` class can be used in the following manner in order to create a very basic webserver serving files relative to the current directory:: @@ -483,7 +525,7 @@ the current directory:: :class:`SimpleHTTPRequestHandler` can also be subclassed to enhance behavior, such as using different index file names by overriding the class attribute -:attr:`index_pages`. +:attr:`~SimpleHTTPRequestHandler.index_pages`. .. _http-server-cli: diff --git a/Doc/tools/.nitignore b/Doc/tools/.nitignore index 7b956f0ef0eb2c..8ac0e8ffcffc27 100644 --- a/Doc/tools/.nitignore +++ b/Doc/tools/.nitignore @@ -9,7 +9,6 @@ Doc/library/ast.rst Doc/library/asyncio-extending.rst Doc/library/email.charset.rst Doc/library/email.parser.rst -Doc/library/http.server.rst Doc/library/importlib.rst Doc/library/logging.config.rst Doc/library/logging.handlers.rst From f7eda8e1302ca346768c11a0a4f67539cb5fbe34 Mon Sep 17 00:00:00 2001 From: sobolevn <mail@sobolevn.me> Date: Sun, 5 Jul 2026 13:41:56 +0300 Subject: [PATCH 579/818] [3.15] gh-150459: Fix `SyntaxError` message for `from x lazy import y` (GH-150877) (#153090) (cherry picked from commit ec5f154e33f5d62257d041dd28aad1fe785fa3db) --- Grammar/python.gram | 8 +- Include/internal/pycore_pyerrors.h | 8 +- Lib/test/test_syntax.py | 93 ++ ...-06-03-21-14-28.gh-issue-150459.qpsCEl.rst | 3 + Parser/action_helpers.c | 71 +- Parser/parser.c | 859 ++++++++++-------- Parser/pegen.h | 6 +- 7 files changed, 649 insertions(+), 399 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-03-21-14-28.gh-issue-150459.qpsCEl.rst diff --git a/Grammar/python.gram b/Grammar/python.gram index 9bf3a67939fcf3..7f98cb5c457d49 100644 --- a/Grammar/python.gram +++ b/Grammar/python.gram @@ -229,8 +229,9 @@ import_name[stmt_ty]: # note below: the ('.' | '...') is necessary because '...' is tokenized as ELLIPSIS import_from[stmt_ty]: + | invalid_import_from | lazy="lazy"? 'from' a=('.' | '...')* b=dotted_name 'import' c=import_from_targets { - _PyPegen_checked_future_import(p, b->v.Name.id, c, _PyPegen_seq_count_dots(a), lazy, EXTRA) } + _PyPegen_checked_from_import(p, a, b, c, lazy, EXTRA) } | lazy="lazy"? 'from' a=('.' | '...')+ 'import' b=import_from_targets { _PyAST_ImportFrom(NULL, b, _PyPegen_seq_count_dots(a), lazy ? 1 : 0, EXTRA) } import_from_targets[asdl_alias_seq*]: @@ -1443,6 +1444,11 @@ invalid_import_from_as_name: RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "cannot use %s as import target", _PyPegen_get_expr_name(a)) } +invalid_import_from: + | 'from' ('.' | '...')* dotted_name a="lazy" 'import' import_from_targets { + RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, + "use 'lazy from ... ' instead of 'from ... lazy import'") } + invalid_import_from_targets: | import_from_as_names ',' NEWLINE { RAISE_SYNTAX_ERROR("trailing comma not allowed without surrounding parentheses") } diff --git a/Include/internal/pycore_pyerrors.h b/Include/internal/pycore_pyerrors.h index e436aa6bf12cb2..c1f9d71e40077c 100644 --- a/Include/internal/pycore_pyerrors.h +++ b/Include/internal/pycore_pyerrors.h @@ -123,9 +123,11 @@ extern void _PyErr_SetNone(PyThreadState *tstate, PyObject *exception); extern PyObject* _PyErr_NoMemory(PyThreadState *tstate); -extern int _PyErr_EmitSyntaxWarning(PyObject *msg, PyObject *filename, int lineno, int col_offset, - int end_lineno, int end_col_offset, - PyObject *module); +// Export for test_peg_generator +PyAPI_FUNC(int) _PyErr_EmitSyntaxWarning(PyObject *msg, PyObject *filename, + int lineno, int col_offset, + int end_lineno, int end_col_offset, + PyObject *module); extern void _PyErr_RaiseSyntaxError(PyObject *msg, PyObject *filename, int lineno, int col_offset, int end_lineno, int end_col_offset); diff --git a/Lib/test/test_syntax.py b/Lib/test/test_syntax.py index a3d485c998ac91..232dcb92ed2901 100644 --- a/Lib/test/test_syntax.py +++ b/Lib/test/test_syntax.py @@ -2872,6 +2872,14 @@ def check_warning(self, code, errtext, filename="<testcase>", mode="exec"): with self.assertWarnsRegex(SyntaxWarning, errtext): compile(code, filename, mode) + def check_no_warning(self, code, filename="<testcase>", mode="exec"): + """Check that compiling code does not raise any warnings.""" + import warnings + with warnings.catch_warnings(record=True) as caught: + warnings.simplefilter("always") + compile(code, filename, mode) + self.assertEqual(caught, []) + def test_return_in_finally(self): source = textwrap.dedent(""" def f(): @@ -2942,6 +2950,75 @@ def test_break_and_continue_in_finally(self): """) self.check_warning(source, f"'{kw}' in a 'finally' block") + def test_from_lazy_imports(self): + # gh-150459 + self.check_warning( + "from . lazy import x", + "did you mean 'lazy from . import'?", + ) + self.check_warning( + "from . lazy import x as y", + "did you mean 'lazy from . import'?", + ) + self.check_warning( + "from . lazy import *", + "did you mean 'lazy from . import'?", + ) + self.check_warning( + "from .. lazy import x", + "did you mean 'lazy from .. import'?", + ) + self.check_warning( + "from ... lazy import x", + "did you mean 'lazy from ... import'?", + ) + self.check_warning( + "from .... lazy import x", + "did you mean 'lazy from .... import'?", + ) + self.check_warning( + "from . \\\n lazy import x", + "did you mean 'lazy from . import'?", + ) + self.check_warning( + "from .\\\nlazy import x", + "did you mean 'lazy from . import'?", + ) + self.check_warning( + "from .\tlazy import x", + "did you mean 'lazy from . import'?", + ) + + def test_not_from_lazy_imports(self): + self.check_no_warning("from .lazy import x") + self.check_no_warning("from .lazy import *") + self.check_no_warning("from ..lazy import x") + self.check_no_warning("from ...lazy import x") + self.check_no_warning("from .lazy.sub import x") + self.check_no_warning("from ..lazy.sub import x") + self.check_no_warning("from ...lazy.sub import x") + self.check_no_warning("from . lazier import x") + self.check_no_warning("from . lazy_module import x") + self.check_no_warning("from . lazy.sub import x") + self.check_no_warning("from . sub.lazy import x") + self.check_no_warning("from lazy import x") + self.check_no_warning("from lazy.sub import x") + self.check_no_warning("lazy from . lazy import x") + self.check_no_warning("from . import lazy") + + def test_from_lazy_imports_as_error(self): + import warnings + with warnings.catch_warnings(): + warnings.simplefilter("error", SyntaxWarning) + with self.assertRaisesRegex( + SyntaxError, + re.escape("did you mean 'lazy from . import'?"), + ) as cm: + compile("from . lazy import x", "<test>", "exec") + self.assertEqual(cm.exception.lineno, 1) + self.assertEqual(cm.exception.offset, 8) + self.assertEqual(cm.exception.end_offset, 12) + class SyntaxErrorTestCase(unittest.TestCase): @@ -3618,6 +3695,22 @@ def inner(): lazy from collections import deque """, "lazy from ... import not allowed inside functions") + self._check_error("""\ +from os lazy import path +""", "use 'lazy from ... ' instead of 'from ... lazy import'") + self._check_error("""\ +from os.path lazy import join +""", "use 'lazy from ... ' instead of 'from ... lazy import'") + self._check_error("""\ +from .mod lazy import join +""", "use 'lazy from ... ' instead of 'from ... lazy import'") + self._check_error("""\ +from ..mod lazy import join +""", "use 'lazy from ... ' instead of 'from ... lazy import'") + self._check_error("""\ +from ...mod lazy import join +""", "use 'lazy from ... ' instead of 'from ... lazy import'") + def test_lazy_import_valid_cases(self): """Test that lazy imports work at module level.""" # These should compile without errors diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-03-21-14-28.gh-issue-150459.qpsCEl.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-03-21-14-28.gh-issue-150459.qpsCEl.rst new file mode 100644 index 00000000000000..a3e3e38ddcd1f4 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-03-21-14-28.gh-issue-150459.qpsCEl.rst @@ -0,0 +1,3 @@ +Fix :exc:`SyntaxError` error message for ``from x lazy import y``. +Raise :exc:`SyntaxWarning` on ``from . lazy import x`` +(with whitespace between the dots and a module named ``lazy``). diff --git a/Parser/action_helpers.c b/Parser/action_helpers.c index 381c173589904b..809f3c0a7b270e 100644 --- a/Parser/action_helpers.c +++ b/Parser/action_helpers.c @@ -2,6 +2,7 @@ #include "pycore_pystate.h" // _PyInterpreterState_GET() #include "pycore_runtime.h" // _PyRuntime #include "pycore_unicodeobject.h" // _PyUnicode_InternImmortal() +#include "pycore_pyerrors.h" // _PyErr_EmitSyntaxWarning() #include "pegen.h" #include "string_parser.h" // _PyPegen_decode_string() @@ -2007,11 +2008,64 @@ _PyPegen_concatenate_strings(Parser *p, asdl_expr_seq *strings, col_offset, end_lineno, end_col_offset, arena); } +static int +_warn_relative_import_of_lazy(Parser *p, asdl_seq *dots, expr_ty module) +{ + // Warn about `from . lazy import x`: the whitespace between the dots and + // the module name is insignificant, so this is parsed exactly like + // `from .lazy import x` (an import of the relative module "lazy"), but it + // is most likely a transposition of `lazy from . import x` (PEP 810). + if (p->call_invalid_rules) { + return 0; + } + + // Only fire if there is whitespace between the last dot and the name, + // i.e. not for the common `from .lazy import x` spelling. + Token *last_dot = asdl_seq_GET_UNTYPED(dots, asdl_seq_LEN(dots) - 1); + if ( + last_dot->end_lineno == module->lineno + && last_dot->end_col_offset == module->col_offset + ) { + return 0; + } + + int count = _PyPegen_seq_count_dots(dots); + char *buf = PyMem_RawMalloc(count + 1); + if (buf == NULL) { + PyErr_NoMemory(); + return -1; + } + memset(buf, '.', count); + buf[count] = '\0'; + + PyObject *msg = PyUnicode_FromFormat( + "'from %s lazy import' is the same as 'from %slazy import'; " + "did you mean 'lazy from %s import'?", + buf, buf, buf); + PyMem_RawFree(buf); + if (msg == NULL) { + return -1; + } + + int res = _PyErr_EmitSyntaxWarning(msg, + p->tok->filename, + module->lineno, + module->col_offset + 1, + module->end_lineno, + module->end_col_offset + 1, + p->tok->module); + Py_DECREF(msg); + return res; +} + stmt_ty -_PyPegen_checked_future_import(Parser *p, identifier module, asdl_alias_seq * names, - int level, expr_ty lazy_token, int lineno, - int col_offset, int end_lineno, int end_col_offset, - PyArena *arena) { +_PyPegen_checked_from_import(Parser *p, asdl_seq *dots, expr_ty module_name, + asdl_alias_seq *names, expr_ty lazy_token, int lineno, + int col_offset, int end_lineno, int end_col_offset, + PyArena *arena) +{ + identifier module = module_name->v.Name.id; + int level = _PyPegen_seq_count_dots(dots); if (level == 0 && PyUnicode_CompareWithASCIIString(module, "__future__") == 0) { if (lazy_token) { RAISE_SYNTAX_ERROR_KNOWN_LOCATION(lazy_token, @@ -2025,6 +2079,15 @@ _PyPegen_checked_future_import(Parser *p, identifier module, asdl_alias_seq * na } } } + else if ( + level > 0 + && lazy_token == NULL + && PyUnicode_CompareWithASCIIString(module, "lazy") == 0 + ) { + if (_warn_relative_import_of_lazy(p, dots, module_name) < 0) { + return NULL; + } + } return _PyAST_ImportFrom(module, names, level, lazy_token ? 1 : 0, lineno, col_offset, end_lineno, end_col_offset, arena); } diff --git a/Parser/parser.c b/Parser/parser.c index c55c081dfc3d8e..3be5f3ad8250bd 100644 --- a/Parser/parser.c +++ b/Parser/parser.c @@ -22,28 +22,28 @@ static KeywordToken *reserved_keywords[] = { (KeywordToken[]) {{NULL, -1}}, (KeywordToken[]) {{NULL, -1}}, (KeywordToken[]) { - {"if", 698}, - {"as", 696}, - {"in", 711}, + {"if", 700}, + {"as", 698}, + {"in", 713}, {"or", 589}, {"is", 597}, {NULL, -1}, }, (KeywordToken[]) { {"del", 634}, - {"def", 715}, - {"for", 710}, - {"try", 672}, + {"def", 717}, + {"for", 712}, + {"try", 674}, {"and", 590}, - {"not", 719}, + {"not", 721}, {NULL, -1}, }, (KeywordToken[]) { - {"from", 646}, + {"from", 650}, {"pass", 527}, - {"with", 663}, - {"elif", 703}, - {"else", 702}, + {"with", 665}, + {"elif", 705}, + {"else", 704}, {"None", 628}, {"True", 627}, {NULL, -1}, @@ -52,24 +52,24 @@ static KeywordToken *reserved_keywords[] = { {"raise", 632}, {"yield", 588}, {"break", 528}, - {"async", 714}, - {"class", 717}, - {"while", 705}, + {"async", 716}, + {"class", 719}, + {"while", 707}, {"False", 629}, {"await", 598}, {NULL, -1}, }, (KeywordToken[]) { - {"import", 647}, + {"import", 651}, {"return", 522}, {"assert", 638}, {"global", 530}, - {"except", 693}, + {"except", 695}, {"lambda", 622}, {NULL, -1}, }, (KeywordToken[]) { - {"finally", 689}, + {"finally", 691}, {NULL, -1}, }, (KeywordToken[]) { @@ -326,222 +326,223 @@ static char *soft_keywords[] = { #define invalid_import_type 1237 #define invalid_dotted_as_name_type 1238 #define invalid_import_from_as_name_type 1239 -#define invalid_import_from_targets_type 1240 -#define invalid_with_stmt_type 1241 -#define invalid_with_stmt_indent_type 1242 -#define invalid_try_stmt_type 1243 -#define invalid_except_stmt_type 1244 -#define invalid_except_star_stmt_type 1245 -#define invalid_finally_stmt_type 1246 -#define invalid_except_stmt_indent_type 1247 -#define invalid_except_star_stmt_indent_type 1248 -#define invalid_match_stmt_type 1249 -#define invalid_case_block_type 1250 -#define invalid_as_pattern_type 1251 -#define invalid_class_pattern_type 1252 -#define invalid_mapping_pattern_type 1253 -#define invalid_class_argument_pattern_type 1254 -#define invalid_if_stmt_type 1255 -#define invalid_elif_stmt_type 1256 -#define invalid_else_stmt_type 1257 -#define invalid_while_stmt_type 1258 -#define invalid_for_stmt_type 1259 -#define invalid_def_raw_type 1260 -#define invalid_class_def_raw_type 1261 -#define invalid_double_starred_kvpairs_type 1262 -#define invalid_kvpair_unpacking_type 1263 -#define invalid_kvpair_type 1264 -#define invalid_starred_expression_unpacking_type 1265 -#define invalid_starred_expression_unpacking_sequence_type 1266 -#define invalid_starred_expression_type 1267 -#define invalid_fstring_replacement_field_type 1268 -#define invalid_fstring_conversion_character_type 1269 -#define invalid_tstring_replacement_field_type 1270 -#define invalid_tstring_conversion_character_type 1271 -#define invalid_string_tstring_concat_type 1272 -#define invalid_arithmetic_type 1273 -#define invalid_factor_type 1274 -#define invalid_type_params_type 1275 -#define _loop0_1_type 1276 -#define _loop1_2_type 1277 -#define _loop0_3_type 1278 -#define _gather_4_type 1279 -#define _tmp_5_type 1280 -#define _tmp_6_type 1281 -#define _tmp_7_type 1282 -#define _tmp_8_type 1283 -#define _tmp_9_type 1284 -#define _tmp_10_type 1285 -#define _tmp_11_type 1286 -#define _loop1_12_type 1287 -#define _loop0_13_type 1288 -#define _gather_14_type 1289 -#define _tmp_15_type 1290 -#define _tmp_16_type 1291 -#define _loop0_17_type 1292 -#define _loop1_18_type 1293 -#define _loop0_19_type 1294 -#define _gather_20_type 1295 -#define _tmp_21_type 1296 -#define _loop0_22_type 1297 -#define _gather_23_type 1298 -#define _loop1_24_type 1299 -#define _tmp_25_type 1300 -#define _tmp_26_type 1301 -#define _loop0_27_type 1302 -#define _loop0_28_type 1303 -#define _loop1_29_type 1304 -#define _loop1_30_type 1305 -#define _loop0_31_type 1306 -#define _loop1_32_type 1307 -#define _loop0_33_type 1308 -#define _gather_34_type 1309 -#define _tmp_35_type 1310 -#define _loop1_36_type 1311 -#define _loop1_37_type 1312 -#define _loop1_38_type 1313 -#define _loop0_39_type 1314 -#define _gather_40_type 1315 -#define _tmp_41_type 1316 -#define _tmp_42_type 1317 -#define _tmp_43_type 1318 -#define _loop0_44_type 1319 -#define _gather_45_type 1320 -#define _loop0_46_type 1321 -#define _gather_47_type 1322 -#define _tmp_48_type 1323 -#define _loop0_49_type 1324 -#define _gather_50_type 1325 -#define _loop0_51_type 1326 -#define _gather_52_type 1327 -#define _loop0_53_type 1328 -#define _gather_54_type 1329 -#define _loop1_55_type 1330 -#define _loop1_56_type 1331 -#define _loop0_57_type 1332 -#define _gather_58_type 1333 -#define _loop0_59_type 1334 -#define _gather_60_type 1335 -#define _loop1_61_type 1336 -#define _loop1_62_type 1337 -#define _loop1_63_type 1338 -#define _tmp_64_type 1339 -#define _loop0_65_type 1340 -#define _gather_66_type 1341 -#define _tmp_67_type 1342 -#define _tmp_68_type 1343 -#define _tmp_69_type 1344 -#define _tmp_70_type 1345 -#define _tmp_71_type 1346 -#define _loop0_72_type 1347 -#define _loop0_73_type 1348 -#define _loop1_74_type 1349 -#define _loop1_75_type 1350 -#define _loop0_76_type 1351 -#define _loop1_77_type 1352 -#define _loop0_78_type 1353 -#define _loop0_79_type 1354 -#define _loop0_80_type 1355 -#define _loop0_81_type 1356 -#define _loop1_82_type 1357 -#define _loop1_83_type 1358 -#define _tmp_84_type 1359 -#define _loop0_85_type 1360 -#define _gather_86_type 1361 -#define _loop1_87_type 1362 -#define _loop0_88_type 1363 -#define _tmp_89_type 1364 -#define _loop0_90_type 1365 -#define _gather_91_type 1366 -#define _tmp_92_type 1367 -#define _loop0_93_type 1368 -#define _gather_94_type 1369 -#define _loop0_95_type 1370 -#define _gather_96_type 1371 -#define _loop0_97_type 1372 -#define _loop0_98_type 1373 -#define _gather_99_type 1374 -#define _loop1_100_type 1375 -#define _tmp_101_type 1376 -#define _loop0_102_type 1377 -#define _gather_103_type 1378 -#define _loop0_104_type 1379 -#define _gather_105_type 1380 -#define _tmp_106_type 1381 -#define _tmp_107_type 1382 -#define _loop0_108_type 1383 -#define _gather_109_type 1384 -#define _tmp_110_type 1385 -#define _tmp_111_type 1386 -#define _tmp_112_type 1387 -#define _tmp_113_type 1388 -#define _tmp_114_type 1389 -#define _loop1_115_type 1390 -#define _tmp_116_type 1391 -#define _tmp_117_type 1392 -#define _tmp_118_type 1393 -#define _tmp_119_type 1394 -#define _tmp_120_type 1395 -#define _loop0_121_type 1396 -#define _loop0_122_type 1397 -#define _tmp_123_type 1398 -#define _tmp_124_type 1399 -#define _tmp_125_type 1400 -#define _tmp_126_type 1401 -#define _tmp_127_type 1402 -#define _tmp_128_type 1403 -#define _tmp_129_type 1404 -#define _tmp_130_type 1405 -#define _loop0_131_type 1406 -#define _gather_132_type 1407 -#define _tmp_133_type 1408 -#define _tmp_134_type 1409 -#define _tmp_135_type 1410 -#define _tmp_136_type 1411 -#define _loop0_137_type 1412 -#define _gather_138_type 1413 -#define _tmp_139_type 1414 -#define _loop0_140_type 1415 -#define _gather_141_type 1416 -#define _loop0_142_type 1417 -#define _gather_143_type 1418 -#define _tmp_144_type 1419 -#define _loop0_145_type 1420 -#define _tmp_146_type 1421 -#define _tmp_147_type 1422 -#define _tmp_148_type 1423 -#define _tmp_149_type 1424 -#define _tmp_150_type 1425 -#define _tmp_151_type 1426 -#define _tmp_152_type 1427 -#define _tmp_153_type 1428 -#define _tmp_154_type 1429 -#define _tmp_155_type 1430 -#define _tmp_156_type 1431 -#define _tmp_157_type 1432 -#define _tmp_158_type 1433 -#define _tmp_159_type 1434 -#define _tmp_160_type 1435 -#define _tmp_161_type 1436 -#define _tmp_162_type 1437 -#define _tmp_163_type 1438 -#define _tmp_164_type 1439 -#define _tmp_165_type 1440 -#define _tmp_166_type 1441 -#define _tmp_167_type 1442 -#define _tmp_168_type 1443 -#define _tmp_169_type 1444 -#define _tmp_170_type 1445 -#define _tmp_171_type 1446 -#define _tmp_172_type 1447 -#define _tmp_173_type 1448 -#define _loop0_174_type 1449 -#define _tmp_175_type 1450 -#define _tmp_176_type 1451 -#define _tmp_177_type 1452 -#define _tmp_178_type 1453 -#define _tmp_179_type 1454 -#define _tmp_180_type 1455 +#define invalid_import_from_type 1240 +#define invalid_import_from_targets_type 1241 +#define invalid_with_stmt_type 1242 +#define invalid_with_stmt_indent_type 1243 +#define invalid_try_stmt_type 1244 +#define invalid_except_stmt_type 1245 +#define invalid_except_star_stmt_type 1246 +#define invalid_finally_stmt_type 1247 +#define invalid_except_stmt_indent_type 1248 +#define invalid_except_star_stmt_indent_type 1249 +#define invalid_match_stmt_type 1250 +#define invalid_case_block_type 1251 +#define invalid_as_pattern_type 1252 +#define invalid_class_pattern_type 1253 +#define invalid_mapping_pattern_type 1254 +#define invalid_class_argument_pattern_type 1255 +#define invalid_if_stmt_type 1256 +#define invalid_elif_stmt_type 1257 +#define invalid_else_stmt_type 1258 +#define invalid_while_stmt_type 1259 +#define invalid_for_stmt_type 1260 +#define invalid_def_raw_type 1261 +#define invalid_class_def_raw_type 1262 +#define invalid_double_starred_kvpairs_type 1263 +#define invalid_kvpair_unpacking_type 1264 +#define invalid_kvpair_type 1265 +#define invalid_starred_expression_unpacking_type 1266 +#define invalid_starred_expression_unpacking_sequence_type 1267 +#define invalid_starred_expression_type 1268 +#define invalid_fstring_replacement_field_type 1269 +#define invalid_fstring_conversion_character_type 1270 +#define invalid_tstring_replacement_field_type 1271 +#define invalid_tstring_conversion_character_type 1272 +#define invalid_string_tstring_concat_type 1273 +#define invalid_arithmetic_type 1274 +#define invalid_factor_type 1275 +#define invalid_type_params_type 1276 +#define _loop0_1_type 1277 +#define _loop1_2_type 1278 +#define _loop0_3_type 1279 +#define _gather_4_type 1280 +#define _tmp_5_type 1281 +#define _tmp_6_type 1282 +#define _tmp_7_type 1283 +#define _tmp_8_type 1284 +#define _tmp_9_type 1285 +#define _tmp_10_type 1286 +#define _tmp_11_type 1287 +#define _loop1_12_type 1288 +#define _loop0_13_type 1289 +#define _gather_14_type 1290 +#define _tmp_15_type 1291 +#define _tmp_16_type 1292 +#define _loop0_17_type 1293 +#define _loop1_18_type 1294 +#define _loop0_19_type 1295 +#define _gather_20_type 1296 +#define _tmp_21_type 1297 +#define _loop0_22_type 1298 +#define _gather_23_type 1299 +#define _loop1_24_type 1300 +#define _tmp_25_type 1301 +#define _tmp_26_type 1302 +#define _loop0_27_type 1303 +#define _loop0_28_type 1304 +#define _loop1_29_type 1305 +#define _loop1_30_type 1306 +#define _loop0_31_type 1307 +#define _loop1_32_type 1308 +#define _loop0_33_type 1309 +#define _gather_34_type 1310 +#define _tmp_35_type 1311 +#define _loop1_36_type 1312 +#define _loop1_37_type 1313 +#define _loop1_38_type 1314 +#define _loop0_39_type 1315 +#define _gather_40_type 1316 +#define _tmp_41_type 1317 +#define _tmp_42_type 1318 +#define _tmp_43_type 1319 +#define _loop0_44_type 1320 +#define _gather_45_type 1321 +#define _loop0_46_type 1322 +#define _gather_47_type 1323 +#define _tmp_48_type 1324 +#define _loop0_49_type 1325 +#define _gather_50_type 1326 +#define _loop0_51_type 1327 +#define _gather_52_type 1328 +#define _loop0_53_type 1329 +#define _gather_54_type 1330 +#define _loop1_55_type 1331 +#define _loop1_56_type 1332 +#define _loop0_57_type 1333 +#define _gather_58_type 1334 +#define _loop0_59_type 1335 +#define _gather_60_type 1336 +#define _loop1_61_type 1337 +#define _loop1_62_type 1338 +#define _loop1_63_type 1339 +#define _tmp_64_type 1340 +#define _loop0_65_type 1341 +#define _gather_66_type 1342 +#define _tmp_67_type 1343 +#define _tmp_68_type 1344 +#define _tmp_69_type 1345 +#define _tmp_70_type 1346 +#define _tmp_71_type 1347 +#define _loop0_72_type 1348 +#define _loop0_73_type 1349 +#define _loop1_74_type 1350 +#define _loop1_75_type 1351 +#define _loop0_76_type 1352 +#define _loop1_77_type 1353 +#define _loop0_78_type 1354 +#define _loop0_79_type 1355 +#define _loop0_80_type 1356 +#define _loop0_81_type 1357 +#define _loop1_82_type 1358 +#define _loop1_83_type 1359 +#define _tmp_84_type 1360 +#define _loop0_85_type 1361 +#define _gather_86_type 1362 +#define _loop1_87_type 1363 +#define _loop0_88_type 1364 +#define _tmp_89_type 1365 +#define _loop0_90_type 1366 +#define _gather_91_type 1367 +#define _tmp_92_type 1368 +#define _loop0_93_type 1369 +#define _gather_94_type 1370 +#define _loop0_95_type 1371 +#define _gather_96_type 1372 +#define _loop0_97_type 1373 +#define _loop0_98_type 1374 +#define _gather_99_type 1375 +#define _loop1_100_type 1376 +#define _tmp_101_type 1377 +#define _loop0_102_type 1378 +#define _gather_103_type 1379 +#define _loop0_104_type 1380 +#define _gather_105_type 1381 +#define _tmp_106_type 1382 +#define _tmp_107_type 1383 +#define _loop0_108_type 1384 +#define _gather_109_type 1385 +#define _tmp_110_type 1386 +#define _tmp_111_type 1387 +#define _tmp_112_type 1388 +#define _tmp_113_type 1389 +#define _tmp_114_type 1390 +#define _loop1_115_type 1391 +#define _tmp_116_type 1392 +#define _tmp_117_type 1393 +#define _tmp_118_type 1394 +#define _tmp_119_type 1395 +#define _tmp_120_type 1396 +#define _loop0_121_type 1397 +#define _loop0_122_type 1398 +#define _tmp_123_type 1399 +#define _tmp_124_type 1400 +#define _tmp_125_type 1401 +#define _tmp_126_type 1402 +#define _tmp_127_type 1403 +#define _tmp_128_type 1404 +#define _tmp_129_type 1405 +#define _tmp_130_type 1406 +#define _loop0_131_type 1407 +#define _gather_132_type 1408 +#define _tmp_133_type 1409 +#define _tmp_134_type 1410 +#define _tmp_135_type 1411 +#define _tmp_136_type 1412 +#define _loop0_137_type 1413 +#define _gather_138_type 1414 +#define _tmp_139_type 1415 +#define _loop0_140_type 1416 +#define _gather_141_type 1417 +#define _loop0_142_type 1418 +#define _gather_143_type 1419 +#define _tmp_144_type 1420 +#define _loop0_145_type 1421 +#define _tmp_146_type 1422 +#define _tmp_147_type 1423 +#define _tmp_148_type 1424 +#define _tmp_149_type 1425 +#define _tmp_150_type 1426 +#define _tmp_151_type 1427 +#define _tmp_152_type 1428 +#define _tmp_153_type 1429 +#define _tmp_154_type 1430 +#define _tmp_155_type 1431 +#define _tmp_156_type 1432 +#define _tmp_157_type 1433 +#define _tmp_158_type 1434 +#define _tmp_159_type 1435 +#define _tmp_160_type 1436 +#define _tmp_161_type 1437 +#define _tmp_162_type 1438 +#define _tmp_163_type 1439 +#define _tmp_164_type 1440 +#define _tmp_165_type 1441 +#define _tmp_166_type 1442 +#define _tmp_167_type 1443 +#define _tmp_168_type 1444 +#define _tmp_169_type 1445 +#define _tmp_170_type 1446 +#define _tmp_171_type 1447 +#define _tmp_172_type 1448 +#define _tmp_173_type 1449 +#define _loop0_174_type 1450 +#define _tmp_175_type 1451 +#define _tmp_176_type 1452 +#define _tmp_177_type 1453 +#define _tmp_178_type 1454 +#define _tmp_179_type 1455 +#define _tmp_180_type 1456 static mod_ty file_rule(Parser *p); static mod_ty interactive_rule(Parser *p); @@ -783,6 +784,7 @@ static void *invalid_group_rule(Parser *p); static void *invalid_import_rule(Parser *p); static void *invalid_dotted_as_name_rule(Parser *p); static void *invalid_import_from_as_name_rule(Parser *p); +static void *invalid_import_from_rule(Parser *p); static void *invalid_import_from_targets_rule(Parser *p); static void *invalid_with_stmt_rule(Parser *p); static void *invalid_with_stmt_indent_rule(Parser *p); @@ -1964,7 +1966,7 @@ compound_stmt_rule(Parser *p) D(fprintf(stderr, "%*c> compound_stmt[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "&'if' if_stmt")); stmt_ty if_stmt_var; if ( - _PyPegen_lookahead_with_int(1, _PyPegen_expect_token, p, 698) // token='if' + _PyPegen_lookahead_with_int(1, _PyPegen_expect_token, p, 700) // token='if' && (if_stmt_var = if_stmt_rule(p)) // if_stmt ) @@ -2048,7 +2050,7 @@ compound_stmt_rule(Parser *p) D(fprintf(stderr, "%*c> compound_stmt[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "&'try' try_stmt")); stmt_ty try_stmt_var; if ( - _PyPegen_lookahead_with_int(1, _PyPegen_expect_token, p, 672) // token='try' + _PyPegen_lookahead_with_int(1, _PyPegen_expect_token, p, 674) // token='try' && (try_stmt_var = try_stmt_rule(p)) // try_stmt ) @@ -2069,7 +2071,7 @@ compound_stmt_rule(Parser *p) D(fprintf(stderr, "%*c> compound_stmt[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "&'while' while_stmt")); stmt_ty while_stmt_var; if ( - _PyPegen_lookahead_with_int(1, _PyPegen_expect_token, p, 705) // token='while' + _PyPegen_lookahead_with_int(1, _PyPegen_expect_token, p, 707) // token='while' && (while_stmt_var = while_stmt_rule(p)) // while_stmt ) @@ -2836,7 +2838,7 @@ raise_stmt_rule(Parser *p) && (a = expression_rule(p)) // expression && - (_keyword_1 = _PyPegen_expect_token(p, 646)) // token='from' + (_keyword_1 = _PyPegen_expect_token(p, 650)) // token='from' && (b = expression_rule(p)) // expression ) @@ -3615,7 +3617,7 @@ import_name_rule(Parser *p) if ( (lazy = _PyPegen_expect_soft_keyword(p, "lazy"), !p->error_indicator) // "lazy"? && - (_keyword = _PyPegen_expect_token(p, 647)) // token='import' + (_keyword = _PyPegen_expect_token(p, 651)) // token='import' && (a = dotted_as_names_rule(p)) // dotted_as_names ) @@ -3649,6 +3651,7 @@ import_name_rule(Parser *p) } // import_from: +// | invalid_import_from // | "lazy"? 'from' (('.' | '...'))* dotted_name 'import' import_from_targets // | "lazy"? 'from' (('.' | '...'))+ 'import' import_from_targets static stmt_ty @@ -3672,6 +3675,25 @@ import_from_rule(Parser *p) UNUSED(_start_lineno); // Only used by EXTRA macro int _start_col_offset = p->tokens[_mark]->col_offset; UNUSED(_start_col_offset); // Only used by EXTRA macro + if (p->call_invalid_rules) { // invalid_import_from + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> import_from[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "invalid_import_from")); + void *invalid_import_from_var; + if ( + (invalid_import_from_var = invalid_import_from_rule(p)) // invalid_import_from + ) + { + D(fprintf(stderr, "%*c+ import_from[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "invalid_import_from")); + _res = invalid_import_from_var; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s import_from[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "invalid_import_from")); + } { // "lazy"? 'from' (('.' | '...'))* dotted_name 'import' import_from_targets if (p->error_indicator) { p->level--; @@ -3687,13 +3709,13 @@ import_from_rule(Parser *p) if ( (lazy = _PyPegen_expect_soft_keyword(p, "lazy"), !p->error_indicator) // "lazy"? && - (_keyword = _PyPegen_expect_token(p, 646)) // token='from' + (_keyword = _PyPegen_expect_token(p, 650)) // token='from' && (a = _loop0_17_rule(p)) // (('.' | '...'))* && (b = dotted_name_rule(p)) // dotted_name && - (_keyword_1 = _PyPegen_expect_token(p, 647)) // token='import' + (_keyword_1 = _PyPegen_expect_token(p, 651)) // token='import' && (c = import_from_targets_rule(p)) // import_from_targets ) @@ -3708,7 +3730,7 @@ import_from_rule(Parser *p) UNUSED(_end_lineno); // Only used by EXTRA macro int _end_col_offset = _token->end_col_offset; UNUSED(_end_col_offset); // Only used by EXTRA macro - _res = _PyPegen_checked_future_import ( p , b -> v . Name . id , c , _PyPegen_seq_count_dots ( a ) , lazy , EXTRA ); + _res = _PyPegen_checked_from_import ( p , a , b , c , lazy , EXTRA ); if ((_res == NULL || p->error_indicator) && PyErr_Occurred()) { p->error_indicator = 1; p->level--; @@ -3734,11 +3756,11 @@ import_from_rule(Parser *p) if ( (lazy = _PyPegen_expect_soft_keyword(p, "lazy"), !p->error_indicator) // "lazy"? && - (_keyword = _PyPegen_expect_token(p, 646)) // token='from' + (_keyword = _PyPegen_expect_token(p, 650)) // token='from' && (a = _loop1_18_rule(p)) // (('.' | '...'))+ && - (_keyword_1 = _PyPegen_expect_token(p, 647)) // token='import' + (_keyword_1 = _PyPegen_expect_token(p, 651)) // token='import' && (b = import_from_targets_rule(p)) // import_from_targets ) @@ -4525,7 +4547,7 @@ class_def_raw_rule(Parser *p) asdl_stmt_seq* c; void *t; if ( - (_keyword = _PyPegen_expect_token(p, 717)) // token='class' + (_keyword = _PyPegen_expect_token(p, 719)) // token='class' && (a = _PyPegen_name_token(p)) // NAME && @@ -4692,7 +4714,7 @@ function_def_raw_rule(Parser *p) void *t; void *tc; if ( - (_keyword = _PyPegen_expect_token(p, 715)) // token='def' + (_keyword = _PyPegen_expect_token(p, 717)) // token='def' && (n = _PyPegen_name_token(p)) // NAME && @@ -4753,9 +4775,9 @@ function_def_raw_rule(Parser *p) void *t; void *tc; if ( - (_keyword = _PyPegen_expect_token(p, 714)) // token='async' + (_keyword = _PyPegen_expect_token(p, 716)) // token='async' && - (_keyword_1 = _PyPegen_expect_token(p, 715)) // token='def' + (_keyword_1 = _PyPegen_expect_token(p, 717)) // token='def' && (n = _PyPegen_name_token(p)) // NAME && @@ -6093,7 +6115,7 @@ if_stmt_rule(Parser *p) asdl_stmt_seq* b; stmt_ty c; if ( - (_keyword = _PyPegen_expect_token(p, 698)) // token='if' + (_keyword = _PyPegen_expect_token(p, 700)) // token='if' && (a = named_expression_rule(p)) // named_expression && @@ -6138,7 +6160,7 @@ if_stmt_rule(Parser *p) asdl_stmt_seq* b; void *c; if ( - (_keyword = _PyPegen_expect_token(p, 698)) // token='if' + (_keyword = _PyPegen_expect_token(p, 700)) // token='if' && (a = named_expression_rule(p)) // named_expression && @@ -6233,7 +6255,7 @@ elif_stmt_rule(Parser *p) asdl_stmt_seq* b; stmt_ty c; if ( - (_keyword = _PyPegen_expect_token(p, 703)) // token='elif' + (_keyword = _PyPegen_expect_token(p, 705)) // token='elif' && (a = named_expression_rule(p)) // named_expression && @@ -6278,7 +6300,7 @@ elif_stmt_rule(Parser *p) asdl_stmt_seq* b; void *c; if ( - (_keyword = _PyPegen_expect_token(p, 703)) // token='elif' + (_keyword = _PyPegen_expect_token(p, 705)) // token='elif' && (a = named_expression_rule(p)) // named_expression && @@ -6359,7 +6381,7 @@ else_block_rule(Parser *p) Token * _literal; asdl_stmt_seq* b; if ( - (_keyword = _PyPegen_expect_token(p, 702)) // token='else' + (_keyword = _PyPegen_expect_token(p, 704)) // token='else' && (_literal = _PyPegen_expect_forced_token(p, 11, ":")) // forced_token=':' && @@ -6438,7 +6460,7 @@ while_stmt_rule(Parser *p) asdl_stmt_seq* b; void *c; if ( - (_keyword = _PyPegen_expect_token(p, 705)) // token='while' + (_keyword = _PyPegen_expect_token(p, 707)) // token='while' && (a = named_expression_rule(p)) // named_expression && @@ -6538,11 +6560,11 @@ for_stmt_rule(Parser *p) expr_ty t; void *tc; if ( - (_keyword = _PyPegen_expect_token(p, 710)) // token='for' + (_keyword = _PyPegen_expect_token(p, 712)) // token='for' && (t = star_targets_rule(p)) // star_targets && - (_keyword_1 = _PyPegen_expect_token(p, 711)) // token='in' + (_keyword_1 = _PyPegen_expect_token(p, 713)) // token='in' && (_cut_var = 1) && @@ -6600,13 +6622,13 @@ for_stmt_rule(Parser *p) expr_ty t; void *tc; if ( - (_keyword = _PyPegen_expect_token(p, 714)) // token='async' + (_keyword = _PyPegen_expect_token(p, 716)) // token='async' && - (_keyword_1 = _PyPegen_expect_token(p, 710)) // token='for' + (_keyword_1 = _PyPegen_expect_token(p, 712)) // token='for' && (t = star_targets_rule(p)) // star_targets && - (_keyword_2 = _PyPegen_expect_token(p, 711)) // token='in' + (_keyword_2 = _PyPegen_expect_token(p, 713)) // token='in' && (_cut_var = 1) && @@ -6735,7 +6757,7 @@ with_stmt_rule(Parser *p) asdl_stmt_seq* b; void *tc; if ( - (_keyword = _PyPegen_expect_token(p, 663)) // token='with' + (_keyword = _PyPegen_expect_token(p, 665)) // token='with' && (_literal = _PyPegen_expect_token(p, 7)) // token='(' && @@ -6786,7 +6808,7 @@ with_stmt_rule(Parser *p) asdl_stmt_seq* b; void *tc; if ( - (_keyword = _PyPegen_expect_token(p, 663)) // token='with' + (_keyword = _PyPegen_expect_token(p, 665)) // token='with' && (a = (asdl_withitem_seq*)_gather_34_rule(p)) // ','.with_item+ && @@ -6835,9 +6857,9 @@ with_stmt_rule(Parser *p) asdl_withitem_seq* a; asdl_stmt_seq* b; if ( - (_keyword = _PyPegen_expect_token(p, 714)) // token='async' + (_keyword = _PyPegen_expect_token(p, 716)) // token='async' && - (_keyword_1 = _PyPegen_expect_token(p, 663)) // token='with' + (_keyword_1 = _PyPegen_expect_token(p, 665)) // token='with' && (_literal = _PyPegen_expect_token(p, 7)) // token='(' && @@ -6887,9 +6909,9 @@ with_stmt_rule(Parser *p) asdl_stmt_seq* b; void *tc; if ( - (_keyword = _PyPegen_expect_token(p, 714)) // token='async' + (_keyword = _PyPegen_expect_token(p, 716)) // token='async' && - (_keyword_1 = _PyPegen_expect_token(p, 663)) // token='with' + (_keyword_1 = _PyPegen_expect_token(p, 665)) // token='with' && (a = (asdl_withitem_seq*)_gather_34_rule(p)) // ','.with_item+ && @@ -6975,7 +6997,7 @@ with_item_rule(Parser *p) if ( (e = expression_rule(p)) // expression && - (_keyword = _PyPegen_expect_token(p, 696)) // token='as' + (_keyword = _PyPegen_expect_token(p, 698)) // token='as' && (t = star_target_rule(p)) // star_target && @@ -7100,7 +7122,7 @@ try_stmt_rule(Parser *p) asdl_stmt_seq* b; asdl_stmt_seq* f; if ( - (_keyword = _PyPegen_expect_token(p, 672)) // token='try' + (_keyword = _PyPegen_expect_token(p, 674)) // token='try' && (_literal = _PyPegen_expect_forced_token(p, 11, ":")) // forced_token=':' && @@ -7144,7 +7166,7 @@ try_stmt_rule(Parser *p) asdl_excepthandler_seq* ex; void *f; if ( - (_keyword = _PyPegen_expect_token(p, 672)) // token='try' + (_keyword = _PyPegen_expect_token(p, 674)) // token='try' && (_literal = _PyPegen_expect_forced_token(p, 11, ":")) // forced_token=':' && @@ -7192,7 +7214,7 @@ try_stmt_rule(Parser *p) asdl_excepthandler_seq* ex; void *f; if ( - (_keyword = _PyPegen_expect_token(p, 672)) // token='try' + (_keyword = _PyPegen_expect_token(p, 674)) // token='try' && (_literal = _PyPegen_expect_forced_token(p, 11, ":")) // forced_token=':' && @@ -7291,7 +7313,7 @@ except_block_rule(Parser *p) asdl_stmt_seq* b; expr_ty e; if ( - (_keyword = _PyPegen_expect_token(p, 693)) // token='except' + (_keyword = _PyPegen_expect_token(p, 695)) // token='except' && (e = expression_rule(p)) // expression && @@ -7335,11 +7357,11 @@ except_block_rule(Parser *p) expr_ty e; expr_ty t; if ( - (_keyword = _PyPegen_expect_token(p, 693)) // token='except' + (_keyword = _PyPegen_expect_token(p, 695)) // token='except' && (e = expression_rule(p)) // expression && - (_keyword_1 = _PyPegen_expect_token(p, 696)) // token='as' + (_keyword_1 = _PyPegen_expect_token(p, 698)) // token='as' && (t = _PyPegen_name_token(p)) // NAME && @@ -7381,7 +7403,7 @@ except_block_rule(Parser *p) asdl_stmt_seq* b; expr_ty e; if ( - (_keyword = _PyPegen_expect_token(p, 693)) // token='except' + (_keyword = _PyPegen_expect_token(p, 695)) // token='except' && (e = expressions_rule(p)) // expressions && @@ -7422,7 +7444,7 @@ except_block_rule(Parser *p) Token * _literal; asdl_stmt_seq* b; if ( - (_keyword = _PyPegen_expect_token(p, 693)) // token='except' + (_keyword = _PyPegen_expect_token(p, 695)) // token='except' && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && @@ -7534,7 +7556,7 @@ except_star_block_rule(Parser *p) asdl_stmt_seq* b; expr_ty e; if ( - (_keyword = _PyPegen_expect_token(p, 693)) // token='except' + (_keyword = _PyPegen_expect_token(p, 695)) // token='except' && (_literal = _PyPegen_expect_token(p, 16)) // token='*' && @@ -7581,13 +7603,13 @@ except_star_block_rule(Parser *p) expr_ty e; expr_ty t; if ( - (_keyword = _PyPegen_expect_token(p, 693)) // token='except' + (_keyword = _PyPegen_expect_token(p, 695)) // token='except' && (_literal = _PyPegen_expect_token(p, 16)) // token='*' && (e = expression_rule(p)) // expression && - (_keyword_1 = _PyPegen_expect_token(p, 696)) // token='as' + (_keyword_1 = _PyPegen_expect_token(p, 698)) // token='as' && (t = _PyPegen_name_token(p)) // NAME && @@ -7630,7 +7652,7 @@ except_star_block_rule(Parser *p) asdl_stmt_seq* b; expr_ty e; if ( - (_keyword = _PyPegen_expect_token(p, 693)) // token='except' + (_keyword = _PyPegen_expect_token(p, 695)) // token='except' && (_literal = _PyPegen_expect_token(p, 16)) // token='*' && @@ -7730,7 +7752,7 @@ finally_block_rule(Parser *p) Token * _literal; asdl_stmt_seq* a; if ( - (_keyword = _PyPegen_expect_token(p, 689)) // token='finally' + (_keyword = _PyPegen_expect_token(p, 691)) // token='finally' && (_literal = _PyPegen_expect_forced_token(p, 11, ":")) // forced_token=':' && @@ -8038,7 +8060,7 @@ guard_rule(Parser *p) Token * _keyword; expr_ty guard; if ( - (_keyword = _PyPegen_expect_token(p, 698)) // token='if' + (_keyword = _PyPegen_expect_token(p, 700)) // token='if' && (guard = named_expression_rule(p)) // named_expression ) @@ -8233,7 +8255,7 @@ as_pattern_rule(Parser *p) if ( (pattern = or_pattern_rule(p)) // or_pattern && - (_keyword = _PyPegen_expect_token(p, 696)) // token='as' + (_keyword = _PyPegen_expect_token(p, 698)) // token='as' && (target = pattern_capture_target_rule(p)) // pattern_capture_target ) @@ -11728,11 +11750,11 @@ if_expression_rule(Parser *p) if ( (a = disjunction_rule(p)) // disjunction && - (_keyword = _PyPegen_expect_token(p, 698)) // token='if' + (_keyword = _PyPegen_expect_token(p, 700)) // token='if' && (b = disjunction_rule(p)) // disjunction && - (_keyword_1 = _PyPegen_expect_token(p, 702)) // token='else' + (_keyword_1 = _PyPegen_expect_token(p, 704)) // token='else' && (c = expression_rule(p)) // expression ) @@ -11799,7 +11821,7 @@ yield_expr_rule(Parser *p) if ( (_keyword = _PyPegen_expect_token(p, 588)) // token='yield' && - (_keyword_1 = _PyPegen_expect_token(p, 646)) // token='from' + (_keyword_1 = _PyPegen_expect_token(p, 650)) // token='from' && (a = expression_rule(p)) // expression ) @@ -12681,7 +12703,7 @@ inversion_rule(Parser *p) Token * _keyword; expr_ty a; if ( - (_keyword = _PyPegen_expect_token(p, 719)) // token='not' + (_keyword = _PyPegen_expect_token(p, 721)) // token='not' && (a = inversion_rule(p)) // inversion ) @@ -13335,9 +13357,9 @@ notin_bitwise_or_rule(Parser *p) Token * _keyword_1; expr_ty a; if ( - (_keyword = _PyPegen_expect_token(p, 719)) // token='not' + (_keyword = _PyPegen_expect_token(p, 721)) // token='not' && - (_keyword_1 = _PyPegen_expect_token(p, 711)) // token='in' + (_keyword_1 = _PyPegen_expect_token(p, 713)) // token='in' && (a = bitwise_or_rule(p)) // bitwise_or ) @@ -13383,7 +13405,7 @@ in_bitwise_or_rule(Parser *p) Token * _keyword; expr_ty a; if ( - (_keyword = _PyPegen_expect_token(p, 711)) // token='in' + (_keyword = _PyPegen_expect_token(p, 713)) // token='in' && (a = bitwise_or_rule(p)) // bitwise_or ) @@ -13432,7 +13454,7 @@ isnot_bitwise_or_rule(Parser *p) if ( (_keyword = _PyPegen_expect_token(p, 597)) // token='is' && - (_keyword_1 = _PyPegen_expect_token(p, 719)) // token='not' + (_keyword_1 = _PyPegen_expect_token(p, 721)) // token='not' && (a = bitwise_or_rule(p)) // bitwise_or ) @@ -18091,13 +18113,13 @@ for_if_clause_rule(Parser *p) expr_ty b; asdl_expr_seq* c; if ( - (_keyword = _PyPegen_expect_token(p, 714)) // token='async' + (_keyword = _PyPegen_expect_token(p, 716)) // token='async' && - (_keyword_1 = _PyPegen_expect_token(p, 710)) // token='for' + (_keyword_1 = _PyPegen_expect_token(p, 712)) // token='for' && (a = star_targets_rule(p)) // star_targets && - (_keyword_2 = _PyPegen_expect_token(p, 711)) // token='in' + (_keyword_2 = _PyPegen_expect_token(p, 713)) // token='in' && (_cut_var = 1) && @@ -18136,11 +18158,11 @@ for_if_clause_rule(Parser *p) expr_ty b; asdl_expr_seq* c; if ( - (_keyword = _PyPegen_expect_token(p, 710)) // token='for' + (_keyword = _PyPegen_expect_token(p, 712)) // token='for' && (a = star_targets_rule(p)) // star_targets && - (_keyword_1 = _PyPegen_expect_token(p, 711)) // token='in' + (_keyword_1 = _PyPegen_expect_token(p, 713)) // token='in' && (_cut_var = 1) && @@ -21467,11 +21489,11 @@ expression_without_invalid_rule(Parser *p) if ( (a = disjunction_rule(p)) // disjunction && - (_keyword = _PyPegen_expect_token(p, 698)) // token='if' + (_keyword = _PyPegen_expect_token(p, 700)) // token='if' && (b = disjunction_rule(p)) // disjunction && - (_keyword_1 = _PyPegen_expect_token(p, 702)) // token='else' + (_keyword_1 = _PyPegen_expect_token(p, 704)) // token='else' && (c = expression_rule(p)) // expression ) @@ -21771,7 +21793,7 @@ invalid_expression_rule(Parser *p) if ( (a = disjunction_rule(p)) // disjunction && - (_keyword = _PyPegen_expect_token(p, 698)) // token='if' + (_keyword = _PyPegen_expect_token(p, 700)) // token='if' && (b = disjunction_rule(p)) // disjunction && @@ -21804,11 +21826,11 @@ invalid_expression_rule(Parser *p) if ( (a = disjunction_rule(p)) // disjunction && - (_keyword = _PyPegen_expect_token(p, 698)) // token='if' + (_keyword = _PyPegen_expect_token(p, 700)) // token='if' && (b = disjunction_rule(p)) // disjunction && - (_keyword_1 = _PyPegen_expect_token(p, 702)) // token='else' + (_keyword_1 = _PyPegen_expect_token(p, 704)) // token='else' && _PyPegen_lookahead_for_expr(0, expression_rule, p) ) @@ -21840,11 +21862,11 @@ invalid_expression_rule(Parser *p) if ( (a = (stmt_ty)_tmp_118_rule(p)) // pass_stmt | break_stmt | continue_stmt && - (_keyword = _PyPegen_expect_token(p, 698)) // token='if' + (_keyword = _PyPegen_expect_token(p, 700)) // token='if' && (b = disjunction_rule(p)) // disjunction && - (_keyword_1 = _PyPegen_expect_token(p, 702)) // token='else' + (_keyword_1 = _PyPegen_expect_token(p, 704)) // token='else' && (c = simple_stmt_rule(p)) // simple_stmt ) @@ -21963,11 +21985,11 @@ invalid_if_expression_rule(Parser *p) if ( (disjunction_var = disjunction_rule(p)) // disjunction && - (_keyword = _PyPegen_expect_token(p, 698)) // token='if' + (_keyword = _PyPegen_expect_token(p, 700)) // token='if' && (b = disjunction_rule(p)) // disjunction && - (_keyword_1 = _PyPegen_expect_token(p, 702)) // token='else' + (_keyword_1 = _PyPegen_expect_token(p, 704)) // token='else' && (a = _PyPegen_expect_token(p, 16)) // token='*' ) @@ -21999,11 +22021,11 @@ invalid_if_expression_rule(Parser *p) if ( (disjunction_var = disjunction_rule(p)) // disjunction && - (_keyword = _PyPegen_expect_token(p, 698)) // token='if' + (_keyword = _PyPegen_expect_token(p, 700)) // token='if' && (b = disjunction_rule(p)) // disjunction && - (_keyword_1 = _PyPegen_expect_token(p, 702)) // token='else' + (_keyword_1 = _PyPegen_expect_token(p, 704)) // token='else' && (a = _PyPegen_expect_token(p, 35)) // token='**' ) @@ -22472,7 +22494,7 @@ invalid_raise_stmt_rule(Parser *p) if ( (a = _PyPegen_expect_token(p, 632)) // token='raise' && - (b = _PyPegen_expect_token(p, 646)) // token='from' + (b = _PyPegen_expect_token(p, 650)) // token='from' ) { D(fprintf(stderr, "%*c+ invalid_raise_stmt[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'raise' 'from'")); @@ -22502,7 +22524,7 @@ invalid_raise_stmt_rule(Parser *p) && (expression_var = expression_rule(p)) // expression && - (a = _PyPegen_expect_token(p, 646)) // token='from' + (a = _PyPegen_expect_token(p, 650)) // token='from' ) { D(fprintf(stderr, "%*c+ invalid_raise_stmt[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'raise' expression 'from'")); @@ -24131,7 +24153,7 @@ invalid_with_item_rule(Parser *p) if ( (expression_var = expression_rule(p)) // expression && - (_keyword = _PyPegen_expect_token(p, 696)) // token='as' + (_keyword = _PyPegen_expect_token(p, 698)) // token='as' && (a = expression_rule(p)) // expression && @@ -24181,13 +24203,13 @@ invalid_for_if_clause_rule(Parser *p) UNUSED(_opt_var); // Silence compiler warnings void *_tmp_136_var; if ( - (_opt_var = _PyPegen_expect_token(p, 714), !p->error_indicator) // 'async'? + (_opt_var = _PyPegen_expect_token(p, 716), !p->error_indicator) // 'async'? && - (_keyword = _PyPegen_expect_token(p, 710)) // token='for' + (_keyword = _PyPegen_expect_token(p, 712)) // token='for' && (_tmp_136_var = _tmp_136_rule(p)) // bitwise_or ((',' bitwise_or))* ','? && - _PyPegen_lookahead_with_int(0, _PyPegen_expect_token, p, 711) // token='in' + _PyPegen_lookahead_with_int(0, _PyPegen_expect_token, p, 713) // token='in' ) { D(fprintf(stderr, "%*c+ invalid_for_if_clause[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'async'? 'for' (bitwise_or ((',' bitwise_or))* ','?) !'in'")); @@ -24233,9 +24255,9 @@ invalid_for_target_rule(Parser *p) UNUSED(_opt_var); // Silence compiler warnings expr_ty a; if ( - (_opt_var = _PyPegen_expect_token(p, 714), !p->error_indicator) // 'async'? + (_opt_var = _PyPegen_expect_token(p, 716), !p->error_indicator) // 'async'? && - (_keyword = _PyPegen_expect_token(p, 710)) // token='for' + (_keyword = _PyPegen_expect_token(p, 712)) // token='for' && (a = star_expressions_rule(p)) // star_expressions ) @@ -24365,11 +24387,11 @@ invalid_import_rule(Parser *p) Token * a; expr_ty dotted_name_var; if ( - (a = _PyPegen_expect_token(p, 647)) // token='import' + (a = _PyPegen_expect_token(p, 651)) // token='import' && (_gather_138_var = _gather_138_rule(p)) // ','.dotted_name+ && - (_keyword = _PyPegen_expect_token(p, 646)) // token='from' + (_keyword = _PyPegen_expect_token(p, 650)) // token='from' && (dotted_name_var = dotted_name_rule(p)) // dotted_name ) @@ -24396,7 +24418,7 @@ invalid_import_rule(Parser *p) Token * _keyword; Token * token; if ( - (_keyword = _PyPegen_expect_token(p, 647)) // token='import' + (_keyword = _PyPegen_expect_token(p, 651)) // token='import' && (token = _PyPegen_expect_token(p, NEWLINE)) // token='NEWLINE' ) @@ -24445,7 +24467,7 @@ invalid_dotted_as_name_rule(Parser *p) if ( (dotted_name_var = dotted_name_rule(p)) // dotted_name && - (_keyword = _PyPegen_expect_token(p, 696)) // token='as' + (_keyword = _PyPegen_expect_token(p, 698)) // token='as' && _PyPegen_lookahead(0, _tmp_139_rule, p) && @@ -24496,7 +24518,7 @@ invalid_import_from_as_name_rule(Parser *p) if ( (name_var = _PyPegen_name_token(p)) // NAME && - (_keyword = _PyPegen_expect_token(p, 696)) // token='as' + (_keyword = _PyPegen_expect_token(p, 698)) // token='as' && _PyPegen_lookahead(0, _tmp_139_rule, p) && @@ -24522,6 +24544,65 @@ invalid_import_from_as_name_rule(Parser *p) return _res; } +// invalid_import_from: +// | 'from' (('.' | '...'))* dotted_name "lazy" 'import' import_from_targets +static void * +invalid_import_from_rule(Parser *p) +{ + if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { + _Pypegen_stack_overflow(p); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + void * _res = NULL; + int _mark = p->mark; + { // 'from' (('.' | '...'))* dotted_name "lazy" 'import' import_from_targets + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> invalid_import_from[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'from' (('.' | '...'))* dotted_name \"lazy\" 'import' import_from_targets")); + Token * _keyword; + Token * _keyword_1; + asdl_seq * _loop0_17_var; + expr_ty a; + expr_ty dotted_name_var; + asdl_alias_seq* import_from_targets_var; + if ( + (_keyword = _PyPegen_expect_token(p, 650)) // token='from' + && + (_loop0_17_var = _loop0_17_rule(p)) // (('.' | '...'))* + && + (dotted_name_var = dotted_name_rule(p)) // dotted_name + && + (a = _PyPegen_expect_soft_keyword(p, "lazy")) // soft_keyword='"lazy"' + && + (_keyword_1 = _PyPegen_expect_token(p, 651)) // token='import' + && + (import_from_targets_var = import_from_targets_rule(p)) // import_from_targets + ) + { + D(fprintf(stderr, "%*c+ invalid_import_from[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'from' (('.' | '...'))* dotted_name \"lazy\" 'import' import_from_targets")); + _res = RAISE_SYNTAX_ERROR_KNOWN_LOCATION ( a , "use 'lazy from ... ' instead of 'from ... lazy import'" ); + if ((_res == NULL || p->error_indicator) && PyErr_Occurred()) { + p->error_indicator = 1; + p->level--; + return NULL; + } + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s invalid_import_from[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'from' (('.' | '...'))* dotted_name \"lazy\" 'import' import_from_targets")); + } + _res = NULL; + done: + p->level--; + return _res; +} + // invalid_import_from_targets: import_from_as_names ',' NEWLINE | NEWLINE static void * invalid_import_from_targets_rule(Parser *p) @@ -24624,9 +24705,9 @@ invalid_with_stmt_rule(Parser *p) UNUSED(_opt_var); // Silence compiler warnings Token * trailing; if ( - (_opt_var = _PyPegen_expect_token(p, 714), !p->error_indicator) // 'async'? + (_opt_var = _PyPegen_expect_token(p, 716), !p->error_indicator) // 'async'? && - (_keyword = _PyPegen_expect_token(p, 663)) // token='with' + (_keyword = _PyPegen_expect_token(p, 665)) // token='with' && (_gather_141_var = _gather_141_rule(p)) // ','.(expression ['as' star_target])+ && @@ -24660,9 +24741,9 @@ invalid_with_stmt_rule(Parser *p) UNUSED(_opt_var); // Silence compiler warnings Token * newline_var; if ( - (_opt_var = _PyPegen_expect_token(p, 714), !p->error_indicator) // 'async'? + (_opt_var = _PyPegen_expect_token(p, 716), !p->error_indicator) // 'async'? && - (_keyword = _PyPegen_expect_token(p, 663)) // token='with' + (_keyword = _PyPegen_expect_token(p, 665)) // token='with' && (_gather_141_var = _gather_141_rule(p)) // ','.(expression ['as' star_target])+ && @@ -24698,9 +24779,9 @@ invalid_with_stmt_rule(Parser *p) UNUSED(_opt_var_1); // Silence compiler warnings Token * newline_var; if ( - (_opt_var = _PyPegen_expect_token(p, 714), !p->error_indicator) // 'async'? + (_opt_var = _PyPegen_expect_token(p, 716), !p->error_indicator) // 'async'? && - (_keyword = _PyPegen_expect_token(p, 663)) // token='with' + (_keyword = _PyPegen_expect_token(p, 665)) // token='with' && (_literal = _PyPegen_expect_token(p, 7)) // token='(' && @@ -24760,9 +24841,9 @@ invalid_with_stmt_indent_rule(Parser *p) Token * a; Token * newline_var; if ( - (_opt_var = _PyPegen_expect_token(p, 714), !p->error_indicator) // 'async'? + (_opt_var = _PyPegen_expect_token(p, 716), !p->error_indicator) // 'async'? && - (a = _PyPegen_expect_token(p, 663)) // token='with' + (a = _PyPegen_expect_token(p, 665)) // token='with' && (_gather_141_var = _gather_141_rule(p)) // ','.(expression ['as' star_target])+ && @@ -24803,9 +24884,9 @@ invalid_with_stmt_indent_rule(Parser *p) Token * a; Token * newline_var; if ( - (_opt_var = _PyPegen_expect_token(p, 714), !p->error_indicator) // 'async'? + (_opt_var = _PyPegen_expect_token(p, 716), !p->error_indicator) // 'async'? && - (a = _PyPegen_expect_token(p, 663)) // token='with' + (a = _PyPegen_expect_token(p, 665)) // token='with' && (_literal = _PyPegen_expect_token(p, 7)) // token='(' && @@ -24868,7 +24949,7 @@ invalid_try_stmt_rule(Parser *p) Token * a; Token * newline_var; if ( - (a = _PyPegen_expect_token(p, 672)) // token='try' + (a = _PyPegen_expect_token(p, 674)) // token='try' && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && @@ -24900,7 +24981,7 @@ invalid_try_stmt_rule(Parser *p) Token * _literal; asdl_stmt_seq* block_var; if ( - (_keyword = _PyPegen_expect_token(p, 672)) // token='try' + (_keyword = _PyPegen_expect_token(p, 674)) // token='try' && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && @@ -24939,7 +25020,7 @@ invalid_try_stmt_rule(Parser *p) Token * b; expr_ty expression_var; if ( - (_keyword = _PyPegen_expect_token(p, 672)) // token='try' + (_keyword = _PyPegen_expect_token(p, 674)) // token='try' && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && @@ -24947,7 +25028,7 @@ invalid_try_stmt_rule(Parser *p) && (_loop1_36_var = _loop1_36_rule(p)) // except_block+ && - (a = _PyPegen_expect_token(p, 693)) // token='except' + (a = _PyPegen_expect_token(p, 695)) // token='except' && (b = _PyPegen_expect_token(p, 16)) // token='*' && @@ -24986,7 +25067,7 @@ invalid_try_stmt_rule(Parser *p) UNUSED(_opt_var); // Silence compiler warnings Token * a; if ( - (_keyword = _PyPegen_expect_token(p, 672)) // token='try' + (_keyword = _PyPegen_expect_token(p, 674)) // token='try' && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && @@ -24994,7 +25075,7 @@ invalid_try_stmt_rule(Parser *p) && (_loop1_37_var = _loop1_37_rule(p)) // except_star_block+ && - (a = _PyPegen_expect_token(p, 693)) // token='except' + (a = _PyPegen_expect_token(p, 695)) // token='except' && (_opt_var = _tmp_146_rule(p), !p->error_indicator) // [expression ['as' NAME]] && @@ -25051,7 +25132,7 @@ invalid_except_stmt_rule(Parser *p) expr_ty expressions_var; expr_ty name_var; if ( - (_keyword = _PyPegen_expect_token(p, 693)) // token='except' + (_keyword = _PyPegen_expect_token(p, 695)) // token='except' && (a = expression_rule(p)) // expression && @@ -25059,7 +25140,7 @@ invalid_except_stmt_rule(Parser *p) && (expressions_var = expressions_rule(p)) // expressions && - (_keyword_1 = _PyPegen_expect_token(p, 696)) // token='as' + (_keyword_1 = _PyPegen_expect_token(p, 698)) // token='as' && (name_var = _PyPegen_name_token(p)) // NAME && @@ -25091,7 +25172,7 @@ invalid_except_stmt_rule(Parser *p) expr_ty expression_var; Token * newline_var; if ( - (a = _PyPegen_expect_token(p, 693)) // token='except' + (a = _PyPegen_expect_token(p, 695)) // token='except' && (expression_var = expression_rule(p)) // expression && @@ -25122,7 +25203,7 @@ invalid_except_stmt_rule(Parser *p) Token * a; Token * newline_var; if ( - (a = _PyPegen_expect_token(p, 693)) // token='except' + (a = _PyPegen_expect_token(p, 695)) // token='except' && (newline_var = _PyPegen_expect_token(p, NEWLINE)) // token='NEWLINE' ) @@ -25153,11 +25234,11 @@ invalid_except_stmt_rule(Parser *p) asdl_stmt_seq* block_var; expr_ty expression_var; if ( - (_keyword = _PyPegen_expect_token(p, 693)) // token='except' + (_keyword = _PyPegen_expect_token(p, 695)) // token='except' && (expression_var = expression_rule(p)) // expression && - (_keyword_1 = _PyPegen_expect_token(p, 696)) // token='as' + (_keyword_1 = _PyPegen_expect_token(p, 698)) // token='as' && (a = expression_rule(p)) // expression && @@ -25217,7 +25298,7 @@ invalid_except_star_stmt_rule(Parser *p) expr_ty expressions_var; expr_ty name_var; if ( - (_keyword = _PyPegen_expect_token(p, 693)) // token='except' + (_keyword = _PyPegen_expect_token(p, 695)) // token='except' && (_literal = _PyPegen_expect_token(p, 16)) // token='*' && @@ -25227,7 +25308,7 @@ invalid_except_star_stmt_rule(Parser *p) && (expressions_var = expressions_rule(p)) // expressions && - (_keyword_1 = _PyPegen_expect_token(p, 696)) // token='as' + (_keyword_1 = _PyPegen_expect_token(p, 698)) // token='as' && (name_var = _PyPegen_name_token(p)) // NAME && @@ -25260,7 +25341,7 @@ invalid_except_star_stmt_rule(Parser *p) expr_ty expression_var; Token * newline_var; if ( - (a = _PyPegen_expect_token(p, 693)) // token='except' + (a = _PyPegen_expect_token(p, 695)) // token='except' && (_literal = _PyPegen_expect_token(p, 16)) // token='*' && @@ -25294,7 +25375,7 @@ invalid_except_star_stmt_rule(Parser *p) void *_tmp_147_var; Token * a; if ( - (a = _PyPegen_expect_token(p, 693)) // token='except' + (a = _PyPegen_expect_token(p, 695)) // token='except' && (_literal = _PyPegen_expect_token(p, 16)) // token='*' && @@ -25328,13 +25409,13 @@ invalid_except_star_stmt_rule(Parser *p) asdl_stmt_seq* block_var; expr_ty expression_var; if ( - (_keyword = _PyPegen_expect_token(p, 693)) // token='except' + (_keyword = _PyPegen_expect_token(p, 695)) // token='except' && (_literal = _PyPegen_expect_token(p, 16)) // token='*' && (expression_var = expression_rule(p)) // expression && - (_keyword_1 = _PyPegen_expect_token(p, 696)) // token='as' + (_keyword_1 = _PyPegen_expect_token(p, 698)) // token='as' && (a = expression_rule(p)) // expression && @@ -25385,7 +25466,7 @@ invalid_finally_stmt_rule(Parser *p) Token * a; Token * newline_var; if ( - (a = _PyPegen_expect_token(p, 689)) // token='finally' + (a = _PyPegen_expect_token(p, 691)) // token='finally' && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && @@ -25441,7 +25522,7 @@ invalid_except_stmt_indent_rule(Parser *p) expr_ty expression_var; Token * newline_var; if ( - (a = _PyPegen_expect_token(p, 693)) // token='except' + (a = _PyPegen_expect_token(p, 695)) // token='except' && (expression_var = expression_rule(p)) // expression && @@ -25477,7 +25558,7 @@ invalid_except_stmt_indent_rule(Parser *p) Token * a; Token * newline_var; if ( - (a = _PyPegen_expect_token(p, 693)) // token='except' + (a = _PyPegen_expect_token(p, 695)) // token='except' && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && @@ -25533,7 +25614,7 @@ invalid_except_star_stmt_indent_rule(Parser *p) expr_ty expression_var; Token * newline_var; if ( - (a = _PyPegen_expect_token(p, 693)) // token='except' + (a = _PyPegen_expect_token(p, 695)) // token='except' && (_literal = _PyPegen_expect_token(p, 16)) // token='*' && @@ -25810,7 +25891,7 @@ invalid_as_pattern_rule(Parser *p) if ( (or_pattern_var = or_pattern_rule(p)) // or_pattern && - (_keyword = _PyPegen_expect_token(p, 696)) // token='as' + (_keyword = _PyPegen_expect_token(p, 698)) // token='as' && (a = _PyPegen_expect_soft_keyword(p, "_")) // soft_keyword='"_"' ) @@ -25840,7 +25921,7 @@ invalid_as_pattern_rule(Parser *p) if ( (or_pattern_var = or_pattern_rule(p)) // or_pattern && - (_keyword = _PyPegen_expect_token(p, 696)) // token='as' + (_keyword = _PyPegen_expect_token(p, 698)) // token='as' && (a = expression_rule(p)) // expression ) @@ -26056,7 +26137,7 @@ invalid_if_stmt_rule(Parser *p) expr_ty named_expression_var; Token * newline_var; if ( - (_keyword = _PyPegen_expect_token(p, 698)) // token='if' + (_keyword = _PyPegen_expect_token(p, 700)) // token='if' && (named_expression_var = named_expression_rule(p)) // named_expression && @@ -26087,7 +26168,7 @@ invalid_if_stmt_rule(Parser *p) expr_ty a_1; Token * newline_var; if ( - (a = _PyPegen_expect_token(p, 698)) // token='if' + (a = _PyPegen_expect_token(p, 700)) // token='if' && (a_1 = named_expression_rule(p)) // named_expression && @@ -26142,7 +26223,7 @@ invalid_elif_stmt_rule(Parser *p) expr_ty named_expression_var; Token * newline_var; if ( - (_keyword = _PyPegen_expect_token(p, 703)) // token='elif' + (_keyword = _PyPegen_expect_token(p, 705)) // token='elif' && (named_expression_var = named_expression_rule(p)) // named_expression && @@ -26173,7 +26254,7 @@ invalid_elif_stmt_rule(Parser *p) expr_ty named_expression_var; Token * newline_var; if ( - (a = _PyPegen_expect_token(p, 703)) // token='elif' + (a = _PyPegen_expect_token(p, 705)) // token='elif' && (named_expression_var = named_expression_rule(p)) // named_expression && @@ -26226,7 +26307,7 @@ invalid_else_stmt_rule(Parser *p) Token * a; Token * newline_var; if ( - (a = _PyPegen_expect_token(p, 702)) // token='else' + (a = _PyPegen_expect_token(p, 704)) // token='else' && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && @@ -26259,13 +26340,13 @@ invalid_else_stmt_rule(Parser *p) Token * _literal; asdl_stmt_seq* block_var; if ( - (_keyword = _PyPegen_expect_token(p, 702)) // token='else' + (_keyword = _PyPegen_expect_token(p, 704)) // token='else' && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && (block_var = block_rule(p)) // block && - (_keyword_1 = _PyPegen_expect_token(p, 703)) // token='elif' + (_keyword_1 = _PyPegen_expect_token(p, 705)) // token='elif' ) { D(fprintf(stderr, "%*c+ invalid_else_stmt[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'else' ':' block 'elif'")); @@ -26312,7 +26393,7 @@ invalid_while_stmt_rule(Parser *p) expr_ty named_expression_var; Token * newline_var; if ( - (_keyword = _PyPegen_expect_token(p, 705)) // token='while' + (_keyword = _PyPegen_expect_token(p, 707)) // token='while' && (named_expression_var = named_expression_rule(p)) // named_expression && @@ -26343,7 +26424,7 @@ invalid_while_stmt_rule(Parser *p) expr_ty named_expression_var; Token * newline_var; if ( - (a = _PyPegen_expect_token(p, 705)) // token='while' + (a = _PyPegen_expect_token(p, 707)) // token='while' && (named_expression_var = named_expression_rule(p)) // named_expression && @@ -26402,13 +26483,13 @@ invalid_for_stmt_rule(Parser *p) expr_ty star_expressions_var; expr_ty star_targets_var; if ( - (_opt_var = _PyPegen_expect_token(p, 714), !p->error_indicator) // 'async'? + (_opt_var = _PyPegen_expect_token(p, 716), !p->error_indicator) // 'async'? && - (_keyword = _PyPegen_expect_token(p, 710)) // token='for' + (_keyword = _PyPegen_expect_token(p, 712)) // token='for' && (star_targets_var = star_targets_rule(p)) // star_targets && - (_keyword_1 = _PyPegen_expect_token(p, 711)) // token='in' + (_keyword_1 = _PyPegen_expect_token(p, 713)) // token='in' && (star_expressions_var = star_expressions_rule(p)) // star_expressions && @@ -26443,13 +26524,13 @@ invalid_for_stmt_rule(Parser *p) expr_ty star_expressions_var; expr_ty star_targets_var; if ( - (_opt_var = _PyPegen_expect_token(p, 714), !p->error_indicator) // 'async'? + (_opt_var = _PyPegen_expect_token(p, 716), !p->error_indicator) // 'async'? && - (a = _PyPegen_expect_token(p, 710)) // token='for' + (a = _PyPegen_expect_token(p, 712)) // token='for' && (star_targets_var = star_targets_rule(p)) // star_targets && - (_keyword = _PyPegen_expect_token(p, 711)) // token='in' + (_keyword = _PyPegen_expect_token(p, 713)) // token='in' && (star_expressions_var = star_expressions_rule(p)) // star_expressions && @@ -26515,9 +26596,9 @@ invalid_def_raw_rule(Parser *p) expr_ty name_var; Token * newline_var; if ( - (_opt_var = _PyPegen_expect_token(p, 714), !p->error_indicator) // 'async'? + (_opt_var = _PyPegen_expect_token(p, 716), !p->error_indicator) // 'async'? && - (a = _PyPegen_expect_token(p, 715)) // token='def' + (a = _PyPegen_expect_token(p, 717)) // token='def' && (name_var = _PyPegen_name_token(p)) // NAME && @@ -26574,9 +26655,9 @@ invalid_def_raw_rule(Parser *p) asdl_stmt_seq* block_var; expr_ty name_var; if ( - (_opt_var = _PyPegen_expect_token(p, 714), !p->error_indicator) // 'async'? + (_opt_var = _PyPegen_expect_token(p, 716), !p->error_indicator) // 'async'? && - (_keyword = _PyPegen_expect_token(p, 715)) // token='def' + (_keyword = _PyPegen_expect_token(p, 717)) // token='def' && (name_var = _PyPegen_name_token(p)) // NAME && @@ -26640,7 +26721,7 @@ invalid_class_def_raw_rule(Parser *p) expr_ty name_var; Token * newline_var; if ( - (_keyword = _PyPegen_expect_token(p, 717)) // token='class' + (_keyword = _PyPegen_expect_token(p, 719)) // token='class' && (name_var = _PyPegen_name_token(p)) // NAME && @@ -26679,7 +26760,7 @@ invalid_class_def_raw_rule(Parser *p) expr_ty name_var; Token * newline_var; if ( - (a = _PyPegen_expect_token(p, 717)) // token='class' + (a = _PyPegen_expect_token(p, 719)) // token='class' && (name_var = _PyPegen_name_token(p)) // NAME && @@ -28315,7 +28396,7 @@ invalid_arithmetic_rule(Parser *p) && (_tmp_157_var = _tmp_157_rule(p)) // '+' | '-' | '*' | '/' | '%' | '//' | '@' && - (a = _PyPegen_expect_token(p, 719)) // token='not' + (a = _PyPegen_expect_token(p, 721)) // token='not' && (b = inversion_rule(p)) // inversion ) @@ -28364,7 +28445,7 @@ invalid_factor_rule(Parser *p) if ( (_tmp_158_var = _tmp_158_rule(p)) // '+' | '-' | '~' && - (a = _PyPegen_expect_token(p, 719)) // token='not' + (a = _PyPegen_expect_token(p, 721)) // token='not' && (b = factor_rule(p)) // factor ) @@ -28711,7 +28792,7 @@ _tmp_5_rule(Parser *p) D(fprintf(stderr, "%*c> _tmp_5[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'import'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 647)) // token='import' + (_keyword = _PyPegen_expect_token(p, 651)) // token='import' ) { D(fprintf(stderr, "%*c+ _tmp_5[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'import'")); @@ -28730,7 +28811,7 @@ _tmp_5_rule(Parser *p) D(fprintf(stderr, "%*c> _tmp_5[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'from'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 646)) // token='from' + (_keyword = _PyPegen_expect_token(p, 650)) // token='from' ) { D(fprintf(stderr, "%*c+ _tmp_5[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'from'")); @@ -28787,7 +28868,7 @@ _tmp_6_rule(Parser *p) D(fprintf(stderr, "%*c> _tmp_6[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'def'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 715)) // token='def' + (_keyword = _PyPegen_expect_token(p, 717)) // token='def' ) { D(fprintf(stderr, "%*c+ _tmp_6[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'def'")); @@ -28825,7 +28906,7 @@ _tmp_6_rule(Parser *p) D(fprintf(stderr, "%*c> _tmp_6[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'async'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 714)) // token='async' + (_keyword = _PyPegen_expect_token(p, 716)) // token='async' ) { D(fprintf(stderr, "%*c+ _tmp_6[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'async'")); @@ -28863,7 +28944,7 @@ _tmp_7_rule(Parser *p) D(fprintf(stderr, "%*c> _tmp_7[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'class'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 717)) // token='class' + (_keyword = _PyPegen_expect_token(p, 719)) // token='class' ) { D(fprintf(stderr, "%*c+ _tmp_7[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'class'")); @@ -28920,7 +29001,7 @@ _tmp_8_rule(Parser *p) D(fprintf(stderr, "%*c> _tmp_8[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'with'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 663)) // token='with' + (_keyword = _PyPegen_expect_token(p, 665)) // token='with' ) { D(fprintf(stderr, "%*c+ _tmp_8[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'with'")); @@ -28939,7 +29020,7 @@ _tmp_8_rule(Parser *p) D(fprintf(stderr, "%*c> _tmp_8[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'async'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 714)) // token='async' + (_keyword = _PyPegen_expect_token(p, 716)) // token='async' ) { D(fprintf(stderr, "%*c+ _tmp_8[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'async'")); @@ -28977,7 +29058,7 @@ _tmp_9_rule(Parser *p) D(fprintf(stderr, "%*c> _tmp_9[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'for'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 710)) // token='for' + (_keyword = _PyPegen_expect_token(p, 712)) // token='for' ) { D(fprintf(stderr, "%*c+ _tmp_9[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'for'")); @@ -28996,7 +29077,7 @@ _tmp_9_rule(Parser *p) D(fprintf(stderr, "%*c> _tmp_9[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'async'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 714)) // token='async' + (_keyword = _PyPegen_expect_token(p, 716)) // token='async' ) { D(fprintf(stderr, "%*c+ _tmp_9[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'async'")); @@ -29697,7 +29778,7 @@ _tmp_21_rule(Parser *p) Token * _keyword; expr_ty z; if ( - (_keyword = _PyPegen_expect_token(p, 696)) // token='as' + (_keyword = _PyPegen_expect_token(p, 698)) // token='as' && (z = _PyPegen_name_token(p)) // NAME ) @@ -35669,7 +35750,7 @@ _tmp_117_rule(Parser *p) D(fprintf(stderr, "%*c> _tmp_117[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'else'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 702)) // token='else' + (_keyword = _PyPegen_expect_token(p, 704)) // token='else' ) { D(fprintf(stderr, "%*c+ _tmp_117[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'else'")); @@ -37332,7 +37413,7 @@ _tmp_144_rule(Parser *p) D(fprintf(stderr, "%*c> _tmp_144[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'except'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 693)) // token='except' + (_keyword = _PyPegen_expect_token(p, 695)) // token='except' ) { D(fprintf(stderr, "%*c+ _tmp_144[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'except'")); @@ -37351,7 +37432,7 @@ _tmp_144_rule(Parser *p) D(fprintf(stderr, "%*c> _tmp_144[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'finally'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 689)) // token='finally' + (_keyword = _PyPegen_expect_token(p, 691)) // token='finally' ) { D(fprintf(stderr, "%*c+ _tmp_144[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'finally'")); @@ -38653,7 +38734,7 @@ _tmp_166_rule(Parser *p) Token * _keyword; expr_ty z; if ( - (_keyword = _PyPegen_expect_token(p, 698)) // token='if' + (_keyword = _PyPegen_expect_token(p, 700)) // token='if' && (z = disjunction_rule(p)) // disjunction ) @@ -39389,7 +39470,7 @@ _tmp_180_rule(Parser *p) Token * _keyword; expr_ty star_target_var; if ( - (_keyword = _PyPegen_expect_token(p, 696)) // token='as' + (_keyword = _PyPegen_expect_token(p, 698)) // token='as' && (star_target_var = star_target_rule(p)) // star_target ) diff --git a/Parser/pegen.h b/Parser/pegen.h index 5c461e82a7f0fa..2b9b1fed8452c8 100644 --- a/Parser/pegen.h +++ b/Parser/pegen.h @@ -365,8 +365,10 @@ mod_ty _PyPegen_make_module(Parser *, asdl_stmt_seq *); void *_PyPegen_arguments_parsing_error(Parser *, expr_ty); expr_ty _PyPegen_get_last_comprehension_item(comprehension_ty comprehension); void *_PyPegen_nonparen_genexp_in_call(Parser *p, expr_ty args, asdl_comprehension_seq *comprehensions); -stmt_ty _PyPegen_checked_future_import(Parser *p, identifier module, asdl_alias_seq *, - int, expr_ty, int, int, int, int, PyArena *); +stmt_ty _PyPegen_checked_from_import(Parser *p, asdl_seq *dots, expr_ty module_name, + asdl_alias_seq *names, expr_ty lazy_token, int lineno, + int col_offset, int end_lineno, int end_col_offset, + PyArena *arena); asdl_stmt_seq* _PyPegen_register_stmts(Parser *p, asdl_stmt_seq* stmts); stmt_ty _PyPegen_register_stmt(Parser *p, stmt_ty s); From 88baea812edb8af03bca41b1bdf7cc9ed704dba8 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 5 Jul 2026 13:07:29 +0200 Subject: [PATCH 580/818] [3.15] Fix various typos in the `http.server` docs (GH-153089) (#153096) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (cherry picked from commit 99b4cdbfa1619a3901f8cf87d3b5fe8d4894e3e7) Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com> --- Doc/library/http.server.rst | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/Doc/library/http.server.rst b/Doc/library/http.server.rst index 9c2ce2dffb185e..0d427db19c0fcd 100644 --- a/Doc/library/http.server.rst +++ b/Doc/library/http.server.rst @@ -70,7 +70,7 @@ handler. Code to create and run the server looks like this:: object fails with a :exc:`RuntimeError`. The *certfile* argument is the path to the SSL certificate chain file, - and the *keyfile* is the path to file containing the private key. + and the *keyfile* is the path to the file containing the private key. A *password* can be specified for files protected and wrapped with PKCS#8, but beware that this could possibly expose hardcoded passwords in clear. @@ -150,7 +150,7 @@ instantiation, of which this module provides three different variants: .. attribute:: path - Contains the request path. If query component of the URL is present, + Contains the request path. If the query component of the URL is present, then ``path`` includes the query. Using the terminology of :rfc:`3986`, ``path`` here includes ``hier-part`` and the ``query``. @@ -200,7 +200,7 @@ instantiation, of which this module provides three different variants: Specifies a format string that should be used by :meth:`send_error` method for building an error response to the client. The string is filled by default with variables from :attr:`responses` based on the status code - that passed to :meth:`send_error`. + passed to :meth:`send_error`. .. attribute:: error_content_type @@ -248,8 +248,8 @@ instantiation, of which this module provides three different variants: .. method:: handle_expect_100() When an HTTP/1.1 conformant server receives an ``Expect: 100-continue`` - request header it responds back with a ``100 Continue`` followed by ``200 - OK`` headers. + request header it responds with a ``100 Continue`` followed by ``200 OK`` + headers. This method can be overridden to raise an error if the server does not want the client to continue. For example, the server can choose to send ``417 Expectation Failed`` as a response header and ``return False``. @@ -305,8 +305,8 @@ instantiation, of which this module provides three different variants: .. method:: send_response_only(code, message=None) Sends the response header only, used for the purposes when ``100 - Continue`` response is sent by the server to the client. The headers not - buffered and sent directly the output stream.If the *message* is not + Continue`` response is sent by the server to the client. The headers are + not buffered and sent directly the output stream. If the *message* is not specified, the HTTP message corresponding the response *code* is sent. This method does not reject *message* containing CRLF sequences. @@ -348,7 +348,7 @@ instantiation, of which this module provides three different variants: to create custom error logging mechanisms. The *format* argument is a standard printf-style format string, where the additional arguments to :meth:`log_message` are applied as inputs to the formatting. The client - ip address and current date and time are prefixed to every message logged. + IP address and current date and time are prefixed to every message logged. .. method:: version_string() @@ -452,7 +452,7 @@ instantiation, of which this module provides three different variants: The request is mapped to a local file by interpreting the request as a path relative to the current working directory. - If the request was mapped to a directory, the directory is checked for a + If the request was mapped to a directory, the directory is checked for an index page as specified by :attr:`index_pages`. If found, the file's contents are returned; otherwise a directory listing is generated by calling the :meth:`list_directory` method. This method uses @@ -507,9 +507,8 @@ instantiation, of which this module provides three different variants: Add :func:`mimetypes.guess_file_type` as a fallback. -The :class:`SimpleHTTPRequestHandler` class can be used in the following -manner in order to create a very basic webserver serving files relative to -the current directory:: +The :class:`SimpleHTTPRequestHandler` class can be used to create a very basic +webserver serving files relative to the current directory as follows:: import http.server import socketserver @@ -641,8 +640,8 @@ The following options are accepted: .. option:: -H, --header <header> <value> - Specify an additional extra HTTP Response Header to send on successful HTTP - 200 responses. Can be used multiple times to send additional custom response + Specify an additional HTTP Response Header to send on successful HTTP 200 + responses. Can be used multiple times to send additional custom response headers. Headers that are sent automatically by the server (for instance Content-Type) will not be overwritten by the server. @@ -657,13 +656,13 @@ Security considerations .. index:: pair: http.server; security :class:`SimpleHTTPRequestHandler` will follow symbolic links when handling -requests, this makes it possible for files outside of the specified directory +requests which makes it possible for files outside of the specified directory to be served. Methods :meth:`BaseHTTPRequestHandler.send_header` and :meth:`BaseHTTPRequestHandler.send_response_only` assume sanitized input and do not perform input validation such as checking for the presence of CRLF -sequences. Untrusted input may result in HTTP Header injection attacks. +sequences. Untrusted input may result in HTTP header injection attacks. Earlier versions of Python did not scrub control characters from the log messages emitted to stderr from ``python -m http.server`` or the From 67d782c6bc76578a1ed28e82953a9013bc6226bd Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 5 Jul 2026 13:15:42 +0200 Subject: [PATCH 581/818] [3.15] gh-75952: Document negative offsets in tkinter geometry strings (GH-152531) (GH-153101) Tk geometry strings can contain a negative offset (e.g. 200x100+-9+-8) when a window edge is positioned beyond the corresponding screen edge. Note this in the geometry() and winfo_geometry() documentation. (cherry picked from commit 19b5e8e1f510eb2fdd3f6261006b61f8cf441101) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --- Doc/library/tkinter.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Doc/library/tkinter.rst b/Doc/library/tkinter.rst index 4687057788d5c3..17ea03d0de4d57 100644 --- a/Doc/library/tkinter.rst +++ b/Doc/library/tkinter.rst @@ -2020,6 +2020,7 @@ Base and mixin classes Return the geometry of the widget, in the form ``widthxheight+x+y``. All dimensions are in pixels. + An offset can be negative; see :meth:`~Wm.geometry`. .. method:: winfo_height() @@ -2480,6 +2481,8 @@ Base and mixin classes *width* and *height* are in pixels (or grid units for a gridded window); a position preceded by ``+`` is measured from the left or top edge of the screen and one preceded by ``-`` from the right or bottom edge. + An offset can be negative, as in ``'200x100+-9+-8'``, when the window + edge is positioned beyond the corresponding screen edge. An empty string cancels any user-specified geometry, letting the window revert to its natural size. With no argument, return the current geometry as a string of the form From a862fbc7f00931d4ac85dc6dc5a22cbe35f08c7d Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 5 Jul 2026 13:15:56 +0200 Subject: [PATCH 582/818] [3.15] gh-123193: Document tkinter Variable lifetime (GH-152625) (GH-153098) A Tk variable wrapper unsets its Tcl variable when garbage collected, so a reference must be kept while a widget uses it. Otherwise Tk recreates the Tcl variable but never unsets it again, leaking it. (cherry picked from commit 820b6ca22d72482e2e68dd738cc370535c83655e) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --- Doc/library/tkinter.rst | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Doc/library/tkinter.rst b/Doc/library/tkinter.rst index 17ea03d0de4d57..a95cf3af5beeb1 100644 --- a/Doc/library/tkinter.rst +++ b/Doc/library/tkinter.rst @@ -656,6 +656,9 @@ method on it, and to change its value you call the :meth:`!set` method. If you follow this protocol, the widget will always track the value of the variable, with no further intervention on your part. +Keep a reference to the variable for as long as a widget uses it, for example +by storing it as an attribute (see :class:`Variable`). + For example:: import tkinter as tk @@ -5736,6 +5739,14 @@ Variable classes :class:`StringVar`, :class:`IntVar`, :class:`DoubleVar` or :class:`BooleanVar` -- rather than :class:`!Variable` directly. + .. note:: + + When a :class:`!Variable` is garbage collected, its Tcl variable is unset. + Keep a reference to it for as long as a widget is linked to it, for example + by storing it as an attribute rather than in a local variable. + Otherwise Tk recreates the Tcl variable to keep the widget working, but it + is never unset again, leaking one Tcl variable per dropped wrapper. + .. versionchanged:: 3.10 Two variables now compare equal (``==``) only when they have the same name, are of the same class, and belong to the same Tcl interpreter. From 7d3b991f4a064e01e1211c31cb5bf3fb62a510d1 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 5 Jul 2026 13:22:09 +0200 Subject: [PATCH 583/818] [3.15] gh-54930: Send a status line in error responses to malformed request lines (GH-152980) (GH-153092) Previously such error responses were sent in the bare HTTP/0.9 style, without a status line and headers. (cherry picked from commit 2ab620b41af57e24c11c131bec02f682561ecfaa) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> --- Lib/http/server.py | 6 +++++- Lib/test/test_httpservers.py | 15 +++++++++++++++ .../2026-07-03-21-10-00.gh-issue-54930.hq09Er.rst | 5 +++++ 3 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2026-07-03-21-10-00.gh-issue-54930.hq09Er.rst diff --git a/Lib/http/server.py b/Lib/http/server.py index ebc85052aecb90..095b5744bd12fc 100644 --- a/Lib/http/server.py +++ b/Lib/http/server.py @@ -334,10 +334,13 @@ def parse_request(self): raise ValueError("unreasonable length http version") version_number = int(version_number[0]), int(version_number[1]) except (ValueError, IndexError): + # Send the error response with a status line and headers. + self.request_version = '' self.send_error( HTTPStatus.BAD_REQUEST, "Bad request version (%r)" % version) return False + self.request_version = version if version_number >= (1, 1) and self.protocol_version >= "HTTP/1.1": self.close_connection = False if version_number >= (2, 0): @@ -345,9 +348,9 @@ def parse_request(self): HTTPStatus.HTTP_VERSION_NOT_SUPPORTED, "Invalid HTTP version (%s)" % base_version_number) return False - self.request_version = version if not 2 <= len(words) <= 3: + self.request_version = '' self.send_error( HTTPStatus.BAD_REQUEST, "Bad request syntax (%r)" % requestline) @@ -356,6 +359,7 @@ def parse_request(self): if len(words) == 2: self.close_connection = True if command != 'GET': + self.request_version = '' self.send_error( HTTPStatus.BAD_REQUEST, "Bad HTTP/0.9 request type (%r)" % command) diff --git a/Lib/test/test_httpservers.py b/Lib/test/test_httpservers.py index 574529c70741d8..70349c6c8869a9 100644 --- a/Lib/test/test_httpservers.py +++ b/Lib/test/test_httpservers.py @@ -386,6 +386,8 @@ def test_simple_get(self): def test_invalid_request(self): self.sock.send(b'POST /index.html\r\n') res = self.sock.recv(1024) + # The error response is not sent in the bare HTTP/0.9 style. + self.assertStartsWith(res, b'HTTP/1.0 400 ') self.assertIn(b"Bad HTTP/0.9 request type ('POST')", res) def test_single_request(self): @@ -1102,6 +1104,19 @@ def test_http_0_9(self): self.assertEqual(result[0], b'<html><body>Data</body></html>\r\n') self.verify_get_called() + @support.subTests('request,code', [ + (b'GET / FUBAR\r\n\r\n', 400), # bad version + (b'GET / HTTP/2.0\r\n\r\n', 505), # unsupported version + (b'GET\r\n', 400), # bad syntax + (b'POST /\r\n', 400), # bad HTTP/0.9 request type + ]) + def test_request_line_error_has_status_line(self, request, code): + self.handler = SocketlessRequestHandler() + result = self.send_typical_request(request) + self.assertStartsWith(result[0], b'HTTP/1.1 %d ' % code) + self.verify_expected_headers(result[1:result.index(b'\r\n')]) + self.assertFalse(self.handler.get_called) + def test_extra_space(self): result = self.send_typical_request( b'GET /spaced out HTTP/1.1\r\n' diff --git a/Misc/NEWS.d/next/Library/2026-07-03-21-10-00.gh-issue-54930.hq09Er.rst b/Misc/NEWS.d/next/Library/2026-07-03-21-10-00.gh-issue-54930.hq09Er.rst new file mode 100644 index 00000000000000..1cfc0212c609a6 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-03-21-10-00.gh-issue-54930.hq09Er.rst @@ -0,0 +1,5 @@ +Error responses of :class:`http.server.BaseHTTPRequestHandler` to malformed +request lines now include a status line and headers instead of being sent in +the bare HTTP/0.9 style. +Only a valid HTTP/0.9 request (a two-word ``GET`` request line) now receives +an HTTP/0.9 style response. From d1fde1822fee8b0f38d88e0061acadc48b1219d6 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 5 Jul 2026 13:24:25 +0200 Subject: [PATCH 584/818] [3.15] gh-76607: Improve documentation of the tkinter cursor option (GH-152481) (GH-153110) Link to the cursors(3tk) manual page for the available cursor names and note that they are platform-dependent. (cherry picked from commit ea5703735f2ff4ba7bc3b0c7e746a44cb9b25081) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --- Doc/library/tkinter.rst | 14 ++++++++++---- Doc/library/tkinter.ttk.rst | 7 ++++--- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/Doc/library/tkinter.rst b/Doc/library/tkinter.rst index a95cf3af5beeb1..0630828c164a72 100644 --- a/Doc/library/tkinter.rst +++ b/Doc/library/tkinter.rst @@ -737,6 +737,8 @@ Here are some examples of typical usage:: myapp.mainloop() +.. _Tk-option-data-types: + Tk option data types ^^^^^^^^^^^^^^^^^^^^ @@ -770,12 +772,16 @@ color represent any legal hex digit. See page 160 of Ousterhout's book for details. cursor - The standard X cursor names from :file:`cursorfont.h` can be used, without the - ``XC_`` prefix. For example to get a hand cursor (``XC_hand2``), use the - string ``"hand2"``. You can also specify a bitmap and mask file of your own. + The name of the mouse cursor to display while the pointer is over the widget. + Tk provides a portable set of cursor names available on all platforms + (for example ``"arrow"``, ``"watch"``, ``"cross"``, or ``"hand2"``); + the standard X cursor names from :file:`cursorfont.h` may also be used, + without the ``XC_`` prefix (so ``XC_hand2`` becomes ``"hand2"``). + The full list of names, including the platform-specific ones, + is given in the :manpage:`cursors(3tk)` manual page. + You can also specify a bitmap and mask file of your own. On Windows a cursor file (:file:`.cur` or :file:`.ani`) may be used directly, giving its path preceded with an ``@``, as in ``"@C:/cursors/bart.ani"``. - See page 179 of Ousterhout's book. distance Screen distances can be specified in either pixels or absolute distances. diff --git a/Doc/library/tkinter.ttk.rst b/Doc/library/tkinter.ttk.rst index 70abe7bb846543..13fead3e65ece7 100644 --- a/Doc/library/tkinter.ttk.rst +++ b/Doc/library/tkinter.ttk.rst @@ -116,9 +116,10 @@ All the :mod:`!ttk` Widgets accept the following options: | | read-only, and may only be specified when the window is | | | created. | +-----------+--------------------------------------------------------------+ -| cursor | Specifies the mouse cursor to be used for the widget. If set | -| | to the empty string (the default), the cursor is inherited | -| | from the parent widget. | +| cursor | Specifies the mouse cursor to be used for the widget. See | +| | the *cursor* option type under :ref:`Tk-option-data-types`. | +| | If set to the empty string (the default), the cursor is | +| | inherited from the parent widget. | +-----------+--------------------------------------------------------------+ | takefocus | Determines whether the window accepts the focus during | | | keyboard traversal. 0, 1 or an empty string is returned. | From 202e751f792cc4218f1b9fea08e30c06c3bddd30 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 5 Jul 2026 13:31:55 +0200 Subject: [PATCH 585/818] [3.15] Fix minor typos in 'Compound statements' docs (GH-149666) (#153113) (cherry picked from commit 856049a9d99119ad74cd991fa8f8a72ebc909122) Co-authored-by: Jonathan Dung <jonathandung@yahoo.com> Co-authored-by: Stan Ulbrych <stan@python.org> --- Doc/reference/compound_stmts.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Doc/reference/compound_stmts.rst b/Doc/reference/compound_stmts.rst index 71bfb608dda728..49526f1e5e8393 100644 --- a/Doc/reference/compound_stmts.rst +++ b/Doc/reference/compound_stmts.rst @@ -279,12 +279,12 @@ and the exception occurs in the :keyword:`!try` clause of the inner handler, the outer handler will not handle the exception.) When an exception has been assigned using ``as target``, it is cleared at the -end of the :keyword:`!except` clause. This is as if :: +end of the :keyword:`!except` clause. This is as if:: except E as N: foo -was translated to :: +was translated to:: except E as N: try: @@ -341,7 +341,7 @@ can have either :keyword:`except` or :keyword:`!except*` clauses, but not both. The exception type for matching is mandatory in the case of :keyword:`!except*`, so ``except*:`` is a syntax error. The type is interpreted as in the case of :keyword:`!except`, but matching is performed on the exceptions contained in the -group that is being handled. An :exc:`TypeError` is raised if a matching +group that is being handled. A :exc:`TypeError` is raised if a matching type is a subclass of :exc:`!BaseExceptionGroup`, because that would have ambiguous semantics. @@ -357,7 +357,7 @@ or the last :keyword:`!except*` clause has run. After all :keyword:`!except*` clauses execute, the group of unhandled exceptions is merged with any exceptions that were raised or re-raised from within -:keyword:`!except*` clauses. This merged exception group propagates on.:: +:keyword:`!except*` clauses. This merged exception group propagates on:: >>> try: ... raise ExceptionGroup("eg", @@ -1311,7 +1311,7 @@ mutable object, such as a list or a dictionary: if the function modifies the object (e.g. by appending an item to a list), the default parameter value is in effect modified. This is generally not what was intended. A way around this is to use ``None`` as the default, and explicitly test for it in the body of the function, -e.g.:: +for example:: def whats_on_the_telly(penguin=None): if penguin is None: From 0416fcd7cf454b3b8d87467f3b6442a647136a1a Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka <storchaka@gmail.com> Date: Sun, 5 Jul 2026 14:42:24 +0300 Subject: [PATCH 586/818] [3.15] gh-69134: Wait until mapped in SimpleDialog keyboard tests (GH-152690) (GH-153104) The SimpleDialog keyboard tests generate key events after focus_force(), which on Windows are dropped until the toplevel is mapped, so they could fail intermittently (seen on the Windows10 buildbot as test_return_no_default). Wait until the window is mapped in these tests, as GH-152599 did for the other keyboard tests. (cherry picked from commit 7d619c2fea131722d0bfdad150c081c44cc0abd7) Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --- Lib/test/test_tkinter/test_simpledialog.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Lib/test/test_tkinter/test_simpledialog.py b/Lib/test/test_tkinter/test_simpledialog.py index 942b7ebf7120b3..64edbb645bc80f 100644 --- a/Lib/test/test_tkinter/test_simpledialog.py +++ b/Lib/test/test_tkinter/test_simpledialog.py @@ -49,6 +49,7 @@ def test_default_button(self): def test_return_activates_default(self): # <Return> invokes the default button. d = self.create() # default 0 + self.require_mapped(d.root) d.root.focus_force() d.root.update() d.root.event_generate('<Return>') @@ -59,6 +60,7 @@ def test_return_no_default(self): # With no default button, <Return> rings the bell and leaves the dialog # open instead of activating a button. d = self.create(default=None) + self.require_mapped(d.root) d.root.focus_force() d.root.update() bells = [] From 2a5f9e0e24f270c77d0eb11b69fe99e6c8aecd8f Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 5 Jul 2026 13:44:44 +0200 Subject: [PATCH 587/818] [3.15] gh-79638: Restore "Treat an unreachable robots.txt as disallow all" (GH-152525) (GH-153107) This change was accidentally reverted by f0daba1652c (gh-106693, GH-149514), which only intended to revert the ob_sval change. The tests were already restored by GH-149569. (cherry picked from commit 70100b9ea0b43a95226eee45652a5735bb91e9c7) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --- Lib/urllib/robotparser.py | 10 +++++++++- .../2025-09-05-20-50-35.gh-issue-79638.Y-JfaH.rst | 2 ++ 2 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2025-09-05-20-50-35.gh-issue-79638.Y-JfaH.rst diff --git a/Lib/urllib/robotparser.py b/Lib/urllib/robotparser.py index e70eae80036784..0c3e5d92890935 100644 --- a/Lib/urllib/robotparser.py +++ b/Lib/urllib/robotparser.py @@ -65,9 +65,17 @@ def read(self): f = urllib.request.urlopen(self.url) except urllib.error.HTTPError as err: if err.code in (401, 403): + # If access to robot.txt has the status Unauthorized/Forbidden, + # then most likely this applies to the entire site. self.disallow_all = True - elif err.code >= 400 and err.code < 500: + elif 400 <= err.code < 500: + # RFC 9309, Section 2.3.1.3: the crawler MAY access any + # resources on the server. self.allow_all = True + elif 500 <= err.code < 600: + # RFC 9309, Section 2.3.1.4: the crawler MUST assume + # complete disallow. + self.disallow_all = True err.close() else: raw = f.read() diff --git a/Misc/NEWS.d/next/Library/2025-09-05-20-50-35.gh-issue-79638.Y-JfaH.rst b/Misc/NEWS.d/next/Library/2025-09-05-20-50-35.gh-issue-79638.Y-JfaH.rst new file mode 100644 index 00000000000000..bd9fff0bc2e31b --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-09-05-20-50-35.gh-issue-79638.Y-JfaH.rst @@ -0,0 +1,2 @@ +Disallow all access in :mod:`urllib.robotparser` if the ``robots.txt`` file +is unreachable due to server or network errors. From 65b69363e72196f98545d5868849f6fad751b2c4 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 5 Jul 2026 15:27:34 +0200 Subject: [PATCH 588/818] [3.15] gh-149930: Clarify imaplib response helper types (GH-149963) (GH-153123) (cherry picked from commit d2d415b9761a539c37ea4f950df4e9aab0eca6ed) Co-authored-by: Savage Mechanic <savagemechanic@github.com> Co-authored-by: savagemechanic <20458938+savagemechanic@users.noreply.github.com> --- Doc/library/imaplib.rst | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/Doc/library/imaplib.rst b/Doc/library/imaplib.rst index 38a749b95f3e0e..8992a6cb7c8124 100644 --- a/Doc/library/imaplib.rst +++ b/Doc/library/imaplib.rst @@ -127,11 +127,11 @@ The second subclass allows for connections created by a child process: The following utility functions are defined: -.. function:: Internaldate2tuple(datestr) +.. function:: Internaldate2tuple(resp) - Parse an IMAP4 ``INTERNALDATE`` string and return corresponding local - time. The return value is a :class:`time.struct_time` tuple or - ``None`` if the string has wrong format. + Parse a :term:`bytes-like object` containing an IMAP4 ``INTERNALDATE`` + response and return the corresponding local time. The return value is a + :class:`time.struct_time` tuple or ``None`` if the input has wrong format. .. function:: Int2AP(num) @@ -139,9 +139,11 @@ The following utility functions are defined: [``A`` .. ``P``]. -.. function:: ParseFlags(flagstr) +.. function:: ParseFlags(resp) - Converts an IMAP4 ``FLAGS`` response to a tuple of individual flags. + Converts a :term:`bytes-like object` containing an IMAP4 ``FLAGS`` response + to a tuple of individual flags as :class:`bytes`. The return value is an + empty tuple if the input has wrong format. .. function:: Time2Internaldate(date_time) From 1289306bcd5c8563d7cf7d357ca1c81eba356fa0 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 5 Jul 2026 16:41:39 +0200 Subject: [PATCH 589/818] [3.15] gh-68147: Fix RFC references in imaplib (GH-153126) (GH-153130) Refer to RFC 3501, which obsoleted RFC 2060. "]" is disallowed in flags, not in tags. (cherry picked from commit 74a2438bf783077cf49460ed0fed8853675fb103) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> --- Doc/library/imaplib.rst | 10 +++++----- Lib/imaplib.py | 6 +++--- Lib/test/test_imaplib.py | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Doc/library/imaplib.rst b/Doc/library/imaplib.rst index 8992a6cb7c8124..e18e9d787665c4 100644 --- a/Doc/library/imaplib.rst +++ b/Doc/library/imaplib.rst @@ -16,7 +16,7 @@ This module defines three classes, :class:`IMAP4`, :class:`IMAP4_SSL` and :class:`IMAP4_stream`, which encapsulate a connection to an IMAP4 server and implement a large subset of the IMAP4rev1 client protocol as defined in -:rfc:`2060`. It is backward compatible with IMAP4 (:rfc:`1730`) servers, but +:rfc:`3501`. It is backward compatible with IMAP4 (:rfc:`1730`) servers, but note that the ``STATUS`` command is not supported in IMAP4. .. include:: ../includes/wasm-notavail.rst @@ -621,7 +621,7 @@ An :class:`IMAP4` instance has the following methods: .. method:: IMAP4.store(message_set, command, flag_list) Alters flag dispositions for messages in mailbox. *command* is specified by - section 6.4.6 of :rfc:`2060` as being one of "FLAGS", "+FLAGS", or "-FLAGS", + section 6.4.6 of :rfc:`3501` as being one of "FLAGS", "+FLAGS", or "-FLAGS", optionally with a suffix of ".SILENT". For example, to set the delete flag on all messages:: @@ -635,11 +635,11 @@ An :class:`IMAP4` instance has the following methods: Creating flags containing ']' (for example: "[test]") violates :rfc:`3501` (the IMAP protocol). However, imaplib has historically - allowed creation of such tags, and popular IMAP servers, such as Gmail, + allowed creation of such flags, and popular IMAP servers, such as Gmail, accept and produce such flags. There are non-Python programs which also - create such tags. Although it is an RFC violation and IMAP clients and + create such flags. Although it is an RFC violation and IMAP clients and servers are supposed to be strict, imaplib still continues to allow - such tags to be created for backward compatibility reasons, and as of + such flags to be created for backward compatibility reasons, and as of Python 3.6, handles them if they are sent from the server, since this improves real-world compatibility. diff --git a/Lib/imaplib.py b/Lib/imaplib.py index a46f3d4c466cb1..8d8edcfd5f21c6 100644 --- a/Lib/imaplib.py +++ b/Lib/imaplib.py @@ -1,6 +1,6 @@ """IMAP4 client. -Based on RFC 2060. +Based on RFC 3501. Public class: IMAP4 Public variable: Debug @@ -43,8 +43,8 @@ AllowedVersions = ('IMAP4REV1', 'IMAP4') # Most recent first # Maximal line length when calling readline(). This is to prevent -# reading arbitrary length lines. RFC 3501 and 2060 (IMAP 4rev1) -# don't specify a line length. RFC 2683 suggests limiting client +# reading arbitrary length lines. RFC 3501 (IMAP 4rev1) +# doesn't specify a line length. RFC 2683 suggests limiting client # command lines to 1000 octets and that servers should be prepared # to accept command lines up to 8000 octets, so we used to use 10K here. # In the modern world (eg: gmail) the response to, for example, a diff --git a/Lib/test/test_imaplib.py b/Lib/test/test_imaplib.py index 55e5c9fe3a6ecf..20d135f06eeede 100644 --- a/Lib/test/test_imaplib.py +++ b/Lib/test/test_imaplib.py @@ -1880,8 +1880,8 @@ def test_connect(self): @threading_helper.reap_threads def test_bracket_flags(self): - # This violates RFC 3501, which disallows ']' characters in tag names, - # but imaplib has allowed producing such tags forever, other programs + # This violates RFC 3501, which disallows ']' characters in flags, + # but imaplib has allowed producing such flags forever, other programs # also produce them (eg: OtherInbox's Organizer app as of 20140716), # and Gmail, for example, accepts them and produces them. So we # support them. See issue #21815. From f2cd7ef89aa8a0dcbc7283bbd39548b76f2a736a Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 5 Jul 2026 17:58:48 +0200 Subject: [PATCH 590/818] [3.15] gh-143921: Narrow the control character check in imaplib commands (GH-153067) (GH-153135) Only NUL, CR and LF are rejected now. Other control characters are valid in quoted strings and can occur in mailbox names returned by the server, so they are now accepted and sent quoted. (cherry picked from commit d0921efb665aff26b378f495e5ff84f7e3fe649d) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> --- Lib/imaplib.py | 6 ++++-- Lib/test/test_imaplib.py | 16 +++++++++++++--- ...026-07-05-10-24-30.gh-issue-143921.wQx3Tn.rst | 4 ++++ 3 files changed, 21 insertions(+), 5 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-07-05-10-24-30.gh-issue-143921.wQx3Tn.rst diff --git a/Lib/imaplib.py b/Lib/imaplib.py index 8d8edcfd5f21c6..44acaa16397e2d 100644 --- a/Lib/imaplib.py +++ b/Lib/imaplib.py @@ -129,7 +129,9 @@ # We compile these in _mode_xxx. _Literal = br'.*{(?P<size>\d+)}$' _Untagged_status = br'\* (?P<data>\d+) (?P<type>[A-Z-]+)( (?P<data2>.*))?' -_control_chars = re.compile(b'[\x00-\x1F\x7F]') +# Only NUL, CR and LF are unsafe (they cannot be represented even in +# a quoted string); other control characters are sent quoted. +_control_chars = re.compile(b'[\x00\r\n]') _non_astring_char = re.compile(br'[(){ \x00-\x1f\x7f-\xff%*\\"]') _non_list_char = re.compile(br'[(){ \x00-\x1f\x7f-\xff\\"]') _quoted = re.compile(br'"(?:[^"\\]|\\.)*+"') @@ -1164,7 +1166,7 @@ def _command(self, name, *args): if isinstance(arg, str): arg = bytes(arg, self._encoding) if _control_chars.search(arg): - raise ValueError("Control characters not allowed in commands") + raise ValueError("NUL, CR and LF not allowed in commands") data = data + b' ' + arg literal = self.literal diff --git a/Lib/test/test_imaplib.py b/Lib/test/test_imaplib.py index 20d135f06eeede..5786f12f322f74 100644 --- a/Lib/test/test_imaplib.py +++ b/Lib/test/test_imaplib.py @@ -1736,10 +1736,20 @@ def test_uppercase_command_names(self): client.NONEXISTENT def test_control_characters(self): - client, _ = self._setup(SimpleIMAPHandler) - for c0 in support.control_characters_c0(): + client, server = self._setup(SimpleIMAPHandler) + client.login('user', 'pass') + for c in '\0\r\n': with self.assertRaises(ValueError): - client.login(f'user{c0}', 'pass') + client.select(f'a{c}b') + # Other control characters are valid in a quoted string and can + # occur in mailbox names returned by the server, so the client + # must be able to send them back. + for c in support.control_characters_c0(): + if c in '\0\r\n': + continue + typ, _ = client.select(f'a{c}b') + self.assertEqual(typ, 'OK') + self.assertEqual(server.is_selected, [f'"a{c}b"']) # property tests diff --git a/Misc/NEWS.d/next/Library/2026-07-05-10-24-30.gh-issue-143921.wQx3Tn.rst b/Misc/NEWS.d/next/Library/2026-07-05-10-24-30.gh-issue-143921.wQx3Tn.rst new file mode 100644 index 00000000000000..04e8bd6d6f9d6c --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-05-10-24-30.gh-issue-143921.wQx3Tn.rst @@ -0,0 +1,4 @@ +Narrow the control character check in :mod:`imaplib` commands: only NUL, CR +and LF are now rejected. Other control characters are valid in quoted +strings and can occur in mailbox names returned by the server, so they are +now accepted and sent quoted. From 986322e6136b7075544df1da9600d36f919e497e Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 5 Jul 2026 19:52:46 +0200 Subject: [PATCH 591/818] [3.15] gh-105708: 'V' could be case insensitive for IPvFuture hostnames (GH-105709) (#153138) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gh-105708: 'V' could be case insensitive for IPvFuture hostnames (GH-105709) * gh-105708: 'V' could be case insensitive for IPvFuture hostnames * gh-105708: 'V' could be case insensitive for IPvFuture hostnames & checking empty hostnames * 📜🤖 Added by blurb_it. * Fix the Merge changing \z to \Z. * Fixed the News Entry. * Fix the lint. --------- (cherry picked from commit a47a66ccef0f98fcf088bc260ca14b889efa9b04) Co-authored-by: Chandra <csreddy1998@gmail.com> Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com> Co-authored-by: Senthil Kumaran <senthil@python.org> --- Lib/test/test_urlparse.py | 15 ++++++++++----- Lib/urllib/parse.py | 4 ++-- ...2023-06-12-21-31-02.gh-issue-105708.5fFwP8.rst | 1 + 3 files changed, 13 insertions(+), 7 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-06-12-21-31-02.gh-issue-105708.5fFwP8.rst diff --git a/Lib/test/test_urlparse.py b/Lib/test/test_urlparse.py index 8e4da0e0f09919..a5b7966c7780e9 100644 --- a/Lib/test/test_urlparse.py +++ b/Lib/test/test_urlparse.py @@ -1653,15 +1653,20 @@ def test_splitting_bracketed_hosts(self): self.assertEqual(p1.username, 'user') self.assertEqual(p1.path, '/path') self.assertEqual(p1.port, 1234) - p2 = urllib.parse.urlsplit('scheme://user@[0439:23af:2309::fae7%test]/path?query') - self.assertEqual(p2.hostname, '0439:23af:2309::fae7%test') + p2 = urllib.parse.urlsplit('scheme://user@[V6a.ip]:1234/path?query') + self.assertEqual(p2.hostname, 'v6a.ip') self.assertEqual(p2.username, 'user') self.assertEqual(p2.path, '/path') - self.assertIs(p2.port, None) - p3 = urllib.parse.urlsplit('scheme://user@[0439:23af:2309::fae7:1234:192.0.2.146%test]/path?query') - self.assertEqual(p3.hostname, '0439:23af:2309::fae7:1234:192.0.2.146%test') + self.assertEqual(p2.port, 1234) + p3 = urllib.parse.urlsplit('scheme://user@[0439:23af:2309::fae7%test]/path?query') + self.assertEqual(p3.hostname, '0439:23af:2309::fae7%test') self.assertEqual(p3.username, 'user') self.assertEqual(p3.path, '/path') + self.assertIs(p3.port, None) + p4 = urllib.parse.urlsplit('scheme://user@[0439:23af:2309::fae7:1234:192.0.2.146%test]/path?query') + self.assertEqual(p4.hostname, '0439:23af:2309::fae7:1234:192.0.2.146%test') + self.assertEqual(p4.username, 'user') + self.assertEqual(p4.path, '/path') def test_port_casting_failure_message(self): message = "Port could not be cast to integer value as 'oracle'" diff --git a/Lib/urllib/parse.py b/Lib/urllib/parse.py index 82b95adbdc283e..4247b9a4b07fa3 100644 --- a/Lib/urllib/parse.py +++ b/Lib/urllib/parse.py @@ -544,8 +544,8 @@ def _check_bracketed_netloc(netloc): # Valid bracketed hosts are defined in # https://www.rfc-editor.org/rfc/rfc3986#page-49 and https://url.spec.whatwg.org/ def _check_bracketed_host(hostname): - if hostname.startswith('v'): - if not re.match(r"\Av[a-fA-F0-9]+\..+\z", hostname): + if hostname.startswith(('v', 'V')): + if not re.match(r"\A[vV][a-fA-F0-9]+\..+\z", hostname): raise ValueError(f"IPvFuture address is invalid") else: ip = ipaddress.ip_address(hostname) # Throws Value Error if not IPv6 or IPv4 diff --git a/Misc/NEWS.d/next/Library/2023-06-12-21-31-02.gh-issue-105708.5fFwP8.rst b/Misc/NEWS.d/next/Library/2023-06-12-21-31-02.gh-issue-105708.5fFwP8.rst new file mode 100644 index 00000000000000..79289c1f0bd421 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-06-12-21-31-02.gh-issue-105708.5fFwP8.rst @@ -0,0 +1 @@ +Accept an uppercase V prefix in IPvFuture addresses in :func:`urllib.parse.urlsplit`. From 5ae62034e5ef8c9799f08364e06ade9064826e39 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 5 Jul 2026 21:36:51 +0200 Subject: [PATCH 592/818] [3.15] gh-153141: Fix mutable default argument in _SharedMemoryTracker.__init__ (GH-153142) (#153145) gh-153141: Fix mutable default argument in _SharedMemoryTracker.__init__ (GH-153142) Fix default argument for segment_names in _SharedMemoryTracker constructor to not use a mutable list. (cherry picked from commit d733b104d53e96584a6881d2772df65ad82573a0) Co-authored-by: Vineet Kumar <108144301+whyvineet@users.noreply.github.com> --- Lib/multiprocessing/managers.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/multiprocessing/managers.py b/Lib/multiprocessing/managers.py index 91bcf243e78e5b..11c6e21de90e69 100644 --- a/Lib/multiprocessing/managers.py +++ b/Lib/multiprocessing/managers.py @@ -1294,9 +1294,9 @@ class SyncManager(BaseManager): class _SharedMemoryTracker: "Manages one or more shared memory segments." - def __init__(self, name, segment_names=[]): + def __init__(self, name, segment_names=None): self.shared_memory_context_name = name - self.segment_names = segment_names + self.segment_names = [] if segment_names is None else segment_names def register_segment(self, segment_name): "Adds the supplied shared memory block name to tracker." From 8e7c2ca7a0546f5fd055afdc79e6186864ad6549 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 6 Jul 2026 11:33:36 +0200 Subject: [PATCH 593/818] [3.15] gh-148765: Fix description of *include_hidden* parameter in `glob.glob()` docs (GH-148768) (#153173) (cherry picked from commit db3a4773e1e5fc1a30597d9e08bcbe41d27e5bbb) Co-authored-by: Eoin Shaughnessy <45000144+EoinTrial@users.noreply.github.com> Co-authored-by: Stan Ulbrych <stan@python.org> --- Doc/library/glob.rst | 7 ++++--- Lib/glob.py | 8 ++++---- Misc/ACKS | 1 + 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/Doc/library/glob.rst b/Doc/library/glob.rst index 942f23d216fc07..bbeb808159d446 100644 --- a/Doc/library/glob.rst +++ b/Doc/library/glob.rst @@ -29,7 +29,7 @@ not by actually invoking a subshell. The pathnames are returned in no particular order. If you need a specific order, sort the results. -Files beginning with a dot (``.``) can only be matched by +By default, files beginning with a dot (``.``) can only be matched by patterns that also start with a dot, unlike :func:`fnmatch.fnmatch` or :func:`pathlib.Path.glob`. For tilde and shell variable expansion, use :func:`os.path.expanduser` and @@ -70,7 +70,8 @@ The :mod:`!glob` module defines the following functions: pattern is followed by an :data:`os.sep` or :data:`os.altsep` then files will not match. - If *include_hidden* is true, "``**``" pattern will match hidden directories. + If *include_hidden* is true, wildcards can match path segments that + begin with a dot (``.``). .. audit-event:: glob.glob pathname,recursive glob.glob .. audit-event:: glob.glob/2 pathname,recursive,root_dir,dir_fd glob.glob @@ -131,7 +132,7 @@ The :mod:`!glob` module defines the following functions: Escape all special characters (``'?'``, ``'*'`` and ``'['``). This is useful if you want to match an arbitrary literal string that may have special characters in it. Special characters in drive/UNC - sharepoints are not escaped, e.g. on Windows + sharepoints are not escaped, for example on Windows ``escape('//?/c:/Quo vadis?.txt')`` returns ``'//?/c:/Quo vadis[?].txt'``. .. versionadded:: 3.4 diff --git a/Lib/glob.py b/Lib/glob.py index 5a8ff46137ba5e..07b9d3eb952ed6 100644 --- a/Lib/glob.py +++ b/Lib/glob.py @@ -34,8 +34,8 @@ def glob(pathname, *, root_dir=None, dir_fd=None, recursive=False, If `dir_fd` is not None, it should be a file descriptor referring to a directory, and paths will then be relative to that directory. - If `include_hidden` is true, the patterns '*', '?', '**' will match - hidden directories. + If `include_hidden` is true, wildcards can match path segments beginning + with a dot ('.'). If `recursive` is true, the pattern '**' will match any files and zero or more directories and subdirectories. @@ -64,8 +64,8 @@ def iglob(pathname, *, root_dir=None, dir_fd=None, recursive=False, If `dir_fd` is not None, it should be a file descriptor referring to a directory, and paths will then be relative to that directory. - If `include_hidden` is true, the patterns '*', '?', '**' will match - hidden directories. + If `include_hidden` is true, wildcards can match path segments beginning + with a dot ('.'). If `recursive` is true, the pattern '**' will match any files and zero or more directories and subdirectories. diff --git a/Misc/ACKS b/Misc/ACKS index 5b5df7ae11f2df..154d1e7ce019ec 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1754,6 +1754,7 @@ Ha Shao Richard Shapiro Soumya Sharma Varun Sharma +Eoin Shaughnessy Daniel Shaulov Vlad Shcherbina Justin Sheehy From 52810f997a3cb3a75ee2810717eda0dd67350390 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 6 Jul 2026 11:50:26 +0200 Subject: [PATCH 594/818] [3.15] gh-145098: Use `macos-26-intel` instead of `macos-15-intel` (GH-149991) (#153179) Co-authored-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> --- .github/workflows/build.yml | 8 ++++---- .github/workflows/reusable-macos.yml | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f5bec534d80cec..1203355512e5be 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -253,16 +253,16 @@ jobs: strategy: fail-fast: false matrix: - # macos-26 is Apple Silicon, macos-15-intel is Intel. - # macos-15-intel only runs tests against the GIL-enabled CPython. + # macos-26 is Apple Silicon, macos-26-intel is Intel. + # macos-26-intel only runs tests against the GIL-enabled CPython. os: - macos-26 - - macos-15-intel + - macos-26-intel free-threading: - false - true exclude: - - os: macos-15-intel + - os: macos-26-intel free-threading: true uses: ./.github/workflows/reusable-macos.yml with: diff --git a/.github/workflows/reusable-macos.yml b/.github/workflows/reusable-macos.yml index 93b419159fa817..65a7f857fc4c77 100644 --- a/.github/workflows/reusable-macos.yml +++ b/.github/workflows/reusable-macos.yml @@ -54,15 +54,15 @@ jobs: --prefix=/opt/python-dev \ --with-openssl="$(brew --prefix openssl@3.5)" - name: Build CPython - if : ${{ inputs.free-threading || inputs.os != 'macos-15-intel' }} + if : ${{ inputs.free-threading || inputs.os != 'macos-26-intel' }} run: gmake -j8 - name: Build CPython for compiler warning check - if : ${{ !inputs.free-threading && inputs.os == 'macos-15-intel' }} + if : ${{ !inputs.free-threading && inputs.os == 'macos-26-intel' }} run: set -o pipefail; gmake -j8 --output-sync 2>&1 | tee compiler_output_macos.txt - name: Display build info run: make pythoninfo - name: Check compiler warnings - if : ${{ !inputs.free-threading && inputs.os == 'macos-15-intel' }} + if : ${{ !inputs.free-threading && inputs.os == 'macos-26-intel' }} run: >- python3 Tools/build/check_warnings.py --compiler-output-file-path=compiler_output_macos.txt From d3fbde571aec254523b8e45427be384d902e88dd Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 6 Jul 2026 14:56:14 +0200 Subject: [PATCH 595/818] [3.15] gh-146531: Skip hanging `wm iconbitmap` test on macOS 26 Intel (GH-148032) (#153190) Co-authored-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> --- Lib/test/test_tkinter/test_misc.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_tkinter/test_misc.py b/Lib/test/test_tkinter/test_misc.py index 2a66ce01e0cf11..40f20b655993b7 100644 --- a/Lib/test/test_tkinter/test_misc.py +++ b/Lib/test/test_tkinter/test_misc.py @@ -1,5 +1,7 @@ import collections.abc import functools +import platform +import sys import unittest import weakref import tkinter @@ -946,12 +948,27 @@ def test_wm_attribute(self): def test_wm_iconbitmap(self): t = tkinter.Toplevel(self.root) + patchlevel = get_tk_patchlevel(t) + + if ( + t._windowingsystem == 'aqua' + and sys.platform == 'darwin' + and platform.machine() == 'x86_64' + and platform.mac_ver()[0].startswith('26.') + and ( + patchlevel[:3] <= (8, 6, 17) + or (9, 0) <= patchlevel[:3] <= (9, 0, 3) + ) + ): + # https://github.com/python/cpython/issues/146531 + # Tk bug 4a2070f0d3a99aa412bc582d386d575ca2f37323 + self.skipTest('wm iconbitmap hangs on macOS 26 Intel') + self.assertEqual(t.wm_iconbitmap(), '') t.wm_iconbitmap('hourglass') bug = False if t._windowingsystem == 'aqua': # Tk bug 13ac26b35dc55f7c37f70b39d59d7ef3e63017c8. - patchlevel = get_tk_patchlevel(t) if patchlevel < (8, 6, 17) or (9, 0) <= patchlevel < (9, 0, 2): bug = True if not bug: From 84af8f5c5a5f7aee763eb175557765b18a5fd9e5 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 6 Jul 2026 16:20:55 +0200 Subject: [PATCH 596/818] [3.15] Add tests for syntax error messages that had no test coverage (GH-153192) (GH-153196) Add tests for syntax error messages that had no test coverage (GH-153192) "illegal target for annotation" and "cannot use dict unpacking here" were not tested at all, and "f-string: expecting '!', or ':', or '}'" was only tested for its t-string variant. (cherry picked from commit 836b2069c86e25cf9456e9210bb612e5166d0779) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> --- Lib/test/test_fstring.py | 3 +++ Lib/test/test_syntax.py | 10 ++++++++++ Lib/test/test_unpack_ex.py | 14 ++++++++++++++ 3 files changed, 27 insertions(+) diff --git a/Lib/test/test_fstring.py b/Lib/test/test_fstring.py index 5cc02c30ec2ba3..9a8e56836fc671 100644 --- a/Lib/test/test_fstring.py +++ b/Lib/test/test_fstring.py @@ -1706,6 +1706,9 @@ def test_invalid_syntax_error_message(self): with self.assertRaisesRegex(SyntaxError, "f-string: expecting '=', or '!', or ':', or '}'"): compile("f'{a $ b}'", "?", "exec") + with self.assertRaisesRegex(SyntaxError, + "f-string: expecting '!', or ':', or '}'"): + compile("f'{a=b}'", "?", "exec") def test_with_two_commas_in_format_specifier(self): error_msg = re.escape("Cannot specify ',' with ','.") diff --git a/Lib/test/test_syntax.py b/Lib/test/test_syntax.py index 232dcb92ed2901..7859387dccef37 100644 --- a/Lib/test/test_syntax.py +++ b/Lib/test/test_syntax.py @@ -2238,6 +2238,16 @@ Traceback (most recent call last): SyntaxError: only single target (not list) can be annotated +>>> 1: int +Traceback (most recent call last): +SyntaxError: illegal target for annotation +>>> -x: int = 1 +Traceback (most recent call last): +SyntaxError: illegal target for annotation +>>> (x for x in y): int +Traceback (most recent call last): +SyntaxError: illegal target for annotation + # 'not' after operators: >>> 3 + not 3 diff --git a/Lib/test/test_unpack_ex.py b/Lib/test/test_unpack_ex.py index 33c96b84964b59..4fe19765cacf11 100644 --- a/Lib/test/test_unpack_ex.py +++ b/Lib/test/test_unpack_ex.py @@ -355,6 +355,20 @@ ^^^ SyntaxError: cannot use dict unpacking in a dictionary value + >>> (**a) + Traceback (most recent call last): + ... + (**a) + ^^ + SyntaxError: cannot use dict unpacking here + + >>> {**a for a in {1: 2}.items(): b} + Traceback (most recent call last): + ... + {**a for a in {1: 2}.items(): b} + ^^ + SyntaxError: cannot use dict unpacking here + # Generator expression in function arguments From 8d215929f4327ea0e5f63c62c51c8d2892b82d18 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 6 Jul 2026 17:22:23 +0200 Subject: [PATCH 597/818] [3.15] gh-148286: Remove invalid test in `test_decodeescape` (GH-153187) (#153204) (cherry picked from commit 8477652cc122e744bcc70c1e133905bcbe2d8516) Co-authored-by: Stan Ulbrych <stan@python.org> --- Lib/test/test_capi/test_bytes.py | 2 +- Tools/ubsan/suppressions.txt | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/Lib/test/test_capi/test_bytes.py b/Lib/test/test_capi/test_bytes.py index 410ebab729c2cf..c591e986bbce35 100644 --- a/Lib/test/test_capi/test_bytes.py +++ b/Lib/test/test_capi/test_bytes.py @@ -222,10 +222,10 @@ def test_decodeescape(self): self.assertEqual(decodeescape(br'x\xa\xy', 'replace'), b'x??y') self.assertEqual(decodeescape(br'x\xa\xy', 'ignore'), b'xy') self.assertRaises(ValueError, decodeescape, b'\\', 'spam') - self.assertEqual(decodeescape(NULL), b'') self.assertRaises(OverflowError, decodeescape, b'abc', NULL, PY_SSIZE_T_MAX) self.assertRaises(OverflowError, decodeescape, NULL, NULL, PY_SSIZE_T_MAX) + # INVALID decodeescape(NULL) # CRASHES decodeescape(b'abc', NULL, -1) # CRASHES decodeescape(NULL, NULL, 1) diff --git a/Tools/ubsan/suppressions.txt b/Tools/ubsan/suppressions.txt index a00e256b333618..e3679bc421f420 100644 --- a/Tools/ubsan/suppressions.txt +++ b/Tools/ubsan/suppressions.txt @@ -20,6 +20,3 @@ pointer-overflow:Modules/_zstd/decompressor.c # Modules/_io/stringio.c:350:24: runtime error: addition of unsigned offset to 0x7fd01ec25850 overflowed to 0x7fd01ec2584c pointer-overflow:Modules/_io/stringio.c - -# Objects/bytesobject.c:1190:25: runtime error: applying zero offset to null pointer -pointer-overflow:Objects/bytesobject.c From 15a21e4ee2c320b95bfb1f20a624a1e4822d3965 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 6 Jul 2026 17:25:47 +0200 Subject: [PATCH 598/818] [3.15] gh-152849: Fix `OverflowError` message for out-of-range timestamps in the `time` module (GH-152850) (#153209) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (cherry picked from commit 2d7a74ece7884c9a5f52cc6ac38a6e7ee691b26c) Co-authored-by: tonghuaroot (童话) <tonghuaroot@gmail.com> Co-authored-by: Stan Ulbrych <stan@python.org> --- Lib/test/test_time.py | 11 +++++++++++ .../2026-07-02-13-30-00.gh-issue-152849.K9dRvP.rst | 2 ++ Python/pytime.c | 4 ++-- 3 files changed, 15 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-07-02-13-30-00.gh-issue-152849.K9dRvP.rst diff --git a/Lib/test/test_time.py b/Lib/test/test_time.py index 1850f053aaffd6..985984b55123ce 100644 --- a/Lib/test/test_time.py +++ b/Lib/test/test_time.py @@ -1013,6 +1013,17 @@ def test_FromSecondsObject(self): with self.assertRaises(ValueError): _PyTime_FromSecondsObject(float('nan'), time_rnd) + def test_FromSecondsObject_float_overflow_message(self): + # Float path must report a PyTime_t overflow, like the integer path. + from _testinternalcapi import _PyTime_FromSecondsObject + for value in (PyTime_MAX, PyTime_MIN): + for time_rnd, _ in ROUNDING_MODES: + with self.subTest(value=value, time_rnd=time_rnd): + with self.assertRaisesRegex( + OverflowError, + "timestamp out of range for C PyTime_t"): + _PyTime_FromSecondsObject(value, time_rnd) + def test_AsSecondsDouble(self): from _testcapi import PyTime_AsSecondsDouble diff --git a/Misc/NEWS.d/next/Library/2026-07-02-13-30-00.gh-issue-152849.K9dRvP.rst b/Misc/NEWS.d/next/Library/2026-07-02-13-30-00.gh-issue-152849.K9dRvP.rst new file mode 100644 index 00000000000000..053a5dfea3f3ff --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-02-13-30-00.gh-issue-152849.K9dRvP.rst @@ -0,0 +1,2 @@ +Out-of-range float and integer timestamps now raise :exc:`OverflowError` +with the same message. Patch by tonghuaroot. diff --git a/Python/pytime.c b/Python/pytime.c index 399ff59ad01ab6..53c82736137a16 100644 --- a/Python/pytime.c +++ b/Python/pytime.c @@ -107,7 +107,7 @@ static void pytime_overflow(void) { PyErr_SetString(PyExc_OverflowError, - "timestamp too large to convert to C PyTime_t"); + "timestamp out of range for C PyTime_t"); } @@ -636,7 +636,7 @@ pytime_from_double(PyTime_t *tp, double value, _PyTime_round_t round, /* See comments in pytime_double_to_denominator */ if (!((double)PyTime_MIN <= d && d < -(double)PyTime_MIN)) { - pytime_time_t_overflow(); + pytime_overflow(); *tp = 0; return -1; } From fdba15ada06ecf8aa30f9f778668fd44203da448 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 6 Jul 2026 17:49:33 +0200 Subject: [PATCH 599/818] [3.15] Docs: Link to the `contextlib.chdir` context manager in the `os.chdir` docs (GH-153152) (#153212) (cherry picked from commit f155dbed4ef30dec5d00b8b09524b0d9f63965bc) Co-authored-by: Cody Maloney <cmaloney@users.noreply.github.com> Co-authored-by: Stan Ulbrych <stan@python.org> --- Doc/library/os.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Doc/library/os.rst b/Doc/library/os.rst index 778ab8714e1117..fba6ece80e5df5 100644 --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -2180,6 +2180,11 @@ features: .. audit-event:: os.chdir path os.chdir + .. seealso:: + + The :func:`contextlib.chdir` context manager, which changes the current + working directory on entering and restores the previous one on exit. + .. versionchanged:: 3.3 Added support for specifying *path* as a file descriptor on some platforms. From ffb5184dfbae44939bbc67c8b6da00a655c0cfbb Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 6 Jul 2026 18:36:32 +0200 Subject: [PATCH 600/818] [3.15] gh-152682: Fix NULL dereference on OOM in `symtable_visit_type_param_bound_or_default` (GH-152684) (#152695) In `symtable_visit_type_param_bound_or_default()`, when a reserved name (e.g. `__classdict__`) is used as a type parameter, `PyUnicode_FromFormat()` is called to build the SyntaxError message. If the allocation fails and returns NULL, the subsequent `PyErr_SetObject()` and `Py_DECREF()` calls would dereference NULL, causing a segfault. Fix by returning 0 immediately when `PyUnicode_FromFormat()` returns NULL. This propagates the MemoryError set by `PyUnicode_FromFormat()`. The bug was introduced in gh-128632 (commit 891c61c). (cherry picked from commit 10ed03edf128ed1101ab8d04bcd715f2033fec55) Co-authored-by: Petr Vaganov <petrvaganoff@gmail.com> * Remove test --------- Co-authored-by: Petr Vaganov <petrvaganoff@gmail.com> Co-authored-by: Stan Ulbrych <stan@python.org> --- .../2026-06-30-14-00-00.gh-issue-152682.yId7e5.rst | 3 +++ Python/symtable.c | 3 +++ 2 files changed, 6 insertions(+) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-30-14-00-00.gh-issue-152682.yId7e5.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-30-14-00-00.gh-issue-152682.yId7e5.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-30-14-00-00.gh-issue-152682.yId7e5.rst new file mode 100644 index 00000000000000..aba0b594382bcf --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-30-14-00-00.gh-issue-152682.yId7e5.rst @@ -0,0 +1,3 @@ +Fix NULL pointer dereference in :func:`compile` when a reserved name (e.g. +``__classdict__``) is used as a type parameter name and memory allocation +fails while formatting the error message. diff --git a/Python/symtable.c b/Python/symtable.c index bd2b5145efdd48..ff4c75514851cf 100644 --- a/Python/symtable.c +++ b/Python/symtable.c @@ -2678,6 +2678,9 @@ symtable_visit_type_param_bound_or_default( PyObject *error_msg = PyUnicode_FromFormat("reserved name '%U' cannot be " "used for type parameter", name); + if (error_msg == NULL) { + return 0; + } PyErr_SetObject(PyExc_SyntaxError, error_msg); Py_DECREF(error_msg); SET_ERROR_LOCATION(st->st_filename, LOCATION(tp)); From 9d603d3c12b8365ef2db26746ec1f21855c98927 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 6 Jul 2026 19:23:15 +0200 Subject: [PATCH 601/818] [3.15] gh-150880: Clarify DirEntry.path construction semantics (GH-153218) (GH-153219) gh-150880: Clarify DirEntry.path construction semantics (GH-153218) (cherry picked from commit 53661afabd2b4a9c92230ee7024dc42782164f8e) Co-authored-by: Zain Nadeem <zainnadeemzainnadeem80@gmail.com> --- Doc/library/os.rst | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/Doc/library/os.rst b/Doc/library/os.rst index fba6ece80e5df5..7dd2333d8dc72e 100644 --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -3037,10 +3037,16 @@ features: .. attribute:: path - The entry's full path name: equivalent to ``os.path.join(scandir_path, - entry.name)`` where *scandir_path* is the :func:`scandir` *path* - argument. The path is only absolute if the :func:`scandir` *path* - argument was absolute. If the :func:`scandir` *path* + The entry's path name: equivalent to ``os.path.join(scandir_path, + entry.name)`` where *scandir_path* is the original :func:`scandir` + *path* argument. Apart from the filename, the path preserves the + original :func:`scandir` argument. If the :func:`scandir` *path* + argument was relative, the :attr:`path` attribute is also relative. + Changing the current working directory after creating the + :func:`scandir` iterator may cause later uses of :attr:`path` to resolve + differently. On some platforms, the constructed path may not be valid + if the original :func:`scandir` argument was usable for enumeration but + not for joining with the entry name. If the :func:`scandir` *path* argument was a :ref:`file descriptor <path_fd>`, the :attr:`path` attribute is the same as the :attr:`name` attribute. From cca9d1c3628c1e1c5774d2c14e0dca089bedc23b Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 6 Jul 2026 21:17:26 +0200 Subject: [PATCH 602/818] [3.15] gh-153200: Fix math.isqrt() for int subclasses with overridden comparison operators (GH-153203) (GH-153223) The final check-and-correct comparison in the arbitrary precision path could call a comparison operator overridden in an int subclass. Compare by value with int's tp_richcompare. (cherry picked from commit 3a1b5473f217fc493f743c9ca8b877d2e76f8e6b) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> --- Lib/test/test_math_integer.py | 18 ++++++++++++++++++ ...-07-06-12-00-00.gh-issue-153200.isqrtLt.rst | 3 +++ Modules/mathintegermodule.c | 10 +++++++--- 3 files changed, 28 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-07-06-12-00-00.gh-issue-153200.isqrtLt.rst diff --git a/Lib/test/test_math_integer.py b/Lib/test/test_math_integer.py index 09a98d93bd636c..d1bc776dc42391 100644 --- a/Lib/test/test_math_integer.py +++ b/Lib/test/test_math_integer.py @@ -15,6 +15,19 @@ def __init__(self, value): def __index__(self): return self.value +# int subclass with broken arithmetic operators; implementations must +# convert their arguments to exact ints instead of using these. +class BadIntSubclass(int): + def _binop(self, other='ignored', mod=None): + return 42 + __add__ = __radd__ = __sub__ = __rsub__ = _binop + __mul__ = __rmul__ = __mod__ = __rmod__ = _binop + __divmod__ = __rdivmod__ = __pow__ = __rpow__ = _binop + __floordiv__ = __rfloordiv__ = _binop + __lshift__ = __rlshift__ = __rshift__ = __rrshift__ = _binop + __and__ = __rand__ = __or__ = __ror__ = __xor__ = __rxor__ = _binop + __lt__ = __le__ = __gt__ = __ge__ = _binop + # Here's a pure Python version of the math.integer.factorial algorithm, for # documentation and comparison purposes. # @@ -226,6 +239,11 @@ def test_isqrt(self): self.assertIntEqual(isqrt(False), 0) self.assertIntEqual(isqrt(MyIndexable(1729)), 41) + # Overridden operators of an int subclass must not affect the + # result. + self.assertIntEqual(isqrt(BadIntSubclass(10**20)), 10**10) + self.assertIntEqual(isqrt(BadIntSubclass(10**20 - 1)), 10**10 - 1) + with self.assertRaises(ValueError): isqrt(MyIndexable(-3)) diff --git a/Misc/NEWS.d/next/Library/2026-07-06-12-00-00.gh-issue-153200.isqrtLt.rst b/Misc/NEWS.d/next/Library/2026-07-06-12-00-00.gh-issue-153200.isqrtLt.rst new file mode 100644 index 00000000000000..a27ac73fe31a70 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-06-12-00-00.gh-issue-153200.isqrtLt.rst @@ -0,0 +1,3 @@ +Fix :func:`math.isqrt` returning an incorrect result for arguments not +less than 2**64 that are instances of an :class:`int` subclass with an +overridden comparison operator. diff --git a/Modules/mathintegermodule.c b/Modules/mathintegermodule.c index cfad4154b2d361..0f660d461e349f 100644 --- a/Modules/mathintegermodule.c +++ b/Modules/mathintegermodule.c @@ -454,16 +454,20 @@ math_integer_isqrt(PyObject *module, PyObject *n) /* The correct result is either a or a - 1. Figure out which, and decrement a if necessary. */ - /* a_too_large = n < a * a */ + /* a_too_large = n < a * a. Compare by value: n can be an instance + of an int subclass with an overridden __lt__ method. */ b = PyNumber_Multiply(a, a); if (b == NULL) { goto error; } - a_too_large = PyObject_RichCompareBool(n, b, Py_LT); + PyObject *cmp = PyLong_Type.tp_richcompare(n, b, Py_LT); Py_DECREF(b); - if (a_too_large == -1) { + if (cmp == NULL) { goto error; } + assert(PyBool_Check(cmp)); + a_too_large = (cmp == Py_True); + Py_DECREF(cmp); if (a_too_large) { Py_SETREF(a, PyNumber_Subtract(a, _PyLong_GetOne())); From 81986cbdaa8e6721c0612df5d8feb1524643363a Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 7 Jul 2026 02:10:18 +0200 Subject: [PATCH 603/818] [3.15] gh-140729: Fix the cProfile module when the executed script contains calls to multiprocessing.Process (GH-144715) (#153243) --- Lib/profiling/tracing/__init__.py | 4 ++- .../test_profiling/test_tracing_profiler.py | 35 ++++++++++++++++++- ...-02-11-16-47-27.gh-issue-140729.2uTPQp.rst | 3 ++ 3 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-02-11-16-47-27.gh-issue-140729.2uTPQp.rst diff --git a/Lib/profiling/tracing/__init__.py b/Lib/profiling/tracing/__init__.py index bd3cbf299aab3b..165665304e05a4 100644 --- a/Lib/profiling/tracing/__init__.py +++ b/Lib/profiling/tracing/__init__.py @@ -197,7 +197,9 @@ def main(): # in the module's namespace. globs = module.__dict__ globs.update({ - '__spec__': spec, + # Set __spec__ to None so the profiled program behaves like a + # script run directly (gh-140729). + '__spec__': None, '__file__': spec.origin, '__name__': spec.name, '__package__': None, diff --git a/Lib/test/test_profiling/test_tracing_profiler.py b/Lib/test/test_profiling/test_tracing_profiler.py index 3668e24e073ce4..a4fabe9d3cc75b 100644 --- a/Lib/test/test_profiling/test_tracing_profiler.py +++ b/Lib/test/test_profiling/test_tracing_profiler.py @@ -1,5 +1,4 @@ """Test suite for the cProfile module.""" - import sys import unittest @@ -192,6 +191,40 @@ class Foo: f.close() assert_python_ok('-m', "cProfile", f.name) + def _test_process_run_pickle(self, start_method): + val = 10 + with tempfile.NamedTemporaryFile("w+", delete_on_close=False) as f: + f.write(textwrap.dedent( + f'''\ + import multiprocessing + + def worker(x): + print(__name__) + exit(x ** 2) + + if __name__ == "__main__": + multiprocessing.set_start_method('{start_method}') + p = multiprocessing.Process(target=worker, args=({val},)) + p.start() + p.join() + print("p.exitcode =", p.exitcode) + ''')) + f.close() + _, out, err = assert_python_ok('-m', "cProfile", f.name) + self.assertIn(b"__mp_main__", out) + self.assertIn(bytes(f"exitcode = {val**2}", encoding='utf8'), out) + self.assertNotIn(b"Can't pickle", err) + + def test_process_spawn_pickle(self): + # gh-140729: test use Process in cProfile. + self._test_process_run_pickle('spawn') + + @unittest.skipIf(sys.platform == 'win32', + "No 'forkserver' start method on Windows") + def test_process_forkserver_pickle(self): + # gh-140729: test use Process in cProfile. + self._test_process_run_pickle('forkserver') + def main(): if '-r' not in sys.argv: diff --git a/Misc/NEWS.d/next/Library/2026-02-11-16-47-27.gh-issue-140729.2uTPQp.rst b/Misc/NEWS.d/next/Library/2026-02-11-16-47-27.gh-issue-140729.2uTPQp.rst new file mode 100644 index 00000000000000..49c9adc4679abb --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-02-11-16-47-27.gh-issue-140729.2uTPQp.rst @@ -0,0 +1,3 @@ +Fix a pickling error in the ``cProfile`` module when profiling a script that +uses :class:`multiprocessing.Process` with the ``spawn`` and ``forkserver`` +start methods. From 78e9fdb78f61f99a0ee05f412b45292df2088cc2 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 7 Jul 2026 02:11:55 +0200 Subject: [PATCH 604/818] [3.15] gh-153068: Preserve cprofile enable errors (GH-153070) (#153241) --- Lib/test/test_profiling/test_tracing_profiler.py | 5 +++-- .../Library/2026-07-05-16-09-31.gh-issue-153068.huY9Jh.rst | 2 ++ Modules/_lsprof.c | 1 - 3 files changed, 5 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-07-05-16-09-31.gh-issue-153068.huY9Jh.rst diff --git a/Lib/test/test_profiling/test_tracing_profiler.py b/Lib/test/test_profiling/test_tracing_profiler.py index a4fabe9d3cc75b..8a7070142b60ee 100644 --- a/Lib/test/test_profiling/test_tracing_profiler.py +++ b/Lib/test/test_profiling/test_tracing_profiler.py @@ -117,8 +117,9 @@ def test_second_profiler(self): pr = self.profilerclass() pr2 = self.profilerclass() pr.enable() - self.assertRaises(ValueError, pr2.enable) - pr.disable() + self.addCleanup(pr.disable) + msg = f"tool {sys.monitoring.PROFILER_ID} is already in use" + self.assertRaisesRegex(ValueError, msg, pr2.enable) def test_throw(self): """ diff --git a/Misc/NEWS.d/next/Library/2026-07-05-16-09-31.gh-issue-153068.huY9Jh.rst b/Misc/NEWS.d/next/Library/2026-07-05-16-09-31.gh-issue-153068.huY9Jh.rst new file mode 100644 index 00000000000000..accf6e99cd6434 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-05-16-09-31.gh-issue-153068.huY9Jh.rst @@ -0,0 +1,2 @@ +Fix :meth:`!cProfile.Profile.enable` to no longer overwrite errors from +:mod:`sys.monitoring`. diff --git a/Modules/_lsprof.c b/Modules/_lsprof.c index 3d341a336ab22e..4e50ca64f59af2 100644 --- a/Modules/_lsprof.c +++ b/Modules/_lsprof.c @@ -821,7 +821,6 @@ _lsprof_Profiler_enable_impl(ProfilerObject *self, int subcalls, "use_tool_id", "is", self->tool_id, "cProfile"); if (check == NULL) { - PyErr_Format(PyExc_ValueError, "Another profiling tool is already active"); goto error; } Py_DECREF(check); From 017e4e9bb8152bf09acd31b5fcaafceac002d84f Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 7 Jul 2026 02:24:44 +0200 Subject: [PATCH 605/818] [3.15] gh-82151: Update and improve urlsplit docstring (GH-152985) (#153154) gh-82151: Update and improve urlsplit docstring (GH-152985) (cherry picked from commit ad54b91b9fa4c5d12f155bb09138dff21a2bdec3) Co-authored-by: Pranav Choudhary <chaudharyypranav@gmail.com> Co-authored-by: idomic <michael.ido@gmail.com> Co-authored-by: Senthil Kumaran <senthil@python.org> --- Doc/library/urllib.parse.rst | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/Doc/library/urllib.parse.rst b/Doc/library/urllib.parse.rst index ef48addaba03e9..3ce20311c42c84 100644 --- a/Doc/library/urllib.parse.rst +++ b/Doc/library/urllib.parse.rst @@ -60,11 +60,16 @@ or on combining URL components into a URL string. *missing_as_none* is true. Not defined component are represented an empty string (by default) or ``None`` if *missing_as_none* is true. - The components are not broken up - into smaller parts (for example, the network location is a single string), and % - escapes are not expanded. The delimiters as shown above are not part of the - result, except for a leading slash in the *path* component, which is retained if - present. For example: + The delimiters as shown above are not part of the result, except for a + leading slash in the *path* component, which is retained if present. + + Additionally, the netloc property is broken down into these additional + attributes added to the returned object: username, password, hostname, and + port. + + Percent-encoded sequences are not decoded. + + For example: .. doctest:: :options: +NORMALIZE_WHITESPACE From 42e245f67c921444660413162f3cb9f07015c5d0 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 7 Jul 2026 11:16:51 +0200 Subject: [PATCH 606/818] [3.15] gh-153227: Use a development version of Pygments (GH-153228) (#153254) Co-authored-by: Peter Bierma <zintensitydev@gmail.com> --- Doc/pylock.toml | 34 +++++++++++++++++----------------- Doc/requirements.txt | 4 ++++ 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/Doc/pylock.toml b/Doc/pylock.toml index 154eee301ec974..64a051c2399b0a 100644 --- a/Doc/pylock.toml +++ b/Doc/pylock.toml @@ -2,6 +2,7 @@ # uv pip compile Doc/requirements.txt --exclude-newer P14D --exclude-newer-package linklint=PT0S --exclude-newer-package python-docs-theme=PT0S --no-cache --output-file Doc/pylock.toml --python-version 3.12 --universal lock-version = "1.0" created-by = "uv" +requires-python = ">=3.12" [[packages]] name = "alabaster" @@ -23,9 +24,9 @@ wheels = [{ url = "https://files.pythonhosted.org/packages/b4/03/374bd9e31b58e8a [[packages]] name = "certifi" -version = "2026.4.22" -sdist = { url = "https://files.pythonhosted.org/packages/25/ee/6caf7a40c36a1220410afe15a1cc64993a1f864871f698c0f93acb72842a/certifi-2026.4.22.tar.gz", upload-time = 2026-04-22T11:26:11Z, size = 137077, hashes = { sha256 = "8d455352a37b71bf76a79caa83a3d6c25afee4a385d632127b6afb3963f1c580" } } -wheels = [{ url = "https://files.pythonhosted.org/packages/22/30/7cd8fdcdfbc5b869528b079bfb76dcdf6056b1a2097a662e5e8c04f42965/certifi-2026.4.22-py3-none-any.whl", upload-time = 2026-04-22T11:26:09Z, size = 135707, hashes = { sha256 = "3cb2210c8f88ba2318d29b0388d1023c8492ff72ecdde4ebdaddbb13a31b1c4a" } }] +version = "2026.6.17" +sdist = { url = "https://files.pythonhosted.org/packages/c9/c7/424b75da314c1045981bd9777432fad05a9e0c69daa4ed7e308bbaffe405/certifi-2026.6.17.tar.gz", upload-time = 2026-06-17T10:31:07Z, size = 134594, hashes = { sha256 = "024c88eeec92ca068db80f02b8b07c9cef7b9fe261d1d535abfd5abd6f6af432" } } +wheels = [{ url = "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl", upload-time = 2026-06-17T10:31:06Z, size = 133289, hashes = { sha256 = "2227dcbaafe0d2f59279d1762ddddc37783ed4354594f194ffc31d20f41fc3db" } }] [[packages]] name = "charset-normalizer" @@ -114,9 +115,9 @@ wheels = [{ url = "https://files.pythonhosted.org/packages/8f/d7/9322c609343d929 [[packages]] name = "idna" -version = "3.13" -sdist = { url = "https://files.pythonhosted.org/packages/ce/cc/762dfb036166873f0059f3b7de4565e1b5bc3d6f28a414c13da27e442f99/idna-3.13.tar.gz", upload-time = 2026-04-22T16:42:42Z, size = 194210, hashes = { sha256 = "585ea8fe5d69b9181ec1afba340451fba6ba764af97026f92a91d4eef164a242" } } -wheels = [{ url = "https://files.pythonhosted.org/packages/5d/13/ad7d7ca3808a898b4612b6fe93cde56b53f3034dcde235acb1f0e1df24c6/idna-3.13-py3-none-any.whl", upload-time = 2026-04-22T16:42:40Z, size = 68629, hashes = { sha256 = "892ea0cde124a99ce773decba204c5552b69c3c67ffd5f232eb7696135bc8bb3" } }] +version = "3.18" +sdist = { url = "https://files.pythonhosted.org/packages/cd/63/9496c57188a2ee585e0f1db071d75089a11e98aa86eb99d9d7618fc1edce/idna-3.18.tar.gz", upload-time = 2026-06-02T14:34:07Z, size = 196711, hashes = { sha256 = "ffb385a7e039654cef1ab9ef32c6fafe283c0c0467bba1d9029738ce4a14a848" } } +wheels = [{ url = "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl", upload-time = 2026-06-02T14:34:06Z, size = 65455, hashes = { sha256 = "7f952cbe720b688055e3f87de14f5c3e5fdaa8bc3928985c4077ca689de849a2" } }] [[packages]] name = "imagesize" @@ -132,9 +133,9 @@ wheels = [{ url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f [[packages]] name = "linklint" -version = "1.0.0" -sdist = { url = "https://files.pythonhosted.org/packages/f3/59/a2bb261b3fc0e3bfdc9d3e6f8a37bdf1fb6eca8d992f23f55a83bf19acb1/linklint-1.0.0.tar.gz", upload-time = 2026-05-02T11:39:39Z, size = 21310, hashes = { sha256 = "52dc292f27b7eb4f3825d23ec1222d4a17bd116945b77c486406d97bb936e6c2" } } -wheels = [{ url = "https://files.pythonhosted.org/packages/7b/78/98e52e4262416060a0eedc2e5514035cfcfc2fd962d09b84e27848c1aef3/linklint-1.0.0-py3-none-any.whl", upload-time = 2026-05-02T11:39:37Z, size = 12521, hashes = { sha256 = "bbb3f589ab65709cf23655ef6097bdc25180f80c0d42a4d9a1714366d2d3edab" } }] +version = "1.0.1" +sdist = { url = "https://files.pythonhosted.org/packages/62/22/c65a97b2192c3c317c472058bf52d7ca88e421998fa8d5c183b2280ab5d4/linklint-1.0.1.tar.gz", upload-time = 2026-06-09T12:30:47Z, size = 22412, hashes = { sha256 = "10201b4366edecfbeb3281883aff857dbe77d40bb56f16f212d372f597342d5f" } } +wheels = [{ url = "https://files.pythonhosted.org/packages/7b/d8/b2f1708f55f4dd5358b48d28be07ff8e0dadd6d23e41ead2ed1424e90256/linklint-1.0.1-py3-none-any.whl", upload-time = 2026-06-09T12:30:46Z, size = 12828, hashes = { sha256 = "c931f110482f1d17808aa2df78b116adc44d7a14e9e79922c57bf9a7cba40a2d" } }] [[packages]] name = "markupsafe" @@ -162,8 +163,7 @@ wheels = [{ url = "https://files.pythonhosted.org/packages/88/ef/eb23f262cca3c0c [[packages]] name = "pygments" version = "2.20.0" -sdist = { url = "https://files.pythonhosted.org/packages/c3/b2/bc9c9196916376152d655522fdcebac55e66de6603a76a02bca1b6414f6c/pygments-2.20.0.tar.gz", upload-time = 2026-03-29T13:29:33Z, size = 4955991, hashes = { sha256 = "6757cd03768053ff99f3039c1a36d6c0aa0b263438fcab17520b30a303a82b5f" } } -wheels = [{ url = "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl", upload-time = 2026-03-29T13:29:30Z, size = 1231151, hashes = { sha256 = "81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176" } }] +archive = { url = "https://github.com/pygments/pygments/archive/2cad2642058441b59782a6a18f03c98c42d081f1.tar.gz", hashes = { sha256 = "e6ae46831285e86355eabb969bf2d0520655b001dd882147637f4bc500e56bfb" } } [[packages]] name = "python-docs-theme" @@ -173,9 +173,9 @@ wheels = [{ url = "https://files.pythonhosted.org/packages/db/05/b9298eb9330c70a [[packages]] name = "requests" -version = "2.33.1" -sdist = { url = "https://files.pythonhosted.org/packages/5f/a4/98b9c7c6428a668bf7e42ebb7c79d576a1c3c1e3ae2d47e674b468388871/requests-2.33.1.tar.gz", upload-time = 2026-03-30T16:09:15Z, size = 134120, hashes = { sha256 = "18817f8c57c6263968bc123d237e3b8b08ac046f5456bd1e307ee8f4250d3517" } } -wheels = [{ url = "https://files.pythonhosted.org/packages/d7/8e/7540e8a2036f79a125c1d2ebadf69ed7901608859186c856fa0388ef4197/requests-2.33.1-py3-none-any.whl", upload-time = 2026-03-30T16:09:13Z, size = 64947, hashes = { sha256 = "4e6d1ef462f3626a1f0a0a9c42dd93c63bad33f9f1c1937509b8c5c8718ab56a" } }] +version = "2.34.2" +sdist = { url = "https://files.pythonhosted.org/packages/ac/c3/e2a2b89f2d3e2179abd6d00ebd70bff6273f37fb3e0cc209f48b39d00cbf/requests-2.34.2.tar.gz", upload-time = 2026-05-14T19:25:27Z, size = 142856, hashes = { sha256 = "f288924cae4e29463698d6d60bc6a4da69c89185ad1e0bcc4104f584e960b9ed" } } +wheels = [{ url = "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl", upload-time = 2026-05-14T19:25:26Z, size = 73075, hashes = { sha256 = "2a0d60c172f83ac6ab31e4554906c0f3b3588d37b5cb939b1c061f4907e278e0" } }] [[packages]] name = "roman-numerals" @@ -251,6 +251,6 @@ wheels = [{ url = "https://files.pythonhosted.org/packages/bf/a4/66c1fd4f8fab88f [[packages]] name = "urllib3" -version = "2.6.3" -sdist = { url = "https://files.pythonhosted.org/packages/c7/24/5f1b3bdffd70275f6661c76461e25f024d5a38a46f04aaca912426a2b1d3/urllib3-2.6.3.tar.gz", upload-time = 2026-01-07T16:24:43Z, size = 435556, hashes = { sha256 = "1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed" } } -wheels = [{ url = "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl", upload-time = 2026-01-07T16:24:42Z, size = 131584, hashes = { sha256 = "bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4" } }] +version = "2.7.0" +sdist = { url = "https://files.pythonhosted.org/packages/53/0c/06f8b233b8fd13b9e5ee11424ef85419ba0d8ba0b3138bf360be2ff56953/urllib3-2.7.0.tar.gz", upload-time = 2026-05-07T16:13:18Z, size = 433602, hashes = { sha256 = "231e0ec3b63ceb14667c67be60f2f2c40a518cb38b03af60abc813da26505f4c" } } +wheels = [{ url = "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl", upload-time = 2026-05-07T16:13:17Z, size = 131087, hashes = { sha256 = "9fb4c81ebbb1ce9531cce37674bbc6f1360472bc18ca9a553ede278ef7276897" } }] diff --git a/Doc/requirements.txt b/Doc/requirements.txt index 536ae57e4efc29..c5cd360ff31752 100644 --- a/Doc/requirements.txt +++ b/Doc/requirements.txt @@ -9,6 +9,10 @@ # Keep this version in sync with ``Doc/conf.py``. sphinx<9.0.0 +# Temporary direct requirement, pending release of Pygments > 2.20.0 +# https://github.com/pygments/pygments/discussions/3145 +pygments @ https://github.com/pygments/pygments/archive/2cad2642058441b59782a6a18f03c98c42d081f1.tar.gz + blurb sphinxext-opengraph~=0.13.0 From 60ced362180013109abef8d920cd61f6e7d54f08 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 7 Jul 2026 11:30:34 +0200 Subject: [PATCH 607/818] [3.15] Seed pip caches for docs on `main`/`3.x` branches (GH-153127) (#153231) Co-authored-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> --- .github/workflows/reusable-docs.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.github/workflows/reusable-docs.yml b/.github/workflows/reusable-docs.yml index 7b524569f85c9e..50d61ef20c6594 100644 --- a/.github/workflows/reusable-docs.yml +++ b/.github/workflows/reusable-docs.yml @@ -3,6 +3,17 @@ name: Reusable Docs on: workflow_call: workflow_dispatch: + # Pushes to CPython branches seed the pip caches under the exact keys every + # docs PR restores from. Without a branch-scoped copy, each PR saves a + # duplicate into its own refs/pull/N/merge scope that nothing else can read. + push: + branches: + - main + - '3.*' + paths: + - 'Doc/pylock.toml' + - 'Doc/requirements.txt' + - '.github/workflows/reusable-docs.yml' permissions: contents: read From fc840db1bc2eb716242df8c9e848b35e0d1b62ca Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 7 Jul 2026 14:40:11 +0200 Subject: [PATCH 608/818] [3.15] gh-153210: Fix `array` module import crash under a memory pressure (GH-153238) (#153249) gh-153210: Fix `array` module import crash under a memory pressure (GH-153238) (cherry picked from commit 12ed8b16feb3502cea427ff846e9d0b3d7fef721) Co-authored-by: sobolevn <mail@sobolevn.me> --- Lib/test/test_array.py | 19 ++++++++++++++++++- ...-07-07-02-26-43.gh-issue-153210.LUXIcm.rst | 1 + Modules/arraymodule.c | 7 ------- 3 files changed, 19 insertions(+), 8 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-07-07-02-26-43.gh-issue-153210.LUXIcm.rst diff --git a/Lib/test/test_array.py b/Lib/test/test_array.py index f7fa56a6e4bfa0..b24d070330164d 100755 --- a/Lib/test/test_array.py +++ b/Lib/test/test_array.py @@ -5,7 +5,7 @@ import collections.abc import unittest from test import support -from test.support import import_helper +from test.support import import_helper, script_helper from test.support import os_helper from test.support import _2G from test.support import subTests @@ -49,6 +49,23 @@ def test_bad_constructor(self): self.assertRaises(ValueError, array.array, 'x') self.assertRaises(ValueError, array.array, 'Z') + @support.cpython_only + def test_does_not_crash_on_broken_imports(self): + # gh-153210 + code = """if 1: + import collections.abc + + del collections.abc.MutableSequence + + try: + import array # it used to crash before + except AttributeError: + pass + else: + raise AssertionError('AttributeError was not raised') + """ + script_helper.assert_python_ok('-c', code) + @support.cpython_only def test_disallow_instantiation(self): my_array = array.array("I") diff --git a/Misc/NEWS.d/next/Library/2026-07-07-02-26-43.gh-issue-153210.LUXIcm.rst b/Misc/NEWS.d/next/Library/2026-07-07-02-26-43.gh-issue-153210.LUXIcm.rst new file mode 100644 index 00000000000000..d5d4b7c1b8c0ed --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-07-02-26-43.gh-issue-153210.LUXIcm.rst @@ -0,0 +1 @@ +Fix crash on :mod:`array` import under a memory pressure. diff --git a/Modules/arraymodule.c b/Modules/arraymodule.c index aefdfe0edc0e1e..88869f2b22e45f 100644 --- a/Modules/arraymodule.c +++ b/Modules/arraymodule.c @@ -3502,22 +3502,15 @@ array_modexec(PyObject *m) CREATE_TYPE(m, state->ArrayIterType, &arrayiter_spec); Py_SET_TYPE(state->ArrayIterType, &PyType_Type); - if (PyModule_AddObjectRef(m, "ArrayType", - (PyObject *)state->ArrayType) < 0) { - return -1; - } - PyObject *mutablesequence = PyImport_ImportModuleAttrString( "collections.abc", "MutableSequence"); if (!mutablesequence) { - Py_DECREF((PyObject *)state->ArrayType); return -1; } PyObject *res = PyObject_CallMethod(mutablesequence, "register", "O", (PyObject *)state->ArrayType); Py_DECREF(mutablesequence); if (!res) { - Py_DECREF((PyObject *)state->ArrayType); return -1; } Py_DECREF(res); From 9ae12fb390ee4d9e8164df495940bdb144493dc5 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 7 Jul 2026 18:24:08 +0200 Subject: [PATCH 609/818] [3.15] gh-150191: Avoid data race in test_sni_callback_race (GH-150193) (#153269) gh-150191: Avoid data race in test_sni_callback_race (GH-150193) (cherry picked from commit fd9d8c3c66fc147cac6024c63b8c109d65e3aec8) Co-authored-by: Sam Gross <colesbury@gmail.com> --- Lib/test/test_ssl.py | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py index f41262d81a8290..0983a54fe1e7d7 100644 --- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py @@ -1606,19 +1606,24 @@ def dummycallback(sock, servername, ctx, cycle=ctx): gc.collect() self.assertIs(wr(), None) - @unittest.skipUnless(support.Py_GIL_DISABLED, - "test is only useful if the GIL is disabled") @threading_helper.requires_working_threading() def test_sni_callback_race(self): - # Replacing sni_callback while handshakes are in-flight must not + # Replacing sni_callback while a handshake is in-flight must not # crash (use-after-free on the callback in free-threaded builds). + # + # Use a single handshake thread: OpenSSL has internal data races + # on shared SSL_CTX state when multiple handshakes run + # concurrently against the same context (gh-150191). Concurrency + # on the *setter* is what exercises the fix from gh-149816, so + # multiple toggler threads race against each other and against + # the one handshake worker. client_ctx, server_ctx, hostname = testing_context() server_ctx.sni_callback = lambda *a: None - done = threading.Event() + deadline = time.monotonic() + 0.1 def do_handshakes(): - while not done.is_set(): + while time.monotonic() < deadline: c_in = ssl.MemoryBIO() c_out = ssl.MemoryBIO() s_in = ssl.MemoryBIO() @@ -1645,19 +1650,11 @@ def do_handshakes(): c_in.write(s_out.read()) def toggle_callback(): - while not done.is_set(): + while time.monotonic() < deadline: server_ctx.sni_callback = lambda *a: None server_ctx.sni_callback = None - workers = max(4, (os.cpu_count() or 4) * 2) - threads = [threading.Thread(target=do_handshakes) - for _ in range(workers)] - threads.append(threading.Thread(target=toggle_callback)) - - with threading_helper.catch_threading_exception() as cm: - with threading_helper.start_threads(threads): - done.set() - self.assertIsNone(cm.exc_value) + threading_helper.run_concurrently([do_handshakes] + 4 * [toggle_callback]) def test_cert_store_stats(self): ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) From 5605808bbaf2982f6a73f8f1f6d536bdc9b30806 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka <storchaka@gmail.com> Date: Tue, 7 Jul 2026 19:26:50 +0300 Subject: [PATCH 610/818] [3.15] gh-83274: Don't crash when a Tcl interpreter is deallocated in the wrong thread (GH-152323) (GH-153271) Deallocating the interpreter from a thread other than the one it was created in ran Tcl_DeleteInterp() there, which makes Tcl abort the process ("Tcl_AsyncDelete: async handler deleted by the wrong thread"). Tkapp_Dealloc() now leaks the interpreter in that case and reports a RuntimeWarning instead. (cherry picked from commit 46d1809ccd4bc0e1439a4696b428d2a1c2edcfbf) Co-authored-by: E. Paine <63801254+E-Paine@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --- Lib/test/test_tkinter/test_misc.py | 29 +++++++++++++++++++ ...6-06-26-16-30-00.gh-issue-83274.Kx9mQv.rst | 3 ++ Modules/_tkinter.c | 22 +++++++++++--- 3 files changed, 50 insertions(+), 4 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-06-26-16-30-00.gh-issue-83274.Kx9mQv.rst diff --git a/Lib/test/test_tkinter/test_misc.py b/Lib/test/test_tkinter/test_misc.py index 40f20b655993b7..14a5f6782877b4 100644 --- a/Lib/test/test_tkinter/test_misc.py +++ b/Lib/test/test_tkinter/test_misc.py @@ -2,6 +2,7 @@ import functools import platform import sys +import textwrap import unittest import weakref import tkinter @@ -9,6 +10,7 @@ import enum from test import support from test.support import os_helper +from test.support.script_helper import assert_python_ok from test.test_tkinter.support import setUpModule # noqa: F401 from test.test_tkinter.support import (AbstractTkTest, AbstractDefaultRootTest, requires_tk, get_tk_patchlevel, @@ -53,6 +55,33 @@ class Button2(tkinter.Button): b4 = Button2(f2) self.assertEqual(len({str(b), str(b2), str(b3), str(b4)}), 4) + def test_dealloc_in_wrong_thread(self): + # gh-83274: deallocating the interpreter in the wrong thread must not + # crash. + script = textwrap.dedent(""" + import threading + import tkinter + root = tkinter.Tk() + root.destroy() + # Let another thread drop the last reference. + ready = threading.Event() + t = threading.Thread(target=lambda obj: ready.wait(), args=(root,)) + t.start() + del root + ready.set() + t.join() + print('ok') + """) + rc, out, err = assert_python_ok('-c', script) + self.assertEqual(out.strip(), b'ok') + if not support.Py_GIL_DISABLED: + # On the free-threaded build the interpreter may instead be + # deallocated in its own thread (deferred reference counting), so + # the warning is not necessarily emitted. The crucial guarantee -- + # no crash -- is already checked by assert_python_ok() above. + self.assertIn(b'RuntimeWarning', err) + self.assertIn(b'gh-83274', err) + @requires_tk(8, 6, 6) def test_tk_busy(self): root = self.root diff --git a/Misc/NEWS.d/next/Library/2026-06-26-16-30-00.gh-issue-83274.Kx9mQv.rst b/Misc/NEWS.d/next/Library/2026-06-26-16-30-00.gh-issue-83274.Kx9mQv.rst new file mode 100644 index 00000000000000..3b722d2176be92 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-26-16-30-00.gh-issue-83274.Kx9mQv.rst @@ -0,0 +1,3 @@ +Deallocating a :mod:`tkinter` application from a thread other than the one it +was created in no longer crashes the interpreter. The underlying Tcl +interpreter is leaked instead, and a :exc:`RuntimeWarning` is reported. diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c index 7361fd04e21671..62a79128d9726c 100644 --- a/Modules/_tkinter.c +++ b/Modules/_tkinter.c @@ -3132,10 +3132,24 @@ Tkapp_Dealloc(PyObject *op) { TkappObject *self = TkappObject_CAST(op); PyTypeObject *tp = Py_TYPE(self); - /*CHECK_TCL_APPARTMENT;*/ - ENTER_TCL - Tcl_DeleteInterp(Tkapp_Interp(self)); - LEAVE_TCL + if (self->threaded && self->thread_id != Tcl_GetCurrentThread()) { + /* Deleting the interpreter from another thread aborts the process + ("Tcl_AsyncDelete: async handler deleted by the wrong thread"). + Leak it instead (gh-83274). */ + if (PyErr_WarnEx(PyExc_RuntimeWarning, + "the Tcl interpreter is leaked because it was " + "deallocated in a thread other than the one it was " + "created in (see gh-83274)", 1) < 0) + { + PyErr_FormatUnraisable("Exception ignored while finalizing " + "a Tcl interpreter"); + } + } + else { + ENTER_TCL + Tcl_DeleteInterp(Tkapp_Interp(self)); + LEAVE_TCL + } Py_XDECREF(self->trace); PyObject_Free(self); Py_DECREF(tp); From 07d8f50265ca0e266a3d7ec4f66cb3464189f8f7 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 7 Jul 2026 18:30:41 +0200 Subject: [PATCH 611/818] [3.15] Temporarily allow the TSan (free-threading) job to fail (GH-152173) (#153268) (cherry picked from commit 4f39efc47de9b1bc1cd9dfa88060efb4ff104d01) Co-authored-by: Stan Ulbrych <stan@python.org> --- .github/workflows/build.yml | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1203355512e5be..8bf05b0632ba80 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -601,7 +601,6 @@ jobs: - Thread free-threading: - false - - true sanitizer: - TSan include: @@ -613,6 +612,17 @@ jobs: sanitizer: ${{ matrix.sanitizer }} free-threading: ${{ matrix.free-threading }} + # XXX: Temporarily allow this job to fail to not block PRs. + build-san-free-threading: + # ${{ '' } is a hack to nest jobs under the same sidebar category. + name: Sanitizers${{ '' }} # zizmor: ignore[obfuscation] + needs: build-context + if: needs.build-context.outputs.run-ubuntu == 'true' + uses: ./.github/workflows/reusable-san.yml + with: + sanitizer: TSan + free-threading: true + cross-build-linux: name: Cross build Linux runs-on: ubuntu-latest @@ -716,6 +726,7 @@ jobs: - test-hypothesis - build-asan - build-san + - build-san-free-threading - cross-build-linux - cifuzz if: always() @@ -727,6 +738,7 @@ jobs: allowed-failures: >- build-android, build-emscripten, + build-san-free-threading, build-windows-msi, build-ubuntu-ssltests, test-hypothesis, From 7342e012531d46e4508f50887a66d58972f35da2 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 7 Jul 2026 18:34:17 +0200 Subject: [PATCH 612/818] [3.15] gh-153205: Set `MemoryError` in stackref array conversion (GH-153206) (#153272) gh-153205: Set `MemoryError` in stackref array conversion (GH-153206) (cherry picked from commit 08759ff1015552d58c1f6ffa13ea08b0ae32e6c0) Co-authored-by: An Long <aisk@users.noreply.github.com> Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com> Co-authored-by: sobolevn <mail@sobolevn.me> --- .../2026-07-07-04-16-48.gh-issue-153205.5fE8QZ.rst | 2 ++ Python/ceval.c | 1 + 2 files changed, 3 insertions(+) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-07-07-04-16-48.gh-issue-153205.5fE8QZ.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-07-07-04-16-48.gh-issue-153205.5fE8QZ.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-07-07-04-16-48.gh-issue-153205.5fE8QZ.rst new file mode 100644 index 00000000000000..9ccfbff7ee6977 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-07-07-04-16-48.gh-issue-153205.5fE8QZ.rst @@ -0,0 +1,2 @@ +Fix a potential :exc:`SystemError` during vector calls when memory allocation fails. +A :exc:`MemoryError` is now raised instead. diff --git a/Python/ceval.c b/Python/ceval.c index 464a00860524fc..0827b87e00790f 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -1057,6 +1057,7 @@ _PyObjectArray_FromStackRefArray(_PyStackRef *input, Py_ssize_t nargs, PyObject // +1 in case PY_VECTORCALL_ARGUMENTS_OFFSET is set. result = PyMem_Malloc((nargs + 1) * sizeof(PyObject *)); if (result == NULL) { + PyErr_NoMemory(); return NULL; } } From 557e99497942e5f965d11aa07cdf15ab36f6ee74 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 7 Jul 2026 19:26:05 +0200 Subject: [PATCH 613/818] [3.15] gh-153210: Restore accidental `array.ArrayType` removal (GH-153261) (#153274) gh-153210: Restore accidental `array.ArrayType` removal (GH-153261) (cherry picked from commit ac2e14b4e29b2d11a14d289969cfffc298ea75d9) Co-authored-by: sobolevn <mail@sobolevn.me> --- Lib/test/test_array.py | 5 +++++ Modules/arraymodule.c | 6 ++++++ 2 files changed, 11 insertions(+) diff --git a/Lib/test/test_array.py b/Lib/test/test_array.py index b24d070330164d..42213120fb6ced 100755 --- a/Lib/test/test_array.py +++ b/Lib/test/test_array.py @@ -38,6 +38,11 @@ def __init__(self, typecode, newarg=None): class MiscTest(unittest.TestCase): + def test_array_type_importable(self): + from array import ArrayType + + self.assertIs(array.array, ArrayType) + def test_array_is_sequence(self): self.assertIsInstance(array.array("B"), collections.abc.MutableSequence) self.assertIsInstance(array.array("B"), collections.abc.Reversible) diff --git a/Modules/arraymodule.c b/Modules/arraymodule.c index 88869f2b22e45f..a775896db874a6 100644 --- a/Modules/arraymodule.c +++ b/Modules/arraymodule.c @@ -3502,6 +3502,12 @@ array_modexec(PyObject *m) CREATE_TYPE(m, state->ArrayIterType, &arrayiter_spec); Py_SET_TYPE(state->ArrayIterType, &PyType_Type); + // Older undocumented alias: + if (PyModule_AddObjectRef(m, "ArrayType", + (PyObject *)state->ArrayType) < 0) { + return -1; + } + PyObject *mutablesequence = PyImport_ImportModuleAttrString( "collections.abc", "MutableSequence"); if (!mutablesequence) { From c30c8a4a65a9d5b0cf711dd761451a3a5128f927 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 7 Jul 2026 19:27:32 +0200 Subject: [PATCH 614/818] [3.15] gh-153252: Fix error handling in `_PyCompile_CodeGen` (GH-153253) (#153281) gh-153252: Fix error handling in `_PyCompile_CodeGen` (GH-153253) (cherry picked from commit a74280e6696125acb7628facc577d0f975c4d69e) Co-authored-by: sobolevn <mail@sobolevn.me> --- Python/compile.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Python/compile.c b/Python/compile.c index f2c1de5e0c07c6..fefb2b04b78db8 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -1689,7 +1689,7 @@ _PyCompile_CodeGen(PyObject *ast, PyObject *filename, PyCompilerFlags *pflags, metadata = PyDict_New(); if (metadata == NULL) { - return NULL; + goto finally; } if (compiler_codegen(c, mod) < 0) { From e597358779cb965a687ba26422b434d70e3cd201 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 8 Jul 2026 03:40:03 +0200 Subject: [PATCH 615/818] [3.15] gh-153056: Fix a data race compiling the string.Template pattern in free-threading builds (GH-153057) (#153302) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gh-153056: Fix a data race compiling the string.Template pattern in free-threading builds (GH-153057) * gh-153056: Fix a data race compiling the string.Template pattern in free-threading builds Template compiles its substitution pattern lazily and caches it on the class. On the free-threaded build two concurrent first uses could race: a thread that observed the pattern another thread had just compiled would try to recompile it, and re.compile() rejects flags on an already-compiled pattern, raising a spurious ValueError. Return the already-compiled pattern instead. As a side effect, a subclass that supplies an already-compiled pattern now works too; previously it raised the same ValueError at class definition. * Trim test comments and NEWS wording * Document that the pattern attribute accepts a string or a compiled regex * Comment the three states of pattern and note the documented-behavior fix in NEWS * Update Doc/library/string.rst --------- (cherry picked from commit 45729033bff28f8abc36c42e802cb2853c205737) Co-authored-by: tonghuaroot (童话) <tonghuaroot@gmail.com> Co-authored-by: Barry Warsaw <barry@python.org> --- Doc/library/string.rst | 3 +- Lib/string/__init__.py | 7 ++++ .../test_string_template_race.py | 35 +++++++++++++++++++ Lib/test/test_string/test_string.py | 14 ++++++++ ...-07-05-12-00-00.gh-issue-153056.tMpLat.rst | 4 +++ 5 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 Lib/test/test_free_threading/test_string_template_race.py create mode 100644 Misc/NEWS.d/next/Library/2026-07-05-12-00-00.gh-issue-153056.tMpLat.rst diff --git a/Doc/library/string.rst b/Doc/library/string.rst index be968a3c53d843..f1abed91d20ed5 100644 --- a/Doc/library/string.rst +++ b/Doc/library/string.rst @@ -971,7 +971,8 @@ attributes: Alternatively, you can provide the entire regular expression pattern by overriding the class attribute *pattern*. If you do this, the value must be a -regular expression object with four named capturing groups. The capturing +regular expression pattern string, or a compiled regular expression +object, with four named capturing groups. The capturing groups correspond to the rules given above, along with the invalid placeholder rule: diff --git a/Lib/string/__init__.py b/Lib/string/__init__.py index b788d7136f1ae3..88f1ae1b9b023e 100644 --- a/Lib/string/__init__.py +++ b/Lib/string/__init__.py @@ -83,7 +83,14 @@ def __init_subclass__(cls): def _compile_pattern(cls): import re # deferred import, for performance + # `pattern` may be the `_TemplatePattern` sentinel (not yet compiled), an + # already-compiled regular expression object (as documented), or a string + # regular expression. An already-compiled object is returned as-is; the + # other two are compiled and cached back on the class. pattern = cls.__dict__.get('pattern', _TemplatePattern) + if isinstance(pattern, re.Pattern): + # re.compile() rejects flags on an already-compiled pattern. + return pattern if pattern is _TemplatePattern: delim = re.escape(cls.delimiter) id = cls.idpattern diff --git a/Lib/test/test_free_threading/test_string_template_race.py b/Lib/test/test_free_threading/test_string_template_race.py new file mode 100644 index 00000000000000..dc4b4e9f18d286 --- /dev/null +++ b/Lib/test/test_free_threading/test_string_template_race.py @@ -0,0 +1,35 @@ +import string +import unittest +from string import Template + +from test.support import threading_helper + + +@threading_helper.requires_working_threading() +class TestTemplateCompileRace(unittest.TestCase): + def test_concurrent_first_use(self): + # Racing the lazy pattern compile must not raise a spurious ValueError + # from recompiling an already-compiled pattern. A throwaway subclass, + # re-armed to the sentinel each round, keeps string.Template unmutated + # (subclasses precompile eagerly in __init_subclass__). + uncompiled = string._TemplatePattern + errors = [] + + def use_template(cls): + try: + cls("$x and ${y}").substitute(x=1, y=2) + except Exception as e: + errors.append(e) + + for _ in range(20): + class T(Template): + pass + T.pattern = uncompiled + T.flags = None + threading_helper.run_concurrently(use_template, nthreads=10, args=(T,)) + + self.assertEqual(errors, [], msg=f"unexpected errors: {errors}") + + +if __name__ == "__main__": + unittest.main() diff --git a/Lib/test/test_string/test_string.py b/Lib/test/test_string/test_string.py index 5394fe4e12cd41..350784a9f00817 100644 --- a/Lib/test/test_string/test_string.py +++ b/Lib/test/test_string/test_string.py @@ -299,6 +299,20 @@ def test_SafeTemplate(self): eq(s.safe_substitute(dict(who='tim', what='ham', meal='dinner')), 'tim likes ham for dinner') + def test_precompiled_pattern(self): + # A subclass may supply an already-compiled pattern; it must be reused, + # not recompiled (re.compile() rejects flags on a compiled pattern). + import re + compiled = re.compile( + r'\$(?:(?P<escaped>\$)|(?P<named>[a-z]+)|' + r'\{(?P<braced>[a-z]+)\}|(?P<invalid>))') + class MyTemplate(Template): + pattern = compiled + self.assertIs(MyTemplate.pattern, compiled) + self.assertEqual( + MyTemplate('$who likes $what').substitute(who='tim', what='ham'), + 'tim likes ham') + def test_invalid_placeholders(self): raises = self.assertRaises s = Template('$who likes $') diff --git a/Misc/NEWS.d/next/Library/2026-07-05-12-00-00.gh-issue-153056.tMpLat.rst b/Misc/NEWS.d/next/Library/2026-07-05-12-00-00.gh-issue-153056.tMpLat.rst new file mode 100644 index 00000000000000..a2bc89f25a53c1 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-05-12-00-00.gh-issue-153056.tMpLat.rst @@ -0,0 +1,4 @@ +Fix :class:`string.Template` raising a spurious :exc:`ValueError` when the +*pattern* attribute is a compiled regular expression object, which the +documentation allows. On the free-threaded build this also occurred as a data +race on the first concurrent use. From 8c5008060f29a034d4afce7f2de6d39558b8f334 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 8 Jul 2026 12:13:44 +0200 Subject: [PATCH 616/818] [3.15] gh-153292: Fix data race in `threading.RLock.__repr__` in FT builds (GH-153299) (#153314) gh-153292: Fix data race in `threading.RLock.__repr__` in FT builds (GH-153299) (cherry picked from commit 1051384fcdfa88dd88d66dfc93b60aec9ca1ad2e) Co-authored-by: sobolevn <mail@sobolevn.me> --- .../test_free_threading/test_threading.py | 26 +++++++++++++++++++ ...-07-08-01-03-17.gh-issue-153292.oHDt3l.rst | 1 + Modules/_threadmodule.c | 2 +- 3 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 Lib/test/test_free_threading/test_threading.py create mode 100644 Misc/NEWS.d/next/Library/2026-07-08-01-03-17.gh-issue-153292.oHDt3l.rst diff --git a/Lib/test/test_free_threading/test_threading.py b/Lib/test/test_free_threading/test_threading.py new file mode 100644 index 00000000000000..b5a5ca272b9405 --- /dev/null +++ b/Lib/test/test_free_threading/test_threading.py @@ -0,0 +1,26 @@ +import unittest +from test.support import threading_helper + +threading_helper.requires_working_threading(module=True) + + +class TestRlock(unittest.TestCase): + def test_repr_race(self): + # gh-153292 + import _thread + r = _thread.RLock() + + def repr_thread(): + for _ in range(2000): + repr(r) + + def mutate_thread(): + for _ in range(2000): + r.acquire() + r.release() + + threading_helper.run_concurrently([repr_thread, mutate_thread]) + + +if __name__ == "__main__": + unittest.main() diff --git a/Misc/NEWS.d/next/Library/2026-07-08-01-03-17.gh-issue-153292.oHDt3l.rst b/Misc/NEWS.d/next/Library/2026-07-08-01-03-17.gh-issue-153292.oHDt3l.rst new file mode 100644 index 00000000000000..dc363e16007430 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-08-01-03-17.gh-issue-153292.oHDt3l.rst @@ -0,0 +1 @@ +Fix data race in repr of :class:`threading.RLock` in free-threading build. diff --git a/Modules/_threadmodule.c b/Modules/_threadmodule.c index 7e1884edf5213e..e999fe20287e2d 100644 --- a/Modules/_threadmodule.c +++ b/Modules/_threadmodule.c @@ -1288,7 +1288,7 @@ static PyObject * rlock_repr(PyObject *op) { rlockobject *self = rlockobject_CAST(op); - PyThread_ident_t owner = self->lock.thread; + PyThread_ident_t owner = FT_ATOMIC_LOAD_ULLONG_RELAXED(self->lock.thread); int locked = rlock_locked_impl(self); size_t count; if (locked) { From 10ea39e3582124901c2a9ce3289cfebafce92a33 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 8 Jul 2026 14:09:01 +0200 Subject: [PATCH 617/818] [3.15] gh-86017: Document displayof for Font.actual() and clarify Font.copy() (GH-153288) (GH-153329) Explain the displayof argument of tkinter.font.Font.actual() and describe what Font.copy() returns, including for a wrapped font description. (cherry picked from commit fa5eafd19c3d395b4498e21b4e1b8faac2ebdb0a) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --- Doc/library/tkinter.font.rst | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Doc/library/tkinter.font.rst b/Doc/library/tkinter.font.rst index 2a9563fffab1f7..947207724ab040 100644 --- a/Doc/library/tkinter.font.rst +++ b/Doc/library/tkinter.font.rst @@ -54,6 +54,8 @@ The different font weights and slants are: requested ones because of platform limitations. With no *option*, return a dictionary of all the attributes; if *option* is given, return the value of that single attribute. + The attributes are resolved on the display of the *displayof* widget, + or the main application window if it is not specified. .. method:: cget(option) @@ -71,7 +73,11 @@ The different font weights and slants are: .. method:: copy() - Return new instance of the current font. + Return a distinct copy of the current font: + a new named font with the same attributes but a different name, + which can be reconfigured independently of the original. + If the current font wraps a font description, + the copy is instead a named font with its resolved attributes. .. method:: measure(text, displayof=None) From 217472d4cec3e5d19e7f3a718df5c429618d6a5f Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 8 Jul 2026 14:17:10 +0200 Subject: [PATCH 618/818] [3.15] gh-88574: Do not swallow the line after a terminating literal in imaplib (GH-153317) (GH-153324) GH-152751 skipped a spurious blank line after a literal unconditionally, corrupting a response that ends with a literal (such as a mailbox name returned by LIST): its empty trailer was mistaken for the blank and the following line was swallowed. The blank is now skipped only inside an unclosed parenthesis. After a literal that ends the response it instead arrives before the next response and is skipped there. (cherry picked from commit 6b81784f57c6e7ddef61c8db26bb896b3633dcae) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --- Lib/imaplib.py | 18 +++++++- Lib/test/test_imaplib.py | 45 +++++++++++++++++++ ...6-07-01-10-00-00.gh-issue-88574.Kz3wQm.rst | 4 +- 3 files changed, 64 insertions(+), 3 deletions(-) diff --git a/Lib/imaplib.py b/Lib/imaplib.py index 44acaa16397e2d..773913864153b1 100644 --- a/Lib/imaplib.py +++ b/Lib/imaplib.py @@ -137,6 +137,12 @@ _quoted = re.compile(br'"(?:[^"\\]|\\.)*+"') +def _paren_depth(data, depth=0): + # Net parenthesis nesting of data, ignoring parentheses in quoted strings. + data = _quoted.sub(b'', data) + return depth + data.count(b'(') - data.count(b')') + + class IMAP4: r"""IMAP4 client class. @@ -1284,6 +1290,11 @@ def _get_response(self, start_timeout=False): else: resp = self._get_line() + # Skip spurious blank lines between responses (some servers send one + # after a literal that ends a response). + while resp == b'': + resp = self._get_line() + # Command completion response? if self._match(self.tagre, resp): @@ -1321,6 +1332,7 @@ def _get_response(self, start_timeout=False): # Is there a literal to come? + depth = 0 # open parenthesis nesting so far while self._match(self.Literal, dat): # Read literal direct from connection. @@ -1334,13 +1346,15 @@ def _get_response(self, start_timeout=False): # Store response with literal as tuple self._append_untagged(typ, (dat, data)) + depth = _paren_depth(dat, depth) # Read trailer - possibly containing another literal dat = self._get_line() - # Skip a blank line that some servers send after a literal. - if dat == b'': + # Skip spurious blank lines after a literal, but only inside an + # unclosed parenthesis (at top level they end the response). + while dat == b'' and depth > 0: dat = self._get_line() self._append_untagged(typ, dat) diff --git a/Lib/test/test_imaplib.py b/Lib/test/test_imaplib.py index 5786f12f322f74..8e724795b58e75 100644 --- a/Lib/test/test_imaplib.py +++ b/Lib/test/test_imaplib.py @@ -988,6 +988,51 @@ def cmd_FETCH(self, tag, args): self.assertEqual(data, [(b'1 (BODY[HEADER] {13}', b'Subject: test'), b')']) + def test_literal_terminating_response(self): + # A literal ending a response (a LIST mailbox name sent as a literal) + # has an empty trailer that must not be swallowed. Conforming case: + # no spurious blank lines. + names = [b'My (box)"', b'Another', b'Third'] + class Handler(SimpleIMAPHandler): + def cmd_LIST(self, tag, args): + for name in names: + self._send(b'* LIST (\\HasNoChildren) "/" {%d}\r\n' + % len(name)) + self._send(name) + self._send(b'\r\n') # ends the response, no blank + self._send_tagged(tag, 'OK', 'LIST completed') + client, _ = self._setup(Handler) + client.login('user', 'pass') + typ, data = client.list() + self.assertEqual(typ, 'OK') + self.assertEqual(data, [ + (b'(\\HasNoChildren) "/" {9}', b'My (box)"'), b'', + (b'(\\HasNoChildren) "/" {7}', b'Another'), b'', + (b'(\\HasNoChildren) "/" {5}', b'Third'), b'', + ]) + + def test_spurious_blank_lines_between_responses(self): + # A spurious blank line after each terminating literal falls between the + # untagged responses and must be skipped, even several in a row. + names = [b'My (box)"', b'Another', b'Third'] + class Handler(SimpleIMAPHandler): + def cmd_LIST(self, tag, args): + for name in names: + self._send(b'* LIST (\\HasNoChildren) "/" {%d}\r\n' + % len(name)) + self._send(name) + self._send(b'\r\n\r\n') # ends the response, then a blank + self._send_tagged(tag, 'OK', 'LIST completed') + client, _ = self._setup(Handler) + client.login('user', 'pass') + typ, data = client.list() + self.assertEqual(typ, 'OK') + self.assertEqual(data, [ + (b'(\\HasNoChildren) "/" {9}', b'My (box)"'), b'', + (b'(\\HasNoChildren) "/" {7}', b'Another'), b'', + (b'(\\HasNoChildren) "/" {5}', b'Third'), b'', + ]) + def test_unselect(self): client, server = self._setup(SimpleIMAPHandler) client.login('user', 'pass') diff --git a/Misc/NEWS.d/next/Library/2026-07-01-10-00-00.gh-issue-88574.Kz3wQm.rst b/Misc/NEWS.d/next/Library/2026-07-01-10-00-00.gh-issue-88574.Kz3wQm.rst index 8d95bbbb5a15e4..371f4d08bccd2e 100644 --- a/Misc/NEWS.d/next/Library/2026-07-01-10-00-00.gh-issue-88574.Kz3wQm.rst +++ b/Misc/NEWS.d/next/Library/2026-07-01-10-00-00.gh-issue-88574.Kz3wQm.rst @@ -1,2 +1,4 @@ :mod:`imaplib` no longer fails when a server sends a spurious blank line -after the counted data of a literal. Such a blank line is now skipped. +after the counted data of a literal, including after a literal that +terminates a response (such as a mailbox name returned by ``LIST``). +Such blank lines are now skipped without swallowing the following line. From a9d4473232f86d6dfc234756f633b8dc5836ad32 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka <storchaka@gmail.com> Date: Wed, 8 Jul 2026 15:58:19 +0300 Subject: [PATCH 619/818] [3.15] gh-143990: Preserve the size when creating a Font from a named font (GH-153267) (GH-153323) tkinter.font.Font now copies the options of a named font (via "font configure") instead of the options resolved by "font actual", which would resolve a size specified in pixels (a negative size) to points. A font description is still resolved, as it cannot be parsed otherwise. Font.copy(), which has always been equivalent to constructing a Font from the original font, is updated to match and now preserves the size too. (cherry picked from commit 45010f441d392558f1be8f3cea7d86954ed2217d) Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --- Lib/test/test_tkinter/test_font.py | 38 +++++++++++++++++-- Lib/tkinter/font.py | 13 +++++-- ...-07-07-17-50-54.gh-issue-143990.FoNtCf.rst | 4 ++ 3 files changed, 49 insertions(+), 6 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-07-07-17-50-54.gh-issue-143990.FoNtCf.rst diff --git a/Lib/test/test_tkinter/test_font.py b/Lib/test/test_tkinter/test_font.py index 8adc9e1151db4e..6423a4e70af01c 100644 --- a/Lib/test/test_tkinter/test_font.py +++ b/Lib/test/test_tkinter/test_font.py @@ -44,17 +44,49 @@ def test_configure(self): self.assertRaises(TypeError, self.font.cget) self.assertRaises(TypeError, self.font.cget, 'size', 'weight') + def test_create_from_named_font(self): + # gh-143990: a font created from a named font copies its configured + # options, preserving a size specified in pixels (a negative size). + sizetype = int if self.wantobjects else str + named = font.Font(root=self.root, name='my named font', # name with spaces + family='Times', size=-20, weight='bold') + # The source is the name of a named font or a Font representing one. + for source in ['my named font', named]: + with self.subTest(source=source): + f = font.Font(root=self.root, font=source) + self.assertEqual(f.cget('size'), sizetype(-20)) + self.assertEqual(f.actual('family'), named.actual('family')) + self.assertEqual(f.actual('weight'), 'bold') + + def test_create_from_description(self): + # gh-143990: a font created from a font description is resolved via + # "font actual", so a size in pixels (negative) becomes a size in points. + descriptions = [ + ('Times', -20), # tuple + ('Times', -20, 'bold'), # tuple with a style + 'Times -20', # string + 'Times -20 bold', # string with a style + '{Times New Roman} -20', # string, family with spaces + ] + for desc in descriptions: + with self.subTest(font=desc): + f = font.Font(root=self.root, font=desc) + self.assertGreater(int(f.cget('size')), 0) # pixels -> points + def test_copy(self): - f = font.Font(root=self.root, family='Times', size=10, weight='bold') + # size=-20 (pixels): copy() copies the configured options, so the + # size is preserved rather than resolved (gh-143990). + f = font.Font(root=self.root, family='Times', size=-20, weight='bold') copied = f.copy() self.assertIsInstance(copied, font.Font) self.assertIsNot(copied, f) self.assertNotEqual(copied.name, f.name) self.assertEqual(copied.actual(), f.actual()) - # The copy is independent of the original. sizetype = int if self.wantobjects else str + self.assertEqual(copied.cget('size'), sizetype(-20)) + # The copy is independent of the original. copied.configure(size=20) - self.assertEqual(f.cget('size'), sizetype(10)) + self.assertEqual(f.cget('size'), sizetype(-20)) self.assertEqual(copied.cget('size'), sizetype(20)) self.assertRaises(TypeError, f.copy, 'x') diff --git a/Lib/tkinter/font.py b/Lib/tkinter/font.py index 896e910d69f6f3..1face04279af7f 100644 --- a/Lib/tkinter/font.py +++ b/Lib/tkinter/font.py @@ -71,8 +71,15 @@ def __init__(self, root=None, font=None, name=None, exists=False, root = tkinter._get_default_root('use font') tk = getattr(root, 'tk', root) if font: - # get actual settings corresponding to the given font - font = tk.splitlist(tk.call("font", "actual", font)) + # start from the settings of the given font + try: + # a named font: copy its options, preserving the size, + # which can be negative (specified in pixels) + font = tk.splitlist(tk.call("font", "configure", font)) + except tkinter.TclError: + # a font description: resolve it ("font configure" only + # accepts a font name); this loses a size in pixels + font = tk.splitlist(tk.call("font", "actual", font)) else: font = self._set(options) if not name: @@ -125,7 +132,7 @@ def __del__(self): def copy(self): "Return a distinct copy of the current font" - return Font(self._tk, **self.actual()) + return Font(self._tk, self.name) def actual(self, option=None, displayof=None): "Return actual font attributes" diff --git a/Misc/NEWS.d/next/Library/2026-07-07-17-50-54.gh-issue-143990.FoNtCf.rst b/Misc/NEWS.d/next/Library/2026-07-07-17-50-54.gh-issue-143990.FoNtCf.rst new file mode 100644 index 00000000000000..a78dcccf482ab5 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-07-17-50-54.gh-issue-143990.FoNtCf.rst @@ -0,0 +1,4 @@ +A :class:`tkinter.font.Font` created from a named font, +including by :meth:`~tkinter.font.Font.copy`, +now copies its configured options rather than the options resolved by Tcl's ``font actual``, +preserving a size specified in pixels (a negative size). From 8cb4b84c69b3ffbb6f4f32147c52bc7e7cc89af1 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 8 Jul 2026 14:59:13 +0200 Subject: [PATCH 620/818] [3.15] gh-153083: Defer GC tracking of an array to the end of construction. (gh-153284) (gh-153336) gh-153083: Defer GC tracking of an array to the end of construction. (gh-153284) (cherry picked from commit 8615062fd580934fc431746f64b1ac7ee6ef8e88) Co-authored-by: Donghee Na <donghee.na@python.org> --- Include/internal/pycore_object.h | 3 +- ...-07-08-01-47-15.gh-issue-153083.XbKZCp.rst | 2 + Modules/arraymodule.c | 42 ++++++++++++++----- 3 files changed, 35 insertions(+), 12 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-07-08-01-47-15.gh-issue-153083.XbKZCp.rst diff --git a/Include/internal/pycore_object.h b/Include/internal/pycore_object.h index c2c508c1a71c5c..a15685450f54db 100644 --- a/Include/internal/pycore_object.h +++ b/Include/internal/pycore_object.h @@ -873,7 +873,8 @@ static inline int _PyType_SUPPORTS_WEAKREFS(PyTypeObject *type) { return (type->tp_weaklistoffset != 0); } -extern PyObject* _PyType_AllocNoTrack(PyTypeObject *type, Py_ssize_t nitems); +// Export for 'array' shared extension. +PyAPI_FUNC(PyObject*) _PyType_AllocNoTrack(PyTypeObject *type, Py_ssize_t nitems); PyAPI_FUNC(PyObject *) _PyType_NewManagedObject(PyTypeObject *type); extern PyTypeObject* _PyType_CalculateMetaclass(PyTypeObject *, PyObject *); diff --git a/Misc/NEWS.d/next/Library/2026-07-08-01-47-15.gh-issue-153083.XbKZCp.rst b/Misc/NEWS.d/next/Library/2026-07-08-01-47-15.gh-issue-153083.XbKZCp.rst new file mode 100644 index 00000000000000..b6d96851e17342 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-08-01-47-15.gh-issue-153083.XbKZCp.rst @@ -0,0 +1,2 @@ +Defer GC tracking of an :class:`array.array` to the end of its construction. +Patch by Donghee Na. diff --git a/Modules/arraymodule.c b/Modules/arraymodule.c index a775896db874a6..46aec5f201c849 100644 --- a/Modules/arraymodule.c +++ b/Modules/arraymodule.c @@ -14,6 +14,7 @@ #include "pycore_floatobject.h" // _PY_FLOAT_BIG_ENDIAN #include "pycore_modsupport.h" // _PyArg_NoKeywords() #include "pycore_moduleobject.h" // _PyModule_GetState() +#include "pycore_object.h" // _PyObject_GC_TRACK() #include "pycore_tuple.h" // _PyTuple_FromPairSteal #include "pycore_weakref.h" // FT_CLEAR_WEAKREFS() @@ -796,7 +797,8 @@ class array.array "arrayobject *" "ArrayType" /*[clinic end generated code: output=da39a3ee5e6b4b0d input=a5c29edf59f176a3]*/ static PyObject * -newarrayobject(PyTypeObject *type, Py_ssize_t size, const struct arraydescr *descr) +newarrayobject_untracked(PyTypeObject *type, Py_ssize_t size, + const struct arraydescr *descr) { arrayobject *op; size_t nbytes; @@ -811,7 +813,7 @@ newarrayobject(PyTypeObject *type, Py_ssize_t size, const struct arraydescr *des return PyErr_NoMemory(); } nbytes = size * descr->itemsize; - op = (arrayobject *) type->tp_alloc(type, 0); + op = (arrayobject *) _PyType_AllocNoTrack(type, 0); if (op == NULL) { return NULL; } @@ -833,6 +835,16 @@ newarrayobject(PyTypeObject *type, Py_ssize_t size, const struct arraydescr *des return (PyObject *) op; } +static PyObject * +newarrayobject(PyTypeObject *type, Py_ssize_t size, const struct arraydescr *descr) +{ + PyObject *op = newarrayobject_untracked(type, size, descr); + if (op != NULL) { + _PyObject_GC_TRACK(op); + } + return op; +} + static PyObject * getarrayitem(PyObject *op, Py_ssize_t i) { @@ -1034,13 +1046,14 @@ array_slice(arrayobject *a, Py_ssize_t ilow, Py_ssize_t ihigh) ihigh = ilow; else if (ihigh > Py_SIZE(a)) ihigh = Py_SIZE(a); - np = (arrayobject *) newarrayobject(state->ArrayType, ihigh - ilow, a->ob_descr); + np = (arrayobject *) newarrayobject_untracked(state->ArrayType, ihigh - ilow, a->ob_descr); if (np == NULL) return NULL; if (ihigh > ilow) { memcpy(np->ob_item, a->ob_item + ilow * a->ob_descr->itemsize, (ihigh-ilow) * a->ob_descr->itemsize); } + _PyObject_GC_TRACK(np); return (PyObject *)np; } @@ -1111,7 +1124,7 @@ array_concat(PyObject *op, PyObject *bb) return PyErr_NoMemory(); } size = Py_SIZE(a) + Py_SIZE(b); - np = (arrayobject *) newarrayobject(state->ArrayType, size, a->ob_descr); + np = (arrayobject *) newarrayobject_untracked(state->ArrayType, size, a->ob_descr); if (np == NULL) { return NULL; } @@ -1122,6 +1135,7 @@ array_concat(PyObject *op, PyObject *bb) memcpy(np->ob_item + Py_SIZE(a)*a->ob_descr->itemsize, b->ob_item, Py_SIZE(b)*b->ob_descr->itemsize); } + _PyObject_GC_TRACK(np); return (PyObject *)np; #undef b } @@ -1139,16 +1153,19 @@ array_repeat(PyObject *op, Py_ssize_t n) return PyErr_NoMemory(); } Py_ssize_t size = array_length * n; - arrayobject* np = (arrayobject *) newarrayobject(state->ArrayType, size, a->ob_descr); + arrayobject* np = (arrayobject *) newarrayobject_untracked(state->ArrayType, size, a->ob_descr); if (np == NULL) return NULL; - if (size == 0) + if (size == 0) { + _PyObject_GC_TRACK(np); return (PyObject *)np; + } const Py_ssize_t oldbytes = array_length * a->ob_descr->itemsize; const Py_ssize_t newbytes = oldbytes * n; _PyBytes_Repeat(np->ob_item, newbytes, a->ob_item, oldbytes); + _PyObject_GC_TRACK(np); return (PyObject *)np; } @@ -2741,17 +2758,17 @@ array_subscr(PyObject *op, PyObject *item) return newarrayobject(state->ArrayType, 0, self->ob_descr); } else if (step == 1) { - PyObject *result = newarrayobject(state->ArrayType, - slicelength, self->ob_descr); + PyObject *result = newarrayobject_untracked(state->ArrayType, slicelength, self->ob_descr); if (result == NULL) return NULL; memcpy(((arrayobject *)result)->ob_item, self->ob_item + start * itemsize, slicelength * itemsize); + _PyObject_GC_TRACK(result); return result; } else { - result = newarrayobject(state->ArrayType, slicelength, self->ob_descr); + result = newarrayobject_untracked(state->ArrayType, slicelength, self->ob_descr); if (!result) return NULL; ar = (arrayobject*)result; @@ -2763,6 +2780,7 @@ array_subscr(PyObject *op, PyObject *item) itemsize); } + _PyObject_GC_TRACK(result); return result; } } @@ -3060,7 +3078,7 @@ array_new(PyTypeObject *type, PyObject *args, PyObject *kwds) else len = 0; - a = newarrayobject(type, len, descr); + a = newarrayobject_untracked(type, len, descr); if (a == NULL) { Py_XDECREF(it); return NULL; @@ -3148,6 +3166,8 @@ array_new(PyTypeObject *type, PyObject *args, PyObject *kwds) } Py_DECREF(it); } + // Track only once fully built. + _PyObject_GC_TRACK(a); return a; } } @@ -3243,7 +3263,7 @@ static PyType_Slot array_slots[] = { {Py_tp_methods, array_methods}, {Py_tp_members, array_members}, {Py_tp_getset, array_getsets}, - {Py_tp_alloc, PyType_GenericAlloc}, + {Py_tp_alloc, _PyType_AllocNoTrack}, {Py_tp_new, array_new}, {Py_tp_traverse, _PyObject_VisitType}, From 34c68c3034301113589af41f7468226786b6c5e8 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 8 Jul 2026 15:43:59 +0200 Subject: [PATCH 621/818] [3.15] gh-145098: Use `macos-26[-intel]` instead of `macos-15[-intel]` in `{jit,tail-call}.yml` (GH-153194) (#153328) Co-authored-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> --- .github/workflows/jit.yml | 4 ++-- .github/workflows/tail-call.yml | 4 ++-- .pre-commit-config.yaml | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/jit.yml b/.github/workflows/jit.yml index 025ff7ecbeeaff..46c08309b8e739 100644 --- a/.github/workflows/jit.yml +++ b/.github/workflows/jit.yml @@ -102,9 +102,9 @@ jobs: - false include: - target: x86_64-apple-darwin/clang - runner: macos-15-intel + runner: macos-26-intel - target: aarch64-apple-darwin/clang - runner: macos-15 + runner: macos-26 steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: diff --git a/.github/workflows/tail-call.yml b/.github/workflows/tail-call.yml index 656a14906b3cb7..a86a313524605b 100644 --- a/.github/workflows/tail-call.yml +++ b/.github/workflows/tail-call.yml @@ -32,9 +32,9 @@ jobs: matrix: include: - target: x86_64-apple-darwin/clang - runner: macos-15-intel + runner: macos-26-intel - target: aarch64-apple-darwin/clang - runner: macos-15 + runner: macos-26 steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 6878a7d92e3bee..fd859093206750 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -101,7 +101,7 @@ repos: - id: check-readthedocs - repo: https://github.com/rhysd/actionlint - rev: 393031adb9afb225ee52ae2ccd7a5af5525e03e8 # frozen: v1.7.11 + rev: 914e7df21a07ef503a81201c76d2b11c789d3fca # frozen: v1.7.12 hooks: - id: actionlint From d63f3fab95d09478545e1dd2b5368a4083c3070b Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 8 Jul 2026 17:10:56 +0200 Subject: [PATCH 622/818] [3.15] gh-153339: Remove extra skip in `test_generators.py` (GH-153340) (#153343) gh-153339: Remove extra skip in `test_generators.py` (GH-153340) (cherry picked from commit f932a741909da03edfac7ab537c093d2379599a4) Co-authored-by: sobolevn <mail@sobolevn.me> --- Lib/test/test_free_threading/test_generators.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_free_threading/test_generators.py b/Lib/test/test_free_threading/test_generators.py index 2b41e28896f5a8..382503eebd123f 100644 --- a/Lib/test/test_free_threading/test_generators.py +++ b/Lib/test/test_free_threading/test_generators.py @@ -3,11 +3,10 @@ import threading import unittest from threading import Barrier -from unittest import TestCase import random import time -from test.support import threading_helper, Py_GIL_DISABLED +from test.support import threading_helper threading_helper.requires_working_threading(module=True) @@ -32,8 +31,7 @@ def set_gen_qualname(g, b): return g.__qualname__ -@unittest.skipUnless(Py_GIL_DISABLED, "Enable only in FT build") -class TestFTGenerators(TestCase): +class TestFTGenerators(unittest.TestCase): NUM_THREADS = 4 def concurrent_write_with_func(self, func): From 288e3cedd1d5761b132eec9e72d952c3f2bf469b Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 8 Jul 2026 17:30:51 +0200 Subject: [PATCH 623/818] [3.15] gh-153298: Fix data race in `GenericAlias` parameter initialization on FT (GH-153318) (#153345) gh-153298: Fix data race in `GenericAlias` parameter initialization on FT (GH-153318) (cherry picked from commit 68abf17fa926db94dc17f01a7095bdcee2a52314) Co-authored-by: sobolevn <mail@sobolevn.me> --- Lib/test/test_free_threading/test_types.py | 33 +++++++++++++++++++ ...-07-08-13-23-11.gh-issue-153298.wvcXxN.rst | 2 ++ Objects/genericaliasobject.c | 12 ++++++- 3 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 Lib/test/test_free_threading/test_types.py create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-07-08-13-23-11.gh-issue-153298.wvcXxN.rst diff --git a/Lib/test/test_free_threading/test_types.py b/Lib/test/test_free_threading/test_types.py new file mode 100644 index 00000000000000..76fcf1590122f5 --- /dev/null +++ b/Lib/test/test_free_threading/test_types.py @@ -0,0 +1,33 @@ +import unittest +from typing import TypeVar +from test.support import threading_helper + +threading_helper.requires_working_threading(module=True) + + +class TestGenericAlias(unittest.TestCase): + def test_parameters_race(self): + # gh-153298 + + T = TypeVar('T') + slot = [list[T]] + + def access(): + for _ in range(2000): + try: + _ = slot[0].__parameters__ + except Exception: + pass + + def refresh(): + for _ in range(2000): + slot[0] = list[T] + + threading_helper.run_concurrently([ + *[access for _ in range(6)], + *[refresh for _ in range(2)], + ]) + + +if __name__ == "__main__": + unittest.main() diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-07-08-13-23-11.gh-issue-153298.wvcXxN.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-07-08-13-23-11.gh-issue-153298.wvcXxN.rst new file mode 100644 index 00000000000000..38d548834d5e02 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-07-08-13-23-11.gh-issue-153298.wvcXxN.rst @@ -0,0 +1,2 @@ +Fixes a data race in :class:`types.GenericAlias` ``__parameters__`` +initialization on free-threading builds. diff --git a/Objects/genericaliasobject.c b/Objects/genericaliasobject.c index c2083e6fcb77f4..4e85927def7ea7 100644 --- a/Objects/genericaliasobject.c +++ b/Objects/genericaliasobject.c @@ -841,7 +841,7 @@ static PyMemberDef ga_members[] = { }; static PyObject * -ga_parameters(PyObject *self, void *unused) +ga_parameters_lock_held(PyObject *self) { gaobject *alias = (gaobject *)self; if (alias->parameters == NULL) { @@ -853,6 +853,16 @@ ga_parameters(PyObject *self, void *unused) return Py_NewRef(alias->parameters); } +static PyObject * +ga_parameters(PyObject *self, void *unused) +{ + PyObject *result; + Py_BEGIN_CRITICAL_SECTION(self); + result = ga_parameters_lock_held(self); + Py_END_CRITICAL_SECTION(); + return result; +} + static PyObject * ga_unpacked_tuple_args(PyObject *self, void *unused) { From c8434e6603e2a2d349002503498e52006085f6bf Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 8 Jul 2026 18:04:13 +0200 Subject: [PATCH 624/818] [3.15] gh-150191: temporarily skip two openssl tests which have internal data races under TSAN (GH-153320) (#153350) gh-150191: temporarily skip two openssl tests which have internal data races under TSAN (GH-153320) (cherry picked from commit c11af48fddb1fd5b38e2f026c333e8487f3bcc53) Co-authored-by: Kumar Aditya <kumaraditya@python.org> --- Lib/test/test_ssl.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py index 0983a54fe1e7d7..90fe087ecb8511 100644 --- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py @@ -1606,6 +1606,9 @@ def dummycallback(sock, servername, ctx, cycle=ctx): gc.collect() self.assertIs(wr(), None) + @support.skip_if_sanitizer("gh-150191: OpenSSL has an internal data race " + "when the SNI callback is replaced during a " + "handshake", thread=True) @threading_helper.requires_working_threading() def test_sni_callback_race(self): # Replacing sni_callback while a handshake is in-flight must not @@ -5045,6 +5048,9 @@ def server_callback(identity): with client_context.wrap_socket(socket.socket()) as s: s.connect((HOST, server.port)) + @support.skip_if_sanitizer("gh-150191: OpenSSL races on SSL->rwstate and " + "the socket BIO flags with concurrent read " + "and write", thread=True) def test_thread_recv_while_main_thread_sends(self): # GH-137583: Locking was added to calls to send() and recv() on SSL # socket objects. This seemed fine at the surface level because those From 6af15c9b208975b53493ff4eb1eeebaaf3ac5878 Mon Sep 17 00:00:00 2001 From: Kumar Aditya <kumaraditya@python.org> Date: Wed, 8 Jul 2026 23:01:34 +0530 Subject: [PATCH 625/818] [3.15] gh-143750: Compile OpenSSL with TSan for TSan CI (#153316) (#153353) gh-143750: Compile OpenSSL with TSan for TSan CI (#153316) (cherry picked from commit fc19ad7b8b08c43667c9087d89f32f08830544ce) Co-authored-by: Sam Gross <colesbury@gmail.com> --- .github/workflows/reusable-san.yml | 65 +++++++++++++++++++++--------- Tools/ssl/multissltests.py | 8 ++++ 2 files changed, 55 insertions(+), 18 deletions(-) diff --git a/.github/workflows/reusable-san.yml b/.github/workflows/reusable-san.yml index aed2776b4bab71..2efa9e781033bd 100644 --- a/.github/workflows/reusable-san.yml +++ b/.github/workflows/reusable-san.yml @@ -17,6 +17,7 @@ permissions: env: FORCE_COLOR: 1 + OPENSSL_VER: 3.5.7 jobs: build-san-reusable: @@ -45,28 +46,55 @@ jobs: sudo update-alternatives --set clang /usr/bin/clang-21 sudo update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-21 100 sudo update-alternatives --set clang++ /usr/bin/clang++-21 - - if [ "${SANITIZER}" = "TSan" ]; then - # Reduce ASLR to avoid TSan crashing - sudo sysctl -w vm.mmap_rnd_bits=28 - fi - - - name: Sanitizer option setup - run: | - if [ "${SANITIZER}" = "TSan" ]; then - echo "TSAN_OPTIONS=${SAN_LOG_OPTION} suppressions=${GITHUB_WORKSPACE}/Tools/tsan/suppressions${{ - fromJSON(inputs.free-threading) - && '_free_threading' - || '' - }}.txt handle_segv=0" >> "$GITHUB_ENV" - else - echo "UBSAN_OPTIONS=${SAN_LOG_OPTION} halt_on_error=1 suppressions=${GITHUB_WORKSPACE}/Tools/ubsan/suppressions.txt" >> "$GITHUB_ENV" - fi echo "CC=clang" >> "$GITHUB_ENV" echo "CXX=clang++" >> "$GITHUB_ENV" + - name: TSan option setup + if: inputs.sanitizer == 'TSan' + run: | + sudo sysctl -w vm.mmap_rnd_bits=28 # Reduce ASLR to avoid TSan crashing + + echo "MULTISSL_DIR=${GITHUB_WORKSPACE}/multissl" >> "$GITHUB_ENV" + echo "OPENSSL_DIR=${GITHUB_WORKSPACE}/multissl/openssl/${OPENSSL_VER}" >> "$GITHUB_ENV" + echo "TSAN_OPTIONS=${SAN_LOG_OPTION} suppressions=${GITHUB_WORKSPACE}/Tools/tsan/suppressions${SUPPRESSIONS_SUFFIX}.txt handle_segv=0" >> "$GITHUB_ENV" env: - SANITIZER: ${{ inputs.sanitizer }} SAN_LOG_OPTION: log_path=${{ github.workspace }}/san_log + SUPPRESSIONS_SUFFIX: >- + ${{ + fromJSON(inputs.free-threading) + && '_free_threading' + || '' + }} + - name: UBSan option setup + if: inputs.sanitizer != 'TSan' + run: >- + echo + "UBSAN_OPTIONS=${SAN_LOG_OPTION} + halt_on_error=1 + suppressions=${GITHUB_WORKSPACE}/Tools/ubsan/suppressions.txt" + >> "$GITHUB_ENV" + env: + SAN_LOG_OPTION: log_path=${{ github.workspace }}/san_log + - name: Add ccache to PATH + run: | + echo "PATH=/usr/lib/ccache:$PATH" >> "$GITHUB_ENV" + - name: 'Restore OpenSSL build (TSan)' + id: cache-openssl + if: inputs.sanitizer == 'TSan' + uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 + with: + path: ./multissl/openssl/${{ env.OPENSSL_VER }} + key: ${{ env.IMAGE_OS_VERSION }}-multissl-openssl-tsan-${{ env.OPENSSL_VER }} + - name: Install OpenSSL (TSan) + if: >- + inputs.sanitizer == 'TSan' + && steps.cache-openssl.outputs.cache-hit != 'true' + run: >- + python3 Tools/ssl/multissltests.py + --steps=library + --base-directory="${MULTISSL_DIR}" + --openssl="${OPENSSL_VER}" + --system=Linux + --tsan - name: Configure CPython run: >- ./configure @@ -77,6 +105,7 @@ jobs: || '--with-undefined-behavior-sanitizer --with-strict-overflow' }} --with-pydebug + ${{ inputs.sanitizer == 'TSan' && '--with-openssl="$OPENSSL_DIR" --with-openssl-rpath=auto' || '' }} ${{ fromJSON(inputs.free-threading) && '--disable-gil' || '' }} - name: Build CPython run: make -j4 diff --git a/Tools/ssl/multissltests.py b/Tools/ssl/multissltests.py index 1a213187b897d1..d5e38993d971df 100755 --- a/Tools/ssl/multissltests.py +++ b/Tools/ssl/multissltests.py @@ -163,6 +163,12 @@ dest='keep_sources', help="Keep original sources for debugging." ) +parser.add_argument( + '--tsan', + action='store_true', + dest='tsan', + help="Build with thread sanitizer. (Disables fips in OpenSSL 3.x)." +) class AbstractBuilder(object): @@ -317,6 +323,8 @@ def _build_src(self, config_args=()): """Now build openssl""" log.info("Running build in {}".format(self.build_dir)) cwd = self.build_dir + if self.args.tsan: + config_args += ("-fsanitize=thread",) cmd = [ "./config", *config_args, "shared", "--debug", From c5e73f8c91dd7a6aa7587b60e526b3e3a915bb3b Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 8 Jul 2026 20:21:20 +0200 Subject: [PATCH 626/818] [3.15] gh-153300: Set global configuration variables in PyConfig_Set() (GH-153301) (#153356) gh-153300: Set global configuration variables in PyConfig_Set() (GH-153301) PyConfig_Set() now also set global configuration variables. For example, PyConfig_Set("inspect", value) now also sets Py_InspectFlag. Use PyConfig_Set() in main.c to set the inspect flag. Python code can now see the updated sys.flags.inspect value. (cherry picked from commit 9fb713f1b8b774c789db007e3824c766a626ccff) Co-authored-by: Victor Stinner <vstinner@python.org> --- Lib/test/test_capi/test_config.py | 41 ++++ ...-07-08-00-38-32.gh-issue-153300.lVoWyR.rst | 3 + Modules/main.c | 16 +- Python/initconfig.c | 192 +++++++++++------- 4 files changed, 167 insertions(+), 85 deletions(-) create mode 100644 Misc/NEWS.d/next/C_API/2026-07-08-00-38-32.gh-issue-153300.lVoWyR.rst diff --git a/Lib/test/test_capi/test_config.py b/Lib/test/test_capi/test_config.py index c750a6c2a477ab..29012634361838 100644 --- a/Lib/test/test_capi/test_config.py +++ b/Lib/test/test_capi/test_config.py @@ -9,6 +9,7 @@ from test.support import import_helper _testcapi = import_helper.import_module('_testcapi') +_testinternalcapi = import_helper.import_module('_testinternalcapi') # Is the Py_STATS macro defined? @@ -378,6 +379,46 @@ def expect_bool_not(value): finally: config_set(name, old_value) + def test_config_set_global_vars(self): + # Test PyConfig_Set() with global configuration variables + config_get = _testcapi.config_get + config_set = _testcapi.config_set + get_configs = _testinternalcapi.get_configs + new_values = (0, 1, 5) + + for name, global_name, not_value in ( + ('bytes_warning', 'Py_BytesWarningFlag', False), + ('inspect', 'Py_InspectFlag', False), + ('interactive', 'Py_InteractiveFlag', False), + ('optimization_level', 'Py_OptimizeFlag', False), + ('parser_debug', 'Py_DebugFlag', False), + ('quiet', 'Py_QuietFlag', False), + ('use_environment', 'Py_IgnoreEnvironmentFlag', True), + ('verbose', 'Py_VerboseFlag', False), + ('write_bytecode', 'Py_DontWriteBytecodeFlag', True), + + # Read-only variables + #('buffered_stdio', 'Py_UnbufferedStdioFlag', True), + #('isolated', 'Py_IsolatedFlag', False), + #('pathconfig_warnings', 'Py_FrozenFlag', True), + #('site_import', 'Py_NoSiteFlag', True), + #('user_site_directory', 'Py_NoUserSiteDirectory', True), + # Windows only + #('legacy_windows_stdio', 'Py_LegacyWindowsStdioFlag', False) + ): + with self.subTest(name=name): + old_value = config_get(name) + try: + for value in new_values: + config_set(name, value) + global_config = get_configs()['global_config'] + expected = value + if not_value: + expected = int(not value) + self.assertEqual(global_config[global_name], expected) + finally: + config_set(name, old_value) + def test_config_set_cpu_count(self): config_get = _testcapi.config_get config_set = _testcapi.config_set diff --git a/Misc/NEWS.d/next/C_API/2026-07-08-00-38-32.gh-issue-153300.lVoWyR.rst b/Misc/NEWS.d/next/C_API/2026-07-08-00-38-32.gh-issue-153300.lVoWyR.rst new file mode 100644 index 00000000000000..3c19c0e15d2bc6 --- /dev/null +++ b/Misc/NEWS.d/next/C_API/2026-07-08-00-38-32.gh-issue-153300.lVoWyR.rst @@ -0,0 +1,3 @@ +:c:func:`PyConfig_Set()` now also set global configuration variables. For +example, ``PyConfig_Set("inspect", value)`` now also sets +:c:var:`Py_InspectFlag`. Patch by Victor Stinner. diff --git a/Modules/main.c b/Modules/main.c index a4dfddd98e257e..2f23513cc2403d 100644 --- a/Modules/main.c +++ b/Modules/main.c @@ -529,11 +529,15 @@ pymain_run_interactive_hook(int *exitcode) static void pymain_set_inspect(PyConfig *config, int inspect) { - config->inspect = inspect; -_Py_COMP_DIAG_PUSH -_Py_COMP_DIAG_IGNORE_DEPR_DECLS - Py_InspectFlag = inspect; -_Py_COMP_DIAG_POP + PyObject *value = PyLong_FromLong(inspect); + if (value == NULL || PyConfig_Set("inspect", value) < 0) { + fprintf(stderr, "Could not set the inspect flag\n"); + PyErr_Print(); + } + else { + assert(config->inspect == inspect); + } + Py_XDECREF(value); } @@ -635,7 +639,7 @@ pymain_run_python(int *exitcode) { PyObject *main_importer_path = NULL; PyInterpreterState *interp = _PyInterpreterState_GET(); - /* pymain_run_stdin() modify the config */ + /* pymain_repl() and pymain_run_stdin() modify the config */ PyConfig *config = (PyConfig*)_PyInterpreterState_GetConfig(interp); /* ensure path config is written into global variables */ diff --git a/Python/initconfig.c b/Python/initconfig.c index 185b5b107d68db..a7cd08de8cc492 100644 --- a/Python/initconfig.c +++ b/Python/initconfig.c @@ -84,120 +84,139 @@ typedef struct { config_sys_flag_setter flag_setter; } PyConfigSysSpec; +typedef struct { + int *ptr; + int not; +} PyConfigGlobalVar; + typedef struct { const char *name; size_t offset; PyConfigMemberType type; PyConfigMemberVisibility visibility; PyConfigSysSpec sys; + PyConfigGlobalVar global_var; } PyConfigSpec; -#define SPEC(MEMBER, TYPE, VISIBILITY, sys) \ +#define SPEC(MEMBER, TYPE, VISIBILITY, sys, global_var) \ {#MEMBER, offsetof(PyConfig, MEMBER), \ - PyConfig_MEMBER_##TYPE, PyConfig_MEMBER_##VISIBILITY, sys} + PyConfig_MEMBER_##TYPE, PyConfig_MEMBER_##VISIBILITY, sys, global_var} #define SYS_ATTR(name) {name, -1, NULL} #define SYS_FLAG_SETTER(index, setter) {NULL, index, setter} #define SYS_FLAG(index) SYS_FLAG_SETTER(index, NULL) #define NO_SYS SYS_ATTR(NULL) +#define GLOBAL(ptr, not) {ptr, not} +#define NO_GLOBAL GLOBAL(NULL, 0) + +// Ignore deprecations on global variables such as Py_IsolatedFlag +_Py_COMP_DIAG_PUSH +_Py_COMP_DIAG_IGNORE_DEPR_DECLS + // Update _test_embed_set_config when adding new members static const PyConfigSpec PYCONFIG_SPEC[] = { // --- Public options ----------- - SPEC(argv, WSTR_LIST, PUBLIC, SYS_ATTR("argv")), - SPEC(base_exec_prefix, WSTR_OPT, PUBLIC, SYS_ATTR("base_exec_prefix")), - SPEC(base_executable, WSTR_OPT, PUBLIC, SYS_ATTR("_base_executable")), - SPEC(base_prefix, WSTR_OPT, PUBLIC, SYS_ATTR("base_prefix")), - SPEC(bytes_warning, UINT, PUBLIC, SYS_FLAG(9)), - SPEC(cpu_count, INT, PUBLIC, NO_SYS), - SPEC(lazy_imports, INT, PUBLIC, NO_SYS), - SPEC(exec_prefix, WSTR_OPT, PUBLIC, SYS_ATTR("exec_prefix")), - SPEC(executable, WSTR_OPT, PUBLIC, SYS_ATTR("executable")), - SPEC(inspect, BOOL, PUBLIC, SYS_FLAG(1)), - SPEC(int_max_str_digits, UINT, PUBLIC, NO_SYS), - SPEC(interactive, BOOL, PUBLIC, SYS_FLAG(2)), - SPEC(module_search_paths, WSTR_LIST, PUBLIC, SYS_ATTR("path")), - SPEC(optimization_level, UINT, PUBLIC, SYS_FLAG(3)), - SPEC(parser_debug, BOOL, PUBLIC, SYS_FLAG(0)), - SPEC(platlibdir, WSTR, PUBLIC, SYS_ATTR("platlibdir")), - SPEC(prefix, WSTR_OPT, PUBLIC, SYS_ATTR("prefix")), - SPEC(pycache_prefix, WSTR_OPT, PUBLIC, SYS_ATTR("pycache_prefix")), - SPEC(quiet, BOOL, PUBLIC, SYS_FLAG(10)), - SPEC(stdlib_dir, WSTR_OPT, PUBLIC, SYS_ATTR("_stdlib_dir")), - SPEC(use_environment, BOOL, PUBLIC, SYS_FLAG_SETTER(7, config_sys_flag_not)), - SPEC(verbose, UINT, PUBLIC, SYS_FLAG(8)), - SPEC(warnoptions, WSTR_LIST, PUBLIC, SYS_ATTR("warnoptions")), - SPEC(write_bytecode, BOOL, PUBLIC, SYS_FLAG_SETTER(4, config_sys_flag_not)), - SPEC(xoptions, WSTR_LIST, PUBLIC, SYS_ATTR("_xoptions")), + SPEC(argv, WSTR_LIST, PUBLIC, SYS_ATTR("argv"), NO_GLOBAL), + SPEC(base_exec_prefix, WSTR_OPT, PUBLIC, SYS_ATTR("base_exec_prefix"), NO_GLOBAL), + SPEC(base_executable, WSTR_OPT, PUBLIC, SYS_ATTR("_base_executable"), NO_GLOBAL), + SPEC(base_prefix, WSTR_OPT, PUBLIC, SYS_ATTR("base_prefix"), NO_GLOBAL), + SPEC(bytes_warning, UINT, PUBLIC, SYS_FLAG(9), GLOBAL(&Py_BytesWarningFlag, 0)), + SPEC(cpu_count, INT, PUBLIC, NO_SYS, NO_GLOBAL), + SPEC(lazy_imports, INT, PUBLIC, NO_SYS, NO_GLOBAL), + SPEC(exec_prefix, WSTR_OPT, PUBLIC, SYS_ATTR("exec_prefix"), NO_GLOBAL), + SPEC(executable, WSTR_OPT, PUBLIC, SYS_ATTR("executable"), NO_GLOBAL), + SPEC(inspect, BOOL, PUBLIC, SYS_FLAG(1), GLOBAL(&Py_InspectFlag, 0)), + SPEC(int_max_str_digits, UINT, PUBLIC, NO_SYS, NO_GLOBAL), + SPEC(interactive, BOOL, PUBLIC, SYS_FLAG(2), GLOBAL(&Py_InteractiveFlag, 0)), + SPEC(module_search_paths, WSTR_LIST, PUBLIC, SYS_ATTR("path"), NO_GLOBAL), + SPEC(optimization_level, UINT, PUBLIC, SYS_FLAG(3), GLOBAL(&Py_OptimizeFlag, 0)), + SPEC(parser_debug, BOOL, PUBLIC, SYS_FLAG(0), GLOBAL(&Py_DebugFlag, 0)), + SPEC(platlibdir, WSTR, PUBLIC, SYS_ATTR("platlibdir"), NO_GLOBAL), + SPEC(prefix, WSTR_OPT, PUBLIC, SYS_ATTR("prefix"), NO_GLOBAL), + SPEC(pycache_prefix, WSTR_OPT, PUBLIC, SYS_ATTR("pycache_prefix"), NO_GLOBAL), + SPEC(quiet, BOOL, PUBLIC, SYS_FLAG(10), GLOBAL(&Py_QuietFlag, 0)), + SPEC(stdlib_dir, WSTR_OPT, PUBLIC, SYS_ATTR("_stdlib_dir"), NO_GLOBAL), + SPEC(use_environment, BOOL, PUBLIC, + SYS_FLAG_SETTER(7, config_sys_flag_not), GLOBAL(&Py_IgnoreEnvironmentFlag, 1)), + SPEC(verbose, UINT, PUBLIC, SYS_FLAG(8), GLOBAL(&Py_VerboseFlag, 0)), + SPEC(warnoptions, WSTR_LIST, PUBLIC, SYS_ATTR("warnoptions"), NO_GLOBAL), + SPEC(write_bytecode, BOOL, PUBLIC, SYS_FLAG_SETTER(4, config_sys_flag_not), + GLOBAL(&Py_DontWriteBytecodeFlag, 1)), + SPEC(xoptions, WSTR_LIST, PUBLIC, SYS_ATTR("_xoptions"), NO_GLOBAL), // --- Read-only options ----------- #ifdef Py_STATS - SPEC(_pystats, BOOL, READ_ONLY, NO_SYS), + SPEC(_pystats, BOOL, READ_ONLY, NO_SYS, NO_GLOBAL), #endif - SPEC(buffered_stdio, BOOL, READ_ONLY, NO_SYS), - SPEC(check_hash_pycs_mode, WSTR, READ_ONLY, NO_SYS), - SPEC(code_debug_ranges, BOOL, READ_ONLY, NO_SYS), - SPEC(configure_c_stdio, BOOL, READ_ONLY, NO_SYS), - SPEC(dev_mode, BOOL, READ_ONLY, NO_SYS), // sys.flags.dev_mode - SPEC(dump_refs, BOOL, READ_ONLY, NO_SYS), - SPEC(dump_refs_file, WSTR_OPT, READ_ONLY, NO_SYS), + SPEC(buffered_stdio, BOOL, READ_ONLY, NO_SYS, + GLOBAL(&Py_UnbufferedStdioFlag, 1)), + SPEC(check_hash_pycs_mode, WSTR, READ_ONLY, NO_SYS, NO_GLOBAL), + SPEC(code_debug_ranges, BOOL, READ_ONLY, NO_SYS, NO_GLOBAL), + SPEC(configure_c_stdio, BOOL, READ_ONLY, NO_SYS, NO_GLOBAL), + SPEC(dev_mode, BOOL, READ_ONLY, NO_SYS, NO_GLOBAL), // sys.flags.dev_mode + SPEC(dump_refs, BOOL, READ_ONLY, NO_SYS, NO_GLOBAL), + SPEC(dump_refs_file, WSTR_OPT, READ_ONLY, NO_SYS, NO_GLOBAL), #ifdef Py_GIL_DISABLED - SPEC(enable_gil, INT, READ_ONLY, NO_SYS), - SPEC(tlbc_enabled, INT, READ_ONLY, NO_SYS), + SPEC(enable_gil, INT, READ_ONLY, NO_SYS, NO_GLOBAL), + SPEC(tlbc_enabled, INT, READ_ONLY, NO_SYS, NO_GLOBAL), #endif - SPEC(faulthandler, BOOL, READ_ONLY, NO_SYS), - SPEC(filesystem_encoding, WSTR, READ_ONLY, NO_SYS), - SPEC(filesystem_errors, WSTR, READ_ONLY, NO_SYS), - SPEC(hash_seed, ULONG, READ_ONLY, NO_SYS), - SPEC(home, WSTR_OPT, READ_ONLY, NO_SYS), - SPEC(thread_inherit_context, INT, READ_ONLY, NO_SYS), - SPEC(context_aware_warnings, INT, READ_ONLY, NO_SYS), - SPEC(import_time, UINT, READ_ONLY, NO_SYS), - SPEC(install_signal_handlers, BOOL, READ_ONLY, NO_SYS), - SPEC(isolated, BOOL, READ_ONLY, NO_SYS), // sys.flags.isolated + SPEC(faulthandler, BOOL, READ_ONLY, NO_SYS, NO_GLOBAL), + SPEC(filesystem_encoding, WSTR, READ_ONLY, NO_SYS, NO_GLOBAL), + SPEC(filesystem_errors, WSTR, READ_ONLY, NO_SYS, NO_GLOBAL), + SPEC(hash_seed, ULONG, READ_ONLY, NO_SYS, NO_GLOBAL), + SPEC(home, WSTR_OPT, READ_ONLY, NO_SYS, NO_GLOBAL), + SPEC(thread_inherit_context, INT, READ_ONLY, NO_SYS, NO_GLOBAL), + SPEC(context_aware_warnings, INT, READ_ONLY, NO_SYS, NO_GLOBAL), + SPEC(import_time, UINT, READ_ONLY, NO_SYS, NO_GLOBAL), + SPEC(install_signal_handlers, BOOL, READ_ONLY, NO_SYS, NO_GLOBAL), + SPEC(isolated, BOOL, READ_ONLY, NO_SYS, GLOBAL(&Py_IsolatedFlag, 0)), // sys.flags.isolated #ifdef MS_WINDOWS - SPEC(legacy_windows_stdio, BOOL, READ_ONLY, NO_SYS), + SPEC(legacy_windows_stdio, BOOL, READ_ONLY, NO_SYS, + GLOBAL(&Py_LegacyWindowsStdioFlag, 0)), #endif - SPEC(malloc_stats, BOOL, READ_ONLY, NO_SYS), - SPEC(pymalloc_hugepages, BOOL, READ_ONLY, NO_SYS), - SPEC(orig_argv, WSTR_LIST, READ_ONLY, SYS_ATTR("orig_argv")), - SPEC(parse_argv, BOOL, READ_ONLY, NO_SYS), - SPEC(pathconfig_warnings, BOOL, READ_ONLY, NO_SYS), - SPEC(perf_profiling, UINT, READ_ONLY, NO_SYS), - SPEC(remote_debug, BOOL, READ_ONLY, NO_SYS), - SPEC(program_name, WSTR, READ_ONLY, NO_SYS), - SPEC(run_command, WSTR_OPT, READ_ONLY, NO_SYS), - SPEC(run_filename, WSTR_OPT, READ_ONLY, NO_SYS), - SPEC(run_module, WSTR_OPT, READ_ONLY, NO_SYS), + SPEC(malloc_stats, BOOL, READ_ONLY, NO_SYS, NO_GLOBAL), + SPEC(pymalloc_hugepages, BOOL, READ_ONLY, NO_SYS, NO_GLOBAL), + SPEC(orig_argv, WSTR_LIST, READ_ONLY, SYS_ATTR("orig_argv"), NO_GLOBAL), + SPEC(parse_argv, BOOL, READ_ONLY, NO_SYS, NO_GLOBAL), + SPEC(pathconfig_warnings, BOOL, READ_ONLY, NO_SYS, + GLOBAL(&Py_FrozenFlag, 1)), + SPEC(perf_profiling, UINT, READ_ONLY, NO_SYS, NO_GLOBAL), + SPEC(remote_debug, BOOL, READ_ONLY, NO_SYS, NO_GLOBAL), + SPEC(program_name, WSTR, READ_ONLY, NO_SYS, NO_GLOBAL), + SPEC(run_command, WSTR_OPT, READ_ONLY, NO_SYS, NO_GLOBAL), + SPEC(run_filename, WSTR_OPT, READ_ONLY, NO_SYS, NO_GLOBAL), + SPEC(run_module, WSTR_OPT, READ_ONLY, NO_SYS, NO_GLOBAL), #ifdef Py_DEBUG - SPEC(run_presite, WSTR_OPT, READ_ONLY, NO_SYS), + SPEC(run_presite, WSTR_OPT, READ_ONLY, NO_SYS, NO_GLOBAL), #endif - SPEC(safe_path, BOOL, READ_ONLY, NO_SYS), - SPEC(show_ref_count, BOOL, READ_ONLY, NO_SYS), - SPEC(site_import, BOOL, READ_ONLY, NO_SYS), // sys.flags.no_site - SPEC(skip_source_first_line, BOOL, READ_ONLY, NO_SYS), - SPEC(stdio_encoding, WSTR, READ_ONLY, NO_SYS), - SPEC(stdio_errors, WSTR, READ_ONLY, NO_SYS), - SPEC(tracemalloc, UINT, READ_ONLY, NO_SYS), - SPEC(use_frozen_modules, BOOL, READ_ONLY, NO_SYS), - SPEC(use_hash_seed, BOOL, READ_ONLY, NO_SYS), + SPEC(safe_path, BOOL, READ_ONLY, NO_SYS, NO_GLOBAL), + SPEC(show_ref_count, BOOL, READ_ONLY, NO_SYS, NO_GLOBAL), + SPEC(site_import, BOOL, READ_ONLY, NO_SYS, GLOBAL(&Py_NoSiteFlag, 1)), // sys.flags.no_site + SPEC(skip_source_first_line, BOOL, READ_ONLY, NO_SYS, NO_GLOBAL), + SPEC(stdio_encoding, WSTR, READ_ONLY, NO_SYS, NO_GLOBAL), + SPEC(stdio_errors, WSTR, READ_ONLY, NO_SYS, NO_GLOBAL), + SPEC(tracemalloc, UINT, READ_ONLY, NO_SYS, NO_GLOBAL), + SPEC(use_frozen_modules, BOOL, READ_ONLY, NO_SYS, NO_GLOBAL), + SPEC(use_hash_seed, BOOL, READ_ONLY, NO_SYS, NO_GLOBAL), #ifdef __APPLE__ - SPEC(use_system_logger, BOOL, READ_ONLY, NO_SYS), + SPEC(use_system_logger, BOOL, READ_ONLY, NO_SYS, NO_GLOBAL), #endif - SPEC(user_site_directory, BOOL, READ_ONLY, NO_SYS), // sys.flags.no_user_site - SPEC(warn_default_encoding, BOOL, READ_ONLY, NO_SYS), + SPEC(user_site_directory, BOOL, READ_ONLY, NO_SYS, + GLOBAL(&Py_NoUserSiteDirectory, 1)), // sys.flags.no_user_site + SPEC(warn_default_encoding, BOOL, READ_ONLY, NO_SYS, NO_GLOBAL), // --- Init-only options ----------- - SPEC(_config_init, UINT, INIT_ONLY, NO_SYS), - SPEC(_init_main, BOOL, INIT_ONLY, NO_SYS), - SPEC(_install_importlib, BOOL, INIT_ONLY, NO_SYS), - SPEC(_is_python_build, BOOL, INIT_ONLY, NO_SYS), - SPEC(module_search_paths_set, BOOL, INIT_ONLY, NO_SYS), - SPEC(pythonpath_env, WSTR_OPT, INIT_ONLY, NO_SYS), - SPEC(sys_path_0, WSTR_OPT, INIT_ONLY, NO_SYS), + SPEC(_config_init, UINT, INIT_ONLY, NO_SYS, NO_GLOBAL), + SPEC(_init_main, BOOL, INIT_ONLY, NO_SYS, NO_GLOBAL), + SPEC(_install_importlib, BOOL, INIT_ONLY, NO_SYS, NO_GLOBAL), + SPEC(_is_python_build, BOOL, INIT_ONLY, NO_SYS, NO_GLOBAL), + SPEC(module_search_paths_set, BOOL, INIT_ONLY, NO_SYS, NO_GLOBAL), + SPEC(pythonpath_env, WSTR_OPT, INIT_ONLY, NO_SYS, NO_GLOBAL), + SPEC(sys_path_0, WSTR_OPT, INIT_ONLY, NO_SYS, NO_GLOBAL), // Array terminator {NULL, 0, 0, 0, NO_SYS}, @@ -233,11 +252,16 @@ static const PyConfigSpec PYPRECONFIG_SPEC[] = { {NULL, 0, 0, 0, NO_SYS}, }; +// End of ignoring deprecations on global variables +_Py_COMP_DIAG_POP + #undef SPEC #undef SYS_ATTR #undef SYS_FLAG_SETTER #undef SYS_FLAG #undef NO_SYS +#undef GLOBAL +#undef NO_GLOBAL // Forward declarations @@ -4951,6 +4975,16 @@ PyConfig_Set(const char *name, PyObject *value) Py_UNREACHABLE(); } + // Set the global variable + if (spec->global_var.ptr != NULL) { + assert(has_int_value); + int value = int_value; + if (spec->global_var.not) { + value = !value; + } + *spec->global_var.ptr = value; + } + if (spec->sys.attr != NULL) { // Set the sys attribute, but don't set PyInterpreterState.config // to keep the code simple. From cbbccf37b2be14fca026e087587b9611da371cbc Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 9 Jul 2026 00:43:48 +0200 Subject: [PATCH 627/818] [3.15] gh-119592: gh-152967: Fix ProcessPoolExecutor stranding submitted work when a max_tasks_per_child worker exits (GH-152978) (#153363) gh-119592: gh-152967: Fix ProcessPoolExecutor stranding submitted work when a max_tasks_per_child worker exits (GH-152978) gh-119592: Fix ProcessPoolExecutor stranding submitted work when a max_tasks_per_child worker exits Worker replacement went through the executor object: the manager thread read executor attributes that shutdown(wait=False) clears concurrently, and could not replace workers at all once the executor was garbage collected. A worker exiting at its max_tasks_per_child limit in those states left the remaining submitted work permanently unexecuted and hung interpreter exit; the racing case could crash the manager thread. Replace workers from the executor manager thread using its own state plus configuration read through the live executor weakref, which shutdown() never clears: - After shutdown(wait=False) with the executor still referenced, a replacement is spawned and the remaining work is executed as documented. - Once the executor has been garbage collected (gh-152967), or a replacement worker cannot be started and no workers remain, the remaining futures now fail with BrokenProcessPool instead of never resolving. - A new _force_shutting_down flag stops both spawn paths from starting workers that would escape terminate_workers()/kill_workers(). (cherry picked from commit 0c6422ff6a13ae309493fb7a358cb35d7ea959c8) Reviewed-multiple-times-by: Gregory P. Smith Co-authored-by: Gregory P. Smith <68491+gpshead@users.noreply.github.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> --- Lib/concurrent/futures/process.py | 167 +++++++++++++----- .../test_process_pool.py | 130 +++++++++++++- ...-07-03-18-30-00.gh-issue-119592.mQr3Vx.rst | 11 ++ 3 files changed, 262 insertions(+), 46 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-07-03-18-30-00.gh-issue-119592.mQr3Vx.rst diff --git a/Lib/concurrent/futures/process.py b/Lib/concurrent/futures/process.py index 8f200fc1c82613..e3b6c4a5305615 100644 --- a/Lib/concurrent/futures/process.py +++ b/Lib/concurrent/futures/process.py @@ -269,6 +269,20 @@ def _process_worker(call_queue, result_queue, initializer, initargs, max_tasks=N return +def _spawn_worker(mp_context, call_queue, result_queue, initializer, + initargs, max_tasks_per_child, processes): + """Start one worker process and record it in *processes* by pid.""" + p = mp_context.Process( + target=_process_worker, + args=(call_queue, + result_queue, + initializer, + initargs, + max_tasks_per_child)) + p.start() + processes[p.pid] = p + + class _ExecutorManagerThread(threading.Thread): """Manages the communication between this process and the worker processes. @@ -321,6 +335,15 @@ def weakref_cb(_, # exiting safely self.max_tasks_per_child = executor._max_tasks_per_child + # gh-119592: Needed to size worker replacement, and immutable, so + # keep a copy rather than reading it back through the executor + # weakref. The rest of the spawn configuration is deliberately NOT + # copied here: holding user-provided objects (initializer, + # initargs, mp_context) in this always-reachable running thread + # could keep the executor itself reachable through them, breaking + # garbage-collection-triggered shutdown. + self.max_workers = executor._max_workers + # A dict mapping work ids to _WorkItems e.g. # {5: <_WorkItem...>, 6: <_WorkItem...>, ...} self.pending_work_items = executor._pending_work_items @@ -357,12 +380,14 @@ def run(self): # while waiting on new results. del result_item - if executor := self.executor_reference(): - if process_exited: - with self.shutdown_lock: - executor._replace_dead_worker() - else: - executor._idle_worker_semaphore.release() + if process_exited: + with self.shutdown_lock: + broken = self._replace_dead_worker() + if broken is not None: + self.terminate_broken(*broken) + return + elif executor := self.executor_reference(): + executor._idle_worker_semaphore.release() del executor if self.is_shutting_down(): @@ -379,6 +404,71 @@ def run(self): self.join_executor_internals() return + def _replace_dead_worker(self): + """Spawn a replacement for a worker that exited at its + max_tasks_per_child limit. Called under self.shutdown_lock. + + Returns None while the pool can still make progress, otherwise a + (cause, message) tuple describing why the remaining work items can + never run, so that run() can fail their futures. + """ + assert self.shutdown_lock.locked() + cause = None + message = None + executor = self.executor_reference() + if executor is None: + # gh-152967: The executor was garbage collected; nothing can + # spawn a replacement worker for it anymore. + message = ("The ProcessPoolExecutor was garbage collected with " + "work pending after its last worker process exited " + "upon reaching max_tasks_per_child; the pending work " + "can never be run.") + elif executor._force_shutting_down: + # terminate_workers()/kill_workers() is tearing the pool down; + # a replacement worker would escape the kill and run work + # items that were enqueued before it. + message = ("A worker process exited while the pool was being " + "forcefully shut down; work that was still enqueued " + "will not be run.") + elif self.pending_work_items or not self.is_shutting_down(): + # gh-115634: Do not consult the executor's + # _idle_worker_semaphore here: it counts task completions, not + # idle workers, so it can hold a stale token released by the + # now-dead worker. Trusting such a token would leave the pool + # a worker short, deadlocking once all workers reach their + # task limit. Spawning from this (manager) thread is safe + # despite gh-90622 because max_tasks_per_child is rejected for + # the "fork" start method. + if len(self.processes) < self.max_workers: + # gh-119592: Spawn using state owned by this thread and + # configuration read through the live weakref (which + # shutdown() never clears), not the executor state that + # shutdown(wait=False) clears concurrently. + try: + _spawn_worker(executor._mp_context, self.call_queue, + self.result_queue, executor._initializer, + executor._initargs, + self.max_tasks_per_child, self.processes) + except Exception as exc: + # While other workers remain the pool has merely lost + # capacity and they keep draining the queue; with none + # left the failure is reported below. + cause = format_exception(exc) + message = ("A replacement worker process could not be " + "started, leaving the pool without workers " + "to run the remaining work.") + del executor + + if not self.processes and (self.pending_work_items + or cause is not None): + # No worker processes remain and no replacement can be + # spawned: any remaining work items can never run. A spawn + # failure breaks the pool even with nothing pending; leaving + # a zero-worker pool alive would hang a later submit() on a + # stale _idle_worker_semaphore token instead of raising. + return (cause, message) + return None + def add_call_item_to_queue(self): # Fills call_queue with _WorkItems from pending_work_items. # This function never blocks. @@ -455,10 +545,11 @@ def is_shutting_down(self): return (_global_shutdown or executor is None or executor._shutdown_thread) - def _terminate_broken(self, cause): + def _terminate_broken(self, cause, bpe_message=None): # Terminate the executor because it is in a broken state. The cause # argument can be used to display more information on the error that - # lead the executor into becoming broken. + # lead the executor into becoming broken. bpe_message overrides the + # default message on the BrokenProcessPool set on pending futures. # Mark the process pool broken so that submits fail right now. executor = self.executor_reference() @@ -489,11 +580,12 @@ def _terminate_broken(self, cause): cause_str = "\n".join(errors) cause_tb = f"\n'''\n{cause_str}'''" if cause_str else None + if bpe_message is None: + bpe_message = ("A process in the process pool was terminated " + "abruptly while the future was running or pending.") # Mark pending tasks as failed. for work_id, work_item in self.pending_work_items.items(): - bpe = BrokenProcessPool("A process in the process pool was " - "terminated abruptly while the future was " - "running or pending.") + bpe = BrokenProcessPool(bpe_message) if cause_tb is not None: bpe.__cause__ = _RemoteTraceback(cause_tb) try: @@ -518,9 +610,9 @@ def _terminate_broken(self, cause): # clean up resources self._join_executor_internals(broken=True) - def terminate_broken(self, cause): + def terminate_broken(self, cause, bpe_message=None): with self.shutdown_lock: - self._terminate_broken(cause) + self._terminate_broken(cause, bpe_message) def flag_executor_shutting_down(self): # Flag the executor as shutting down and cancel remaining tasks if @@ -733,6 +825,7 @@ def __init__(self, max_workers=None, mp_context=None, self._queue_count = 0 self._pending_work_items = {} self._cancel_pending_futures = False + self._force_shutting_down = False # _ThreadWakeup is a communication channel used to interrupt the wait # of the main loop of executor_manager_thread from another thread (e.g. @@ -772,34 +865,15 @@ def _start_executor_manager_thread(self): _threads_wakeups[self._executor_manager_thread] = \ self._executor_manager_thread_wakeup - def _replace_dead_worker(self): + def _adjust_process_count(self): # gh-132969: avoid error when state is reset and executor is still running, # which will happen when shutdown(wait=False) is called. if self._processes is None: return - # A replacement is pointless when shutting down with nothing left - # to run. Both attributes are read under _shutdown_lock, which - # shutdown() holds while setting _shutdown_thread. - assert self._shutdown_lock.locked() - if self._shutdown_thread and not self._pending_work_items: - return - - # gh-115634: A worker exited after reaching max_tasks_per_child and - # has been removed from self._processes. Do not consult - # _idle_worker_semaphore here: it counts task completions, not idle - # workers, so it can hold a stale token released by the now-dead - # worker. Trusting such a token would leave the pool a worker short, - # deadlocking once all workers reach their task limit. Spawning is - # safe from this (manager) thread despite gh-90622 because - # max_tasks_per_child is rejected for the "fork" start method. - if len(self._processes) < self._max_workers: - self._spawn_process() - - def _adjust_process_count(self): - # gh-132969: avoid error when state is reset and executor is still running, - # which will happen when shutdown(wait=False) is called. - if self._processes is None: + # gh-152967: A forceful shutdown is in progress; a worker spawned + # here could escape its process snapshot and keep running work. + if self._force_shutting_down: return # if there's an idle process, we don't need to spawn a new one. @@ -825,15 +899,10 @@ def _launch_processes(self): self._spawn_process() def _spawn_process(self): - p = self._mp_context.Process( - target=_process_worker, - args=(self._call_queue, - self._result_queue, - self._initializer, - self._initargs, - self._max_tasks_per_child)) - p.start() - self._processes[p.pid] = p + _spawn_worker(self._mp_context, self._call_queue, + self._result_queue, self._initializer, + self._initargs, self._max_tasks_per_child, + self._processes) def submit(self, fn, /, *args, **kwargs): with self._shutdown_lock: @@ -930,6 +999,14 @@ def _force_shutdown(self, operation): if operation not in _SHUTDOWN_CALLBACK_OPERATION: raise ValueError(f"Unsupported operation: {operation!r}") + # gh-152967: Stop the manager thread from spawning replacement + # workers before we copy the processes to signal: a worker spawned + # after the copy would survive the loop below and run enqueued + # work items. Taking the lock orders this against the manager's + # worker replacement, which runs under the same lock. + with self._shutdown_lock: + self._force_shutting_down = True + processes = {} if self._processes: processes = self._processes.copy() diff --git a/Lib/test/test_concurrent_futures/test_process_pool.py b/Lib/test/test_concurrent_futures/test_process_pool.py index 38e2cb302c6d51..c7d489c4f5b0a4 100644 --- a/Lib/test/test_concurrent_futures/test_process_pool.py +++ b/Lib/test/test_concurrent_futures/test_process_pool.py @@ -6,11 +6,12 @@ import traceback import unittest import unittest.mock +import weakref from concurrent import futures from concurrent.futures.process import BrokenProcessPool from test import support -from test.support import hashlib_helper, warnings_helper +from test.support import hashlib_helper, threading_helper, warnings_helper from test.test_importlib.metadata.fixtures import parameterize from .executor import ExecutorTest, mul @@ -42,6 +43,13 @@ def _put_wait_put(queue, event): queue.put('finished') +def _report_wait_return(queue, event, value): + """ Used as part of _run_stranded_worker_exit_test """ + queue.put(value) + event.wait() + return value + + class ProcessPoolExecutorTest(ExecutorTest): @unittest.skipUnless(sys.platform=='win32', 'Windows-only process limit') @@ -267,6 +275,126 @@ def test_max_tasks_per_child_pending_tasks_gh115634(self): finally: executor.shutdown(wait=True, cancel_futures=True) + def _run_stranded_worker_exit_test(self, *, shutdown, drop_reference): + # A worker exits upon reaching its max_tasks_per_child limit while + # more submitted work is queued. While the executor object is + # alive a replacement worker must be spawned and the remaining + # work executed; once it has been garbage collected no replacement + # is possible and the remaining futures must fail promptly instead + # of never resolving. + context = self.get_context() + if context.get_start_method(allow_none=False) == "fork": + raise unittest.SkipTest("Incompatible with the fork start method.") + manager = context.Manager() + self.addCleanup(manager.join) + self.addCleanup(manager.shutdown) + started = manager.Queue() + gate = manager.Event() + + executor = self.executor_type( + 1, mp_context=context, max_tasks_per_child=1) + futs = [executor.submit(_report_wait_return, started, gate, i) + for i in range(3)] + self.addCleanup(threading_helper.join_thread, + executor._executor_manager_thread) + # Wait until the worker is inside the first task so that it exits + # at its task limit only after the executor has been shut down + # and/or garbage collected below. + self.assertEqual(started.get(timeout=support.SHORT_TIMEOUT), 0) + if shutdown: + executor.shutdown(wait=False) + if drop_reference: + executor_ref = weakref.ref(executor) + executor = None + for _ in support.sleeping_retry(support.SHORT_TIMEOUT): + support.gc_collect() + if executor_ref() is None: + break + gate.set() + + self.assertEqual(futs[0].result(timeout=support.SHORT_TIMEOUT), 0) + if drop_reference: + for fut in futs[1:]: + with self.assertRaisesRegex(BrokenProcessPool, + "garbage collected"): + fut.result(timeout=support.SHORT_TIMEOUT) + else: + results = [f.result(timeout=support.SHORT_TIMEOUT) + for f in futs[1:]] + self.assertEqual(results, [1, 2]) + + def test_shutdown_no_wait_max_tasks_gh119592(self): + # gh-119592: shutdown(wait=False) used to clear executor state that + # worker replacement relied on. A worker exiting at its + # max_tasks_per_child limit afterwards could not be replaced, so + # the remaining submitted work never ran, and a racing worker exit + # could crash the manager thread on the partially cleared state. + for drop_reference in (False, True): + with self.subTest(drop_reference=drop_reference): + self._run_stranded_worker_exit_test( + shutdown=True, drop_reference=drop_reference) + + def test_gc_during_max_tasks_worker_exit_gh152967(self): + # gh-152967: If the executor was garbage collected without + # shutdown() while its last worker exited at its + # max_tasks_per_child limit, no replacement worker could be + # spawned and the remaining futures were never resolved. + self._run_stranded_worker_exit_test( + shutdown=False, drop_reference=True) + + def _run_unreplaceable_worker_exit_test(self, *, error_regex, + force_shutting_down=False, + failing_spawn=False): + # Drive a max_tasks_per_child worker exit while worker + # replacement is impossible; the queued futures must fail + # promptly with a BrokenProcessPool explaining why. + context = self.get_context() + if context.get_start_method(allow_none=False) == "fork": + raise unittest.SkipTest("Incompatible with the fork start method.") + manager = context.Manager() + self.addCleanup(manager.join) + self.addCleanup(manager.shutdown) + started = manager.Queue() + gate = manager.Event() + + executor = self.executor_type( + 1, mp_context=context, max_tasks_per_child=1) + futs = [executor.submit(_report_wait_return, started, gate, i) + for i in range(3)] + self.addCleanup(threading_helper.join_thread, + executor._executor_manager_thread) + self.assertEqual(started.get(timeout=support.SHORT_TIMEOUT), 0) + if force_shutting_down: + with executor._shutdown_lock: + executor._force_shutting_down = True + if failing_spawn: + spawn_patch = unittest.mock.patch( + "concurrent.futures.process._spawn_worker", + side_effect=OSError("spawn failed")) + spawn_patch.start() + self.addCleanup(spawn_patch.stop) + gate.set() + + self.assertEqual(futs[0].result(timeout=support.SHORT_TIMEOUT), 0) + for fut in futs[1:]: + with self.assertRaisesRegex(BrokenProcessPool, error_regex): + fut.result(timeout=support.SHORT_TIMEOUT) + + def test_force_shutdown_during_max_tasks_worker_exit(self): + # A worker exiting at its max_tasks_per_child limit during + # terminate_workers()/kill_workers() must not be replaced (the + # replacement would escape the kill); queued futures fail instead. + self._run_unreplaceable_worker_exit_test( + force_shutting_down=True, + error_regex="forcefully shut down") + + def test_failed_worker_replacement_breaks_pool(self): + # If no replacement worker can be started and no workers remain, + # the pool must break rather than strand the queued futures. + self._run_unreplaceable_worker_exit_test( + failing_spawn=True, + error_regex="could not be started") + def test_max_tasks_early_shutdown(self): context = self.get_context() if context.get_start_method(allow_none=False) == "fork": diff --git a/Misc/NEWS.d/next/Library/2026-07-03-18-30-00.gh-issue-119592.mQr3Vx.rst b/Misc/NEWS.d/next/Library/2026-07-03-18-30-00.gh-issue-119592.mQr3Vx.rst new file mode 100644 index 00000000000000..f718c877c8ed22 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-03-18-30-00.gh-issue-119592.mQr3Vx.rst @@ -0,0 +1,11 @@ +Fix :class:`concurrent.futures.ProcessPoolExecutor` stranding submitted +work forever when a worker process exited upon reaching its +*max_tasks_per_child* limit after +:meth:`~concurrent.futures.Executor.shutdown` was called with +``wait=False``: a replacement worker is now spawned and the remaining work +executed as documented. If the executor has instead been garbage collected +without ``shutdown()`` (:gh:`152967`), or a replacement worker cannot be +started, the remaining futures now fail with +:exc:`~concurrent.futures.process.BrokenProcessPool` instead of never +resolving. A worker exit racing ``shutdown(wait=False)`` can also no +longer crash the executor management thread. From c512e8f0fb6b78da7fe91aa267700ea516dfd1f6 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 9 Jul 2026 01:25:18 +0200 Subject: [PATCH 628/818] [3.15] gh-151213: Document asyncio debugging tools (GH-151392) (#153370) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gh-151213: Document asyncio debugging tools (GH-151392) (cherry picked from commit b2d8db1ac818e74ffe666146335e9e6c7f1f3f56) Co-authored-by: Bartosz Sławecki <bartosz@ilikepython.com> --- Doc/library/asyncio-graph.rst | 8 +- Doc/library/asyncio-tools.rst | 157 ++++++++++++++++++++++++++++++++++ Doc/library/asyncio.rst | 13 +++ 3 files changed, 177 insertions(+), 1 deletion(-) create mode 100644 Doc/library/asyncio-tools.rst diff --git a/Doc/library/asyncio-graph.rst b/Doc/library/asyncio-graph.rst index 5f642a32bf75c2..1a8cdcf6a9e8cb 100644 --- a/Doc/library/asyncio-graph.rst +++ b/Doc/library/asyncio-graph.rst @@ -4,7 +4,7 @@ .. _asyncio-graph: ======================== -Call Graph Introspection +Call graph introspection ======================== **Source code:** :source:`Lib/asyncio/graph.py` @@ -17,6 +17,12 @@ a suspended *future*. These utilities and the underlying machinery can be used from within a Python program or by external profilers and debuggers. +.. seealso:: + + :ref:`asyncio-introspection-tools` + Command-line tools for inspecting tasks in another running Python + process. + .. versionadded:: 3.14 diff --git a/Doc/library/asyncio-tools.rst b/Doc/library/asyncio-tools.rst new file mode 100644 index 00000000000000..1782640e83f53a --- /dev/null +++ b/Doc/library/asyncio-tools.rst @@ -0,0 +1,157 @@ +.. currentmodule:: asyncio + +.. _asyncio-introspection-tools: + +================================ +Command-line introspection tools +================================ + +**Source code:** :source:`Lib/asyncio/tools.py` + +------------------------------------- + +The :mod:`!asyncio` module can be invoked as a script via ``python -m +asyncio`` to inspect the task graph of another running Python process without +modifying it or restarting it. The :mod:`!asyncio.tools` submodule implements +this interface. + +The following commands inspect the process identified by ``PID``: + +.. code-block:: shell-session + + $ python -m asyncio pstree [--retries N] PID + $ python -m asyncio ps [--retries N] PID + +The commands read the target process state without executing any code in it. +They are only available on supported platforms and may require permission to +inspect another process. See the :ref:`permission-requirements <permission-requirements>` for details. + +.. seealso:: + + :ref:`asyncio-graph` + Programmatic APIs for inspecting the async call graph of a task or + future in the current process. + +The command examples below use this program, which creates a task hierarchy +suitable for inspection and prints its process ID: + +.. code-block:: python + :caption: example.py + + import asyncio + import os + + async def play(track): + await asyncio.sleep(3600) + print(f"🎵 Finished: {track}") + + async def album(name, tracks): + async with asyncio.TaskGroup() as tg: + for track in tracks: + tg.create_task(play(track), name=track) + + async def main(): + print(f"PID: {os.getpid()}") + async with asyncio.TaskGroup() as tg: + tg.create_task( + album("Sundowning", ["TNDNBTG", "Levitate"]), + name="Sundowning", + ) + tg.create_task( + album("TMBTE", ["DYWTYLM", "Aqua Regia"]), + name="TMBTE", + ) + + asyncio.run(main()) + +Run the program in one terminal and leave it running: + +.. code-block:: shell-session + + $ python example.py + PID: 12345 + +Then pass the printed process ID to the commands from another terminal. +Thread IDs, task IDs, file paths, and line numbers vary between runs and +source layouts. + +.. versionadded:: 3.14 + +Command-line options +==================== + +.. option:: pstree PID + + Display task and coroutine relationships as a tree. Each task is shown + with its full coroutine stack, nested under the task (if any) that is + awaiting it. This subcommand is useful for quickly identifying which branch + of a task hierarchy is blocked and where in its coroutine stack execution + has paused: + + .. code-block:: shell-session + + $ python -m asyncio pstree 12345 + └── (T) Task-1 + └── main example.py:12 + └── TaskGroup.__aexit__ Lib/asyncio/taskgroups.py:75 + └── TaskGroup._aexit Lib/asyncio/taskgroups.py:124 + ├── (T) Sundowning + │ └── album example.py:7 + │ └── TaskGroup.__aexit__ Lib/asyncio/taskgroups.py:75 + │ └── TaskGroup._aexit Lib/asyncio/taskgroups.py:124 + │ ├── (T) TNDNBTG + │ │ └── play example.py:4 + │ │ └── sleep Lib/asyncio/tasks.py:702 + │ └── (T) Levitate + │ └── play example.py:4 + │ └── sleep Lib/asyncio/tasks.py:702 + └── (T) TMBTE + └── album example.py:7 + └── TaskGroup.__aexit__ Lib/asyncio/taskgroups.py:75 + └── TaskGroup._aexit Lib/asyncio/taskgroups.py:124 + ├── (T) DYWTYLM + │ └── play example.py:4 + │ └── sleep Lib/asyncio/tasks.py:702 + └── (T) Aqua Regia + └── play example.py:4 + └── sleep Lib/asyncio/tasks.py:702 + + If the await graph contains a cycle, ``pstree`` reports an error instead + of printing a tree. A cycle in the await graph is unusual and typically + indicates a programming error: + + .. code-block:: shell-session + + $ python -m asyncio pstree 12345 + ERROR: await-graph contains cycles - cannot print a tree! + + cycle: Task-2 → Task-3 → Task-2 + +.. option:: ps PID + + Display a flat table of all pending tasks in the process *PID*. Each row + shows the event-loop thread ID, task ID and name, coroutine stack, and the + awaiting task's stack, name, and ID, if any. + + This subcommand prints all tasks regardless of whether the await graph + contains cycles: + + .. code-block:: shell-session + + $ python -m asyncio ps 12345 + tid task id task name coroutine stack awaiter chain awaiter name awaiter id + ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ + 18445801 0x10a456060 Task-1 TaskGroup._aexit -> TaskGroup.__aexit__ -> main 0x0 + 18445801 0x10a439f60 Sundowning TaskGroup._aexit -> TaskGroup.__aexit__ -> album TaskGroup._aexit -> TaskGroup.__aexit__ -> main Task-1 0x10a456060 + 18445801 0x10a439d70 TMBTE TaskGroup._aexit -> TaskGroup.__aexit__ -> album TaskGroup._aexit -> TaskGroup.__aexit__ -> main Task-1 0x10a456060 + 18445801 0x10a2a3a80 TNDNBTG sleep -> play TaskGroup._aexit -> TaskGroup.__aexit__ -> album Sundowning 0x10a439f60 + 18445801 0x10a2a38a0 Levitate sleep -> play TaskGroup._aexit -> TaskGroup.__aexit__ -> album Sundowning 0x10a439f60 + 18445801 0x10a2d7150 DYWTYLM sleep -> play TaskGroup._aexit -> TaskGroup.__aexit__ -> album TMBTE 0x10a439d70 + 18445801 0x10a6bdaa0 Aqua Regia sleep -> play TaskGroup._aexit -> TaskGroup.__aexit__ -> album TMBTE 0x10a439d70 + +.. option:: --retries N + + Retry failed attempts to inspect the target process up to *N* times. This + can help when the target process changes while its state is being read. + + .. versionadded:: 3.15 diff --git a/Doc/library/asyncio.rst b/Doc/library/asyncio.rst index 90a465f3e1d3af..8d19f49f6a0621 100644 --- a/Doc/library/asyncio.rst +++ b/Doc/library/asyncio.rst @@ -47,6 +47,13 @@ asyncio provides a set of **high-level** APIs to: * :ref:`synchronize <asyncio-sync>` concurrent code; +For **introspection**, asyncio provides APIs and tools for: + +* inspecting the :ref:`async call graph <asyncio-graph>` of tasks and futures; + +* inspecting tasks in another running Python process with + :ref:`command-line tools <asyncio-introspection-tools>`; + Additionally, there are **low-level** APIs for *library and framework developers* to: @@ -108,7 +115,13 @@ for full functionality and the latest features. asyncio-subprocess.rst asyncio-queue.rst asyncio-exceptions.rst + +.. toctree:: + :caption: Introspection APIs + :maxdepth: 1 + asyncio-graph.rst + asyncio-tools.rst .. toctree:: :caption: Low-level APIs From 9fb25cbd41410fb9bdf230d6242f0358885405ae Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 9 Jul 2026 06:15:30 +0200 Subject: [PATCH 629/818] =?UTF-8?q?[3.15]=20gh-47005:=20fix=20do=5Fopen()?= =?UTF-8?q?=20to=20let=20regular=20headers=20override=20unredirected=20?= =?UTF-8?q?=E2=80=A6=20(GH-146506)=20(#153377)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gh-47005: fix do_open() to let regular headers override unredirected … (GH-146506) AbstractHTTPHandler.do_open() was building the request header dict by starting with unredirected_hdrs and only inserting regular headers that were not already present, giving unredirected headers priority. This contradicts get_header() and header_items(), both of which give regular headers the higher priority. Fix by unconditionally updating with req.headers so that a header set via add_header() always overrides one set via add_unredirected_header(). --------- (cherry picked from commit 6d386684ad69f42cb57c72fe0e0ffcec82ec7e12) Co-authored-by: CHINMAY <89741289+Das-Chinmay@users.noreply.github.com> Co-authored-by: Senthil Kumaran <senthil@python.org> --- Lib/test/test_urllib2.py | 29 +++++++++++++++++++ Lib/urllib/request.py | 3 +- ...6-03-26-00-00-00.gh-issue-47005.xxc89c.rst | 4 +++ 3 files changed, 34 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-03-26-00-00-00.gh-issue-47005.xxc89c.rst diff --git a/Lib/test/test_urllib2.py b/Lib/test/test_urllib2.py index 3a77b9e5ab7928..d2fd111f6d9de0 100644 --- a/Lib/test/test_urllib2.py +++ b/Lib/test/test_urllib2.py @@ -980,6 +980,35 @@ def test_http(self): self.assertEqual(req.unredirected_hdrs["Host"], "baz") self.assertEqual(req.unredirected_hdrs["Spam"], "foo") + def test_http_header_priority(self): + # gh-47005: regular headers set via add_header() must override + # unredirected headers with the same name in do_open(), consistent + # with get_header() and header_items(). + cases = [ + ("Content-Type", "application/json", "application/x-www-form-urlencoded"), + ("Content-Length", "99", "0"), + ("Host", "override.example.com", "internal.example.com"), + ("Authorization", "Bearer user-token", "Basic stale="), + ("Cookie", "a=1", "b=2"), + ("User-Agent", "MyApp/1.0", "Python-urllib/test"), + ] + h = urllib.request.AbstractHTTPHandler() + h.parent = MockOpener() + + for key, regular, unredirected in cases: + req = Request("http://example.com/", headers={key: regular}) + req.timeout = None + req.add_unredirected_header(key, unredirected) + + http = MockHTTPClass() + h.do_open(http, req) + + sent_headers = dict(http.req_headers) + self.assertEqual(sent_headers[key], regular) + # key is capitalized by add_header() and add_unredirected_header() calls + self.assertEqual(req.get_header(key.capitalize()), regular) + self.assertEqual(dict(req.header_items())[key.capitalize()], regular) + def test_http_body_file(self): # A regular file - chunked encoding is used unless Content Length is # already set. diff --git a/Lib/urllib/request.py b/Lib/urllib/request.py index f5f17f223a4585..660301fef61258 100644 --- a/Lib/urllib/request.py +++ b/Lib/urllib/request.py @@ -1293,8 +1293,7 @@ def do_open(self, http_class, req, **http_conn_args): h.set_debuglevel(self._debuglevel) headers = dict(req.unredirected_hdrs) - headers.update({k: v for k, v in req.headers.items() - if k not in headers}) + headers.update(req.headers) # TODO(jhylton): Should this be redesigned to handle # persistent connections? diff --git a/Misc/NEWS.d/next/Library/2026-03-26-00-00-00.gh-issue-47005.xxc89c.rst b/Misc/NEWS.d/next/Library/2026-03-26-00-00-00.gh-issue-47005.xxc89c.rst new file mode 100644 index 00000000000000..646367f0fa069d --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-03-26-00-00-00.gh-issue-47005.xxc89c.rst @@ -0,0 +1,4 @@ +Fix :meth:`!urllib.request.AbstractHTTPHandler.do_open` to give regular +headers set via :meth:`~urllib.request.Request.add_header` priority over +unredirected headers, consistent with :meth:`~urllib.request.Request.get_header` +and :meth:`~urllib.request.Request.header_items`. From 069ed2aef19b1c58ad68e12d8787d0d411992641 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 9 Jul 2026 07:19:45 +0200 Subject: [PATCH 630/818] [3.15] gh-130578: clarify urllib.parse.quote parameter defaults behavior (GH-130598) (#153383) gh-130578: clarify urllib.parse.quote parameter defaults behavior (GH-130598) (cherry picked from commit bc9bb7386597e22693662f489a7474998788e228) Co-authored-by: Kanishk Pachauri <itskanishkp.py@gmail.com> Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> --- Doc/library/urllib.parse.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Doc/library/urllib.parse.rst b/Doc/library/urllib.parse.rst index 3ce20311c42c84..26e159306c8107 100644 --- a/Doc/library/urllib.parse.rst +++ b/Doc/library/urllib.parse.rst @@ -649,8 +649,9 @@ task isn't already covered by the URL parsing functions above. The optional *encoding* and *errors* parameters specify how to deal with non-ASCII characters, as accepted by the :meth:`str.encode` method. - *encoding* defaults to ``'utf-8'``. - *errors* defaults to ``'strict'``, meaning unsupported characters raise a + Although these parameters default to ``None`` in the function signature, + when processing :class:`str` inputs, *encoding* effectively defaults to ``'utf-8'`` + and *errors* to ``'strict'``, meaning unsupported characters raise a :class:`UnicodeEncodeError`. *encoding* and *errors* must not be supplied if *string* is a :class:`bytes`, or a :class:`TypeError` is raised. From 3e19df0e05c076e66f7534fee23bae388fa3e801 Mon Sep 17 00:00:00 2001 From: Peter Bierma <zintensitydev@gmail.com> Date: Thu, 9 Jul 2026 02:19:26 -0400 Subject: [PATCH 631/818] [3.15] gh-151640: Track sharing of `BytesIO` buffer in free-threaded builds (GH-151651) (gh-153151) (cherry picked from commit 881a13a97c7a29b9de57913c773cd5f195270fbd) Remove peek() call from backported test, not in Python 3.15. Co-authored-by: Pedram Karimi <147748351+pedramkarimii@users.noreply.github.com> Co-authored-by: Neil Schemenauer <nas-github@arctrix.com> --- Lib/test/test_free_threading/test_io.py | 28 +++++++++++ Lib/test/test_io/test_memoryio.py | 5 +- ...-06-18-12-48-03.gh-issue-151640.R4c3Fx.rst | 3 ++ Modules/_io/bytesio.c | 49 ++++++++++++++++++- 4 files changed, 82 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-06-18-12-48-03.gh-issue-151640.R4c3Fx.rst diff --git a/Lib/test/test_free_threading/test_io.py b/Lib/test/test_free_threading/test_io.py index 8a0ad30c4bc770..fad8339af2edd6 100644 --- a/Lib/test/test_free_threading/test_io.py +++ b/Lib/test/test_free_threading/test_io.py @@ -117,6 +117,34 @@ def sizeof(barrier, b, *ignore): class CBytesIOTest(ThreadSafetyMixin, TestCase): ioclass = io.BytesIO + @threading_helper.requires_working_threading() + @threading_helper.reap_threads + def test_concurrent_whole_buffer_read_and_resize(self): + shared = self.ioclass(b"x" * 64) + writers = 2 + readers = 8 + loops = 2000 + barrier = threading.Barrier(writers + readers) + + def writer(): + barrier.wait() + for i in range(loops): + shared.seek(0) + shared.write(b"a" * (64 + (i & 63))) + + def reader(): + barrier.wait() + for _ in range(loops): + shared.seek(0) + shared.read() + shared.seek(0) + shared.getvalue() + + threads = [threading.Thread(target=writer) for _ in range(writers)] + threads += [threading.Thread(target=reader) for _ in range(readers)] + with threading_helper.start_threads(threads): + pass + class PyBytesIOTest(ThreadSafetyMixin, TestCase): ioclass = pyio.BytesIO diff --git a/Lib/test/test_io/test_memoryio.py b/Lib/test/test_io/test_memoryio.py index 3669ac0b038b71..464fbf67a84b83 100644 --- a/Lib/test/test_io/test_memoryio.py +++ b/Lib/test/test_io/test_memoryio.py @@ -868,7 +868,10 @@ def test_setstate(self): @support.cpython_only def test_sizeof(self): - basesize = support.calcobjsize('P2n2Pn') + if support.Py_GIL_DISABLED: + basesize = support.calcobjsize('P2n2Pni') + else: + basesize = support.calcobjsize('P2n2Pn') check = self.check_sizeof self.assertEqual(object.__sizeof__(io.BytesIO()), basesize) check(io.BytesIO(), basesize ) diff --git a/Misc/NEWS.d/next/Library/2026-06-18-12-48-03.gh-issue-151640.R4c3Fx.rst b/Misc/NEWS.d/next/Library/2026-06-18-12-48-03.gh-issue-151640.R4c3Fx.rst new file mode 100644 index 00000000000000..ef61a7d27dd07d --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-18-12-48-03.gh-issue-151640.R4c3Fx.rst @@ -0,0 +1,3 @@ +Fix a data race in :class:`io.BytesIO` in free-threaded builds when +whole-buffer reads or peeks, or :meth:`~io.BytesIO.getvalue`, share the +internal buffer with concurrent writes. diff --git a/Modules/_io/bytesio.c b/Modules/_io/bytesio.c index 8cdcbd0d89c718..5e78f776c92e97 100644 --- a/Modules/_io/bytesio.c +++ b/Modules/_io/bytesio.c @@ -22,6 +22,9 @@ typedef struct { PyObject *dict; PyObject *weakreflist; Py_ssize_t exports; +#ifdef Py_GIL_DISABLED + int buf_shared; +#endif } bytesio; #define bytesio_CAST(op) ((bytesio *)(op)) @@ -71,7 +74,45 @@ check_exports(bytesio *self) return NULL; \ } +#ifdef Py_GIL_DISABLED +#define SHARED_BUF(self) ((self)->buf_shared || !_PyObject_IsUniquelyReferenced((self)->buf)) +#else #define SHARED_BUF(self) (!_PyObject_IsUniquelyReferenced((self)->buf)) +#endif + +static inline void +set_shared_buf(bytesio *self) +{ +#ifdef Py_GIL_DISABLED + self->buf_shared = 1; +#endif +} + +static inline void +clear_shared_buf(bytesio *self) +{ +#ifdef Py_GIL_DISABLED + self->buf_shared = 0; +#endif +} + +static int +resize_unshared_buffer_lock_held(bytesio *self, Py_ssize_t size) +{ + _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(self); + +#ifdef Py_GIL_DISABLED + /* If the internal bytes object escaped via a zero-copy getvalue(), read(), + or peek(), resizing it would mutate an object visible to Python code. + Callers must detach first. */ + assert(!self->buf_shared); +#endif + int ret = _PyBytes_Resize(&self->buf, size); + if (ret == 0) { + clear_shared_buf(self); + } + return ret; +} /* Internal routine to get a line from the buffer of a BytesIO @@ -128,6 +169,7 @@ unshare_buffer_lock_held(bytesio *self, size_t size) memcpy(PyBytes_AS_STRING(new_buf), PyBytes_AS_STRING(self->buf), self->string_size); Py_SETREF(self->buf, new_buf); + clear_shared_buf(self); return 0; } @@ -173,7 +215,7 @@ resize_buffer_lock_held(bytesio *self, size_t size) return -1; } else { - if (_PyBytes_Resize(&self->buf, alloc) < 0) + if (resize_unshared_buffer_lock_held(self, alloc) < 0) return -1; } @@ -381,10 +423,11 @@ _io_BytesIO_getvalue_impl(bytesio *self) return NULL; } else { - if (_PyBytes_Resize(&self->buf, self->string_size) < 0) + if (resize_unshared_buffer_lock_held(self, self->string_size) < 0) return NULL; } } + set_shared_buf(self); return Py_NewRef(self->buf); } @@ -433,6 +476,7 @@ read_bytes_lock_held(bytesio *self, Py_ssize_t size) self->pos == 0 && size == PyBytes_GET_SIZE(self->buf) && FT_ATOMIC_LOAD_SSIZE_RELAXED(self->exports) == 0) { self->pos += size; + set_shared_buf(self); return Py_NewRef(self->buf); } @@ -1046,6 +1090,7 @@ _io_BytesIO___init___impl(bytesio *self, PyObject *initvalue) if (initvalue && initvalue != Py_None) { if (PyBytes_CheckExact(initvalue)) { Py_XSETREF(self->buf, Py_NewRef(initvalue)); + clear_shared_buf(self); self->string_size = PyBytes_GET_SIZE(initvalue); } else { From dd3770610b7ea015b4428c10593f34eeae7d9fd2 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 9 Jul 2026 08:43:55 +0200 Subject: [PATCH 632/818] [3.15] gh-153380: Adapt ttk tests to Tk 9.1 changes (GH-153381) (GH-153386) - selectmode: new 'single' and 'multiple' modes - set(): includes the tree column '#0' - insert()/selection(): item ids keep the passed value's type - heading_callback: avoid a double click on the second click - theme_create_image: don't assert the exact (now scaled) width (cherry picked from commit d6855c8ad00ffa2bee318b510d0e90573dddbbab) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --- Lib/test/test_ttk/test_style.py | 3 ++- Lib/test/test_ttk/test_widgets.py | 35 ++++++++++++++++++++++++------- 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/Lib/test/test_ttk/test_style.py b/Lib/test/test_ttk/test_style.py index f85f76eb499278..56d8a5931fdfa5 100644 --- a/Lib/test/test_ttk/test_style.py +++ b/Lib/test/test_ttk/test_style.py @@ -420,7 +420,8 @@ def test_theme_create_image(self): b = ttk.Label(self.root, style='TestWidget') b.pack(expand=True, fill='both') - self.assertEqual(b.winfo_reqwidth(), 134) + # The exact width varies with the Tk version and display scaling. + self.assertGreater(b.winfo_reqwidth(), 130) self.assertEqual(b.winfo_reqheight(), 100) style.theme_use(curr_theme) diff --git a/Lib/test/test_ttk/test_widgets.py b/Lib/test/test_ttk/test_widgets.py index 5b1000b699e4b0..b2cc7f16f89446 100644 --- a/Lib/test/test_ttk/test_widgets.py +++ b/Lib/test/test_ttk/test_widgets.py @@ -1500,8 +1500,13 @@ def test_configure_height(self): def test_configure_selectmode(self): widget = self.create() - self.checkEnumParam(widget, 'selectmode', - 'none', 'browse', 'extended') + if tk_version >= (9, 1): + self.checkEnumParam(widget, 'selectmode', + 'none', 'single', 'browse', 'extended', + 'multiple') + else: + self.checkEnumParam(widget, 'selectmode', + 'none', 'browse', 'extended') @requires_tk(8, 7) def test_configure_selecttype(self): @@ -1784,6 +1789,9 @@ def simulate_heading_click(x, y): commands = self.tv.master._tclCommands self.tv.heading('#0', command=str(self.tv.heading('#0', command=None))) self.assertEqual(commands, self.tv.master._tclCommands) + # Click elsewhere first, so the second heading click is not reported + # as a double click (which does not invoke the command). + simulate_mouse_click(self.tv, 5, 50) simulate_heading_click(5, 5) if not success: self.fail("The command associated to the treeview heading wasn't " @@ -1892,10 +1900,11 @@ def test_insert_item(self): value) # test for values which are not None + keep_type = self.wantobjects and tk_version >= (9, 1) itemid = self.tv.insert('', 'end', 0) - self.assertEqual(itemid, '0') + self.assertEqual(itemid, 0 if keep_type else '0') itemid = self.tv.insert('', 'end', 0.0) - self.assertEqual(itemid, '0.0') + self.assertEqual(itemid, 0.0 if keep_type else '0.0') # this is because False resolves to 0 and element with 0 iid is already present self.assertRaises(tkinter.TclError, self.tv.insert, '', 'end', False) self.assertRaises(tkinter.TclError, self.tv.insert, '', 'end', '') @@ -1955,7 +1964,10 @@ def test_selection(self): self.tv.insert('', 'end', id=b'bytes\xe2\x82\xac') self.tv.selection_set(b'bytes\xe2\x82\xac') - self.assertEqual(self.tv.selection(), ('bytes\xe2\x82\xac',)) + self.assertEqual(self.tv.selection(), + (b'bytes\xe2\x82\xac',) + if self.wantobjects and tk_version >= (9, 1) + else ('bytes\xe2\x82\xac',)) self.tv.selection_set() self.assertEqual(self.tv.selection(), ()) @@ -2004,14 +2016,19 @@ def test_virtual_events(self): def test_set(self): self.tv['columns'] = ['A', 'B'] item = self.tv.insert('', 'end', values=['a', 'b']) - self.assertEqual(self.tv.set(item), {'A': 'a', 'B': 'b'}) + values = self.tv.set(item) + if tk_version >= (9, 1): + self.assertEqual(values.pop('#0'), '') + self.assertEqual(values, {'A': 'a', 'B': 'b'}) self.tv.set(item, 'B', 'a') self.assertEqual(self.tv.item(item, values=None), ('a', 'a') if self.wantobjects else 'a a') self.tv['columns'] = ['B'] - self.assertEqual(self.tv.set(item), {'B': 'a'}) + values = self.tv.set(item) + values.pop('#0', None) + self.assertEqual(values, {'B': 'a'}) self.tv.set(item, 'B', 'b') self.assertEqual(self.tv.set(item, column='B'), 'b') @@ -2023,7 +2040,9 @@ def test_set(self): 123 if self.wantobjects else '123') self.assertEqual(self.tv.item(item, values=None), (123, 'a') if self.wantobjects else '123 a') - self.assertEqual(self.tv.set(item), + values = self.tv.set(item) + values.pop('#0', None) + self.assertEqual(values, {'B': 123} if self.wantobjects else {'B': '123'}) # inexistent column From 7307d776290d54fc84b246b6b4cdcdcc63397ffa Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 9 Jul 2026 12:27:08 +0200 Subject: [PATCH 633/818] [3.15] gh-69134: Harden NotebookTest.test_traversal (GH-153403) (GH-153408) identify(5, 5) could run before the notebook reached its requested size, so the pixel fell outside the first tab and returned ''. Guard it with a new opt-in wait_until_mapped(full_size=True). (cherry picked from commit 53b04980284b668c27fc6d5adb0de19d38efe95b) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --- Lib/test/test_tkinter/support.py | 19 ++++++++++++++----- Lib/test/test_ttk/test_widgets.py | 8 ++++++-- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/Lib/test/test_tkinter/support.py b/Lib/test/test_tkinter/support.py index df0cca95a33a18..31feee2b8a40ee 100644 --- a/Lib/test/test_tkinter/support.py +++ b/Lib/test/test_tkinter/support.py @@ -93,7 +93,7 @@ def destroy_default_root(): tkinter._default_root.destroy() tkinter._default_root = None -def wait_until_mapped(widget, timeout=None): +def wait_until_mapped(widget, timeout=None, *, full_size=False): """Wait until *widget* is actually mapped and laid out by the window manager, so that realized-geometry queries (winfo_width(), identify(), coords(), ...) return meaningful values. @@ -103,6 +103,10 @@ def wait_until_mapped(widget, timeout=None): ``support.LOOPBACK_TIMEOUT``). Unlike Misc.wait_visibility(), this never blocks indefinitely, so it is safe under a window manager that never maps the window (see gh-69134, gh-74941, bpo-40722). + + If *full_size* is true, also wait until the realized size reaches the + requested size, so that per-pixel queries near an edge (e.g. identify()) + are reliable even under load. """ if timeout is None: timeout = support.LOOPBACK_TIMEOUT @@ -110,10 +114,15 @@ def wait_until_mapped(widget, timeout=None): widget.update_idletasks() while True: widget.update() # drain pending Map/Configure events - if (widget.winfo_ismapped() - and widget.winfo_width() > 1 - and widget.winfo_height() > 1): - return True + if widget.winfo_ismapped(): + if full_size: + w_ok = widget.winfo_width() >= widget.winfo_reqwidth() > 1 + h_ok = widget.winfo_height() >= widget.winfo_reqheight() > 1 + else: + w_ok = widget.winfo_width() > 1 + h_ok = widget.winfo_height() > 1 + if w_ok and h_ok: + return True if time.monotonic() >= deadline: return False time.sleep(0.01) diff --git a/Lib/test/test_ttk/test_widgets.py b/Lib/test/test_ttk/test_widgets.py index b2cc7f16f89446..c833058d3bf87d 100644 --- a/Lib/test/test_ttk/test_widgets.py +++ b/Lib/test/test_ttk/test_widgets.py @@ -1224,7 +1224,10 @@ def test_traversal(self): focus_identify_as = 'focus' else: focus_identify_as = 'focus' if tk_version < (8, 7) else 'padding' - self.assertEqual(self.nb.identify(5, 5), focus_identify_as) + # identify() at (5, 5) needs the tab realized there; under focus + # contention the mapped size can lag, so wait for the full size. + if wait_until_mapped(self.nb, full_size=True): + self.assertEqual(self.nb.identify(5, 5), focus_identify_as) simulate_mouse_click(self.nb, 5, 5) self.nb.focus_force() self.nb.event_generate('<Control-Tab>') @@ -1240,7 +1243,8 @@ def test_traversal(self): self.nb.tab(self.child2, text='e', underline=0) self.nb.enable_traversal() self.nb.focus_force() - self.assertEqual(self.nb.identify(5, 5), focus_identify_as) + if wait_until_mapped(self.nb, full_size=True): + self.assertEqual(self.nb.identify(5, 5), focus_identify_as) simulate_mouse_click(self.nb, 5, 5) # on macOS Emacs-style keyboard shortcuts are region-dependent; # let's use the regular arrow keys instead From 64048038a645e4da9789d56959f6d4a7ed6a14c9 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 9 Jul 2026 13:21:50 +0200 Subject: [PATCH 634/818] [3.15] gh-152132: Test all PyRun functions in test_capi.test_run (GH-153352) (#153411) gh-152132: Test all PyRun functions in test_capi.test_run (GH-153352) PyRun_InteractiveOneObjectEx() now raises TypeError if the second parameter type is not str. (cherry picked from commit cd9994e2831ea743e5423c1db56ca2ca42154e0a) Co-authored-by: Victor Stinner <vstinner@python.org> --- Lib/test/test_capi/test_run.py | 326 +++++++++++++-- Modules/_testcapi/run.c | 723 ++++++++++++++++++++++++++++++++- Python/pythonrun.c | 6 + 3 files changed, 993 insertions(+), 62 deletions(-) diff --git a/Lib/test/test_capi/test_run.py b/Lib/test/test_capi/test_run.py index 894f66b437a39c..d0418cdee62867 100644 --- a/Lib/test/test_capi/test_run.py +++ b/Lib/test/test_capi/test_run.py @@ -1,48 +1,72 @@ import os +import sys +import tempfile import unittest from collections import UserDict +from test import support from test.support import import_helper from test.support.os_helper import unlink, TESTFN, TESTFN_ASCII, TESTFN_UNDECODABLE + NULL = None _testcapi = import_helper.import_module('_testcapi') Py_single_input = _testcapi.Py_single_input Py_file_input = _testcapi.Py_file_input Py_eval_input = _testcapi.Py_eval_input +STDIN = '<stdin>' +STDERR_FD = 2 + +# Code raising a SyntaxError +SYNTAX_ERROR = 'True = 1' + +# Raise a SystemExit with exit code 42 +CODE_EXIT_42 = 'raise SystemExit(42)' + + +def create_text_file(filename, text): + with open(filename, 'w', encoding='utf8') as fp: + fp.write(text) class DictSubclass(dict): pass -class CAPITest(unittest.TestCase): - # TODO: Test the following functions: - # - # PyRun_SimpleStringFlags - # PyRun_AnyFileExFlags - # PyRun_SimpleFileExFlags - # PyRun_InteractiveOneFlags - # PyRun_InteractiveOneObject - # PyRun_InteractiveLoopFlags - # PyRun_String (may be a macro) - # PyRun_AnyFile (may be a macro) - # PyRun_AnyFileEx (may be a macro) - # PyRun_AnyFileFlags (may be a macro) - # PyRun_SimpleString (may be a macro) - # PyRun_SimpleFile (may be a macro) - # PyRun_SimpleFileEx (may be a macro) - # PyRun_InteractiveOne (may be a macro) - # PyRun_InteractiveLoop (may be a macro) - # PyRun_File (may be a macro) - # PyRun_FileEx (may be a macro) - # PyRun_FileFlags (may be a macro) +class capture_excepthook: + def __init__(self): + self.exc = None + self._old_hook = None - def test_run_stringflags(self): - # Test PyRun_StringFlags(). - # XXX: fopen() uses different path encoding than Python on Windows. + def _hook(self, exc_type, exc_value, exc_tb): + # Storing the exception instance creates a reference cycle. + self.exc = exc_value + + def __enter__(self): + self._old_hook = sys.excepthook + sys.excepthook = self._hook + return self + + def __exit__(self, *exc_info): + sys.excepthook = self._old_hook + self.exc = None + + +class CAPITest(unittest.TestCase): + def check_run_string(self, func): def run(s, *args): - return _testcapi.run_stringflags(s, Py_file_input, *args) - source = b'a\n' + return func(s, Py_file_input, *args) + + ns = {} + self.assertIsNone(run(b'x = 1', ns, ns)) + self.assertEqual(ns['x'], 1) + + with self.assertRaises(SyntaxError) as cm: + run(SYNTAX_ERROR.encode(), {}) + self.assertEqual(cm.exception.filename, '<string>') + + with self.assertRaises(ValueError) as cm: + run(b'raise ValueError("BUG")', {}) + self.assertEqual(str(cm.exception), 'BUG') self.assertIsNone(run(b'a\n', dict(a=1))) self.assertIsNone(run(b'a\n', dict(a=1), {})) @@ -70,20 +94,29 @@ def run(s, *args): # CRASHES run(NULL, {}) - def test_run_fileexflags(self): - # Test PyRun_FileExFlags(). + def test_run_string(self): + # Test PyRun_String() + self.check_run_string(_testcapi.run_string) + + def test_run_stringflags(self): + # Test PyRun_StringFlags(). + self.check_run_string(_testcapi.run_stringflags) + + def check_run_file(self, func, support_closeit): + # XXX: fopen() uses different path encoding than Python on Windows. filename = os.fsencode(TESTFN if os.name != 'nt' else TESTFN_ASCII) - with open(filename, 'wb') as fp: - fp.write(b'a\n') + create_text_file(filename, 'a\n') self.addCleanup(unlink, filename) def run(*args): - return _testcapi.run_fileexflags(filename, Py_file_input, *args) + return func(filename, Py_file_input, *args) self.assertIsNone(run(dict(a=1))) self.assertIsNone(run(dict(a=1), {})) self.assertIsNone(run({}, dict(a=1))) self.assertIsNone(run({}, UserDict(a=1))) - self.assertIsNone(run(dict(a=1), {}, 1)) # closeit = True + if support_closeit: + closeit = 1 + self.assertIsNone(run(dict(a=1), {}, closeit)) self.assertRaises(NameError, run, {}) self.assertRaises(NameError, run, {}, {}) @@ -101,17 +134,228 @@ def run(*args): self.assertRaises(SystemError, run, UserDict(), {}) self.assertRaises(SystemError, run, UserDict(), dict(a=1)) - @unittest.skipUnless(TESTFN_UNDECODABLE, 'only works if there are undecodable paths') - @unittest.skipIf(os.name == 'nt', 'does not work on Windows') - def test_run_fileexflags_with_undecodable_filename(self): - run = _testcapi.run_fileexflags + # syntax error + create_text_file(filename, SYNTAX_ERROR) + with self.assertRaises(SyntaxError) as cm: + self.assertIsNone(run({})) + self.assertEqual(cm.exception.filename, os.fsdecode(filename)) + + # raise exception + create_text_file(filename, 'raise ValueError("BUG")') + with self.assertRaises(ValueError) as cm: + self.assertIsNone(run({})) + self.assertEqual(str(cm.exception), 'BUG') + + # Test undecodable filename + if TESTFN_UNDECODABLE and os.name != 'nt': + try: + create_text_file(TESTFN_UNDECODABLE, 'a\n') + self.addCleanup(unlink, TESTFN_UNDECODABLE) + except OSError: + # undecodable paths are not supported + pass + else: + self.assertIsNone(func(TESTFN_UNDECODABLE, Py_file_input, dict(a=1))) + + def test_run_file(self): + # Test PyRun_File(). + self.check_run_file(_testcapi.run_file, False) + + def test_run_fileex(self): + # Test PyRun_FileEx(). + self.check_run_file(_testcapi.run_fileex, True) + + def test_run_fileflags(self): + # Test PyRun_FileFlags(). + self.check_run_file(_testcapi.run_fileflags, True) + + def test_run_fileexflags(self): + # Test PyRun_FileExFlags(). + self.check_run_file(_testcapi.run_fileexflags, True) + + def check_run_simplefile(self, func_name, have_closeit): + run = getattr(_testcapi, func_name) + + open_filename = TESTFN + with open(open_filename, 'w') as fp: + print('import sys', file=fp) + print('print(__file__)', file=fp) + print('mod = sys.modules["__main__"]', file=fp) + print('print(type(mod.__loader__).__name__)', file=fp) + self.addCleanup(unlink, open_filename) + + class MockLoader: + pass + loader = MockLoader() + + for closeit in (0, 1): + for set_file in (False, True): + for filename in (open_filename, 'custom filename', STDIN): + set_loader = (filename != STDIN) + with self.subTest(closeit=closeit, + set_file=set_file, + filename=filename): + mod = sys.modules['__main__'] + mod_file = mod.__file__ + with (support.captured_stdout() as stdout, + support.swap_attr(mod, '__loader__', loader)): + try: + if set_file: + del mod.__file__ + filename_arg = os.fsencode(filename) + if have_closeit: + res = run(open_filename, filename_arg, closeit) + else: + res = run(open_filename, filename_arg) + if set_file: + self.assertFalse(hasattr(mod, '__file__')) + finally: + mod.__file__ = mod_file + + self.assertEqual(res, 0) + expected = [filename if set_file else mod_file] + if set_loader: + expected.append('SourceFileLoader') + else: + expected.append('MockLoader') + self.assertEqual(stdout.getvalue().splitlines(), + expected) + + def test_run_simplefile(self): + # Test PyRun_SimpleFile() + self.check_run_simplefile('run_simplefile', False) + + def test_run_simplefileex(self): + # Test PyRun_SimpleFileEx() + self.check_run_simplefile('run_simplefileex', True) + + def test_run_simplefileexflags(self): + # Test PyRun_SimpleFileExFlags() + self.check_run_simplefile('run_simplefileexflags', True) + + def test_run_anyfile(self): + # Test PyRun_AnyFile() + self.check_run_simplefile('run_anyfile', False) + + def test_run_anyfileex(self): + # Test PyRun_AnyFileEx() + self.check_run_simplefile('run_anyfileex', True) + + def test_run_anyfileflags(self): + # Test PyRun_AnyFileFlags() + self.check_run_simplefile('run_anyfileflags', True) + + def _check_run_interactive(self, run, encode_filename, use_loop): + open_filename = TESTFN + if use_loop: + with open(open_filename, 'w') as fp: + print('welcome = "hello REPL"', file=fp) + print('print(welcome)', file=fp) + else: + create_text_file(open_filename, 'print("hello REPL")') + self.addCleanup(unlink, open_filename) + + for filename in ('filename', STDIN): + with self.subTest(filename=filename): + with support.captured_stdout() as stdout: + if encode_filename: + filename = filename.encode() + self.assertEqual(run(open_filename, filename), 0) + self.assertEqual(stdout.getvalue(), 'hello REPL\n') + + create_text_file(open_filename, SYNTAX_ERROR) + filename = 'custom filename' + if encode_filename: + filename_arg = filename.encode() + else: + filename_arg = filename + with capture_excepthook() as excepthook: + expected = (0 if use_loop else -1) + self.assertEqual(run(open_filename, filename_arg), expected) + self.assertIsInstance(excepthook.exc, SyntaxError) + self.assertEqual(excepthook.exc.filename, filename) + + create_text_file(open_filename, 'raise ValueError("BUG")') + with capture_excepthook() as excepthook: + expected = (0 if use_loop else -1) + self.assertEqual(run(open_filename, filename_arg), expected) + self.assertIsInstance(excepthook.exc, ValueError) + self.assertEqual(str(excepthook.exc), 'BUG') + + if not encode_filename: + # wrong type for the second parameter (filename) + with capture_excepthook() as excepthook: + self.assertEqual(run(open_filename, b'bytes'), -1) + self.assertIsInstance(excepthook.exc, TypeError) + + def check_run_interactive(self, run, encode_filename, use_loop=False): + # Redirect stderr to a temporary file to hide '>>> ' from the REPL try: - with open(TESTFN_UNDECODABLE, 'wb') as fp: - fp.write(b'a\n') - self.addCleanup(unlink, TESTFN_UNDECODABLE) + stderr_copy = os.dup(STDERR_FD) except OSError: - self.skipTest('undecodable paths are not supported') - self.assertIsNone(run(TESTFN_UNDECODABLE, Py_file_input, dict(a=1))) + # On WASI, dup(STDERR_FD) fails with "OSError: [Errno 58] Not + # supported". In this case, run the test without redirecting + # stderr to a temporary file. + self._check_run_interactive(run, encode_filename, use_loop) + else: + with tempfile.TemporaryFile() as tmp: + try: + os.dup2(tmp.fileno(), STDERR_FD) + self._check_run_interactive(run, encode_filename, use_loop) + finally: + os.dup2(stderr_copy, STDERR_FD) + + def test_run_interactiveone(self): + # Test PyRun_InteractiveOne() + run = _testcapi.run_interactiveone + self.check_run_interactive(run, True) + + def test_run_interactiveoneflags(self): + # Test PyRun_InteractiveOneFlags() + run = _testcapi.run_interactiveoneflags + self.check_run_interactive(run, True) + + def test_run_interactiveoneobject(self): + # Test PyRun_InteractiveOneObject() + run = _testcapi.run_interactiveoneobject + self.check_run_interactive(run, False) + + def test_run_interactiveloop(self): + # Test PyRun_InteractiveLoop() + run = _testcapi.run_interactiveloop + self.check_run_interactive(run, True, use_loop=True) + + def test_run_interactiveloopflags(self): + # Test PyRun_InteractiveLoopFlags() + run = _testcapi.run_interactiveloopflags + self.check_run_interactive(run, True, use_loop=True) + + def test_run_anyfileexflags(self): + # Test PyRun_AnyFileExFlags() + self.check_run_simplefile('run_anyfileexflags', True) + + def check_run_simplestring(self, run): + with support.captured_stdout() as stdout: + run(b'print("simple hello")') + self.assertEqual(stdout.getvalue(), 'simple hello\n') + + with capture_excepthook() as excepthook: + self.assertEqual(run(SYNTAX_ERROR.encode()), -1) + self.assertIsInstance(excepthook.exc, SyntaxError) + self.assertEqual(excepthook.exc.filename, '<string>') + + with capture_excepthook() as excepthook: + self.assertEqual(run(b'raise ValueError("BUG")'), -1) + self.assertIsInstance(excepthook.exc, ValueError) + self.assertEqual(str(excepthook.exc), 'BUG') + + def test_run_simplestring(self): + # Test PyRun_SimpleString() + self.check_run_simplestring(_testcapi.run_simplestring) + + def test_run_simplestringflags(self): + # Test PyRun_SimpleStringFlags() + self.check_run_simplestring(_testcapi.run_simplestringflags) if __name__ == '__main__': diff --git a/Modules/_testcapi/run.c b/Modules/_testcapi/run.c index c9db7ccdd965a2..4a63c0f98a74d4 100644 --- a/Modules/_testcapi/run.c +++ b/Modules/_testcapi/run.c @@ -7,8 +7,62 @@ #include <errno.h> -static PyObject * -run_stringflags(PyObject *mod, PyObject *pos_args) +// Test functions, not macros +#undef PyRun_AnyFile +#undef PyRun_AnyFileEx +#undef PyRun_AnyFileFlags +#undef PyRun_File +#undef PyRun_FileEx +#undef PyRun_FileFlags +#undef PyRun_SimpleFile +#undef PyRun_SimpleFileEx +#undef PyRun_String +#undef PyRun_SimpleString +#undef Py_CompileString +#undef Py_CompileStringFlags +#undef PyRun_InteractiveOne +#undef PyRun_InteractiveLoop + + +// Some PyRun functions crash if start is invalid, +// so validate the start argument. +static int +check_start(int start) +{ + if (start == Py_single_input || start == Py_file_input + || start == Py_eval_input || start == Py_func_type_input) + { + return 0; + } + PyErr_SetString(PyExc_ValueError, "invalid start argument"); + return -1; +} + + +// Test PyRun_String() +static PyObject* +run_string(PyObject *mod, PyObject *args) +{ + const char *str; + int start = 0; + PyObject *globals = NULL; + PyObject *locals = NULL; + + if (!PyArg_ParseTuple(args, "y|iOO", &str, &start, &globals, &locals)) { + return NULL; + } + if (check_start(start) < 0) { + return NULL; + } + NULLABLE(globals); + NULLABLE(locals); + + return PyRun_String(str, start, globals, locals); +} + +// Test PyRun_StringFlags() +static PyObject* +run_stringflags(PyObject *mod, PyObject *args) { const char *str; Py_ssize_t size; @@ -20,12 +74,14 @@ run_stringflags(PyObject *mod, PyObject *pos_args) int cf_flags = 0; int cf_feature_version = 0; - if (!PyArg_ParseTuple(pos_args, "z#iO|Oii", + if (!PyArg_ParseTuple(args, "z#iO|Oii", &str, &size, &start, &globals, &locals, &cf_flags, &cf_feature_version)) { return NULL; } - + if (check_start(start) < 0) { + return NULL; + } NULLABLE(globals); NULLABLE(locals); if (cf_flags || cf_feature_version) { @@ -37,8 +93,402 @@ run_stringflags(PyObject *mod, PyObject *pos_args) return PyRun_StringFlags(str, start, globals, locals, pflags); } -static PyObject * -run_fileexflags(PyObject *mod, PyObject *pos_args) +static FILE* +open_file(PyObject *filename, int *closeit) +{ + if (PyUnicode_EqualToUTF8(filename, "<stdin>")) { + if (closeit) { + // override closeit + *closeit = 0; + } + return stdin; + } + return Py_fopen(filename, "r"); +} + + +// Test PyRun_SimpleFile() +static PyObject* +run_simplefile(PyObject *mod, PyObject *args) +{ + PyObject *open_filename; + const char *filename; + + if (!PyArg_ParseTuple(args, "Oy", &open_filename, &filename)) { + return NULL; + } + + FILE *fp = open_file(open_filename, NULL); + if (fp == NULL) { + return NULL; + } + int fd = fileno(fp); + + int res = PyRun_SimpleFile(fp, filename); + + assert(_Py_IsValidFD(fd)); + fclose(fp); + + if (res == -1 && PyErr_Occurred()) { + return NULL; + } + assert(!PyErr_Occurred()); + return PyLong_FromLong(res); +} + +static int +close_fd(FILE *fp, int fd, int closeit) +{ + if (closeit && _Py_IsValidFD(fd)) { + PyErr_SetString(PyExc_AssertionError, "File was not closed after execution"); + fclose(fp); + return -1; + } + + if (!closeit && !_Py_IsValidFD(fd)) { + PyErr_SetString(PyExc_AssertionError, "Bad file descriptor after execution"); + return -1; + } + + if (!closeit) { + fclose(fp); + } + return 0; +} + +static int +close_fd_result(FILE *fp, int fd, int closeit, PyObject *result) +{ + if (closeit && result && _Py_IsValidFD(fd)) { + PyErr_SetString(PyExc_AssertionError, "File was not closed after execution"); + Py_DECREF(result); + fclose(fp); + return -1; + } + + if (!closeit && !_Py_IsValidFD(fd)) { + PyErr_SetString(PyExc_AssertionError, "Bad file descriptor after execution"); + Py_XDECREF(result); + return -1; + } + + if (!closeit) { + fclose(fp); + } + return 0; +} + +// Test PyRun_SimpleFileEx() +static PyObject* +run_simplefileex(PyObject *mod, PyObject *args) +{ + PyObject *open_filename; + const char *filename; + int closeit = 0; + + if (!PyArg_ParseTuple(args, "Oy|i", + &open_filename, &filename, &closeit)) { + return NULL; + } + + FILE *fp = open_file(open_filename, &closeit); + if (fp == NULL) { + return NULL; + } + int fd = fileno(fp); + + int res = PyRun_SimpleFileEx(fp, filename, closeit); + + if (close_fd(fp, fd, closeit) < 0) { + return NULL; + } + + if (res == -1 && PyErr_Occurred()) { + return NULL; + } + assert(!PyErr_Occurred()); + return PyLong_FromLong(res); +} + +// Test PyRun_SimpleFileExFlags() +static PyObject* +run_simplefileexflags(PyObject *mod, PyObject *args) +{ + PyObject *open_filename; + const char *filename; + int closeit = 0; + PyCompilerFlags flags = _PyCompilerFlags_INIT; + PyCompilerFlags *pflags = NULL; + int cf_flags = 0; + + if (!PyArg_ParseTuple(args, "Oy|ii", + &open_filename, &filename, &closeit, &cf_flags)) { + return NULL; + } + + FILE *fp = open_file(open_filename, &closeit); + if (fp == NULL) { + return NULL; + } + int fd = fileno(fp); + + if (cf_flags) { + flags.cf_flags = cf_flags; + pflags = &flags; + } + + int res = PyRun_SimpleFileExFlags(fp, filename, closeit, pflags); + + if (close_fd(fp, fd, closeit) < 0) { + return NULL; + } + + if (res == -1 && PyErr_Occurred()) { + return NULL; + } + assert(!PyErr_Occurred()); + return PyLong_FromLong(res); +} + +// Test PyRun_AnyFile() +static PyObject* +run_anyfile(PyObject *mod, PyObject *args) +{ + PyObject *open_filename; + const char *filename; + + if (!PyArg_ParseTuple(args, "Oy", &open_filename, &filename)) { + return NULL; + } + + FILE *fp = open_file(open_filename, NULL); + if (fp == NULL) { + return NULL; + } + int fd = fileno(fp); + + int res = PyRun_AnyFile(fp, filename); + + assert(_Py_IsValidFD(fd)); + fclose(fp); + + if (res == -1 && PyErr_Occurred()) { + return NULL; + } + assert(!PyErr_Occurred()); + return PyLong_FromLong(res); +} + +// Test PyRun_AnyFileFlags() +static PyObject* +run_anyfileflags(PyObject *mod, PyObject *args) +{ + PyObject *open_filename; + const char *filename; + PyCompilerFlags flags = _PyCompilerFlags_INIT; + PyCompilerFlags *pflags = NULL; + int cf_flags = 0; + + if (!PyArg_ParseTuple(args, "Oy|i", + &open_filename, &filename, &cf_flags)) { + return NULL; + } + + FILE *fp = open_file(open_filename, NULL); + if (fp == NULL) { + return NULL; + } + int fd = fileno(fp); + + if (cf_flags) { + flags.cf_flags = cf_flags; + pflags = &flags; + } + + int res = PyRun_AnyFileFlags(fp, filename, pflags); + + assert(_Py_IsValidFD(fd)); + fclose(fp); + + if (res == -1 && PyErr_Occurred()) { + return NULL; + } + assert(!PyErr_Occurred()); + return PyLong_FromLong(res); +} + +// Test PyRun_AnyFileEx() +static PyObject* +run_anyfileex(PyObject *mod, PyObject *args) +{ + PyObject *open_filename; + const char *filename; + int closeit = 0; + + if (!PyArg_ParseTuple(args, "Oy|i", + &open_filename, &filename, &closeit)) { + return NULL; + } + + FILE *fp = open_file(open_filename, &closeit); + if (fp == NULL) { + return NULL; + } + int fd = fileno(fp); + + int res = PyRun_AnyFileEx(fp, filename, closeit); + + if (close_fd(fp, fd, closeit) < 0) { + return NULL; + } + + if (res == -1 && PyErr_Occurred()) { + return NULL; + } + assert(!PyErr_Occurred()); + return PyLong_FromLong(res); +} + +// Test PyRun_AnyFileExFlags() +static PyObject* +run_anyfileexflags(PyObject *mod, PyObject *args) +{ + PyObject *open_filename; + const char *filename; + int closeit = 0; + PyCompilerFlags flags = _PyCompilerFlags_INIT; + PyCompilerFlags *pflags = NULL; + int cf_flags = 0; + + if (!PyArg_ParseTuple(args, "Oy|ii", + &open_filename, &filename, &closeit, &cf_flags)) { + return NULL; + } + + FILE *fp = open_file(open_filename, &closeit); + if (fp == NULL) { + return NULL; + } + int fd = fileno(fp); + + if (cf_flags) { + flags.cf_flags = cf_flags; + pflags = &flags; + } + + int res = PyRun_AnyFileExFlags(fp, filename, closeit, pflags); + + if (close_fd(fp, fd, closeit) < 0) { + return NULL; + } + + if (res == -1 && PyErr_Occurred()) { + return NULL; + } + assert(!PyErr_Occurred()); + return PyLong_FromLong(res); +} + + +// Test PyRun_InteractiveOne() +static PyObject* +run_interactiveone(PyObject *mod, PyObject *args) +{ + PyObject *open_filename; + char *filename; + + if (!PyArg_ParseTuple(args, "Oy", &open_filename, &filename)) { + return NULL; + } + + FILE *fp = open_file(open_filename, NULL); + if (fp == NULL) { + return NULL; + } + int fd = fileno(fp); + + int res = PyRun_InteractiveOne(fp, filename); + assert(!PyErr_Occurred()); + + assert(_Py_IsValidFD(fd)); + fclose(fp); + + return PyLong_FromLong(res); +} + +// Test PyRun_InteractiveOneFlags() +static PyObject* +run_interactiveoneflags(PyObject *mod, PyObject *args) +{ + PyObject *open_filename; + char *filename; + PyCompilerFlags flags = _PyCompilerFlags_INIT; + PyCompilerFlags *pflags = NULL; + int cf_flags = 0; + + if (!PyArg_ParseTuple(args, "Oy|i", + &open_filename, &filename, &cf_flags)) { + return NULL; + } + + FILE *fp = open_file(open_filename, NULL); + if (fp == NULL) { + return NULL; + } + int fd = fileno(fp); + + if (cf_flags) { + flags.cf_flags = cf_flags; + pflags = &flags; + } + + int res = PyRun_InteractiveOneFlags(fp, filename, pflags); + assert(!PyErr_Occurred()); + + assert(_Py_IsValidFD(fd)); + fclose(fp); + + return PyLong_FromLong(res); +} + +// Test PyRun_InteractiveOneObject() +static PyObject* +run_interactiveoneobject(PyObject *mod, PyObject *args) +{ + PyObject *open_filename; + PyObject *filename; + PyCompilerFlags flags = _PyCompilerFlags_INIT; + PyCompilerFlags *pflags = NULL; + int cf_flags = 0; + + if (!PyArg_ParseTuple(args, "OO|i", + &open_filename, &filename, &cf_flags)) { + return NULL; + } + + FILE *fp = open_file(open_filename, NULL); + if (fp == NULL) { + return NULL; + } + int fd = fileno(fp); + + if (cf_flags) { + flags.cf_flags = cf_flags; + pflags = &flags; + } + + int res = PyRun_InteractiveOneObject(fp, filename, pflags); + assert(!PyErr_Occurred()); + + assert(_Py_IsValidFD(fd)); + fclose(fp); + + return PyLong_FromLong(res); +} + +// Test PyRun_File() +static PyObject* +run_file(PyObject *mod, PyObject *args) { PyObject *result = NULL; const char *filename = NULL; @@ -46,20 +496,140 @@ run_fileexflags(PyObject *mod, PyObject *pos_args) int start; PyObject *globals = NULL; PyObject *locals = NULL; + + if (!PyArg_ParseTuple(args, "z#iO|O", + &filename, &filename_size, &start, + &globals, &locals)) { + return NULL; + } + if (check_start(start) < 0) { + return NULL; + } + NULLABLE(globals); + NULLABLE(locals); + + FILE *fp = fopen(filename, "r"); + if (fp == NULL) { + PyErr_SetFromErrnoWithFilename(PyExc_OSError, filename); + return NULL; + } + int fd = fileno(fp); + + result = PyRun_File(fp, filename, start, globals, locals); + + assert(_Py_IsValidFD(fd)); + fclose(fp); + + return result; +} + +// Test PyRun_FileEx() +static PyObject* +run_fileex(PyObject *mod, PyObject *args) +{ + const char *filename = NULL; + Py_ssize_t filename_size; + int start; + PyObject *globals = NULL; + PyObject *locals = NULL; int closeit = 0; + + if (!PyArg_ParseTuple(args, "z#iO|Oi", + &filename, &filename_size, &start, &globals, &locals, + &closeit)) { + return NULL; + } + if (check_start(start) < 0) { + return NULL; + } + NULLABLE(globals); + NULLABLE(locals); + + FILE *fp = fopen(filename, "r"); + if (fp == NULL) { + PyErr_SetFromErrnoWithFilename(PyExc_OSError, filename); + return NULL; + } + int fd = fileno(fp); + + PyObject *result = PyRun_FileEx(fp, filename, start, globals, locals, + closeit); + + if (close_fd_result(fp, fd, closeit, result) < 0) { + return NULL; + } + + return result; +} + +// Test PyRun_FileFlags +static PyObject* +run_fileflags(PyObject *mod, PyObject *args) +{ + const char *filename = NULL; + Py_ssize_t filename_size; + int start; + PyObject *globals = NULL; + PyObject *locals = NULL; PyCompilerFlags flags = _PyCompilerFlags_INIT; PyCompilerFlags *pflags = NULL; int cf_flags = 0; int cf_feature_version = 0; - FILE *fp = NULL; + if (!PyArg_ParseTuple(args, "z#iO|Oii", + &filename, &filename_size, &start, &globals, &locals, + &cf_flags, &cf_feature_version)) { + return NULL; + } + if (check_start(start) < 0) { + return NULL; + } + NULLABLE(globals); + NULLABLE(locals); + if (cf_flags || cf_feature_version) { + flags.cf_flags = cf_flags; + flags.cf_feature_version = cf_feature_version; + pflags = &flags; + } + + FILE *fp = fopen(filename, "r"); + if (fp == NULL) { + PyErr_SetFromErrnoWithFilename(PyExc_OSError, filename); + return NULL; + } + int fd = fileno(fp); + + PyObject *result = PyRun_FileFlags(fp, filename, start, globals, locals, + pflags); + + assert(_Py_IsValidFD(fd)); + fclose(fp); + + return result; +} + +static PyObject* +run_fileexflags(PyObject *mod, PyObject *args) +{ + const char *filename = NULL; + Py_ssize_t filename_size; + int start; + PyObject *globals = NULL; + PyObject *locals = NULL; + int closeit = 0; + PyCompilerFlags flags = _PyCompilerFlags_INIT; + PyCompilerFlags *pflags = NULL; + int cf_flags = 0; + int cf_feature_version = 0; - if (!PyArg_ParseTuple(pos_args, "z#iO|Oiii", + if (!PyArg_ParseTuple(args, "z#iO|Oiii", &filename, &filename_size, &start, &globals, &locals, &closeit, &cf_flags, &cf_feature_version)) { return NULL; } - + if (check_start(start) < 0) { + return NULL; + } NULLABLE(globals); NULLABLE(locals); if (cf_flags || cf_feature_version) { @@ -68,38 +638,149 @@ run_fileexflags(PyObject *mod, PyObject *pos_args) pflags = &flags; } - fp = fopen(filename, "r"); + FILE *fp = fopen(filename, "r"); if (fp == NULL) { PyErr_SetFromErrnoWithFilename(PyExc_OSError, filename); return NULL; } int fd = fileno(fp); - result = PyRun_FileExFlags(fp, filename, start, globals, locals, closeit, pflags); + PyObject *result = PyRun_FileExFlags(fp, filename, start, globals, locals, + closeit, pflags); - if (closeit && result && _Py_IsValidFD(fd)) { - PyErr_SetString(PyExc_AssertionError, "File was not closed after execution"); - Py_DECREF(result); - fclose(fp); + if (close_fd_result(fp, fd, closeit, result) < 0) { return NULL; } - if (!closeit && !_Py_IsValidFD(fd)) { - PyErr_SetString(PyExc_AssertionError, "Bad file descriptor after execution"); - Py_XDECREF(result); + return result; +} + +static PyObject* +run_simplestring(PyObject *mod, PyObject *args) +{ + const char *str; + if (!PyArg_ParseTuple(args, "y", &str)) { return NULL; } - if (!closeit) { - fclose(fp); /* don't need open file any more*/ + int res = PyRun_SimpleString(str); + if (res == -1 && PyErr_Occurred()) { + return NULL; } + assert(!PyErr_Occurred()); + return PyLong_FromLong(res); +} - return result; +static PyObject* +run_simplestringflags(PyObject *mod, PyObject *args) +{ + const char *str; + PyCompilerFlags flags = _PyCompilerFlags_INIT; + PyCompilerFlags *pflags = NULL; + int cf_flags = 0; + + if (!PyArg_ParseTuple(args, "y|i", &str, &flags)) { + return NULL; + } + + if (cf_flags) { + flags.cf_flags = cf_flags; + pflags = &flags; + } + + int res = PyRun_SimpleStringFlags(str, pflags); + if (res == -1 && PyErr_Occurred()) { + return NULL; + } + assert(!PyErr_Occurred()); + return PyLong_FromLong(res); } + +// Test PyRun_InteractiveLoop() +static PyObject* +run_interactiveloop(PyObject *mod, PyObject *args) +{ + PyObject *open_filename; + char *filename; + + if (!PyArg_ParseTuple(args, "Oy|i", &open_filename, &filename)) { + return NULL; + } + + FILE *fp = open_file(open_filename, NULL); + if (fp == NULL) { + return NULL; + } + int fd = fileno(fp); + + int res = PyRun_InteractiveLoop(fp, filename); + assert(!PyErr_Occurred()); + + assert(_Py_IsValidFD(fd)); + fclose(fp); + + return PyLong_FromLong(res); +} + + +// Test PyRun_InteractiveLoopFlags() +static PyObject* +run_interactiveloopflags(PyObject *mod, PyObject *args) +{ + PyObject *open_filename; + char *filename; + PyCompilerFlags flags = _PyCompilerFlags_INIT; + PyCompilerFlags *pflags = NULL; + int cf_flags = 0; + + if (!PyArg_ParseTuple(args, "Oy|i", + &open_filename, &filename, &cf_flags)) { + return NULL; + } + + FILE *fp = open_file(open_filename, NULL); + if (fp == NULL) { + return NULL; + } + int fd = fileno(fp); + + if (cf_flags) { + flags.cf_flags = cf_flags; + pflags = &flags; + } + + int res = PyRun_InteractiveLoopFlags(fp, filename, pflags); + assert(!PyErr_Occurred()); + + assert(_Py_IsValidFD(fd)); + fclose(fp); + + return PyLong_FromLong(res); +} + + static PyMethodDef test_methods[] = { + {"run_string", run_string, METH_VARARGS}, {"run_stringflags", run_stringflags, METH_VARARGS}, + {"run_simplefile", run_simplefile, METH_VARARGS}, + {"run_simplefileex", run_simplefileex, METH_VARARGS}, + {"run_simplefileexflags", run_simplefileexflags, METH_VARARGS}, + {"run_anyfile", run_anyfile, METH_VARARGS}, + {"run_anyfileflags", run_anyfileflags, METH_VARARGS}, + {"run_anyfileex", run_anyfileex, METH_VARARGS}, + {"run_anyfileexflags", run_anyfileexflags, METH_VARARGS}, + {"run_interactiveone", run_interactiveone, METH_VARARGS}, + {"run_interactiveoneflags", run_interactiveoneflags, METH_VARARGS}, + {"run_interactiveoneobject", run_interactiveoneobject, METH_VARARGS}, + {"run_file", run_file, METH_VARARGS}, + {"run_fileex", run_fileex, METH_VARARGS}, + {"run_fileflags", run_fileflags, METH_VARARGS}, {"run_fileexflags", run_fileexflags, METH_VARARGS}, + {"run_simplestring", run_simplestring, METH_VARARGS}, + {"run_simplestringflags", run_simplestringflags, METH_VARARGS}, + {"run_interactiveloop", run_interactiveloop, METH_VARARGS}, + {"run_interactiveloopflags", run_interactiveloopflags, METH_VARARGS}, {NULL}, }; diff --git a/Python/pythonrun.c b/Python/pythonrun.c index 971ab064777a41..8c441e7ebd3c79 100644 --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -290,6 +290,12 @@ static int PyRun_InteractiveOneObjectEx(FILE *fp, PyObject *filename, PyCompilerFlags *flags) { + if (!PyUnicode_Check(filename)) { + PyErr_Format(PyExc_TypeError, "expect str for filename, got %T", + filename); + return -1; + } + PyArena *arena = _PyArena_New(); if (arena == NULL) { return -1; From c42d55c8b830ec915733a53b50549ab6430c478c Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 9 Jul 2026 16:19:21 +0200 Subject: [PATCH 635/818] [3.15] gh-153417: Fix BytesWarning in imaplib error messages for bytes arguments (GH-153423) (GH-153430) IMAP4.select() and IMAP4.uid() formatted the mailbox and command argument with %s in their error messages, which raised BytesWarning under -bb when the argument was bytes and masked the real error. Use %r instead, which is safe for bytes and also quotes the value. (cherry picked from commit 11f1b70f4c981b781aaa94427dc1fceb637b2187) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --- Lib/imaplib.py | 4 +-- Lib/test/test_imaplib.py | 26 +++++++++++++++++++ ...-07-09-14-00-00.gh-issue-153417.Bw7Rq2.rst | 3 +++ 3 files changed, 31 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-07-09-14-00-00.gh-issue-153417.Bw7Rq2.rst diff --git a/Lib/imaplib.py b/Lib/imaplib.py index 773913864153b1..d78ad08ce35b46 100644 --- a/Lib/imaplib.py +++ b/Lib/imaplib.py @@ -899,7 +899,7 @@ def select(self, mailbox='INBOX', readonly=False): if __debug__: if self.debug >= 1: self._dump_ur(self.untagged_responses) - raise self.readonly('%s is not writable' % mailbox) + raise self.readonly('%r is not writable' % (mailbox,)) return typ, self.untagged_responses.get('EXISTS', [None]) @@ -1024,7 +1024,7 @@ def uid(self, command, *args): """ command = command.upper() if not command in Commands: - raise self.error("Unknown IMAP4 UID command: %s" % command) + raise self.error("Unknown IMAP4 UID command: %r" % (command,)) if self.state not in Commands[command]: raise self.error("command %s illegal in state %s, " "only allowed in states %s" % diff --git a/Lib/test/test_imaplib.py b/Lib/test/test_imaplib.py index 8e724795b58e75..308fa365c0384c 100644 --- a/Lib/test/test_imaplib.py +++ b/Lib/test/test_imaplib.py @@ -942,6 +942,32 @@ def cmd_CAPABILITY(self, tag, args): client.login('user', 'pass') self.assertIn('ENABLE', client.capabilities) + def test_readonly_error_reports_mailbox(self): + # The read-only error reports the mailbox via repr(), which also + # avoids BytesWarning for a bytes mailbox under -bb. + class ReadOnlyHandler(SimpleIMAPHandler): + def cmd_SELECT(self, tag, args): + self._send_line(b'* 2 EXISTS') + self._send_tagged(tag, 'OK', '[READ-ONLY] SELECT completed.') + client, _ = self._setup(ReadOnlyHandler) + client.login('user', 'pass') + for mailbox, expected in [('INBOX', "'INBOX'"), (b'INBOX', r"b'INBOX'")]: + with self.subTest(mailbox=mailbox): + with self.assertRaisesRegex(imaplib.IMAP4.readonly, + r"%s is not writable" % expected): + client.select(mailbox) + + def test_uid_unknown_command_reports_command(self): + # The unknown-UID-command error reports the command via repr(), which + # also avoids BytesWarning for a bytes command under -bb. + client, _ = self._setup(SimpleIMAPHandler) + for command, expected in [('BOGUS', "'BOGUS'"), (b'BOGUS', r"b'BOGUS'")]: + with self.subTest(command=command): + with self.assertRaisesRegex( + imaplib.IMAP4.error, + r"Unknown IMAP4 UID command: %s" % expected): + client.uid(command, '1') + def test_logout(self): client, _ = self._setup(SimpleIMAPHandler) typ, data = client.login('user', 'pass') diff --git a/Misc/NEWS.d/next/Library/2026-07-09-14-00-00.gh-issue-153417.Bw7Rq2.rst b/Misc/NEWS.d/next/Library/2026-07-09-14-00-00.gh-issue-153417.Bw7Rq2.rst new file mode 100644 index 00000000000000..ebc36fa7c228d0 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-09-14-00-00.gh-issue-153417.Bw7Rq2.rst @@ -0,0 +1,3 @@ +Error messages from :meth:`imaplib.IMAP4.select` and :meth:`imaplib.IMAP4.uid` +no longer raise :exc:`BytesWarning` under :option:`!-bb` +when the mailbox or command argument is :class:`bytes`. From 1604c80008d72b4c9a5bd789900ecf9aff402c1e Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka <storchaka@gmail.com> Date: Thu, 9 Jul 2026 18:16:50 +0300 Subject: [PATCH 636/818] [3.15] gh-153422: Assert bool return type in tkinter tests (GH-153429) (GH-153439) The tests for PhotoImage.transparency_get(), Text.debug() and Treeview.exists() now assert the exact bool type, and the documentation and docstrings use "true"/"false" instead of "1"/"0". Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --- Doc/library/tkinter.rst | 10 +++++----- Lib/test/test_tkinter/test_images.py | 8 ++++---- Lib/test/test_tkinter/test_text.py | 8 ++++---- Lib/test/test_ttk/test_widgets.py | 6 +++--- Lib/tkinter/ttk.py | 4 ++-- 5 files changed, 18 insertions(+), 18 deletions(-) diff --git a/Doc/library/tkinter.rst b/Doc/library/tkinter.rst index 0630828c164a72..7ac2e033cea88c 100644 --- a/Doc/library/tkinter.rst +++ b/Doc/library/tkinter.rst @@ -2015,7 +2015,7 @@ Base and mixin classes .. method:: winfo_exists() - Return ``1`` if the widget exists, ``0`` otherwise. + Return true if the widget exists, false otherwise. .. method:: winfo_fpixels(number) @@ -2054,7 +2054,7 @@ Base and mixin classes .. method:: winfo_ismapped() - Return ``1`` if the widget is currently mapped, ``0`` otherwise. + Return true if the widget is currently mapped, false otherwise. .. method:: winfo_manager() @@ -2185,8 +2185,8 @@ Base and mixin classes .. method:: winfo_viewable() - Return ``1`` if the widget and all of its ancestors up through the - nearest toplevel window are mapped, ``0`` otherwise. + Return true if the widget and all of its ancestors up through the + nearest toplevel window are mapped, false otherwise. .. method:: winfo_visual() @@ -5591,7 +5591,7 @@ Widget classes .. method:: edit_modified(arg=None) If *arg* is omitted, return the current state of the modified flag as - ``0`` or ``1``; the flag is set automatically whenever the text is + true or false; the flag is set automatically whenever the text is inserted or deleted. Otherwise set the flag to the boolean *arg*. diff --git a/Lib/test/test_tkinter/test_images.py b/Lib/test/test_tkinter/test_images.py index f9b314da9e8a91..db399d66c35e51 100644 --- a/Lib/test/test_tkinter/test_images.py +++ b/Lib/test/test_tkinter/test_images.py @@ -655,12 +655,12 @@ def test_data(self): def test_transparency(self): image = self.create() - self.assertEqual(image.transparency_get(0, 0), True) - self.assertEqual(image.transparency_get(4, 6), False) + self.assertIs(image.transparency_get(0, 0), True) + self.assertIs(image.transparency_get(4, 6), False) image.transparency_set(4, 6, True) - self.assertEqual(image.transparency_get(4, 6), True) + self.assertIs(image.transparency_get(4, 6), True) image.transparency_set(4, 6, False) - self.assertEqual(image.transparency_get(4, 6), False) + self.assertIs(image.transparency_get(4, 6), False) self.assertRaises(tkinter.TclError, image.transparency_get, -1, 0) self.assertRaises(tkinter.TclError, image.transparency_get, 16, 0) self.assertRaises(tkinter.TclError, image.transparency_set, -1, 0, True) diff --git a/Lib/test/test_tkinter/test_text.py b/Lib/test/test_tkinter/test_text.py index 3d15e7f4909e83..6379a6ca98421c 100644 --- a/Lib/test/test_tkinter/test_text.py +++ b/Lib/test/test_tkinter/test_text.py @@ -18,10 +18,10 @@ def test_debug(self): text = self.text olddebug = text.debug() try: - text.debug(0) - self.assertEqual(text.debug(), 0) - text.debug(1) - self.assertEqual(text.debug(), 1) + text.debug(False) + self.assertIs(text.debug(), False) + text.debug(True) + self.assertIs(text.debug(), True) finally: text.debug(olddebug) self.assertEqual(text.debug(), olddebug) diff --git a/Lib/test/test_ttk/test_widgets.py b/Lib/test/test_ttk/test_widgets.py index c833058d3bf87d..787c96cfd77cbf 100644 --- a/Lib/test/test_ttk/test_widgets.py +++ b/Lib/test/test_ttk/test_widgets.py @@ -1685,9 +1685,9 @@ def test_detach_reattach(self): self.assertEqual(self.tv.get_children(item_id), ()) def test_exists(self): - self.assertEqual(self.tv.exists('something'), False) - self.assertEqual(self.tv.exists(''), True) - self.assertEqual(self.tv.exists({}), False) + self.assertIs(self.tv.exists('something'), False) + self.assertIs(self.tv.exists(''), True) + self.assertIs(self.tv.exists({}), False) # the following will make a tk.call equivalent to # tk.call(treeview, "exists") which should result in an error diff --git a/Lib/tkinter/ttk.py b/Lib/tkinter/ttk.py index 36f21453dc7390..4ca8d12dc28801 100644 --- a/Lib/tkinter/ttk.py +++ b/Lib/tkinter/ttk.py @@ -1483,8 +1483,8 @@ def tag_configure(self, tagname, option=None, **kw): def tag_has(self, tagname, item=None): - """If item is specified, returns 1 or 0 depending on whether the - specified item has the given tagname. Otherwise, returns a list of + """If item is specified, returns True if the specified item has the + given tagname, False otherwise. Otherwise, returns a list of all items which have the specified tag. * Availability: Tk 8.6""" From 0891295ac15b338fcd74ca0a647cbf975864fd98 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 9 Jul 2026 20:55:52 +0200 Subject: [PATCH 637/818] [3.15] gh-146531: Broaden `wm_iconbitmap` skip on macOS 26 Intel (GH-153348) (#153450) gh-146531: Broaden `wm_iconbitmap` skip on macOS 26 Intel (GH-153348) (cherry picked from commit 6ba3ad55bd922f164acf8f20b884730b718ee433) Co-authored-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> --- Lib/test/test_tkinter/test_misc.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Lib/test/test_tkinter/test_misc.py b/Lib/test/test_tkinter/test_misc.py index 14a5f6782877b4..698ba818029fe8 100644 --- a/Lib/test/test_tkinter/test_misc.py +++ b/Lib/test/test_tkinter/test_misc.py @@ -984,13 +984,10 @@ def test_wm_iconbitmap(self): and sys.platform == 'darwin' and platform.machine() == 'x86_64' and platform.mac_ver()[0].startswith('26.') - and ( - patchlevel[:3] <= (8, 6, 17) - or (9, 0) <= patchlevel[:3] <= (9, 0, 3) - ) ): # https://github.com/python/cpython/issues/146531 # Tk bug 4a2070f0d3a99aa412bc582d386d575ca2f37323 + # Not fixed as of Tk 8.6.18 and 9.0.4. self.skipTest('wm iconbitmap hangs on macOS 26 Intel') self.assertEqual(t.wm_iconbitmap(), '') From 76c28fc1077719ecb0ef6c4a276d36647f7a66c0 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 9 Jul 2026 21:00:28 +0200 Subject: [PATCH 638/818] [3.15] gh-152132: Fix Py_RunMain() to return an exit code (GH-153446) (#153454) gh-152132: Fix Py_RunMain() to return an exit code (GH-153446) * Fix Py_RunMain() to return an exit code, rather than calling Py_Exit(), when running a script, a command, or the REPL. * _PyRun_SimpleFile() now logs errors to stderr, for example if setting __main__.__file__ fails. * Add tests on Py_RunMain() exitcode. * Rename functions: * _PyRun_SimpleStringFlagsWithName() => _PyRun_SimpleString() * _PyRun_SimpleFileObject() => _PyRun_SimpleFile() * _PyRun_AnyFileObject() => _PyRun_AnyFile() * _PyRun_InteractiveLoopObject() => _PyRun_InteractiveLoop() * Change _PyRun_SimpleString(), _PyRun_SimpleFile(), _PyRun_AnyFile() and _PyRun_InteractiveLoop() return type to PyObject*. * pymain_repl() now displays the error if PySys_Audit() or import _pyrepl failed. * PyRun_SimpleFileExFlags() and PyRun_AnyFileExFlags() now log PyUnicode_DecodeFSDefault() error. So these functions can no longer return -1 with an exception set. (cherry picked from commit fac72f1ee91fb380640a4c4be6df07a8f02d3110) Co-authored-by: Victor Stinner <vstinner@python.org> --- Include/internal/pycore_pylifecycle.h | 3 - Include/internal/pycore_pythonrun.h | 15 +- Lib/test/test_embed.py | 68 +++++- ...-07-09-17-33-29.gh-issue-152132.Ma8MJZ.rst | 3 + Modules/_testcapi/run.c | 27 --- Modules/main.c | 173 ++++++++------- Programs/_testembed.c | 161 +++++++++++--- Python/pythonrun.c | 199 +++++++++--------- 8 files changed, 398 insertions(+), 251 deletions(-) create mode 100644 Misc/NEWS.d/next/C_API/2026-07-09-17-33-29.gh-issue-152132.Ma8MJZ.rst diff --git a/Include/internal/pycore_pylifecycle.h b/Include/internal/pycore_pylifecycle.h index 8faf7a4d403f84..386ce2e145fb75 100644 --- a/Include/internal/pycore_pylifecycle.h +++ b/Include/internal/pycore_pylifecycle.h @@ -111,9 +111,6 @@ extern int _Py_LegacyLocaleDetected(int warn); // Export for 'readline' shared extension PyAPI_FUNC(char*) _Py_SetLocaleFromEnv(int category); -// Export for special main.c string compiling with source tracebacks -int _PyRun_SimpleStringFlagsWithName(const char *command, const char* name, PyCompilerFlags *flags); - /* interpreter config */ diff --git a/Include/internal/pycore_pythonrun.h b/Include/internal/pycore_pythonrun.h index 2a544edc431e6b..349992d4a3c59c 100644 --- a/Include/internal/pycore_pythonrun.h +++ b/Include/internal/pycore_pythonrun.h @@ -8,23 +8,18 @@ extern "C" { # error "this header requires Py_BUILD_CORE define" #endif -extern int _PyRun_SimpleFileObject( +extern PyObject* _PyRun_SimpleFile( FILE *fp, PyObject *filename, int closeit, PyCompilerFlags *flags); -extern int _PyRun_AnyFileObject( +extern PyObject* _PyRun_AnyFile( FILE *fp, PyObject *filename, int closeit, PyCompilerFlags *flags); -extern int _PyRun_InteractiveLoopObject( - FILE *fp, - PyObject *filename, - PyCompilerFlags *flags); - extern int _PyObject_SupportedAsScript(PyObject *); extern const char* _Py_SourceAsString( PyObject *cmd, @@ -39,6 +34,12 @@ extern PyObject * _Py_CompileStringObjectWithModule( PyCompilerFlags *flags, int optimize, PyObject *module); +// Export for special main.c string compiling with source tracebacks +extern PyObject* _PyRun_SimpleString( + const char *command, + PyObject* name, + PyCompilerFlags *flags); + /* Stack size, in "pointers". This must be large enough, so * no two calls to check recursion depth are more than this far diff --git a/Lib/test/test_embed.py b/Lib/test/test_embed.py index 6a464e6d8f9cac..420eb7e8c2ca52 100644 --- a/Lib/test/test_embed.py +++ b/Lib/test/test_embed.py @@ -68,6 +68,9 @@ if not os.path.isfile(os.path.join(STDLIB_INSTALL, 'os.py')): STDLIB_INSTALL = None +CODE_EXITCODE_123 = 'raise SystemExit(123)' + + def debug_build(program): program = os.path.basename(program) name = os.path.splitext(program)[0] @@ -117,12 +120,16 @@ def run_embedded_interpreter(self, *args, env=None, env = env.copy() env['SYSTEMROOT'] = os.environ['SYSTEMROOT'] - p = subprocess.Popen(cmd, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - universal_newlines=True, - env=env, - cwd=cwd) + kwargs = dict( + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + universal_newlines=True, + env=env, + cwd=cwd, + ) + if input is not None: + kwargs['stdin'] = subprocess.PIPE + p = subprocess.Popen(cmd, **kwargs) try: (out, err) = p.communicate(input=input, timeout=timeout) except: @@ -565,6 +572,55 @@ def _nogil_filtered_err(err: str, mod_name: str) -> str: ] return "\n".join(filtered_err_lines) + def check_program_exitcode(self, *args, check_stderr=True, **kwargs): + out, err = self.run_embedded_interpreter(*args, **kwargs) + self.assertEqual(out.rstrip(), 'ok! Py_RunMain() returned 123') + if check_stderr: + self.assertEqual(err, '') + + def test_init_run_main_code_exitcode(self): + code = CODE_EXITCODE_123 + self.check_program_exitcode("test_init_run_main_code_exitcode", code) + + def test_init_run_main_script_exitcode(self): + with tempfile.TemporaryDirectory() as tmpdir: + filename = os.path.join(tmpdir, 'script.py') + with open(filename, 'w') as fp: + fp.write(CODE_EXITCODE_123) + + self.check_program_exitcode("test_init_run_main_script_exitcode", + filename) + + def test_init_run_main_interactive_exitcode(self): + code = CODE_EXITCODE_123 + self.check_program_exitcode("test_init_run_main_interactive_exitcode", + input=code, + check_stderr=False) + + def test_init_run_main_startup_exitcode(self): + with tempfile.TemporaryDirectory() as tmpdir: + filename = os.path.join(tmpdir, 'startup.py') + with open(filename, 'x') as fp: + fp.write(CODE_EXITCODE_123) + + env = dict(os.environ) + env['PYTHONSTARTUP'] = filename + self.check_program_exitcode("test_init_run_main_interactive_exitcode", + env=env, + check_stderr=False) + + def test_init_run_main_module_exitcode(self): + with tempfile.TemporaryDirectory() as tmpdir: + modname = '_testembed_testmodule' + filename = os.path.join(tmpdir, modname + '.py') + with open(filename, 'x', encoding='utf8') as fp: + fp.write(CODE_EXITCODE_123) + + env = dict(os.environ) + env['PYTHONPATH'] = tmpdir + self.check_program_exitcode("test_init_run_main_module_exitcode", + modname, env=env) + def config_dev_mode(preconfig, config): preconfig['allocator'] = PYMEM_ALLOCATOR_DEBUG diff --git a/Misc/NEWS.d/next/C_API/2026-07-09-17-33-29.gh-issue-152132.Ma8MJZ.rst b/Misc/NEWS.d/next/C_API/2026-07-09-17-33-29.gh-issue-152132.Ma8MJZ.rst new file mode 100644 index 00000000000000..633c41e40bf269 --- /dev/null +++ b/Misc/NEWS.d/next/C_API/2026-07-09-17-33-29.gh-issue-152132.Ma8MJZ.rst @@ -0,0 +1,3 @@ +Fix :c:func:`Py_RunMain` to return an exit code, rather than calling +:c:func:`Py_Exit`, when running a script, a command, or the REPL. Patch by +Victor Stinner. diff --git a/Modules/_testcapi/run.c b/Modules/_testcapi/run.c index 4a63c0f98a74d4..7fc180e136559b 100644 --- a/Modules/_testcapi/run.c +++ b/Modules/_testcapi/run.c @@ -129,9 +129,6 @@ run_simplefile(PyObject *mod, PyObject *args) assert(_Py_IsValidFD(fd)); fclose(fp); - if (res == -1 && PyErr_Occurred()) { - return NULL; - } assert(!PyErr_Occurred()); return PyLong_FromLong(res); } @@ -203,9 +200,6 @@ run_simplefileex(PyObject *mod, PyObject *args) return NULL; } - if (res == -1 && PyErr_Occurred()) { - return NULL; - } assert(!PyErr_Occurred()); return PyLong_FromLong(res); } @@ -243,9 +237,6 @@ run_simplefileexflags(PyObject *mod, PyObject *args) return NULL; } - if (res == -1 && PyErr_Occurred()) { - return NULL; - } assert(!PyErr_Occurred()); return PyLong_FromLong(res); } @@ -272,9 +263,6 @@ run_anyfile(PyObject *mod, PyObject *args) assert(_Py_IsValidFD(fd)); fclose(fp); - if (res == -1 && PyErr_Occurred()) { - return NULL; - } assert(!PyErr_Occurred()); return PyLong_FromLong(res); } @@ -310,9 +298,6 @@ run_anyfileflags(PyObject *mod, PyObject *args) assert(_Py_IsValidFD(fd)); fclose(fp); - if (res == -1 && PyErr_Occurred()) { - return NULL; - } assert(!PyErr_Occurred()); return PyLong_FromLong(res); } @@ -342,9 +327,6 @@ run_anyfileex(PyObject *mod, PyObject *args) return NULL; } - if (res == -1 && PyErr_Occurred()) { - return NULL; - } assert(!PyErr_Occurred()); return PyLong_FromLong(res); } @@ -382,9 +364,6 @@ run_anyfileexflags(PyObject *mod, PyObject *args) return NULL; } - if (res == -1 && PyErr_Occurred()) { - return NULL; - } assert(!PyErr_Occurred()); return PyLong_FromLong(res); } @@ -664,9 +643,6 @@ run_simplestring(PyObject *mod, PyObject *args) } int res = PyRun_SimpleString(str); - if (res == -1 && PyErr_Occurred()) { - return NULL; - } assert(!PyErr_Occurred()); return PyLong_FromLong(res); } @@ -689,9 +665,6 @@ run_simplestringflags(PyObject *mod, PyObject *args) } int res = PyRun_SimpleStringFlags(str, pflags); - if (res == -1 && PyErr_Occurred()) { - return NULL; - } assert(!PyErr_Occurred()); return PyLong_FromLong(res); } diff --git a/Modules/main.c b/Modules/main.c index 2f23513cc2403d..a65247dc1e5c61 100644 --- a/Modules/main.c +++ b/Modules/main.c @@ -10,7 +10,7 @@ #include "pycore_pathconfig.h" // _PyPathConfig_ComputeSysPath0() #include "pycore_pylifecycle.h" // _Py_PreInitializeFromPyArgv() #include "pycore_pystate.h" // _PyInterpreterState_GET() -#include "pycore_pythonrun.h" // _PyRun_AnyFileObject() +#include "pycore_pythonrun.h" // _PyRun_AnyFile() #include "pycore_tuple.h" // _PyTuple_FromPair #include "pycore_unicodeobject.h" // _PyUnicode_Dedent() @@ -235,7 +235,6 @@ static int pymain_run_command(wchar_t *command) { PyObject *unicode, *bytes; - int ret; unicode = PyUnicode_FromWideChar(command, -1); if (unicode == NULL) { @@ -259,9 +258,18 @@ pymain_run_command(wchar_t *command) PyCompilerFlags cf = _PyCompilerFlags_INIT; cf.cf_flags |= PyCF_IGNORE_COOKIE; - ret = _PyRun_SimpleStringFlagsWithName(PyBytes_AsString(bytes), "<string>", &cf); + PyObject *result = NULL; + PyObject *string_obj = PyUnicode_FromString("<string>"); + if (string_obj != NULL) { + result = _PyRun_SimpleString(PyBytes_AsString(bytes), + string_obj, &cf); + Py_DECREF(string_obj); + } Py_DECREF(bytes); - return (ret != 0); + if (result == NULL) { + return pymain_exit_err_print(); + } + return 0; error: PySys_WriteStderr("Unable to decode the command from the command line:\n"); @@ -270,9 +278,9 @@ pymain_run_command(wchar_t *command) static int -pymain_start_pyrepl(int pythonstartup) +pymain_run_pyrepl(int pythonstartup) { - int res = 0; + int exitcode = 0; PyObject *console = NULL; PyObject *empty_tuple = NULL; PyObject *kwargs = NULL; @@ -282,37 +290,41 @@ pymain_start_pyrepl(int pythonstartup) PyObject *pyrepl = PyImport_ImportModule("_pyrepl.main"); if (pyrepl == NULL) { fprintf(stderr, "Could not import _pyrepl.main\n"); - res = pymain_exit_err_print(); - goto done; + goto error; } + console = PyObject_GetAttrString(pyrepl, "interactive_console"); if (console == NULL) { fprintf(stderr, "Could not access _pyrepl.main.interactive_console\n"); - res = pymain_exit_err_print(); - goto done; + goto error; } + empty_tuple = PyTuple_New(0); if (empty_tuple == NULL) { - res = pymain_exit_err_print(); - goto done; + goto error; } kwargs = PyDict_New(); if (kwargs == NULL) { - res = pymain_exit_err_print(); - goto done; + goto error; } + main_module = PyImport_AddModuleRef("__main__"); if (main_module == NULL) { - res = pymain_exit_err_print(); - goto done; + goto error; } - if (!PyDict_SetItemString(kwargs, "mainmodule", main_module) - && !PyDict_SetItemString(kwargs, "pythonstartup", pythonstartup ? Py_True : Py_False)) { - console_result = PyObject_Call(console, empty_tuple, kwargs); - if (console_result == NULL) { - res = pymain_exit_err_print(); - } + + PyObject *value = pythonstartup ? Py_True : Py_False; + if (PyDict_SetItemString(kwargs, "mainmodule", main_module) + || PyDict_SetItemString(kwargs, "pythonstartup", value)) + { + goto error; + } + + console_result = PyObject_Call(console, empty_tuple, kwargs); + if (console_result == NULL) { + goto error; } + done: Py_XDECREF(console_result); Py_XDECREF(kwargs); @@ -320,7 +332,11 @@ pymain_start_pyrepl(int pythonstartup) Py_XDECREF(console); Py_XDECREF(pyrepl); Py_XDECREF(main_module); - return res; + return exitcode; + +error: + exitcode = pymain_exit_err_print(); + goto done; } @@ -406,10 +422,14 @@ pymain_run_file_obj(PyObject *program_name, PyObject *filename, return pymain_exit_err_print(); } - /* PyRun_AnyFileExFlags(closeit=1) calls fclose(fp) before running code */ + /* _PyRun_AnyFile(closeit=1) calls fclose(fp) before running code */ PyCompilerFlags cf = _PyCompilerFlags_INIT; - int run = _PyRun_AnyFileObject(fp, filename, 1, &cf); - return (run != 0); + PyObject *result = _PyRun_AnyFile(fp, filename, 1, &cf); + if (result == NULL) { + return pymain_exit_err_print(); + } + Py_DECREF(result); + return 0; } static int @@ -417,28 +437,26 @@ pymain_run_file(const PyConfig *config) { PyObject *filename = PyUnicode_FromWideChar(config->run_filename, -1); if (filename == NULL) { - PyErr_Print(); - return -1; + return pymain_exit_err_print(); } PyObject *program_name = PyUnicode_FromWideChar(config->program_name, -1); if (program_name == NULL) { Py_DECREF(filename); - PyErr_Print(); - return -1; + return pymain_exit_err_print(); } - int res = pymain_run_file_obj(program_name, filename, - config->skip_source_first_line); + int exitcode = pymain_run_file_obj(program_name, filename, + config->skip_source_first_line); Py_DECREF(filename); Py_DECREF(program_name); - return res; + return exitcode; } static int pymain_run_startup(PyConfig *config, int *exitcode) { - int ret; + int ret = 0; if (!config->use_environment) { return 0; } @@ -478,10 +496,12 @@ pymain_run_startup(PyConfig *config, int *exitcode) } PyCompilerFlags cf = _PyCompilerFlags_INIT; - (void) _PyRun_SimpleFileObject(fp, startup, 0, &cf); - PyErr_Clear(); + PyObject *result = _PyRun_SimpleFile(fp, startup, 0, &cf); fclose(fp); - ret = 0; + if (result == NULL) { + goto error; + } + Py_DECREF(result); done: Py_XDECREF(startup); @@ -542,22 +562,8 @@ pymain_set_inspect(PyConfig *config, int inspect) static int -pymain_run_stdin(PyConfig *config) +_pymain_run_repl(PyConfig *config, int startup) { - if (stdin_is_interactive(config)) { - // do exit on SystemExit - pymain_set_inspect(config, 0); - - int exitcode; - if (pymain_run_startup(config, &exitcode)) { - return exitcode; - } - - if (pymain_run_interactive_hook(&exitcode)) { - return exitcode; - } - } - /* call pending calls like signal handlers (SIGINT) */ if (Py_MakePendingCalls() == -1) { return pymain_exit_err_print(); @@ -567,14 +573,13 @@ pymain_run_stdin(PyConfig *config) return pymain_exit_err_print(); } - int run; if (isatty(fileno(stdin)) && !_Py_GetEnv(config->use_environment, "PYTHON_BASIC_REPL")) { PyObject *pyrepl = PyImport_ImportModule("_pyrepl"); if (pyrepl != NULL) { - run = pymain_start_pyrepl(0); + int exitcode = pymain_run_pyrepl(startup); Py_DECREF(pyrepl); - return run; + return exitcode; } if (!PyErr_ExceptionMatches(PyExc_ModuleNotFoundError)) { fprintf(stderr, "Could not import _pyrepl.main\n"); @@ -584,8 +589,37 @@ pymain_run_stdin(PyConfig *config) } PyCompilerFlags cf = _PyCompilerFlags_INIT; - run = PyRun_AnyFileExFlags(stdin, "<stdin>", 0, &cf); - return (run != 0); + PyObject *result = NULL; + PyObject *stdin_obj = PyUnicode_FromString("<stdin>"); + if (stdin_obj != NULL) { + result = _PyRun_AnyFile(stdin, stdin_obj, 0, &cf); + Py_DECREF(stdin_obj); + } + if (result == NULL) { + return pymain_exit_err_print(); + } + Py_DECREF(result); + return 0; +} + +static int +pymain_run_stdin(PyConfig *config) +{ + if (stdin_is_interactive(config)) { + // do exit on SystemExit + pymain_set_inspect(config, 0); + + int exitcode; + if (pymain_run_startup(config, &exitcode)) { + return exitcode; + } + + if (pymain_run_interactive_hook(&exitcode)) { + return exitcode; + } + } + + return _pymain_run_repl(config, 0); } @@ -607,30 +641,7 @@ pymain_repl(PyConfig *config, int *exitcode) return; } - if (PySys_Audit("cpython.run_stdin", NULL) < 0) { - return; - } - - if (isatty(fileno(stdin)) - && !_Py_GetEnv(config->use_environment, "PYTHON_BASIC_REPL")) { - PyObject *pyrepl = PyImport_ImportModule("_pyrepl"); - if (pyrepl != NULL) { - int run = pymain_start_pyrepl(1); - *exitcode = (run != 0); - Py_DECREF(pyrepl); - return; - } - if (!PyErr_ExceptionMatches(PyExc_ModuleNotFoundError)) { - PyErr_Clear(); - fprintf(stderr, "Could not import _pyrepl.main\n"); - return; - } - PyErr_Clear(); - } - PyCompilerFlags cf = _PyCompilerFlags_INIT; - int run = PyRun_AnyFileExFlags(stdin, "<stdin>", 0, &cf); - *exitcode = (run != 0); - return; + *exitcode = _pymain_run_repl(config, 1); } diff --git a/Programs/_testembed.c b/Programs/_testembed.c index fa223c24b2e79a..f4df1014b7aeaf 100644 --- a/Programs/_testembed.c +++ b/Programs/_testembed.c @@ -59,6 +59,53 @@ static void error(const char *msg) } +static void error_fmt(const char *format, ...) +{ + va_list vargs; + va_start(vargs, format); + fprintf(stderr, "ERROR: "); + vfprintf(stderr, format, vargs); + fprintf(stderr, "\n"); + va_end(vargs); + fflush(stderr); +} + + +static wchar_t* py_getenv(const char *name) +{ + const char *env = getenv(name); + if (env == NULL) { + error_fmt("need %s env var", name); + return NULL; + } + + wchar_t *result = Py_DecodeLocale(env, NULL); + if (result == NULL) { + error("Py_DecodeLocale() failed"); + return NULL; + } + return result; +} + + +static wchar_t* get_cmdline_arg(const char *arg_name) +{ + if (main_argc < 3) { + const char *test = main_argv[1]; + fprintf(stderr, "usage: %s %s %s\n", PROGRAM, test, arg_name); + return NULL; + } + const char *arg = main_argv[2]; + + wchar_t *result = Py_DecodeLocale(arg, NULL); + if (result == NULL) { + error_fmt("failed to decode %s command line argument", arg_name); + return NULL; + } + return result; +} + + static void config_set_string(PyConfig *config, wchar_t **config_str, const wchar_t *str) { PyStatus status = PyConfig_SetString(config, config_str, str); @@ -1559,14 +1606,8 @@ static int test_init_sys_add(void) static int test_init_setpath(void) { - char *env = getenv("TESTPATH"); - if (!env) { - error("missing TESTPATH env var"); - return 1; - } - wchar_t *path = Py_DecodeLocale(env, NULL); + wchar_t *path = py_getenv("TESTPATH"); if (path == NULL) { - error("failed to decode TESTPATH"); return 1; } Py_SetPath(path); @@ -1592,14 +1633,8 @@ static int test_init_setpath_config(void) Py_ExitStatusException(status); } - char *env = getenv("TESTPATH"); - if (!env) { - error("missing TESTPATH env var"); - return 1; - } - wchar_t *path = Py_DecodeLocale(env, NULL); + wchar_t *path = py_getenv("TESTPATH"); if (path == NULL) { - error("failed to decode TESTPATH"); return 1; } Py_SetPath(path); @@ -1621,14 +1656,8 @@ static int test_init_setpath_config(void) static int test_init_setpythonhome(void) { - char *env = getenv("TESTHOME"); - if (!env) { - error("missing TESTHOME env var"); - return 1; - } - wchar_t *home = Py_DecodeLocale(env, NULL); + wchar_t *home = py_getenv("TESTHOME"); if (home == NULL) { - error("failed to decode TESTHOME"); return 1; } Py_SetPythonHome(home); @@ -1646,14 +1675,8 @@ static int test_init_is_python_build(void) { // gh-91985: in-tree builds fail to check for build directory landmarks // under the effect of 'home' or PYTHONHOME environment variable. - char *env = getenv("TESTHOME"); - if (!env) { - error("missing TESTHOME env var"); - return 1; - } - wchar_t *home = Py_DecodeLocale(env, NULL); + wchar_t *home = py_getenv("TESTHOME"); if (home == NULL) { - error("failed to decode TESTHOME"); return 1; } @@ -1667,7 +1690,7 @@ static int test_init_is_python_build(void) // Use an impossible value so we can detect whether it isn't updated // during initialization. config._is_python_build = INT_MAX; - env = getenv("NEGATIVE_ISPYTHONBUILD"); + char *env = getenv("NEGATIVE_ISPYTHONBUILD"); if (env && strcmp(env, "0") != 0) { config._is_python_build = INT_MIN; } @@ -1992,6 +2015,82 @@ static int test_init_run_main(void) } +static int test_init_run_main_exitcode(Py_ssize_t argc, wchar_t * const *argv) +{ + PyConfig config; + PyConfig_InitPythonConfig(&config); + + config.parse_argv = 1; + config_set_argv(&config, argc, argv); + config_set_string(&config, &config.program_name, L"./python3"); + + init_from_config_clear(&config); + + int exitcode = Py_RunMain(); + if (exitcode != 123) { + error_fmt("Py_RunMain() returned %i, expected 123", exitcode); + return 1; + } + + // If Py_RunMain() calls Py_Exit(), this message is not written to stdout + printf("ok! Py_RunMain() returned 123\n"); + + return 0; +} + + +static int test_init_run_main_script_exitcode(void) +{ + wchar_t *filename = get_cmdline_arg("FILENAME"); + if (filename == NULL) { + return 1; + } + + wchar_t* argv[] = {L"python3", filename}; + int res = test_init_run_main_exitcode(Py_ARRAY_LENGTH(argv), argv); + PyMem_RawFree(filename); + + return res; +} + + +static int test_init_run_main_module_exitcode(void) +{ + wchar_t *module = get_cmdline_arg("MODULE"); + if (module == NULL) { + return 1; + } + + wchar_t* argv[] = {L"python3", L"-m", module}; + int res = test_init_run_main_exitcode(Py_ARRAY_LENGTH(argv), argv); + PyMem_RawFree(module); + + return res; +} + + +static int test_init_run_main_interactive_exitcode(void) +{ + wchar_t* argv[] = {L"python3", L"-i"}; + return test_init_run_main_exitcode(Py_ARRAY_LENGTH(argv), argv); +} + + +static int test_init_run_main_code_exitcode(void) +{ + wchar_t *code = get_cmdline_arg("CODE"); + if (code == NULL) { + return 1; + } + + wchar_t* argv[] = {L"python3", L"-c", code}; + int res = test_init_run_main_exitcode(Py_ARRAY_LENGTH(argv), argv); + PyMem_RawFree(code); + + return res; +} + + static int test_init_main(void) { PyConfig config; @@ -2933,6 +3032,10 @@ static struct TestCase TestCases[] = { {"test_preinit_parse_argv", test_preinit_parse_argv}, {"test_preinit_dont_parse_argv", test_preinit_dont_parse_argv}, {"test_init_run_main", test_init_run_main}, + {"test_init_run_main_code_exitcode", test_init_run_main_code_exitcode}, + {"test_init_run_main_script_exitcode", test_init_run_main_script_exitcode}, + {"test_init_run_main_module_exitcode", test_init_run_main_module_exitcode}, + {"test_init_run_main_interactive_exitcode", test_init_run_main_interactive_exitcode}, {"test_init_main", test_init_main}, {"test_init_sys_add", test_init_sys_add}, {"test_init_setpath", test_init_setpath}, diff --git a/Python/pythonrun.c b/Python/pythonrun.c index 8c441e7ebd3c79..e0a752720dfcc2 100644 --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -22,7 +22,7 @@ #include "pycore_pyerrors.h" // _PyErr_GetRaisedException() #include "pycore_pylifecycle.h" // _Py_FdIsInteractive() #include "pycore_pystate.h" // _PyInterpreterState_GET() -#include "pycore_pythonrun.h" // export _PyRun_InteractiveLoopObject() +#include "pycore_pythonrun.h" // export _PyRun_AnyFile() #include "pycore_sysmodule.h" // _PySys_SetAttr() #include "pycore_traceback.h" // _PyTraceBack_Print() #include "pycore_unicodeobject.h" // _PyUnicode_Equal() @@ -41,50 +41,53 @@ # include "windows.h" #endif -/* Forward */ +/* Forward declarations */ static void flush_io(void); static PyObject *run_mod(mod_ty, PyObject *, PyObject *, PyObject *, PyCompilerFlags *, PyArena *, PyObject*, int); static PyObject *run_pyc_file(FILE *, PyObject *, PyObject *, PyCompilerFlags *); -static int PyRun_InteractiveOneObjectEx(FILE *, PyObject *, PyCompilerFlags *); -static PyObject* pyrun_file(FILE *fp, PyObject *filename, int start, - PyObject *globals, PyObject *locals, int closeit, - PyCompilerFlags *flags); static PyObject * -_PyRun_StringFlagsWithName(const char *str, PyObject* name, int start, - PyObject *globals, PyObject *locals, PyCompilerFlags *flags, - int generate_new_source); +_PyRun_String(const char *str, PyObject* name, int start, + PyObject *globals, PyObject *locals, PyCompilerFlags *flags, + int generate_new_source); +static PyObject* +_PyRun_InteractiveLoop(FILE *fp, PyObject *filename, PyCompilerFlags *flags); +static int +_PyRun_InteractiveOne(FILE *fp, PyObject *filename, PyCompilerFlags *flags); +static PyObject * +_PyRun_File(FILE *fp, PyObject *filename, int start, PyObject *globals, + PyObject *locals, int closeit, PyCompilerFlags *flags); -int -_PyRun_AnyFileObject(FILE *fp, PyObject *filename, int closeit, - PyCompilerFlags *flags) + +PyObject* +_PyRun_AnyFile(FILE *fp, PyObject *filename, int closeit, + PyCompilerFlags *flags) { int decref_filename = 0; if (filename == NULL) { filename = PyUnicode_FromString("???"); if (filename == NULL) { - PyErr_Print(); - return -1; + return NULL; } decref_filename = 1; } - int res; + PyObject *result; if (_Py_FdIsInteractive(fp, filename)) { - res = _PyRun_InteractiveLoopObject(fp, filename, flags); + result = _PyRun_InteractiveLoop(fp, filename, flags); if (closeit) { fclose(fp); } } else { - res = _PyRun_SimpleFileObject(fp, filename, closeit, flags); + result = _PyRun_SimpleFile(fp, filename, closeit, flags); } if (decref_filename) { Py_DECREF(filename); } - return res; + return result; } int @@ -99,14 +102,20 @@ PyRun_AnyFileExFlags(FILE *fp, const char *filename, int closeit, return -1; } } - int res = _PyRun_AnyFileObject(fp, filename_obj, closeit, flags); + + PyObject *result = _PyRun_AnyFile(fp, filename_obj, closeit, flags); Py_XDECREF(filename_obj); - return res; + if (result == NULL) { + PyErr_Print(); + return -1; + } + Py_DECREF(result); + return 0; } -int -_PyRun_InteractiveLoopObject(FILE *fp, PyObject *filename, PyCompilerFlags *flags) +static PyObject* +_PyRun_InteractiveLoop(FILE *fp, PyObject *filename, PyCompilerFlags *flags) { PyCompilerFlags local_flags = _PyCompilerFlags_INIT; if (flags == NULL) { @@ -115,8 +124,7 @@ _PyRun_InteractiveLoopObject(FILE *fp, PyObject *filename, PyCompilerFlags *flag PyObject *v; if (PySys_GetOptionalAttr(&_Py_ID(ps1), &v) < 0) { - PyErr_Print(); - return -1; + return NULL; } if (v == NULL) { v = PyUnicode_FromString(">>> "); @@ -129,8 +137,7 @@ _PyRun_InteractiveLoopObject(FILE *fp, PyObject *filename, PyCompilerFlags *flag } Py_XDECREF(v); if (PySys_GetOptionalAttr(&_Py_ID(ps2), &v) < 0) { - PyErr_Print(); - return -1; + return NULL; } if (v == NULL) { v = PyUnicode_FromString("... "); @@ -146,36 +153,41 @@ _PyRun_InteractiveLoopObject(FILE *fp, PyObject *filename, PyCompilerFlags *flag #ifdef Py_REF_DEBUG int show_ref_count = _Py_GetConfig()->show_ref_count; #endif - int err = 0; - int ret; int nomem_count = 0; + int ret; do { - ret = PyRun_InteractiveOneObjectEx(fp, filename, flags); + ret = _PyRun_InteractiveOne(fp, filename, flags); if (ret == -1 && PyErr_Occurred()) { /* Prevent an endless loop after multiple consecutive MemoryErrors * while still allowing an interactive command to fail with a * MemoryError. */ if (PyErr_ExceptionMatches(PyExc_MemoryError)) { if (++nomem_count > 16) { - PyErr_Clear(); - err = -1; - break; + return NULL; } } else { nomem_count = 0; } + + int inspect = _Py_GetConfig()->inspect; + if (!inspect && PyErr_ExceptionMatches(PyExc_SystemExit)) { + return NULL; + } + PyErr_Print(); - flush_io(); - } else { + } + else { nomem_count = 0; } + #ifdef Py_REF_DEBUG if (show_ref_count) { _PyDebug_PrintTotalRefs(); } #endif } while (ret != E_EOF); - return err; + + Py_RETURN_NONE; } @@ -188,10 +200,14 @@ PyRun_InteractiveLoopFlags(FILE *fp, const char *filename, PyCompilerFlags *flag return -1; } - int err = _PyRun_InteractiveLoopObject(fp, filename_obj, flags); + PyObject *result = _PyRun_InteractiveLoop(fp, filename_obj, flags); Py_DECREF(filename_obj); - return err; - + if (result == NULL) { + PyErr_Print(); + return -1; + } + Py_DECREF(result); + return 0; } @@ -287,8 +303,7 @@ pyrun_one_parse_ast(FILE *fp, PyObject *filename, /* A PyRun_InteractiveOneObject() auxiliary function that does not print the * error on failure. */ static int -PyRun_InteractiveOneObjectEx(FILE *fp, PyObject *filename, - PyCompilerFlags *flags) +_PyRun_InteractiveOne(FILE *fp, PyObject *filename, PyCompilerFlags *flags) { if (!PyUnicode_Check(filename)) { PyErr_Format(PyExc_TypeError, "expect str for filename, got %T", @@ -362,9 +377,7 @@ PyRun_InteractiveOneObjectEx(FILE *fp, PyObject *filename, int PyRun_InteractiveOneObject(FILE *fp, PyObject *filename, PyCompilerFlags *flags) { - int res; - - res = PyRun_InteractiveOneObjectEx(fp, filename, flags); + int res = _PyRun_InteractiveOne(fp, filename, flags); if (res == -1) { PyErr_Print(); flush_io(); @@ -464,24 +477,26 @@ set_main_loader(PyObject *d, PyObject *filename, const char *loader_name) } -int -_PyRun_SimpleFileObject(FILE *fp, PyObject *filename, int closeit, - PyCompilerFlags *flags) +PyObject* +_PyRun_SimpleFile(FILE *fp, PyObject *filename, int closeit, + PyCompilerFlags *flags) { - int ret = -1; + PyObject *res = NULL; + int set_file_name = 0; PyObject *main_module = PyImport_AddModuleRef("__main__"); - if (main_module == NULL) - return -1; + if (main_module == NULL) { + goto done; + } PyObject *dict = PyModule_GetDict(main_module); // borrowed ref - int set_file_name = 0; int has_file = PyDict_ContainsString(dict, "__file__"); if (has_file < 0) { goto done; } if (!has_file) { if (PyDict_SetItemString(dict, "__file__", filename) < 0) { + fprintf(stderr, "python: failed to set __main__.__file__\n"); goto done; } set_file_name = 1; @@ -492,7 +507,6 @@ _PyRun_SimpleFileObject(FILE *fp, PyObject *filename, int closeit, goto done; } - PyObject *v; if (pyc) { FILE *pyc_fp; /* Try to run a pyc file. First, re-open in binary */ @@ -508,39 +522,31 @@ _PyRun_SimpleFileObject(FILE *fp, PyObject *filename, int closeit, if (set_main_loader(dict, filename, "SourcelessFileLoader") < 0) { fprintf(stderr, "python: failed to set __main__.__loader__\n"); - ret = -1; fclose(pyc_fp); goto done; } - v = run_pyc_file(pyc_fp, dict, dict, flags); + res = run_pyc_file(pyc_fp, dict, dict, flags); } else { /* When running from stdin, leave __main__.__loader__ alone */ if ((!PyUnicode_Check(filename) || !PyUnicode_EqualToUTF8(filename, "<stdin>")) && set_main_loader(dict, filename, "SourceFileLoader") < 0) { fprintf(stderr, "python: failed to set __main__.__loader__\n"); - ret = -1; goto done; } - v = pyrun_file(fp, filename, Py_file_input, dict, dict, - closeit, flags); + res = _PyRun_File(fp, filename, Py_file_input, dict, dict, + closeit, flags); } flush_io(); - if (v == NULL) { - Py_CLEAR(main_module); - PyErr_Print(); - goto done; - } - Py_DECREF(v); - ret = 0; done: if (set_file_name) { if (PyDict_PopString(dict, "__file__", NULL) < 0) { - PyErr_Print(); + fprintf(stderr, "python: failed to delete __main__.__file__\n"); + Py_CLEAR(res); } } Py_XDECREF(main_module); - return ret; + return res; } @@ -550,51 +556,47 @@ PyRun_SimpleFileExFlags(FILE *fp, const char *filename, int closeit, { PyObject *filename_obj = PyUnicode_DecodeFSDefault(filename); if (filename_obj == NULL) { + PyErr_Print(); return -1; } - int res = _PyRun_SimpleFileObject(fp, filename_obj, closeit, flags); + PyObject *result = _PyRun_SimpleFile(fp, filename_obj, closeit, flags); Py_DECREF(filename_obj); - return res; + if (result == NULL) { + PyErr_Print(); + return -1; + } + return 0; } -int -_PyRun_SimpleStringFlagsWithName(const char *command, const char* name, PyCompilerFlags *flags) { +PyObject* +_PyRun_SimpleString(const char *command, PyObject* name, + PyCompilerFlags *flags) +{ PyObject *main_module = PyImport_AddModuleRef("__main__"); if (main_module == NULL) { - return -1; + return NULL; } PyObject *dict = PyModule_GetDict(main_module); // borrowed ref - PyObject *res = NULL; - if (name == NULL) { - res = PyRun_StringFlags(command, Py_file_input, dict, dict, flags); - } else { - PyObject* the_name = PyUnicode_FromString(name); - if (!the_name) { - PyErr_Print(); - Py_DECREF(main_module); - return -1; - } - res = _PyRun_StringFlagsWithName(command, the_name, Py_file_input, dict, dict, flags, 0); - Py_DECREF(the_name); - } + PyObject *res = _PyRun_String(command, name, Py_file_input, + dict, dict, flags, 0); Py_DECREF(main_module); + return res; +} + +int +PyRun_SimpleStringFlags(const char *command, PyCompilerFlags *flags) +{ + PyObject *res = _PyRun_SimpleString(command, NULL, flags); if (res == NULL) { PyErr_Print(); return -1; } - Py_DECREF(res); return 0; } -int -PyRun_SimpleStringFlags(const char *command, PyCompilerFlags *flags) -{ - return _PyRun_SimpleStringFlagsWithName(command, NULL, flags); -} - static int parse_exit_code(PyObject *code, int *exitcode_p) { @@ -1231,9 +1233,9 @@ void PyErr_DisplayException(PyObject *exc) } static PyObject * -_PyRun_StringFlagsWithName(const char *str, PyObject* name, int start, - PyObject *globals, PyObject *locals, PyCompilerFlags *flags, - int generate_new_source) +_PyRun_String(const char *str, PyObject* name, int start, + PyObject *globals, PyObject *locals, PyCompilerFlags *flags, + int generate_new_source) { PyObject *ret = NULL; mod_ty mod; @@ -1277,12 +1279,12 @@ PyObject * PyRun_StringFlags(const char *str, int start, PyObject *globals, PyObject *locals, PyCompilerFlags *flags) { - return _PyRun_StringFlagsWithName(str, NULL, start, globals, locals, flags, 0); + return _PyRun_String(str, NULL, start, globals, locals, flags, 0); } static PyObject * -pyrun_file(FILE *fp, PyObject *filename, int start, PyObject *globals, - PyObject *locals, int closeit, PyCompilerFlags *flags) +_PyRun_File(FILE *fp, PyObject *filename, int start, PyObject *globals, + PyObject *locals, int closeit, PyCompilerFlags *flags) { PyArena *arena = _PyArena_New(); if (arena == NULL) { @@ -1316,11 +1318,12 @@ PyRun_FileExFlags(FILE *fp, const char *filename, int start, PyObject *globals, { PyObject *filename_obj = PyUnicode_DecodeFSDefault(filename); if (filename_obj == NULL) { + PyErr_Print(); return NULL; } - PyObject *res = pyrun_file(fp, filename_obj, start, globals, - locals, closeit, flags); + PyObject *res = _PyRun_File(fp, filename_obj, start, globals, + locals, closeit, flags); Py_DECREF(filename_obj); return res; From a004341bd4695968dd5853368acfda145373b6c2 Mon Sep 17 00:00:00 2001 From: Victor Stinner <vstinner@python.org> Date: Thu, 9 Jul 2026 21:51:19 +0200 Subject: [PATCH 639/818] [3.15] gh-152769: Enable perf trampoline on musl (Alpine Linux) (#152774) (#153456) gh-152769: Enable perf trampoline on musl (Alpine Linux) (#152774) (cherry picked from commit b9e8979dcd563ee913c66802c8544aa050fda2d5) Co-authored-by: Xiaowei Lu <weixlu420302@gmail.com> --- .../next/Build/2026-07-01-17-53-00.gh-issue-152769.Kp7mQ2.rst | 4 ++++ configure | 4 ++++ configure.ac | 2 ++ 3 files changed, 10 insertions(+) create mode 100644 Misc/NEWS.d/next/Build/2026-07-01-17-53-00.gh-issue-152769.Kp7mQ2.rst diff --git a/Misc/NEWS.d/next/Build/2026-07-01-17-53-00.gh-issue-152769.Kp7mQ2.rst b/Misc/NEWS.d/next/Build/2026-07-01-17-53-00.gh-issue-152769.Kp7mQ2.rst new file mode 100644 index 00000000000000..04a6ef4f5e0a7f --- /dev/null +++ b/Misc/NEWS.d/next/Build/2026-07-01-17-53-00.gh-issue-152769.Kp7mQ2.rst @@ -0,0 +1,4 @@ +Enable the :ref:`perf profiler <perf_profiling>` trampoline on Alpine Linux with the +musl C library on ``x86_64`` and ``aarch64``. The +trampoline is architecture-specific and does not depend on the C library, so +the same assembly trampoline used for glibc is reused for musl. diff --git a/configure b/configure index b24bb35148beee..90f026976d0e54 100755 --- a/configure +++ b/configure @@ -14431,6 +14431,10 @@ case $PLATFORM_TRIPLET in #( perf_trampoline=yes ;; #( aarch64-linux-gnu) : perf_trampoline=yes ;; #( + x86_64-linux-gnu) : + perf_trampoline=yes ;; #( + x86_64-linux-musl) : + perf_trampoline=yes ;; #( darwin) : case $MACOSX_DEPLOYMENT_TARGET in #( 10.[0-9]|10.1[0-1]) : diff --git a/configure.ac b/configure.ac index 09a985dc9ce0d7..bdb94d6d280338 100644 --- a/configure.ac +++ b/configure.ac @@ -3873,6 +3873,8 @@ AC_MSG_CHECKING([perf trampoline]) AS_CASE([$PLATFORM_TRIPLET], [x86_64-linux-gnu], [perf_trampoline=yes], [aarch64-linux-gnu], [perf_trampoline=yes], + [x86_64-linux-gnu], [perf_trampoline=yes], + [x86_64-linux-musl], [perf_trampoline=yes], [darwin], [AS_CASE([$MACOSX_DEPLOYMENT_TARGET], [[10.[0-9]|10.1[0-1]]], [perf_trampoline=no], [perf_trampoline=yes] From 4b564b3f080ab81fa8a9291ee0447b21acc21ca0 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 9 Jul 2026 21:53:04 +0200 Subject: [PATCH 640/818] [3.15] gh-153406: Raise ValueError, not OverflowError, for out-of-range dates in email.utils.parsedate_to_datetime (GH-153407) (#153435) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit email.utils.parsedate_to_datetime documented that it raises ValueError for an invalid date, but it leaked OverflowError when the parsed year or timezone offset was too large for the datetime and timedelta constructors, and that OverflowError also escaped the modern header parsing path since DateHeader.parse only caught ValueError. Wrap the datetime and timezone construction so an OverflowError is re-raised as a ValueError with the original chained as the cause, which restores the documented contract and lets the existing header handler record an InvalidDateDefect instead of raising. (cherry picked from commit 37a26b9b94b147b5d683bfce0ef5a4c2fbc21085) Co-authored-by: tonghuaroot (童话) <tonghuaroot@gmail.com> --- Lib/email/utils.py | 11 +++++++---- Lib/test/test_email/test_headerregistry.py | 8 ++++++++ Lib/test/test_email/test_utils.py | 9 +++++++++ .../2026-07-09-00-00-00.gh-issue-153406.vyMmB6.rst | 3 +++ 4 files changed, 27 insertions(+), 4 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-07-09-00-00-00.gh-issue-153406.vyMmB6.rst diff --git a/Lib/email/utils.py b/Lib/email/utils.py index d4824dc3601b2d..f497cc43bd84ab 100644 --- a/Lib/email/utils.py +++ b/Lib/email/utils.py @@ -317,10 +317,13 @@ def parsedate_to_datetime(data): if parsed_date_tz is None: raise ValueError('Invalid date value or format "%s"' % str(data)) *dtuple, tz = parsed_date_tz - if tz is None: - return datetime.datetime(*dtuple[:6]) - return datetime.datetime(*dtuple[:6], - tzinfo=datetime.timezone(datetime.timedelta(seconds=tz))) + try: + if tz is None: + return datetime.datetime(*dtuple[:6]) + return datetime.datetime(*dtuple[:6], + tzinfo=datetime.timezone(datetime.timedelta(seconds=tz))) + except OverflowError as exc: + raise ValueError('Invalid date value or format "%s"' % str(data)) from exc def parseaddr(addr, *, strict=True): diff --git a/Lib/test/test_email/test_headerregistry.py b/Lib/test/test_email/test_headerregistry.py index aa918255d15c37..c118fd5e20d048 100644 --- a/Lib/test/test_email/test_headerregistry.py +++ b/Lib/test/test_email/test_headerregistry.py @@ -221,6 +221,14 @@ def test_invalid_date_value(self): self.assertEqual(len(h.defects), 1) self.assertIsInstance(h.defects[0], errors.InvalidDateDefect) + def test_out_of_range_date_value(self): + s = 'Mon, 20 Nov 9999999999 12:00:00 +0000' + h = self.make_header('date', s) + self.assertEqual(h, s) + self.assertIsNone(h.datetime) + self.assertEqual(len(h.defects), 1) + self.assertIsInstance(h.defects[0], errors.InvalidDateDefect) + def test_datetime_read_only(self): h = self.make_header('date', self.datestring) with self.assertRaises(AttributeError): diff --git a/Lib/test/test_email/test_utils.py b/Lib/test/test_email/test_utils.py index c9d09098b502f9..86d1bfff891a7e 100644 --- a/Lib/test/test_email/test_utils.py +++ b/Lib/test/test_email/test_utils.py @@ -77,6 +77,15 @@ def test_parsedate_to_datetime_with_invalid_raises_valueerror(self): with self.subTest(dtstr=dtstr): self.assertRaises(ValueError, utils.parsedate_to_datetime, dtstr) + def test_parsedate_to_datetime_out_of_range_raises_valueerror(self): + out_of_range_dates = [ + 'Mon, 20 Nov 9999999999 12:00:00 +0000', + 'Mon, 20 Nov 2017 12:00:00 +24000000000000', + ] + for dtstr in out_of_range_dates: + with self.subTest(dtstr=dtstr): + self.assertRaises(ValueError, utils.parsedate_to_datetime, dtstr) + class LocaltimeTests(unittest.TestCase): def test_localtime_is_tz_aware_daylight_true(self): diff --git a/Misc/NEWS.d/next/Library/2026-07-09-00-00-00.gh-issue-153406.vyMmB6.rst b/Misc/NEWS.d/next/Library/2026-07-09-00-00-00.gh-issue-153406.vyMmB6.rst new file mode 100644 index 00000000000000..c09575754e3380 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-09-00-00-00.gh-issue-153406.vyMmB6.rst @@ -0,0 +1,3 @@ +:func:`email.utils.parsedate_to_datetime` now raises :exc:`ValueError` +instead of :exc:`OverflowError` when the parsed year or timezone offset is +out of range, matching its documented behavior. From ef5569e03dc774a3c214bce7659c4075af429400 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 9 Jul 2026 23:15:51 +0200 Subject: [PATCH 641/818] [3.15] gh-98894: Quote test_dtrace tracer subcommands (GH-152901) (#153459) gh-98894: Quote test_dtrace tracer subcommands (GH-152901) Use shlex.join() when building tracer -c command strings for avoiding issues with spaces. (cherry picked from commit a159c6851f47549d2bc0cd37a0f555951bb11d7b) Co-authored-by: stratakis <cstratak@redhat.com> --- Lib/test/test_dtrace.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/Lib/test/test_dtrace.py b/Lib/test/test_dtrace.py index e1662a70b26d3e..30731b8f90ac14 100644 --- a/Lib/test/test_dtrace.py +++ b/Lib/test/test_dtrace.py @@ -1,6 +1,7 @@ import dis import os.path import re +import shlex import signal import subprocess import sys @@ -92,7 +93,7 @@ def run_readelf(cmd): if proc.returncode: raise AssertionError( - f"Command {' '.join(cmd)!r} failed " + f"Command {shlex.join(cmd)!r} failed " f"with exit code {proc.returncode}: " f"stdout={stdout!r} stderr={stderr!r}" ) @@ -139,7 +140,7 @@ def trace(self, script_file, subcommand=None, *, timeout=None, raise if check_returncode and proc.returncode: raise AssertionError( - f"Command {' '.join(command)!r} failed " + f"Command {shlex.join(command)!r} failed " f"with exit code {proc.returncode}: output={stdout!r}" ) return stdout @@ -148,7 +149,7 @@ def trace_python(self, script_file, python_file, optimize_python=None): python_flags = [] if optimize_python: python_flags.extend(["-O"] * optimize_python) - subcommand = " ".join([sys.executable] + python_flags + [python_file]) + subcommand = shlex.join([sys.executable] + python_flags + [python_file]) return self.trace(script_file, subcommand, timeout=60, check_returncode=True) @@ -276,7 +277,7 @@ def run_case(self, name, optimize_python=None): try: proc = create_process_group( - ["bpftrace", "-e", program, "-c", " ".join(subcommand)], + ["bpftrace", "-e", program, "-c", shlex.join(subcommand)], stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True, @@ -314,7 +315,8 @@ def assert_usable(self): program = f'usdt:{sys.executable}:python:function__entry {{ printf("probe: success\\n"); exit(); }}' try: proc = create_process_group( - ["bpftrace", "-e", program, "-c", f"{sys.executable} -c pass"], + ["bpftrace", "-e", program, "-c", + shlex.join([sys.executable, "-c", "pass"])], stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True, From cecafebc2e30ab2aac5f046ed5c9fbc75d6bfb51 Mon Sep 17 00:00:00 2001 From: Victor Stinner <vstinner@python.org> Date: Fri, 10 Jul 2026 02:18:41 +0200 Subject: [PATCH 642/818] [3.15] gh-152132: Fix bugs in Py_RunMain() (#153461) (#153466) * Check for signals more often. Previously, a pending exception could be removed by PyErr_Clear(). * Only call _PyInterpreterState_SetNotRunningMain() if _PyInterpreterState_SetRunningMain() has been called. * Convert _PyPathConfig_UpdateGlobal() PyStatus error to an exception. --- Modules/main.c | 48 +++++++++++++++++++++++++++++++++++++----------- 1 file changed, 37 insertions(+), 11 deletions(-) diff --git a/Modules/main.c b/Modules/main.c index a65247dc1e5c61..7d30935cd9e356 100644 --- a/Modules/main.c +++ b/Modules/main.c @@ -80,6 +80,12 @@ pymain_init(const _PyArgv *args) /* --- pymain_run_python() ---------------------------------------- */ +static int +pymain_check_signals(void) +{ + return Py_MakePendingCalls(); +} + /* Non-zero if filename, command (-c) or module (-m) is set on the command line */ static inline int config_run_code(const PyConfig *config) @@ -201,17 +207,21 @@ pymain_header(const PyConfig *config) } -static void +static int pymain_import_readline(const PyConfig *config) { + if (pymain_check_signals() < 0) { + return -1; + } + if (config->isolated) { - return; + return 0; } if (!config->inspect && config_run_code(config)) { - return; + return 0; } if (!isatty(fileno(stdin))) { - return; + return 0; } PyObject *mod = PyImport_ImportModule("readline"); @@ -228,6 +238,7 @@ pymain_import_readline(const PyConfig *config) else { Py_DECREF(mod); } + return 0; } @@ -416,8 +427,7 @@ pymain_run_file_obj(PyObject *program_name, PyObject *filename, return 1; } - // Call pending calls like signal handlers (SIGINT) - if (Py_MakePendingCalls() == -1) { + if (pymain_check_signals() < 0) { fclose(fp); return pymain_exit_err_print(); } @@ -564,8 +574,7 @@ pymain_set_inspect(PyConfig *config, int inspect) static int _pymain_run_repl(PyConfig *config, int startup) { - /* call pending calls like signal handlers (SIGINT) */ - if (Py_MakePendingCalls() == -1) { + if (pymain_check_signals() < 0) { return pymain_exit_err_print(); } @@ -648,13 +657,17 @@ pymain_repl(PyConfig *config, int *exitcode) static void pymain_run_python(int *exitcode) { + int set_running_main = 0; + PyObject *main_importer_path = NULL; PyInterpreterState *interp = _PyInterpreterState_GET(); /* pymain_repl() and pymain_run_stdin() modify the config */ PyConfig *config = (PyConfig*)_PyInterpreterState_GetConfig(interp); /* ensure path config is written into global variables */ - if (_PyStatus_EXCEPTION(_PyPathConfig_UpdateGlobal(config))) { + PyStatus status = _PyPathConfig_UpdateGlobal(config); + if (_PyStatus_EXCEPTION(status)) { + _PyErr_SetFromPyStatus(status); goto error; } @@ -676,7 +689,9 @@ pymain_run_python(int *exitcode) } // import readline and rlcompleter before script dir is added to sys.path - pymain_import_readline(config); + if (pymain_import_readline(config) < 0) { + goto error; + } PyObject *path0 = NULL; if (main_importer_path != NULL) { @@ -715,8 +730,13 @@ pymain_run_python(int *exitcode) pymain_header(config); _PyInterpreterState_SetRunningMain(interp); + set_running_main = 1; assert(!PyErr_Occurred()); + if (pymain_check_signals() < 0) { + goto error; + } + if (config->run_command) { *exitcode = pymain_run_command(config->run_command); } @@ -733,6 +753,10 @@ pymain_run_python(int *exitcode) *exitcode = pymain_run_stdin(config); } + if (pymain_check_signals() < 0) { + goto error; + } + pymain_repl(config, exitcode); goto done; @@ -740,7 +764,9 @@ pymain_run_python(int *exitcode) *exitcode = pymain_exit_err_print(); done: - _PyInterpreterState_SetNotRunningMain(interp); + if (set_running_main) { + _PyInterpreterState_SetNotRunningMain(interp); + } Py_XDECREF(main_importer_path); } From 462f62819bbc47ddec7586dd045ed843ca99e924 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 10 Jul 2026 04:07:38 +0200 Subject: [PATCH 643/818] [3.15] gh-152132: Test Py_CompileString() in test_capi.test_run (GH-153470) (#153472) gh-152132: Test Py_CompileString() in test_capi.test_run (GH-153470) PyRun functions now raises ValueError if the start argument is invalid. * Add Modules/_testlimitedcapi/run.c. * Rename _Py_CompileStringObjectWithModule() to _Py_CompileStringObject(). (cherry picked from commit d83d26724b8c3be5f535e56ded88593cc6803b86) Co-authored-by: Victor Stinner <vstinner@python.org> --- Include/cpython/pythonrun.h | 5 + Include/internal/pycore_pythonrun.h | 2 +- Lib/test/test_capi/test_run.py | 74 ++++++++++++- Modules/Setup.stdlib.in | 2 +- Modules/_testcapi/run.c | 126 ++++++++++++++++------- Modules/_testlimitedcapi.c | 3 + Modules/_testlimitedcapi/parts.h | 1 + Modules/_testlimitedcapi/run.c | 35 +++++++ PCbuild/_testlimitedcapi.vcxproj | 1 + PCbuild/_testlimitedcapi.vcxproj.filters | 1 + Python/bltinmodule.c | 6 +- Python/pythonrun.c | 33 +++++- 12 files changed, 243 insertions(+), 46 deletions(-) create mode 100644 Modules/_testlimitedcapi/run.c diff --git a/Include/cpython/pythonrun.h b/Include/cpython/pythonrun.h index edc40952254029..b0bf527f4f0ec1 100644 --- a/Include/cpython/pythonrun.h +++ b/Include/cpython/pythonrun.h @@ -40,6 +40,11 @@ PyAPI_FUNC(PyObject *) PyRun_FileExFlags( PyCompilerFlags *flags); +PyAPI_FUNC(PyObject *) Py_CompileStringFlags( + const char *str, + const char *filename, + int start, + PyCompilerFlags *flags); PyAPI_FUNC(PyObject *) Py_CompileStringExFlags( const char *str, const char *filename, /* decoded from the filesystem encoding */ diff --git a/Include/internal/pycore_pythonrun.h b/Include/internal/pycore_pythonrun.h index 349992d4a3c59c..c58ae9bb7af446 100644 --- a/Include/internal/pycore_pythonrun.h +++ b/Include/internal/pycore_pythonrun.h @@ -28,7 +28,7 @@ extern const char* _Py_SourceAsString( PyCompilerFlags *cf, PyObject **cmd_copy); -extern PyObject * _Py_CompileStringObjectWithModule( +extern PyObject * _Py_CompileString( const char *str, PyObject *filename, int start, PyCompilerFlags *flags, int optimize, diff --git a/Lib/test/test_capi/test_run.py b/Lib/test/test_capi/test_run.py index d0418cdee62867..14f9833f63a4fb 100644 --- a/Lib/test/test_capi/test_run.py +++ b/Lib/test/test_capi/test_run.py @@ -1,20 +1,27 @@ +import ast import os import sys import tempfile +import textwrap import unittest from collections import UserDict from test import support from test.support import import_helper from test.support.os_helper import unlink, TESTFN, TESTFN_ASCII, TESTFN_UNDECODABLE +_testcapi = import_helper.import_module('_testcapi') +_testlimitedcapi = import_helper.import_module('_testlimitedcapi') + NULL = None -_testcapi = import_helper.import_module('_testcapi') Py_single_input = _testcapi.Py_single_input Py_file_input = _testcapi.Py_file_input Py_eval_input = _testcapi.Py_eval_input +INVALID_START = Py_single_input - 1 STDIN = '<stdin>' STDERR_FD = 2 +PyCF_ONLY_AST = _testcapi.PyCF_ONLY_AST +PyCF_IGNORE_COOKIE = _testcapi.PyCF_IGNORE_COOKIE # Code raising a SyntaxError SYNTAX_ERROR = 'True = 1' @@ -68,6 +75,9 @@ def run(s, *args): run(b'raise ValueError("BUG")', {}) self.assertEqual(str(cm.exception), 'BUG') + with self.assertRaises(ValueError): + func(b'x = 1', INVALID_START, {}) + self.assertIsNone(run(b'a\n', dict(a=1))) self.assertIsNone(run(b'a\n', dict(a=1), {})) self.assertIsNone(run(b'a\n', {}, dict(a=1))) @@ -118,6 +128,9 @@ def run(*args): closeit = 1 self.assertIsNone(run(dict(a=1), {}, closeit)) + with self.assertRaises(ValueError): + func(filename, INVALID_START, {}) + self.assertRaises(NameError, run, {}) self.assertRaises(NameError, run, {}, {}) self.assertRaises(TypeError, run, dict(a=1), []) @@ -357,6 +370,65 @@ def test_run_simplestringflags(self): # Test PyRun_SimpleStringFlags() self.check_run_simplestring(_testcapi.run_simplestringflags) + def check_compilestring(self, compilestring, has_flags, encode_filename=True): + filename_str = TESTFN + if encode_filename: + filename = os.fsencode(filename_str) + else: + filename = filename_str + + def check_code(co, name, value): + ns = {} + exec(co, ns, ns) + self.assertEqual(ns[name], value) + + co = compilestring(b'x = 1', filename, Py_file_input) + self.assertEqual(co.co_filename, filename_str) + check_code(co, 'x', 1) + + if has_flags: + code = textwrap.dedent(""" + # encoding: latin1 + x = 'a\xe9' + """) + co = compilestring(code.encode(), filename, Py_file_input, PyCF_IGNORE_COOKIE) + self.assertEqual(co.co_filename, filename_str) + check_code(co, 'x', 'a\xe9') + + co = compilestring(code.encode(), filename, Py_file_input) + self.assertEqual(co.co_filename, filename_str) + check_code(co, 'x', 'a\xc3\xa9') + + tree = compilestring(b'x = 1', filename, Py_file_input, PyCF_ONLY_AST) + self.assertIsInstance(tree, ast.AST) + + co = compilestring(b'raise ValueError("BUG")', filename, Py_file_input) + with self.assertRaises(ValueError): + exec(co, {}) + + with self.assertRaises(SyntaxError) as cm: + compilestring(SYNTAX_ERROR.encode(), filename, Py_file_input) + + with self.assertRaises(ValueError): + compilestring(b'x = 1', filename, INVALID_START) + + def test_compilestring(self): + # Test Py_CompileString() + self.check_compilestring(_testlimitedcapi.run_compilestring, False) + + def test_compilestringflags(self): + # Test Py_CompileStringFlags() + self.check_compilestring(_testcapi.run_compilestringflags, True) + + def test_compilestringexflags(self): + # Test Py_CompileStringExFlags() + self.check_compilestring(_testcapi.run_compilestringexflags, True) + + def test_compilestringobject(self): + # Test Py_CompileStringObject() + self.check_compilestring(_testcapi.run_compilestringobject, True, + encode_filename=False) + if __name__ == '__main__': unittest.main() diff --git a/Modules/Setup.stdlib.in b/Modules/Setup.stdlib.in index b8043d7e2c8c85..139c4ecf99ab4b 100644 --- a/Modules/Setup.stdlib.in +++ b/Modules/Setup.stdlib.in @@ -176,7 +176,7 @@ @MODULE__TESTBUFFER_TRUE@_testbuffer _testbuffer.c @MODULE__TESTINTERNALCAPI_TRUE@_testinternalcapi _testinternalcapi.c _testinternalcapi/test_lock.c _testinternalcapi/pytime.c _testinternalcapi/set.c _testinternalcapi/test_critical_sections.c _testinternalcapi/complex.c _testinternalcapi/interpreter.c _testinternalcapi/tuple.c @MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c _testcapi/heaptype.c _testcapi/abstract.c _testcapi/unicode.c _testcapi/dict.c _testcapi/set.c _testcapi/list.c _testcapi/tuple.c _testcapi/getargs.c _testcapi/datetime.c _testcapi/docstring.c _testcapi/mem.c _testcapi/watchers.c _testcapi/long.c _testcapi/float.c _testcapi/complex.c _testcapi/numbers.c _testcapi/structmember.c _testcapi/exceptions.c _testcapi/code.c _testcapi/buffer.c _testcapi/pyatomic.c _testcapi/run.c _testcapi/file.c _testcapi/codec.c _testcapi/immortal.c _testcapi/gc.c _testcapi/hash.c _testcapi/time.c _testcapi/bytes.c _testcapi/object.c _testcapi/modsupport.c _testcapi/monitoring.c _testcapi/config.c _testcapi/import.c _testcapi/frame.c _testcapi/type.c _testcapi/function.c _testcapi/module.c _testcapi/weakref.c -@MODULE__TESTLIMITEDCAPI_TRUE@_testlimitedcapi _testlimitedcapi.c _testlimitedcapi/abstract.c _testlimitedcapi/bytearray.c _testlimitedcapi/bytes.c _testlimitedcapi/codec.c _testlimitedcapi/complex.c _testlimitedcapi/dict.c _testlimitedcapi/eval.c _testlimitedcapi/float.c _testlimitedcapi/heaptype_relative.c _testlimitedcapi/import.c _testlimitedcapi/list.c _testlimitedcapi/long.c _testlimitedcapi/object.c _testlimitedcapi/pyos.c _testlimitedcapi/set.c _testlimitedcapi/slots.c _testlimitedcapi/sys.c _testlimitedcapi/threadstate.c _testlimitedcapi/tuple.c _testlimitedcapi/unicode.c _testlimitedcapi/vectorcall_limited.c _testlimitedcapi/version.c _testlimitedcapi/file.c _testlimitedcapi/weakref.c +@MODULE__TESTLIMITEDCAPI_TRUE@_testlimitedcapi _testlimitedcapi.c _testlimitedcapi/abstract.c _testlimitedcapi/bytearray.c _testlimitedcapi/bytes.c _testlimitedcapi/codec.c _testlimitedcapi/complex.c _testlimitedcapi/dict.c _testlimitedcapi/eval.c _testlimitedcapi/float.c _testlimitedcapi/heaptype_relative.c _testlimitedcapi/import.c _testlimitedcapi/list.c _testlimitedcapi/long.c _testlimitedcapi/object.c _testlimitedcapi/pyos.c _testlimitedcapi/set.c _testlimitedcapi/slots.c _testlimitedcapi/sys.c _testlimitedcapi/threadstate.c _testlimitedcapi/tuple.c _testlimitedcapi/unicode.c _testlimitedcapi/vectorcall_limited.c _testlimitedcapi/version.c _testlimitedcapi/file.c _testlimitedcapi/weakref.c _testlimitedcapi/run.c @MODULE__TESTCLINIC_TRUE@_testclinic _testclinic.c @MODULE__TESTCLINIC_LIMITED_TRUE@_testclinic_limited _testclinic_limited.c diff --git a/Modules/_testcapi/run.c b/Modules/_testcapi/run.c index 7fc180e136559b..6812af994a4330 100644 --- a/Modules/_testcapi/run.c +++ b/Modules/_testcapi/run.c @@ -24,34 +24,16 @@ #undef PyRun_InteractiveLoop -// Some PyRun functions crash if start is invalid, -// so validate the start argument. -static int -check_start(int start) -{ - if (start == Py_single_input || start == Py_file_input - || start == Py_eval_input || start == Py_func_type_input) - { - return 0; - } - PyErr_SetString(PyExc_ValueError, "invalid start argument"); - return -1; -} - - // Test PyRun_String() static PyObject* run_string(PyObject *mod, PyObject *args) { const char *str; - int start = 0; + int start; PyObject *globals = NULL; PyObject *locals = NULL; - if (!PyArg_ParseTuple(args, "y|iOO", &str, &start, &globals, &locals)) { - return NULL; - } - if (check_start(start) < 0) { + if (!PyArg_ParseTuple(args, "yi|OO", &str, &start, &globals, &locals)) { return NULL; } NULLABLE(globals); @@ -79,9 +61,6 @@ run_stringflags(PyObject *mod, PyObject *args) &cf_flags, &cf_feature_version)) { return NULL; } - if (check_start(start) < 0) { - return NULL; - } NULLABLE(globals); NULLABLE(locals); if (cf_flags || cf_feature_version) { @@ -481,9 +460,6 @@ run_file(PyObject *mod, PyObject *args) &globals, &locals)) { return NULL; } - if (check_start(start) < 0) { - return NULL; - } NULLABLE(globals); NULLABLE(locals); @@ -518,9 +494,6 @@ run_fileex(PyObject *mod, PyObject *args) &closeit)) { return NULL; } - if (check_start(start) < 0) { - return NULL; - } NULLABLE(globals); NULLABLE(locals); @@ -560,9 +533,6 @@ run_fileflags(PyObject *mod, PyObject *args) &cf_flags, &cf_feature_version)) { return NULL; } - if (check_start(start) < 0) { - return NULL; - } NULLABLE(globals); NULLABLE(locals); if (cf_flags || cf_feature_version) { @@ -606,9 +576,6 @@ run_fileexflags(PyObject *mod, PyObject *args) &closeit, &cf_flags, &cf_feature_version)) { return NULL; } - if (check_start(start) < 0) { - return NULL; - } NULLABLE(globals); NULLABLE(locals); if (cf_flags || cf_feature_version) { @@ -733,6 +700,86 @@ run_interactiveloopflags(PyObject *mod, PyObject *args) } +// Test Py_CompileStringFlags() +static PyObject* +run_compilestringflags(PyObject *mod, PyObject *args) +{ + const char *str; + const char *filename; + int start; + PyCompilerFlags flags = _PyCompilerFlags_INIT; + PyCompilerFlags *pflags = NULL; + int cf_flags = 0; + int cf_feature_version = 0; + + if (!PyArg_ParseTuple(args, "yyi|ii", &str, &filename, &start, + &cf_flags, &cf_feature_version)) { + return NULL; + } + if (cf_flags || cf_feature_version) { + flags.cf_flags = cf_flags; + flags.cf_feature_version = cf_feature_version; + pflags = &flags; + } + + return Py_CompileStringFlags(str, filename, start, pflags); +} + + +// Test Py_CompileStringExFlags() +static PyObject* +run_compilestringexflags(PyObject *mod, PyObject *args) +{ + const char *str; + const char *filename; + int start; + PyCompilerFlags flags = _PyCompilerFlags_INIT; + PyCompilerFlags *pflags = NULL; + int cf_flags = 0; + int cf_feature_version = 0; + int optimize = -1; + + if (!PyArg_ParseTuple(args, "yyi|iii", &str, &filename, &start, + &cf_flags, &cf_feature_version, &optimize)) { + return NULL; + } + if (cf_flags || cf_feature_version) { + flags.cf_flags = cf_flags; + flags.cf_feature_version = cf_feature_version; + pflags = &flags; + } + + return Py_CompileStringExFlags(str, filename, start, pflags, optimize); +} + + +// Test Py_CompileStringObject() +static PyObject* +run_compilestringobject(PyObject *mod, PyObject *args) +{ + const char *str; + PyObject *filename; + int start; + PyCompilerFlags flags = _PyCompilerFlags_INIT; + PyCompilerFlags *pflags = NULL; + int cf_flags = 0; + int cf_feature_version = 0; + int optimize = -1; + + if (!PyArg_ParseTuple(args, "yOi|iii", &str, &filename, &start, + &cf_flags, &cf_feature_version, &optimize)) { + return NULL; + } + if (cf_flags || cf_feature_version) { + flags.cf_flags = cf_flags; + flags.cf_feature_version = cf_feature_version; + pflags = &flags; + } + + return Py_CompileStringObject(str, filename, start, pflags, optimize); +} + + static PyMethodDef test_methods[] = { {"run_string", run_string, METH_VARARGS}, {"run_stringflags", run_stringflags, METH_VARARGS}, @@ -754,6 +801,9 @@ static PyMethodDef test_methods[] = { {"run_simplestringflags", run_simplestringflags, METH_VARARGS}, {"run_interactiveloop", run_interactiveloop, METH_VARARGS}, {"run_interactiveloopflags", run_interactiveloopflags, METH_VARARGS}, + {"run_compilestringflags", run_compilestringflags, METH_VARARGS}, + {"run_compilestringexflags", run_compilestringexflags, METH_VARARGS}, + {"run_compilestringobject", run_compilestringobject, METH_VARARGS}, {NULL}, }; @@ -763,5 +813,11 @@ _PyTestCapi_Init_Run(PyObject *mod) if (PyModule_AddFunctions(mod, test_methods) < 0) { return -1; } + if (PyModule_AddIntMacro(mod, PyCF_ONLY_AST) < 0) { + return -1; + } + if (PyModule_AddIntMacro(mod, PyCF_IGNORE_COOKIE) < 0) { + return -1; + } return 0; } diff --git a/Modules/_testlimitedcapi.c b/Modules/_testlimitedcapi.c index 9314fccc6c915a..8ce704502af010 100644 --- a/Modules/_testlimitedcapi.c +++ b/Modules/_testlimitedcapi.c @@ -101,5 +101,8 @@ PyInit__testlimitedcapi(void) if (_PyTestLimitedCAPI_Init_Weakref(mod) < 0) { return NULL; } + if (_PyTestLimitedCAPI_Init_Run(mod) < 0) { + return NULL; + } return mod; } diff --git a/Modules/_testlimitedcapi/parts.h b/Modules/_testlimitedcapi/parts.h index c51d285e19ab0d..a11e0edb8311e3 100644 --- a/Modules/_testlimitedcapi/parts.h +++ b/Modules/_testlimitedcapi/parts.h @@ -46,5 +46,6 @@ int _PyTestLimitedCAPI_Init_VectorcallLimited(PyObject *module); int _PyTestLimitedCAPI_Init_Version(PyObject *module); int _PyTestLimitedCAPI_Init_File(PyObject *module); int _PyTestLimitedCAPI_Init_Weakref(PyObject *module); +int _PyTestLimitedCAPI_Init_Run(PyObject *module); #endif // Py_TESTLIMITEDCAPI_PARTS_H diff --git a/Modules/_testlimitedcapi/run.c b/Modules/_testlimitedcapi/run.c new file mode 100644 index 00000000000000..ca12e5faa5b3f9 --- /dev/null +++ b/Modules/_testlimitedcapi/run.c @@ -0,0 +1,35 @@ +#include "parts.h" +#include "util.h" + + +// Test functions, not macros +#undef Py_CompileString + + +// Test Py_CompileString() +static PyObject* +run_compilestring(PyObject *mod, PyObject *args) +{ + const char *str; + const char *filename; + int start; + + if (!PyArg_ParseTuple(args, "yyi", &str, &filename, &start)) { + return NULL; + } + + return Py_CompileString(str, filename, start); +} + + +static PyMethodDef test_methods[] = { + {"run_compilestring", run_compilestring, METH_VARARGS}, + {NULL}, +}; + +int +_PyTestLimitedCAPI_Init_Run(PyObject *m) +{ + return PyModule_AddFunctions(m, test_methods); +} + diff --git a/PCbuild/_testlimitedcapi.vcxproj b/PCbuild/_testlimitedcapi.vcxproj index 69558d204dbb8e..7ddcee6d9735ce 100644 --- a/PCbuild/_testlimitedcapi.vcxproj +++ b/PCbuild/_testlimitedcapi.vcxproj @@ -118,6 +118,7 @@ <ClCompile Include="..\Modules\_testlimitedcapi\version.c" /> <ClCompile Include="..\Modules\_testlimitedcapi\file.c" /> <ClCompile Include="..\Modules\_testlimitedcapi\weakref.c" /> + <ClCompile Include="..\Modules\_testlimitedcapi\run.c" /> </ItemGroup> <ItemGroup> <ResourceCompile Include="..\PC\python_nt.rc" /> diff --git a/PCbuild/_testlimitedcapi.vcxproj.filters b/PCbuild/_testlimitedcapi.vcxproj.filters index 2bcc3f6ff176bd..66a0a47d8e5548 100644 --- a/PCbuild/_testlimitedcapi.vcxproj.filters +++ b/PCbuild/_testlimitedcapi.vcxproj.filters @@ -34,6 +34,7 @@ <ClCompile Include="..\Modules\_testlimitedcapi\version.c" /> <ClCompile Include="..\Modules\_testlimitedcapi\file.c" /> <ClCompile Include="..\Modules\_testlimitedcapi\weakref.c" /> + <ClCompile Include="..\Modules\_testlimitedcapi\run.c" /> <ClCompile Include="..\Modules\_testlimitedcapi.c" /> </ItemGroup> <ItemGroup> diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c index fa64255be00e75..cbe59c8883d5a5 100644 --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -960,9 +960,9 @@ builtin_compile_impl(PyObject *module, PyObject *source, PyObject *filename, tstate->suppress_co_const_immortalization++; #endif - result = _Py_CompileStringObjectWithModule(str, filename, - start[compile_mode], &cf, - optimize, modname); + result = _Py_CompileString(str, filename, + start[compile_mode], &cf, + optimize, modname); #ifdef Py_GIL_DISABLED tstate->suppress_co_const_immortalization--; diff --git a/Python/pythonrun.c b/Python/pythonrun.c index e0a752720dfcc2..698ee23780ae10 100644 --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -1232,11 +1232,27 @@ void PyErr_DisplayException(PyObject *exc) PyErr_Display(NULL, exc, NULL); } +static int +check_start(int start) +{ + if (start == Py_single_input || start == Py_file_input + || start == Py_eval_input || start == Py_func_type_input) + { + return 0; + } + PyErr_SetString(PyExc_ValueError, "invalid start argument"); + return -1; +} + static PyObject * _PyRun_String(const char *str, PyObject* name, int start, PyObject *globals, PyObject *locals, PyCompilerFlags *flags, int generate_new_source) { + if (check_start(start) < 0) { + return NULL; + } + PyObject *ret = NULL; mod_ty mod; PyArena *arena; @@ -1286,6 +1302,10 @@ static PyObject * _PyRun_File(FILE *fp, PyObject *filename, int start, PyObject *globals, PyObject *locals, int closeit, PyCompilerFlags *flags) { + if (check_start(start) < 0) { + return NULL; + } + PyArena *arena = _PyArena_New(); if (arena == NULL) { return NULL; @@ -1530,14 +1550,17 @@ PyObject * Py_CompileStringObject(const char *str, PyObject *filename, int start, PyCompilerFlags *flags, int optimize) { - return _Py_CompileStringObjectWithModule(str, filename, start, - flags, optimize, NULL); + return _Py_CompileString(str, filename, start, flags, optimize, NULL); } PyObject * -_Py_CompileStringObjectWithModule(const char *str, PyObject *filename, int start, - PyCompilerFlags *flags, int optimize, PyObject *module) +_Py_CompileString(const char *str, PyObject *filename, int start, + PyCompilerFlags *flags, int optimize, PyObject *module) { + if (check_start(start) < 0) { + return NULL; + } + PyCodeObject *co; mod_ty mod; PyArena *arena = _PyArena_New(); @@ -1746,7 +1769,7 @@ Py_CompileString(const char *str, const char *p, int s) } #undef Py_CompileStringFlags -PyAPI_FUNC(PyObject *) +PyObject* Py_CompileStringFlags(const char *str, const char *p, int s, PyCompilerFlags *flags) { From cb912e108c590bb0b8ded55653e63ad47f945362 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 10 Jul 2026 04:49:38 +0200 Subject: [PATCH 644/818] [3.15] gh-121608: Fix test_samply_profiler: only check samply once (GH-153424) (#153457) gh-121608: Fix test_samply_profiler: only check samply once (GH-153424) Only run samply_command_works() once. Remove also dead code. (cherry picked from commit 311444998140240c164092640897013500b05963) Co-authored-by: Victor Stinner <vstinner@python.org> --- Lib/test/test_samply_profiler.py | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/Lib/test/test_samply_profiler.py b/Lib/test/test_samply_profiler.py index f9ab9207c3c23d..6c3be8f38ed0c0 100644 --- a/Lib/test/test_samply_profiler.py +++ b/Lib/test/test_samply_profiler.py @@ -31,12 +31,7 @@ def supports_trampoline_profiling(): raise unittest.SkipTest("perf trampoline profiling not supported") -def samply_command_works(): - try: - cmd = ["samply", "--help"] - except (subprocess.SubprocessError, OSError): - return False - +def _samply_command_works(): # Check that we can run a simple samply run with temp_dir() as script_dir: try: @@ -90,8 +85,10 @@ def run_samply(cwd, *args, **env_vars): with gzip.open(output_file, mode="rt", encoding="utf-8") as f: return f.read() +SAMPLY_COMMAND_WORKS = _samply_command_works() + -@unittest.skipUnless(samply_command_works(), "samply command doesn't work") +@unittest.skipUnless(SAMPLY_COMMAND_WORKS, "samply command doesn't work") class TestSamplyProfilerMixin: def run_samply(self, script_dir, perf_mode, script): raise NotImplementedError() @@ -145,7 +142,7 @@ def baz(n): self.assertNotIn(f"py::baz:{script}", output) -@unittest.skipUnless(samply_command_works(), "samply command doesn't work") +@unittest.skipUnless(SAMPLY_COMMAND_WORKS, "samply command doesn't work") class TestSamplyProfiler(unittest.TestCase, TestSamplyProfilerMixin): def run_samply(self, script_dir, script, activate_trampoline=True): if activate_trampoline: @@ -240,7 +237,7 @@ def compile_trampolines_for_all_functions(): self.assertIn(line, child_perf_file_contents) -@unittest.skipUnless(samply_command_works(), "samply command doesn't work") +@unittest.skipUnless(SAMPLY_COMMAND_WORKS, "samply command doesn't work") class TestSamplyProfilerWithJitDump(unittest.TestCase, TestSamplyProfilerMixin): # Regression test for gh-150723: exercises the binary jitdump backend # (-Xperf_jit) end to end through samply, unlike TestSamplyProfiler which From 45a769f26108257758cab941f9a344685fe29b14 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 10 Jul 2026 11:51:58 +0200 Subject: [PATCH 645/818] [3.15] gh-145633: Allow PyFloat_Pack8 & PyFloat_UnPack* to fail in future CPython versions (GH-153440) (#153490) gh-145633: Allow PyFloat_Pack8 & PyFloat_UnPack* to fail in future CPython versions (GH-153440) (cherry picked from commit 9324f84b0f5722d165456b5858a683a2c82eefd2) Co-authored-by: Petr Viktorin <encukou@gmail.com> --- Doc/c-api/float.rst | 6 ------ .../C_API/2026-07-09-16-46-30.gh-issue-145633.jyNwAs.rst | 2 ++ 2 files changed, 2 insertions(+), 6 deletions(-) create mode 100644 Misc/NEWS.d/next/C_API/2026-07-09-16-46-30.gh-issue-145633.jyNwAs.rst diff --git a/Doc/c-api/float.rst b/Doc/c-api/float.rst index a12ad11abb107d..c484b3e5bdb513 100644 --- a/Doc/c-api/float.rst +++ b/Doc/c-api/float.rst @@ -233,9 +233,6 @@ most likely :exc:`OverflowError`). Pack a C double as the IEEE 754 binary64 double precision format. - .. impl-detail:: - This function always succeeds in CPython. - Unpack functions ^^^^^^^^^^^^^^^^ @@ -251,9 +248,6 @@ Return value: The unpacked double. On error, this is ``-1.0`` and :c:func:`PyErr_Occurred` is true (and an exception is set, most likely :exc:`OverflowError`). -.. impl-detail:: - These functions always succeed in CPython. - .. c:function:: double PyFloat_Unpack2(const char *p, int le) Unpack the IEEE 754 binary16 half-precision format as a C double. diff --git a/Misc/NEWS.d/next/C_API/2026-07-09-16-46-30.gh-issue-145633.jyNwAs.rst b/Misc/NEWS.d/next/C_API/2026-07-09-16-46-30.gh-issue-145633.jyNwAs.rst new file mode 100644 index 00000000000000..cdb68372b6ba7d --- /dev/null +++ b/Misc/NEWS.d/next/C_API/2026-07-09-16-46-30.gh-issue-145633.jyNwAs.rst @@ -0,0 +1,2 @@ +:c:func:`PyFloat_Pack8` and ``PyFloat_Unpack*`` functions are no longer +guaranteed to always succeed on CPython. From bcc1a3637e91956ad43332d304c902a1fb00123e Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 10 Jul 2026 12:19:24 +0200 Subject: [PATCH 646/818] [3.15] gh-153201: Make TSan CI mandatory (GH-153491) (#153497) gh-153201: Make TSan CI mandatory (GH-153491) (cherry picked from commit d0714388278510c6807ef6d5af03609a525f6063) Co-authored-by: Kumar Aditya <kumaraditya@python.org> --- .github/workflows/build.yml | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8bf05b0632ba80..1203355512e5be 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -601,6 +601,7 @@ jobs: - Thread free-threading: - false + - true sanitizer: - TSan include: @@ -612,17 +613,6 @@ jobs: sanitizer: ${{ matrix.sanitizer }} free-threading: ${{ matrix.free-threading }} - # XXX: Temporarily allow this job to fail to not block PRs. - build-san-free-threading: - # ${{ '' } is a hack to nest jobs under the same sidebar category. - name: Sanitizers${{ '' }} # zizmor: ignore[obfuscation] - needs: build-context - if: needs.build-context.outputs.run-ubuntu == 'true' - uses: ./.github/workflows/reusable-san.yml - with: - sanitizer: TSan - free-threading: true - cross-build-linux: name: Cross build Linux runs-on: ubuntu-latest @@ -726,7 +716,6 @@ jobs: - test-hypothesis - build-asan - build-san - - build-san-free-threading - cross-build-linux - cifuzz if: always() @@ -738,7 +727,6 @@ jobs: allowed-failures: >- build-android, build-emscripten, - build-san-free-threading, build-windows-msi, build-ubuntu-ssltests, test-hypothesis, From 3cd6168e6554e1e3e79b7b81c5a6e619c6f5342f Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 10 Jul 2026 12:35:53 +0200 Subject: [PATCH 647/818] [3.15] gh-151942: Fix all Sphinx nitpicks in the 2.5 What's New (GH-153120) (#153499) (cherry picked from commit fb00514a1a3ab0eda80dce493a3cc3eeaaefe032) Co-authored-by: Stan Ulbrych <stan@python.org> --- Doc/tools/.nitignore | 1 - Doc/whatsnew/2.5.rst | 310 ++++++++++++++++++++++--------------------- 2 files changed, 160 insertions(+), 151 deletions(-) diff --git a/Doc/tools/.nitignore b/Doc/tools/.nitignore index 8ac0e8ffcffc27..e5855736439b67 100644 --- a/Doc/tools/.nitignore +++ b/Doc/tools/.nitignore @@ -34,5 +34,4 @@ Doc/library/xml.sax.rst Doc/library/xmlrpc.client.rst Doc/library/xmlrpc.server.rst Doc/whatsnew/2.4.rst -Doc/whatsnew/2.5.rst Doc/whatsnew/2.6.rst diff --git a/Doc/whatsnew/2.5.rst b/Doc/whatsnew/2.5.rst index 03e612fb651e71..33d8b741ba1766 100644 --- a/Doc/whatsnew/2.5.rst +++ b/Doc/whatsnew/2.5.rst @@ -16,8 +16,8 @@ release schedule. Python 2.5 was released on September 19, 2006. The changes in Python 2.5 are an interesting mix of language and library improvements. The library enhancements will be more important to Python's user community, I think, because several widely useful packages were added. New -modules include ElementTree for XML processing (:mod:`xml.etree`), -the SQLite database module (:mod:`sqlite`), and the :mod:`ctypes` +modules include ElementTree for XML processing (:mod:`xml.etree.ElementTree`), +the SQLite database module (:mod:`sqlite3`), and the :mod:`ctypes` module for calling C functions. The language changes are of middling significance. Some pleasant new features @@ -134,14 +134,14 @@ PEP 309: Partial Function Application The :mod:`functools` module is intended to contain tools for functional-style programming. -One useful tool in this module is the :func:`partial` function. For programs +One useful tool in this module is the :func:`~functools.partial` function. For programs written in a functional style, you'll sometimes want to construct variants of existing functions that have some of the parameters filled in. Consider a Python function ``f(a, b, c)``; you could create a new function ``g(b, c)`` that was equivalent to ``f(1, b, c)``. This is called "partial function application". -:func:`partial` takes the arguments ``(function, arg1, arg2, ... kwarg1=value1, +:func:`~functools.partial` takes the arguments ``(function, arg1, arg2, ... kwarg1=value1, kwarg2=value2)``. The resulting object is callable, so you can just call it to invoke *function* with the filled-in arguments. @@ -159,7 +159,7 @@ Here's a small but realistic example:: Here's another example, from a program that uses PyGTK. Here a context-sensitive pop-up menu is being constructed dynamically. The callback provided -for the menu option is a partially applied version of the :meth:`open_item` +for the menu option is a partially applied version of the ``open_item()`` method, where the first argument has been provided. :: ... @@ -172,7 +172,7 @@ method, where the first argument has been provided. :: Another function in the :mod:`functools` module is the ``update_wrapper(wrapper, wrapped)`` function that helps you write -well-behaved decorators. :func:`update_wrapper` copies the name, module, and +well-behaved decorators. :func:`~functools.update_wrapper` copies the name, module, and docstring attribute to a wrapper function so that tracebacks inside the wrapped function are easier to understand. For example, you might write:: @@ -183,7 +183,7 @@ function are easier to understand. For example, you might write:: functools.update_wrapper(wrapper, f) return wrapper -:func:`wraps` is a decorator that can be used inside your own decorators to copy +:func:`~functools.wraps` is a decorator that can be used inside your own decorators to copy the wrapped function's information. An alternate version of the previous example would be:: @@ -209,7 +209,7 @@ example would be:: PEP 314: Metadata for Python Software Packages v1.1 =================================================== -Some simple dependency support was added to Distutils. The :func:`setup` +Some simple dependency support was added to Distutils. The :func:`!setup` function now has ``requires``, ``provides``, and ``obsoletes`` keyword parameters. When you build a source distribution using the ``sdist`` command, the dependency information will be recorded in the :file:`PKG-INFO` file. @@ -271,26 +271,26 @@ Let's say you have a package directory like this:: pkg/main.py pkg/string.py -This defines a package named :mod:`pkg` containing the :mod:`pkg.main` and -:mod:`pkg.string` submodules. +This defines a package named ``pkg`` containing the ``pkg.main`` and +``pkg.string`` submodules. Consider the code in the :file:`main.py` module. What happens if it executes the statement ``import string``? In Python 2.4 and earlier, it will first look in the package's directory to perform a relative import, finds :file:`pkg/string.py`, imports the contents of that file as the -:mod:`pkg.string` module, and that module is bound to the name ``string`` in the -:mod:`pkg.main` module's namespace. +``pkg.string`` module, and that module is bound to the name ``string`` in the +``pkg.main`` module's namespace. -That's fine if :mod:`pkg.string` was what you wanted. But what if you wanted +That's fine if ``pkg.string`` was what you wanted. But what if you wanted Python's standard :mod:`string` module? There's no clean way to ignore -:mod:`pkg.string` and look for the standard module; generally you had to look at +``pkg.string`` and look for the standard module; generally you had to look at the contents of ``sys.modules``, which is slightly unclean. Holger Krekel's -:mod:`py.std` package provides a tidier way to perform imports from the standard +:mod:`!py.std` package provides a tidier way to perform imports from the standard library, ``import py; py.std.string.join()``, but that package isn't available on all Python installations. Reading code which relies on relative imports is also less clear, because a -reader may be confused about which module, :mod:`string` or :mod:`pkg.string`, +reader may be confused about which module, :mod:`string` or ``pkg.string``, is intended to be used. Python users soon learned not to duplicate the names of standard library modules in the names of their packages' submodules, but you can't protect against having your submodule's name being used for a new module @@ -313,9 +313,9 @@ name when using the ``from ... import`` form:: from . import string This imports the :mod:`string` module relative to the current package, so in -:mod:`pkg.main` this will import *name1* and *name2* from :mod:`pkg.string`. +``pkg.main`` this will import *name1* and *name2* from ``pkg.string``. Additional leading periods perform the relative import starting from the parent -of the current package. For example, code in the :mod:`A.B.C` module can do:: +of the current package. For example, code in the ``A.B.C`` module can do:: from . import D # Imports A.B.D from .. import E # Imports A.E @@ -331,7 +331,7 @@ statement, only the ``from ... import`` form. PEP written by Aahz; implemented by Thomas Wouters. https://pylib.readthedocs.io/ - The py library by Holger Krekel, which contains the :mod:`py.std` package. + The py library by Holger Krekel, which contains the :mod:`!py.std` package. .. ====================================================================== @@ -347,7 +347,7 @@ Python interpreter, the switch now uses an implementation in a new module, :mod:`runpy`. The :mod:`runpy` module implements a more sophisticated import mechanism so that -it's now possible to run modules in a package such as :mod:`pychecker.checker`. +it's now possible to run modules in a package such as :mod:`!pychecker.checker`. The module also supports alternative import mechanisms such as the :mod:`zipimport` module. This means you can add a .zip archive's path to ``sys.path`` and then use the :option:`-m` switch to execute code from the @@ -392,8 +392,8 @@ write:: The code in *block-1* is executed. If the code raises an exception, the various :keyword:`except` blocks are tested: if the exception is of class -:class:`Exception1`, *handler-1* is executed; otherwise if it's of class -:class:`Exception2`, *handler-2* is executed, and so forth. If no exception is +``Exception1``, *handler-1* is executed; otherwise if it's of class +``Exception2``, *handler-2* is executed, and so forth. If no exception is raised, the *else-block* is executed. No matter what happened previously, the *final-block* is executed once the code @@ -492,21 +492,21 @@ And here's an example of changing the counter:: :keyword:`yield` will usually return :const:`None`, so you should always check for this case. Don't just use its value in expressions unless you're sure that -the :meth:`send` method will be the only method used to resume your generator +the :meth:`~generator.send` method will be the only method used to resume your generator function. -In addition to :meth:`send`, there are two other new methods on generators: +In addition to :meth:`~generator.send`, there are two other new methods on generators: * ``throw(type, value=None, traceback=None)`` is used to raise an exception inside the generator; the exception is raised by the :keyword:`yield` expression where the generator's execution is paused. -* :meth:`close` raises a new :exc:`GeneratorExit` exception inside the generator +* :meth:`~generator.close` raises a new :exc:`GeneratorExit` exception inside the generator to terminate the iteration. On receiving this exception, the generator's code must either raise :exc:`GeneratorExit` or :exc:`StopIteration`. Catching the :exc:`GeneratorExit` exception and returning a value is illegal and will trigger a :exc:`RuntimeError`; if the function raises some other exception, that - exception is propagated to the caller. :meth:`close` will also be called by + exception is propagated to the caller. :meth:`~generator.close` will also be called by Python's garbage collector when the generator is garbage-collected. If you need to run cleanup code when a :exc:`GeneratorExit` occurs, I suggest @@ -521,8 +521,8 @@ function, and a :keyword:`return` statement), but coroutines can be entered, exited, and resumed at many different points (the :keyword:`yield` statements). We'll have to figure out patterns for using coroutines effectively in Python. -The addition of the :meth:`close` method has one side effect that isn't obvious. -:meth:`close` is called when a generator is garbage-collected, so this means the +The addition of the :meth:`~generator.close` method has one side effect that isn't obvious. +:meth:`~generator.close` is called when a generator is garbage-collected, so this means the generator's code gets one last chance to run before the generator is destroyed. This last chance means that ``try...finally`` statements in generators can now be guaranteed to work; the :keyword:`finally` clause will now always get a @@ -534,8 +534,8 @@ seems like a minor bit of language trivia, but using generators and in the following section. Another even more esoteric effect of this change: previously, the -:attr:`gi_frame` attribute of a generator was always a frame object. It's now -possible for :attr:`gi_frame` to be ``None`` once the generator has been +:attr:`!gi_frame` attribute of a generator was always a frame object. It's now +possible for :attr:`!gi_frame` to be ``None`` once the generator has been exhausted. @@ -622,7 +622,7 @@ The :mod:`threading` module's locks and condition variables also support the The lock is acquired before the block is executed and always released once the block is complete. -The new :func:`localcontext` function in the :mod:`decimal` module makes it easy +The new :func:`~decimal.localcontext` function in the :mod:`decimal` module makes it easy to save and restore the current decimal context, which encapsulates the desired precision and rounding characteristics for computations:: @@ -692,7 +692,7 @@ be to let the user write code like this:: The transaction should be committed if the code in the block runs flawlessly or rolled back if there's an exception. Here's the basic interface for -:class:`DatabaseConnection` that I'll assume:: +``DatabaseConnection`` that I'll assume:: class DatabaseConnection: # Database interface @@ -745,7 +745,7 @@ The contextlib module The new :mod:`contextlib` module provides some functions and a decorator that are useful for writing objects for use with the ':keyword:`with`' statement. -The decorator is called :func:`contextmanager`, and lets you write a single +The decorator is called :deco:`~contextlib.contextmanager`, and lets you write a single generator function instead of defining a new class. The generator should yield exactly one value. The code up to the :keyword:`yield` will be executed as the :meth:`~object.__enter__` method, and the value yielded will be the method's return @@ -910,7 +910,7 @@ may therefore need to have some variables changed to :c:type:`Py_ssize_t`. The :c:func:`PyArg_ParseTuple` and :c:func:`Py_BuildValue` functions have a new conversion code, ``n``, for :c:type:`Py_ssize_t`. :c:func:`PyArg_ParseTuple`'s ``s#`` and ``t#`` still output :c:expr:`int` by default, but you can define the -macro :c:macro:`PY_SSIZE_T_CLEAN` before including :file:`Python.h` to make +macro :c:macro:`!PY_SSIZE_T_CLEAN` before including :file:`Python.h` to make them return :c:type:`Py_ssize_t`. :pep:`353` has a section on conversion guidelines that extension authors should @@ -931,19 +931,19 @@ PEP 357: The '__index__' method =============================== The NumPy developers had a problem that could only be solved by adding a new -special method, :meth:`__index__`. When using slice notation, as in +special method, :meth:`~object.__index__`. When using slice notation, as in ``[start:stop:step]``, the values of the *start*, *stop*, and *step* indexes must all be either integers or long integers. NumPy defines a variety of specialized integer types corresponding to unsigned and signed integers of 8, 16, 32, and 64 bits, but there was no way to signal that these types could be used as slice indexes. -Slicing can't just use the existing :meth:`__int__` method because that method +Slicing can't just use the existing :meth:`~object.__int__` method because that method is also used to implement coercion to integers. If slicing used -:meth:`__int__`, floating-point numbers would also become legal slice indexes +:meth:`~object.__int__`, floating-point numbers would also become legal slice indexes and that's clearly an undesirable behaviour. -Instead, a new special method called :meth:`__index__` was added. It takes no +Instead, a new special method called :meth:`~object.__index__` was added. It takes no arguments and returns an integer giving the slice index to use. For example:: class C: @@ -957,7 +957,7 @@ interpreter will check that the type returned is correct, and raises a A corresponding :c:member:`~PyNumberMethods.nb_index` slot was added to the C-level :c:type:`PyNumberMethods` structure to let C extensions implement this protocol. ``PyNumber_Index(obj)`` can be used in extension code to call the -:meth:`__index__` function and retrieve its result. +:meth:`~object.__index__` function and retrieve its result. .. seealso:: @@ -978,7 +978,7 @@ Here are all of the changes that Python 2.5 makes to the core Python language. * The :class:`dict` type has a new hook for letting subclasses provide a default value when a key isn't contained in the dictionary. When a key isn't found, the dictionary's ``__missing__(key)`` method will be called. This hook is used - to implement the new :class:`defaultdict` class in the :mod:`collections` + to implement the new :class:`~collections.defaultdict` class in the :mod:`collections` module. The following example defines a dictionary that returns zero for any missing key:: @@ -1017,7 +1017,7 @@ Here are all of the changes that Python 2.5 makes to the core Python language. (Implemented by Fredrik Lundh following a suggestion by Raymond Hettinger.) -* The :meth:`startswith` and :meth:`endswith` methods of string types now accept +* The :meth:`~str.startswith` and :meth:`~str.endswith` methods of string types now accept tuples of strings to check for. :: def is_image_file (filename): @@ -1028,7 +1028,7 @@ Here are all of the changes that Python 2.5 makes to the core Python language. .. RFE #1491485 * The :func:`min` and :func:`max` built-in functions gained a ``key`` keyword - parameter analogous to the ``key`` argument for :meth:`sort`. This parameter + parameter analogous to the ``key`` argument for :meth:`~list.sort`. This parameter supplies a function that takes a single argument and is called for every value in the list; :func:`min`/:func:`max` will return the element with the smallest/largest return value from this function. For example, to find the @@ -1049,12 +1049,12 @@ Here are all of the changes that Python 2.5 makes to the core Python language. returned by the iterator evaluate as true. (Suggested by Guido van Rossum, and implemented by Raymond Hettinger.) -* The result of a class's :meth:`__hash__` method can now be either a long +* The result of a class's :meth:`~object.__hash__` method can now be either a long integer or a regular integer. If a long integer is returned, the hash of that value is taken. In earlier versions the hash value was required to be a regular integer, but in 2.5 the :func:`id` built-in was changed to always return non-negative numbers, and users often seem to use ``id(self)`` in - :meth:`__hash__` methods (though this is discouraged). + :meth:`~object.__hash__` methods (though this is discouraged). .. Bug #1536021 @@ -1166,7 +1166,7 @@ marked in the following list. .. Patch 1442927 * It's now illegal to mix iterating over a file with ``for line in file`` and - calling the file object's :meth:`read`/:meth:`readline`/:meth:`readlines` + calling the file object's :meth:`!read`/:meth:`!readline`/:meth:`!readlines` methods. Iteration uses an internal buffer and the :meth:`!read\*` methods don't use that buffer. Instead they would return the data following the buffer, causing the data to appear out of order. Mixing iteration and these @@ -1204,7 +1204,7 @@ marked in the following list. Sean Reifschneider at the NeedForSpeed sprint.) * Importing now caches the paths tried, recording whether they exist or not so - that the interpreter makes fewer :c:func:`open` and :c:func:`stat` calls on + that the interpreter makes fewer :c:func:`!open` and :c:func:`!stat` calls on startup. (Contributed by Martin von Löwis and Georg Brandl.) .. Patch 921466 @@ -1226,23 +1226,24 @@ complete list of changes, or look through the SVN logs for all the details. u-LAW encoding has been improved. (Contributed by Lars Immisch.) * The :mod:`codecs` module gained support for incremental codecs. The - :func:`codec.lookup` function now returns a :class:`CodecInfo` instance instead - of a tuple. :class:`CodecInfo` instances behave like a 4-tuple to preserve - backward compatibility but also have the attributes :attr:`encode`, - :attr:`decode`, :attr:`incrementalencoder`, :attr:`incrementaldecoder`, - :attr:`streamwriter`, and :attr:`streamreader`. Incremental codecs can receive + :func:`codecs.lookup` function now returns a :class:`~codecs.CodecInfo` instance instead + of a tuple. :class:`~codecs.CodecInfo` instances behave like a 4-tuple to preserve + backward compatibility but also have the attributes :attr:`~codecs.CodecInfo.encode`, + :attr:`~codecs.CodecInfo.decode`, :attr:`~codecs.CodecInfo.incrementalencoder`, + :attr:`~codecs.CodecInfo.incrementaldecoder`, :attr:`~codecs.CodecInfo.streamwriter`, + and :attr:`~codecs.CodecInfo.streamreader`. Incremental codecs can receive input and produce output in multiple chunks; the output is the same as if the entire input was fed to the non-incremental codec. See the :mod:`codecs` module documentation for details. (Designed and implemented by Walter Dörwald.) .. Patch 1436130 -* The :mod:`collections` module gained a new type, :class:`defaultdict`, that +* The :mod:`collections` module gained a new type, :class:`~collections.defaultdict`, that subclasses the standard :class:`dict` type. The new type mostly behaves like a dictionary but constructs a default value when a key isn't present, automatically adding it to the dictionary for the requested key value. - The first argument to :class:`defaultdict`'s constructor is a factory function + The first argument to :class:`~collections.defaultdict`'s constructor is a factory function that gets called whenever a key is requested but not found. This factory function receives no arguments, so you can use built-in type constructors such as :func:`list` or :func:`int`. For example, you can make an index of words @@ -1268,7 +1269,7 @@ complete list of changes, or look through the SVN logs for all the details. (Contributed by Guido van Rossum.) -* The :class:`deque` double-ended queue type supplied by the :mod:`collections` +* The :class:`~collections.deque` double-ended queue type supplied by the :mod:`collections` module now has a ``remove(value)`` method that removes the first occurrence of *value* in the queue, raising :exc:`ValueError` if the value isn't found. (Contributed by Raymond Hettinger.) @@ -1287,15 +1288,15 @@ complete list of changes, or look through the SVN logs for all the details. Also, the :mod:`pstats` module for analyzing the data measured by the profiler now supports directing the output to any file object by supplying a *stream* - argument to the :class:`Stats` constructor. (Contributed by Skip Montanaro.) + argument to the :class:`~pstats.Stats` constructor. (Contributed by Skip Montanaro.) * The :mod:`csv` module, which parses files in comma-separated value format, received several enhancements and a number of bugfixes. You can now set the maximum size in bytes of a field by calling the ``csv.field_size_limit(new_limit)`` function; omitting the *new_limit* - argument will return the currently set limit. The :class:`reader` class now has - a :attr:`line_num` attribute that counts the number of physical lines read from - the source; records can span multiple physical lines, so :attr:`line_num` is not + argument will return the currently set limit. The :class:`~csv.reader` class now has + a :attr:`~csv.csvreader.line_num` attribute that counts the number of physical lines read from + the source; records can span multiple physical lines, so :attr:`~csv.csvreader.line_num` is not the same as the number of records read. The CSV parser is now stricter about multi-line quoted fields. Previously, if a @@ -1318,7 +1319,7 @@ complete list of changes, or look through the SVN logs for all the details. ts = dt.datetime.strptime('10:13:15 2006-03-07', '%H:%M:%S %Y-%m-%d') -* The :meth:`SequenceMatcher.get_matching_blocks` method in the :mod:`difflib` +* The :meth:`difflib.SequenceMatcher.get_matching_blocks` method in the :mod:`difflib` module now guarantees to return a minimal list of blocks describing matching subsequences. Previously, the algorithm would occasionally break a block of matching elements into two list entries. (Enhancement by Tim Peters.) @@ -1327,8 +1328,8 @@ complete list of changes, or look through the SVN logs for all the details. being executed at all. This is intended for code snippets that are usage examples intended for the reader and aren't actually test cases. - An *encoding* parameter was added to the :func:`testfile` function and the - :class:`DocFileSuite` class to specify the file's encoding. This makes it + An *encoding* parameter was added to the :func:`~doctest.testfile` function and the + :class:`~doctest.DocFileSuite` class to specify the file's encoding. This makes it easier to use non-ASCII characters in tests contained within a docstring. (Contributed by Bjorn Tillenius.) @@ -1347,20 +1348,20 @@ complete list of changes, or look through the SVN logs for all the details. :func:`input` function to allow opening files in binary or :term:`universal newlines` mode. Another new parameter, *openhook*, lets you use a function other than :func:`open` to open the input files. Once you're iterating over - the set of files, the :class:`FileInput` object's new :meth:`~fileinput.fileno` returns + the set of files, the :class:`~fileinput.FileInput` object's new :meth:`~fileinput.fileno` returns the file descriptor for the currently opened file. (Contributed by Georg Brandl.) -* In the :mod:`gc` module, the new :func:`get_count` function returns a 3-tuple +* In the :mod:`gc` module, the new :func:`~gc.get_count` function returns a 3-tuple containing the current collection counts for the three GC generations. This is accounting information for the garbage collector; when these counts reach a specified threshold, a garbage collection sweep will be made. The existing :func:`gc.collect` function now takes an optional *generation* argument of 0, 1, or 2 to specify which generation to collect. (Contributed by Barry Warsaw.) -* The :func:`nsmallest` and :func:`nlargest` functions in the :mod:`heapq` +* The :func:`~heapq.nsmallest` and :func:`~heapq.nlargest` functions in the :mod:`heapq` module now support a ``key`` keyword parameter similar to the one provided by - the :func:`min`/:func:`max` functions and the :meth:`sort` methods. For + the :func:`min`/:func:`max` functions and the :meth:`~list.sort` methods. For example:: >>> import heapq @@ -1382,7 +1383,7 @@ complete list of changes, or look through the SVN logs for all the details. (Contributed by Raymond Hettinger.) * The :func:`format` function in the :mod:`locale` module has been modified and - two new functions were added, :func:`format_string` and :func:`currency`. + two new functions were added, :func:`~locale.format_string` and :func:`~locale.currency`. The :func:`format` function's *val* parameter could previously be a string as long as no more than one %char specifier appeared; now the parameter must be @@ -1391,10 +1392,10 @@ complete list of changes, or look through the SVN logs for all the details. formatting currency in placing a separator between groups of three digits. To format strings with multiple %char specifiers, use the new - :func:`format_string` function that works like :func:`format` but also supports + :func:`~locale.format_string` function that works like :func:`format` but also supports mixing %char specifiers with arbitrary text. - A new :func:`currency` function was also added that formats a number according + A new :func:`~locale.currency` function was also added that formats a number according to the current locale's settings. (Contributed by Georg Brandl.) @@ -1403,9 +1404,11 @@ complete list of changes, or look through the SVN logs for all the details. * The :mod:`mailbox` module underwent a massive rewrite to add the capability to modify mailboxes in addition to reading them. A new set of classes that include - :class:`mbox`, :class:`MH`, and :class:`Maildir` are used to read mailboxes, and + :class:`~mailbox.mbox`, :class:`~mailbox.MH`, and :class:`~mailbox.Maildir` + are used to read mailboxes, and have an ``add(message)`` method to add messages, ``remove(key)`` to - remove messages, and :meth:`lock`/:meth:`unlock` to lock/unlock the mailbox. + remove messages, and :meth:`~mailbox.Mailbox.lock`/:meth:`~mailbox.Mailbox.unlock` + to lock/unlock the mailbox. The following example converts a maildir-format mailbox into an mbox-format one:: @@ -1430,19 +1433,19 @@ complete list of changes, or look through the SVN logs for all the details. default domain by supplying a *domain* argument to the :func:`!nis.match` and :func:`!nis.maps` functions. (Contributed by Ben Bell.) -* The :mod:`operator` module's :func:`itemgetter` and :func:`attrgetter` +* The :mod:`operator` module's :func:`~operator.itemgetter` and :func:`~operator.attrgetter` functions now support multiple fields. A call such as ``operator.attrgetter('a', 'b')`` will return a function that retrieves the - :attr:`a` and :attr:`b` attributes. Combining this new feature with the - :meth:`sort` method's ``key`` parameter lets you easily sort lists using + ``a`` and ``b`` attributes. Combining this new feature with the + :meth:`~list.sort` method's ``key`` parameter lets you easily sort lists using multiple fields. (Contributed by Raymond Hettinger.) * The :mod:`optparse` module was updated to version 1.5.1 of the Optik library. - The :class:`OptionParser` class gained an :attr:`epilog` attribute, a string - that will be printed after the help message, and a :meth:`destroy` method to + The :class:`~optparse.OptionParser` class gained an :attr:`!epilog` attribute, a string + that will be printed after the help message, and a :meth:`!destroy` method to break reference cycles created by the object. (Contributed by Greg Ward.) -* The :mod:`os` module underwent several changes. The :attr:`stat_float_times` +* The :mod:`os` module underwent several changes. The :attr:`!stat_float_times` variable now defaults to true, meaning that :func:`os.stat` will now return time values as floats. (This doesn't necessarily mean that :func:`os.stat` will return times that are precise to fractions of a second; not all systems support @@ -1453,19 +1456,20 @@ complete list of changes, or look through the SVN logs for all the details. :func:`os.lseek` function. Two new constants for locking are :const:`os.O_SHLOCK` and :const:`os.O_EXLOCK`. - Two new functions, :func:`wait3` and :func:`wait4`, were added. They're similar - the :func:`waitpid` function which waits for a child process to exit and returns - a tuple of the process ID and its exit status, but :func:`wait3` and - :func:`wait4` return additional information. :func:`wait3` doesn't take a + Two new functions, :func:`~os.wait3` and :func:`~os.wait4`, were added. They're similar + the :func:`~os.waitpid` function which waits for a child process to exit and returns + a tuple of the process ID and its exit status, but :func:`~os.wait3` and + :func:`~os.wait4` return additional information. :func:`~os.wait3` doesn't take a process ID as input, so it waits for any child process to exit and returns a 3-tuple of *process-id*, *exit-status*, *resource-usage* as returned from the :func:`resource.getrusage` function. ``wait4(pid)`` does take a process ID. (Contributed by Chad J. Schroeder.) On FreeBSD, the :func:`os.stat` function now returns times with nanosecond - resolution, and the returned object now has :attr:`st_gen` and - :attr:`st_birthtime`. The :attr:`st_flags` attribute is also available, if the - platform supports it. (Contributed by Antti Louko and Diego Pettenò.) + resolution, and the returned object now has :attr:`~os.stat_result.st_gen` and + :attr:`~os.stat_result.st_birthtime`. The :attr:`~os.stat_result.st_flags` + attribute is also available, if the platform supports it. + (Contributed by Antti Louko and Diego Pettenò.) .. (Patch 1180695, 1212117) @@ -1495,21 +1499,21 @@ complete list of changes, or look through the SVN logs for all the details. instead of performing many different operations and reducing the result to a single number as :file:`pystone.py` does. -* The :mod:`pyexpat` module now uses version 2.0 of the Expat parser. +* The :mod:`!pyexpat` module now uses version 2.0 of the Expat parser. (Contributed by Trent Mick.) -* The :class:`~queue.Queue` class provided by the :mod:`Queue` module gained two new - methods. :meth:`join` blocks until all items in the queue have been retrieved +* The :class:`~queue.Queue` class provided by the :mod:`queue` module gained two new + methods. :meth:`~queue.Queue.join` blocks until all items in the queue have been retrieved and all processing work on the items have been completed. Worker threads call - the other new method, :meth:`task_done`, to signal that processing for an item + the other new method, :meth:`~queue.Queue.task_done`, to signal that processing for an item has been completed. (Contributed by Raymond Hettinger.) -* The old :mod:`regex` and :mod:`regsub` modules, which have been deprecated +* The old :mod:`!regex` and :mod:`!regsub` modules, which have been deprecated ever since Python 2.0, have finally been deleted. Other deleted modules: - :mod:`statcache`, :mod:`tzparse`, :mod:`whrandom`. + :mod:`!statcache`, :mod:`!tzparse`, :mod:`!whrandom`. * Also deleted: the :file:`lib-old` directory, which includes ancient modules - such as :mod:`dircmp` and :mod:`ni`, was removed. :file:`lib-old` wasn't on the + such as :mod:`!dircmp` and :mod:`!ni`, was removed. :file:`lib-old` wasn't on the default ``sys.path``, so unless your programs explicitly added the directory to ``sys.path``, this removal shouldn't affect your code. @@ -1519,14 +1523,16 @@ complete list of changes, or look through the SVN logs for all the details. .. Patch #1472854 -* The :mod:`SimpleXMLRPCServer <xmlrpc.server>` and :mod:`DocXMLRPCServer <xmlrpc.server>` classes now have a - :attr:`rpc_paths` attribute that constrains XML-RPC operations to a limited set +* The :mod:`SimpleXMLRPCServer <xmlrpc.server>` and :mod:`DocXMLRPCServer + <xmlrpc.server>` classes now have a :attr:`~xmlrpc.server.SimpleXMLRPCRequestHandler.rpc_paths` + attribute that constrains XML-RPC operations to a limited set of URL paths; the default is to allow only ``'/'`` and ``'/RPC2'``. Setting - :attr:`rpc_paths` to ``None`` or an empty tuple disables this path checking. + :attr:`~xmlrpc.server.SimpleXMLRPCRequestHandler.rpc_paths` to ``None`` or an + empty tuple disables this path checking. .. Bug #1473048 -* The :mod:`socket` module now supports :const:`AF_NETLINK` sockets on Linux, +* The :mod:`socket` module now supports :const:`!AF_NETLINK` sockets on Linux, thanks to a patch from Philippe Biondi. Netlink sockets are a Linux-specific mechanism for communications between a user-space process and kernel code; an introductory article about them is at https://www.linuxjournal.com/article/7356. @@ -1538,19 +1544,19 @@ complete list of changes, or look through the SVN logs for all the details. supports the buffer protocol instead of returning the data as a string. This means you can put the data directly into an array or a memory-mapped file. - Socket objects also gained :meth:`getfamily`, :meth:`gettype`, and - :meth:`getproto` accessor methods to retrieve the family, type, and protocol + Socket objects also gained :meth:`!getfamily`, :meth:`!gettype`, and + :meth:`!getproto` accessor methods to retrieve the family, type, and protocol values for the socket. * New module: the :mod:`!spwd` module provides functions for accessing the shadow password database on systems that support shadow passwords. * The :mod:`struct` is now faster because it compiles format strings into - :class:`Struct` objects with :meth:`pack` and :meth:`unpack` methods. This is + :class:`~struct.Struct` objects with :meth:`~struct.Struct.pack` and :meth:`~struct.Struct.unpack` methods. This is similar to how the :mod:`re` module lets you create compiled regular expression - objects. You can still use the module-level :func:`pack` and :func:`unpack` - functions; they'll create :class:`Struct` objects and cache them. Or you can - use :class:`Struct` instances directly:: + objects. You can still use the module-level :func:`~struct.pack` and :func:`~struct.unpack` + functions; they'll create :class:`~struct.Struct` objects and cache them. Or you can + use :class:`~struct.Struct` instances directly:: s = struct.Struct('ih3s') @@ -1562,7 +1568,7 @@ complete list of changes, or look through the SVN logs for all the details. offset)`` methods. This lets you store data directly into an array or a memory-mapped file. - (:class:`Struct` objects were implemented by Bob Ippolito at the NeedForSpeed + (:class:`~struct.Struct` objects were implemented by Bob Ippolito at the NeedForSpeed sprint. Support for buffer objects was added by Martin Blais, also at the NeedForSpeed sprint.) @@ -1582,8 +1588,8 @@ complete list of changes, or look through the SVN logs for all the details. topmost stack frame currently active in that thread at the time the function is called. (Contributed by Tim Peters.) -* The :class:`TarFile` class in the :mod:`tarfile` module now has an - :meth:`extractall` method that extracts all members from the archive into the +* The :class:`~tarfile.TarFile` class in the :mod:`tarfile` module now has an + :meth:`~tarfile.TarFile.extractall` method that extracts all members from the archive into the current working directory. It's also possible to set a different directory as the extraction target, and to unpack only a subset of the archive's members. @@ -1607,8 +1613,8 @@ complete list of changes, or look through the SVN logs for all the details. * New module: the :mod:`uuid` module generates universally unique identifiers (UUIDs) according to :rfc:`4122`. The RFC defines several different UUID versions that are generated from a starting string, from system properties, or - purely randomly. This module contains a :class:`UUID` class and functions - named :func:`uuid1`, :func:`uuid3`, :func:`uuid4`, and :func:`uuid5` to + purely randomly. This module contains a :class:`~uuid.UUID` class and functions + named :func:`~uuid.uuid1`, :func:`~uuid.uuid3`, :func:`~uuid.uuid4`, and :func:`~uuid.uuid5` to generate different versions of UUID. (Version 2 UUIDs are not specified in :rfc:`4122` and are not supported by this module.) :: @@ -1631,18 +1637,18 @@ complete list of changes, or look through the SVN logs for all the details. (Contributed by Ka-Ping Yee.) -* The :mod:`weakref` module's :class:`WeakKeyDictionary` and - :class:`WeakValueDictionary` types gained new methods for iterating over the - weak references contained in the dictionary. :meth:`iterkeyrefs` and - :meth:`keyrefs` methods were added to :class:`WeakKeyDictionary`, and - :meth:`itervaluerefs` and :meth:`valuerefs` were added to - :class:`WeakValueDictionary`. (Contributed by Fred L. Drake, Jr.) +* The :mod:`weakref` module's :class:`~weakref.WeakKeyDictionary` and + :class:`~weakref.WeakValueDictionary` types gained new methods for iterating over the + weak references contained in the dictionary. :meth:`!iterkeyrefs` and + :meth:`~weakref.WeakKeyDictionary.keyrefs` methods were added to :class:`~weakref.WeakKeyDictionary`, and + :meth:`!itervaluerefs` and :meth:`~weakref.WeakValueDictionary.valuerefs` were added to + :class:`~weakref.WeakValueDictionary`. (Contributed by Fred L. Drake, Jr.) * The :mod:`webbrowser` module received a number of enhancements. It's now usable as a script with ``python -m webbrowser``, taking a URL as the argument; there are a number of switches to control the behaviour (:option:`!-n` for a new browser window, :option:`!-t` for a new tab). New module-level functions, - :func:`open_new` and :func:`open_new_tab`, were added to support this. The + :func:`~webbrowser.open_new` and :func:`~webbrowser.open_new_tab`, were added to support this. The module's :func:`open` function supports an additional feature, an *autoraise* parameter that signals whether to raise the open window when possible. A number of additional browsers were added to the supported list such as Firefox, Opera, @@ -1663,9 +1669,9 @@ complete list of changes, or look through the SVN logs for all the details. .. Patch 1446489 -* The :mod:`zlib` module's :class:`Compress` and :class:`Decompress` objects now +* The :mod:`zlib` module's :class:`!Compress` and :class:`!Decompress` objects now support a :meth:`copy` method that makes a copy of the object's internal state - and returns a new :class:`Compress` or :class:`Decompress` object. + and returns a new :class:`!Compress` or :class:`!Decompress` object. (Contributed by Chris AtLee.) .. Patch 1435422 @@ -1685,34 +1691,34 @@ provides functions for loading shared libraries and calling functions in them. The :mod:`ctypes` package is much fancier. To load a shared library or DLL, you must create an instance of the -:class:`CDLL` class and provide the name or path of the shared library or DLL. +:class:`~ctypes.CDLL` class and provide the name or path of the shared library or DLL. Once that's done, you can call arbitrary functions by accessing them as -attributes of the :class:`CDLL` object. :: +attributes of the :class:`~ctypes.CDLL` object. :: import ctypes libc = ctypes.CDLL('libc.so.6') result = libc.printf("Line of output\n") -Type constructors for the various C types are provided: :func:`c_int`, -:func:`c_float`, :func:`c_double`, :func:`c_char_p` (equivalent to :c:expr:`char +Type constructors for the various C types are provided: :func:`~ctypes.c_int`, +:func:`~ctypes.c_float`, :func:`~ctypes.c_double`, :func:`~ctypes.c_char_p` (equivalent to :c:expr:`char \*`), and so forth. Unlike Python's types, the C versions are all mutable; you -can assign to their :attr:`value` attribute to change the wrapped value. Python +can assign to their :attr:`~ctypes._SimpleCData.value` attribute to change the wrapped value. Python integers and strings will be automatically converted to the corresponding C types, but for other types you must call the correct type constructor. (And I mean *must*; getting it wrong will often result in the interpreter crashing with a segmentation fault.) -You shouldn't use :func:`c_char_p` with a Python string when the C function will +You shouldn't use :func:`~ctypes.c_char_p` with a Python string when the C function will be modifying the memory area, because Python strings are supposed to be immutable; breaking this rule will cause puzzling bugs. When you need a -modifiable memory area, use :func:`create_string_buffer`:: +modifiable memory area, use :func:`~ctypes.create_string_buffer`:: s = "this is a string" buf = ctypes.create_string_buffer(s) libc.strfry(buf) -C functions are assumed to return integers, but you can set the :attr:`restype` +C functions are assumed to return integers, but you can set the :attr:`~ctypes._CFuncPtr.restype` attribute of the function object to change this:: >>> libc.atof('2.71828') @@ -1760,9 +1766,9 @@ The ElementTree package ----------------------- A subset of Fredrik Lundh's ElementTree library for processing XML has been -added to the standard library as :mod:`xml.etree`. The available modules are -:mod:`ElementTree`, :mod:`ElementPath`, and :mod:`ElementInclude` from -ElementTree 1.2.6. The :mod:`cElementTree` accelerator module is also +added to the standard library as :mod:`!xml.etree`. The available modules are +:mod:`!ElementTree`, :mod:`!ElementPath`, and :mod:`!ElementInclude` from +ElementTree 1.2.6. The :mod:`!cElementTree` accelerator module is also included. The rest of this section will provide a brief overview of using ElementTree. @@ -1770,14 +1776,15 @@ Full documentation for ElementTree is available at https://web.archive.org/web/20201124024954/http://effbot.org/zone/element-index.htm. ElementTree represents an XML document as a tree of element nodes. The text -content of the document is stored as the :attr:`text` and :attr:`tail` +content of the document is stored as the :attr:`~xml.etree.ElementTree.Element.text` +and :attr:`~xml.etree.ElementTree.Element.tail` attributes of (This is one of the major differences between ElementTree and the Document Object Model; in the DOM there are many different types of node, -including :class:`TextNode`.) +including :class:`!TextNode`.) -The most commonly used parsing function is :func:`parse`, that takes either a +The most commonly used parsing function is :func:`~xml.etree.ElementTree.parse`, that takes either a string (assumed to contain a filename) or a file-like object and returns an -:class:`ElementTree` instance:: +:class:`~xml.etree.ElementTree.ElementTree` instance:: from xml.etree import ElementTree as ET @@ -1787,11 +1794,13 @@ string (assumed to contain a filename) or a file-like object and returns an 'http://planet.python.org/rss10.xml') tree = ET.parse(feed) -Once you have an :class:`ElementTree` instance, you can call its :meth:`getroot` -method to get the root :class:`Element` node. +Once you have an :class:`~xml.etree.ElementTree.ElementTree` instance, you can +call its :meth:`~xml.etree.ElementTree.ElementTree.getroot` +method to get the root :class:`~xml.etree.ElementTree.Element` node. -There's also an :func:`XML` function that takes a string literal and returns an -:class:`Element` node (not an :class:`ElementTree`). This function provides a +There's also an :func:`~xml.etree.ElementTree.XML` function that takes a string +literal and returns an :class:`~xml.etree.ElementTree.Element` node (not an +:class:`~xml.etree.ElementTree.ElementTree`). This function provides a tidy way to incorporate XML fragments, approaching the convenience of an XML literal:: @@ -1834,7 +1843,7 @@ list-like operations are used to access child nodes. | ``del elem.attrib[name]`` | Deletes attribute *name*. | +-------------------------------+--------------------------------------------+ -Comments and processing instructions are also represented as :class:`Element` +Comments and processing instructions are also represented as :class:`~xml.etree.ElementTree.Element` nodes. To check if a node is a comment or processing instructions:: if elem.tag is ET.Comment: @@ -1842,8 +1851,8 @@ nodes. To check if a node is a comment or processing instructions:: elif elem.tag is ET.ProcessingInstruction: ... -To generate XML output, you should call the :meth:`ElementTree.write` method. -Like :func:`parse`, it can take either a string or a file-like object:: +To generate XML output, you should call the :meth:`xml.etree.ElementTree.ElementTree.write` method. +Like :func:`~xml.etree.ElementTree.parse`, it can take either a string or a file-like object:: # Encoding is US-ASCII tree.write('output.xml') @@ -1913,7 +1922,7 @@ differently. :: Once a hash object has been created, its methods are the same as before: ``update(string)`` hashes the specified string into the current digest -state, :meth:`digest` and :meth:`hexdigest` return the digest value as a binary +state, :meth:`~hashlib.hash.digest` and :meth:`~hashlib.hash.hexdigest` return the digest value as a binary string or a string of hex digits, and :meth:`copy` returns a new hashing object with the same digest state. @@ -1949,7 +1958,7 @@ doesn't include the SQLite code, only the wrapper module. You'll need to have the SQLite libraries and headers installed before compiling Python, and the build process will compile the module when the necessary headers are available. -To use the module, you must first create a :class:`Connection` object that +To use the module, you must first create a :class:`~sqlite3.Connection` object that represents the database. Here the data will be stored in the :file:`/tmp/example` file:: @@ -1957,8 +1966,8 @@ represents the database. Here the data will be stored in the You can also supply the special name ``:memory:`` to create a database in RAM. -Once you have a :class:`Connection`, you can create a :class:`Cursor` object -and call its :meth:`execute` method to perform SQL commands:: +Once you have a :class:`~sqlite3.Connection`, you can create a :class:`~sqlite3.Cursor` object +and call its :meth:`~sqlite3.Cursor.execute` method to perform SQL commands:: c = conn.cursor() @@ -1977,7 +1986,7 @@ is insecure; it makes your program vulnerable to an SQL injection attack. Instead, use the DB-API's parameter substitution. Put ``?`` as a placeholder wherever you want to use a value, and then provide a tuple of values as the -second argument to the cursor's :meth:`execute` method. (Other database modules +second argument to the cursor's :meth:`~sqlite3.Cursor.execute` method. (Other database modules may use a different placeholder, such as ``%s`` or ``:1``.) For example:: # Never do this -- insecure! @@ -1996,8 +2005,8 @@ may use a different placeholder, such as ``%s`` or ``:1``.) For example:: c.execute('insert into stocks values (?,?,?,?,?)', t) To retrieve data after executing a SELECT statement, you can either treat the -cursor as an iterator, call the cursor's :meth:`fetchone` method to retrieve a -single matching row, or call :meth:`fetchall` to get a list of the matching +cursor as an iterator, call the cursor's :meth:`~sqlite3.Cursor.fetchone` method to retrieve a +single matching row, or call :meth:`~sqlite3.Cursor.fetchall` to get a list of the matching rows. This example uses the iterator form:: @@ -2118,7 +2127,7 @@ Changes to Python's build process and to the C API include: discusses the design. To start learning about the code, read the definition of the various AST nodes in :file:`Parser/Python.asdl`. A Python script reads this file and generates a set of C structure definitions in - :file:`Include/Python-ast.h`. The :c:func:`PyParser_ASTFromString` and + :file:`Include/Python-ast.h`. The :c:func:`!PyParser_ASTFromString` and :c:func:`!PyParser_ASTFromFile`, defined in :file:`Include/pythonrun.h`, take Python source as input and return the root of an AST representing the contents. This AST can then be turned into a code object by :c:func:`!PyAST_Compile`. For @@ -2235,9 +2244,9 @@ code: encoding declaration. In Python 2.4 this triggered a warning, not a syntax error. -* Previously, the :attr:`gi_frame` attribute of a generator was always a frame +* Previously, the :attr:`!gi_frame` attribute of a generator was always a frame object. Because of the :pep:`342` changes described in section :ref:`pep-342`, - it's now possible for :attr:`gi_frame` to be ``None``. + it's now possible for :attr:`!gi_frame` to be ``None``. * A new warning, :class:`UnicodeWarning`, is triggered when you attempt to compare a Unicode string and an 8-bit string that can't be converted to Unicode @@ -2258,11 +2267,12 @@ code: return a tuple of arguments instead. The modules also no longer accept the deprecated *bin* keyword parameter. -* Library: The :mod:`SimpleXMLRPCServer <xmlrpc.server>` and :mod:`DocXMLRPCServer <xmlrpc.server>` classes now - have a :attr:`rpc_paths` attribute that constrains XML-RPC operations to a +* Library: The :mod:`SimpleXMLRPCServer <xmlrpc.server>` and :mod:`DocXMLRPCServer + <xmlrpc.server>` classes now have a :attr:`~xmlrpc.server.SimpleXMLRPCRequestHandler.rpc_paths` + attribute that constrains XML-RPC operations to a limited set of URL paths; the default is to allow only ``'/'`` and ``'/RPC2'``. - Setting :attr:`rpc_paths` to ``None`` or an empty tuple disables this path - checking. + Setting :attr:`~xmlrpc.server.SimpleXMLRPCRequestHandler.rpc_paths` to ``None`` + or an empty tuple disables this path checking. * C API: Many functions now use :c:type:`Py_ssize_t` instead of :c:expr:`int` to allow processing more data on 64-bit machines. Extension code may need to make From 7e530749c6f69219c29f1ee0d092f95b22b87dec Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 10 Jul 2026 12:44:28 +0200 Subject: [PATCH 648/818] [3.15] gh-151942: Fix all Sphinx nitpicks in the Python 2.4 What's New (GH-153116) (#153503) (cherry picked from commit fc9fe142f8af744870d3535ce8ab561e8a390edd) Co-authored-by: Stan Ulbrych <stan@python.org> --- Doc/tools/.nitignore | 1 - Doc/whatsnew/2.4.rst | 218 ++++++++++++++++++++++--------------------- 2 files changed, 110 insertions(+), 109 deletions(-) diff --git a/Doc/tools/.nitignore b/Doc/tools/.nitignore index e5855736439b67..c5d47489596611 100644 --- a/Doc/tools/.nitignore +++ b/Doc/tools/.nitignore @@ -33,5 +33,4 @@ Doc/library/xml.sax.reader.rst Doc/library/xml.sax.rst Doc/library/xmlrpc.client.rst Doc/library/xmlrpc.server.rst -Doc/whatsnew/2.4.rst Doc/whatsnew/2.6.rst diff --git a/Doc/whatsnew/2.4.rst b/Doc/whatsnew/2.4.rst index 7628cfefe0ec96..87c7b6b17477b5 100644 --- a/Doc/whatsnew/2.4.rst +++ b/Doc/whatsnew/2.4.rst @@ -35,7 +35,7 @@ implementation and design rationale. PEP 218: Built-In Set Objects ============================= -Python 2.3 introduced the :mod:`sets` module. C implementations of set data +Python 2.3 introduced the :mod:`!sets` module. C implementations of set data types have now been added to the Python core as two new built-in types, ``set(iterable)`` and ``frozenset(iterable)``. They provide high speed operations for membership testing, for eliminating duplicates from sequences, @@ -72,8 +72,8 @@ The :func:`frozenset` type is an immutable version of :func:`set`. Since it is immutable and hashable, it may be used as a dictionary key or as a member of another set. -The :mod:`sets` module remains in the standard library, and may be useful if you -wish to subclass the :class:`Set` or :class:`ImmutableSet` classes. There are +The :mod:`!sets` module remains in the standard library, and may be useful if you +wish to subclass the :class:`!Set` or :class:`!ImmutableSet` classes. There are currently no plans to deprecate the module. @@ -189,7 +189,7 @@ aren't aware of the Python language. The format string's syntax is complicated to explain to such users, and if they make a mistake, it's difficult to provide helpful feedback to them. -PEP 292 adds a :class:`Template` class to the :mod:`string` module that uses +PEP 292 adds a :class:`~string.Template` class to the :mod:`string` module that uses ``$`` to indicate a substitution:: >>> import string @@ -197,9 +197,9 @@ PEP 292 adds a :class:`Template` class to the :mod:`string` module that uses >>> t.substitute({'page':2, 'title': 'The Best of Times'}) '2: The Best of Times' -If a key is missing from the dictionary, the :meth:`substitute` method will -raise a :exc:`KeyError`. There's also a :meth:`safe_substitute` method that -ignores missing keys:: +If a key is missing from the dictionary, the :meth:`~string.Template.substitute` +method will raise a :exc:`KeyError`. There's also a +:meth:`~string.Template.safe_substitute` method that ignores missing keys:: >>> t = string.Template('$page: $title') >>> t.safe_substitute({'page':3}) @@ -430,14 +430,14 @@ The constructor has a number of handy options: * *universal_newlines* opens the child's input and output using Python's :term:`universal newlines` feature. -Once you've created the :class:`Popen` instance, you can call its :meth:`wait` -method to pause until the subprocess has exited, :meth:`poll` to check if it's +Once you've created the :class:`~subprocess.Popen` instance, you can call its :meth:`~subprocess.Popen.wait` +method to pause until the subprocess has exited, :meth:`~subprocess.Popen.poll` to check if it's exited without pausing, or ``communicate(data)`` to send the string *data* to the subprocess's standard input. ``communicate(data)`` then reads any data that the subprocess has sent to its standard output or standard error, returning a tuple ``(stdout_data, stderr_data)``. -:func:`call` is a shortcut that passes its arguments along to the :class:`Popen` +:func:`~subprocess.call` is a shortcut that passes its arguments along to the :class:`~subprocess.Popen` constructor, waits for the command to complete, and returns the status code of the subprocess. It can serve as a safer analog to :func:`os.system`:: @@ -476,7 +476,7 @@ Python has always supported floating-point (FP) numbers, based on the underlying C :c:expr:`double` type, as a data type. However, while most programming languages provide a floating-point type, many people (even programmers) are unaware that floating-point numbers don't represent certain decimal fractions -accurately. The new :class:`Decimal` type can represent these fractions +accurately. The new :class:`~decimal.Decimal` type can represent these fractions accurately, up to a user-specified precision limit. @@ -531,20 +531,20 @@ decimal places, the error is never apparent. However, for applications where it does matter, it's a lot of work to implement your own custom arithmetic routines. -Hence, the :class:`Decimal` type was created. +Hence, the :class:`~decimal.Decimal` type was created. -The :class:`Decimal` type -------------------------- +The :class:`~decimal.Decimal` type +---------------------------------- A new module, :mod:`decimal`, was added to Python's standard library. It -contains two classes, :class:`Decimal` and :class:`Context`. :class:`Decimal` -instances represent numbers, and :class:`Context` instances are used to wrap up +contains two classes, :class:`~decimal.Decimal` and :class:`~decimal.Context`. :class:`~decimal.Decimal` +instances represent numbers, and :class:`~decimal.Context` instances are used to wrap up various settings such as the precision and default rounding mode. -:class:`Decimal` instances are immutable, like regular Python integers and FP +:class:`~decimal.Decimal` instances are immutable, like regular Python integers and FP numbers; once it's been created, you can't change the value an instance -represents. :class:`Decimal` instances can be created from integers or +represents. :class:`~decimal.Decimal` instances can be created from integers or strings:: >>> import decimal @@ -567,7 +567,7 @@ number representing 1.1 turn into the decimal number for exactly 1.1, or for 1.1 plus whatever inaccuracies are introduced? The decision was to dodge the issue and leave such a conversion out of the API. Instead, you should convert the floating-point number into a string using the desired precision and pass the -string to the :class:`Decimal` constructor:: +string to the :class:`~decimal.Decimal` constructor:: >>> f = 1.1 >>> decimal.Decimal(str(f)) @@ -575,7 +575,7 @@ string to the :class:`Decimal` constructor:: >>> decimal.Decimal('%.12f' % f) Decimal("1.100000000000") -Once you have :class:`Decimal` instances, you can perform the usual mathematical +Once you have :class:`~decimal.Decimal` instances, you can perform the usual mathematical operations on them. One limitation: exponentiation requires an integer exponent:: @@ -596,7 +596,7 @@ exponent:: ... decimal.InvalidOperation: x ** (non-integer) -You can combine :class:`Decimal` instances with integers, but not with +You can combine :class:`~decimal.Decimal` instances with integers, but not with floating-point numbers:: >>> a + 4 @@ -607,11 +607,11 @@ floating-point numbers:: TypeError: You can interact Decimal only with int, long or Decimal data types. >>> -:class:`Decimal` numbers can be used with the :mod:`math` and :mod:`cmath` +:class:`~decimal.Decimal` numbers can be used with the :mod:`math` and :mod:`cmath` modules, but note that they'll be immediately converted to floating-point numbers before the operation is performed, resulting in a possible loss of precision and accuracy. You'll also get back a regular floating-point number -and not a :class:`Decimal`. :: +and not a :class:`~decimal.Decimal`. :: >>> import math, cmath >>> d = decimal.Decimal('123456789012.345') @@ -620,32 +620,33 @@ and not a :class:`Decimal`. :: >>> cmath.sqrt(-d) 351364.18288201344j -:class:`Decimal` instances have a :meth:`sqrt` method that returns a -:class:`Decimal`, but if you need other things such as trigonometric functions +:class:`~decimal.Decimal` instances have a :meth:`~decimal.Decimal.sqrt` method that returns a +:class:`~decimal.Decimal`, but if you need other things such as trigonometric functions you'll have to implement them. :: >>> d.sqrt() Decimal("351364.1828820134592177245001") -The :class:`Context` type -------------------------- +The :class:`~decimal.Context` type +---------------------------------- -Instances of the :class:`Context` class encapsulate several settings for +Instances of the :class:`~decimal.Context` class encapsulate several settings for decimal operations: -* :attr:`prec` is the precision, the number of decimal places. +* :attr:`~decimal.Context.prec` is the precision, the number of decimal places. -* :attr:`rounding` specifies the rounding mode. The :mod:`decimal` module has - constants for the various possibilities: :const:`ROUND_DOWN`, - :const:`ROUND_CEILING`, :const:`ROUND_HALF_EVEN`, and various others. +* :attr:`~decimal.Context.rounding` specifies the rounding mode. The + :mod:`decimal` module has constants for the various possibilities: + :const:`~decimal.ROUND_DOWN`, :const:`~decimal.ROUND_CEILING`, + :const:`~decimal.ROUND_HALF_EVEN`, and various others. -* :attr:`traps` is a dictionary specifying what happens on encountering certain +* :attr:`~decimal.Context.traps` is a dictionary specifying what happens on encountering certain error conditions: either an exception is raised or a value is returned. Some examples of error conditions are division by zero, loss of precision, and overflow. -There's a thread-local default context available by calling :func:`getcontext`; +There's a thread-local default context available by calling :func:`~decimal.getcontext`; you can change the properties of this context to alter the default precision, rounding, or trap handling. The following example shows the effect of changing the precision of the default context:: @@ -671,8 +672,8 @@ raised:: Decimal("Infinity") >>> -The :class:`Context` instance also has various methods for formatting numbers -such as :meth:`to_eng_string` and :meth:`to_sci_string`. +The :class:`~decimal.Context` instance also has various methods for formatting numbers +such as :meth:`~decimal.Context.to_eng_string` and :meth:`~decimal.Context.to_sci_string`. For more information, see the documentation for the :mod:`decimal` module, which includes a quick-start tutorial and a reference. @@ -740,7 +741,7 @@ display conventions that are localized to a particular country or language. However, the module was careful to not change the numeric locale because various functions in Python's implementation required that the numeric locale remain set to the ``'C'`` locale. Often this was because the code was using the C -library's :c:func:`atof` function. +library's :c:func:`!atof` function. Not setting the numeric locale caused trouble for extensions that used third-party C libraries, however, because they wouldn't have the correct locale set. @@ -793,11 +794,11 @@ Here are all of the changes that Python 2.4 makes to the core Python language. :class:`dict` constructor. This includes any mapping, any iterable of key/value pairs, and keyword arguments. (Contributed by Raymond Hettinger.) -* The string methods :meth:`ljust`, :meth:`rjust`, and :meth:`center` now take +* The string methods :meth:`~str.ljust`, :meth:`~str.rjust`, and :meth:`~str.center` now take an optional argument for specifying a fill character other than a space. (Contributed by Raymond Hettinger.) -* Strings also gained an :meth:`rsplit` method that works like the :meth:`split` +* Strings also gained an :meth:`~str.rsplit` method that works like the :meth:`~str.split` method but splits from the end of the string. (Contributed by Sean Reifschneider.) :: @@ -807,13 +808,13 @@ Here are all of the changes that Python 2.4 makes to the core Python language. ['www.python', 'org'] * Three keyword parameters, *cmp*, *key*, and *reverse*, were added to the - :meth:`sort` method of lists. These parameters make some common usages of - :meth:`sort` simpler. All of these parameters are optional. + :meth:`~list.sort` method of lists. These parameters make some common usages of + :meth:`~list.sort` simpler. All of these parameters are optional. For the *cmp* parameter, the value should be a comparison function that takes two parameters and returns -1, 0, or +1 depending on how the parameters compare. This function will then be used to sort the list. Previously this was the only - parameter that could be provided to :meth:`sort`. + parameter that could be provided to :meth:`~list.sort`. *key* should be a single-parameter function that takes a list element and returns a comparison key for the element. The list is then sorted using the @@ -834,9 +835,9 @@ Here are all of the changes that Python 2.4 makes to the core Python language. The last example, which uses the *cmp* parameter, is the old way to perform a case-insensitive sort. It works but is slower than using a *key* parameter. - Using *key* calls :meth:`lower` method once for each element in the list while + Using *key* calls :meth:`~str.lower` method once for each element in the list while using *cmp* will call it twice for each comparison, so using *key* saves on - invocations of the :meth:`lower` method. + invocations of the :meth:`~str.lower` method. For simple key functions and comparison functions, it is often possible to avoid a :keyword:`lambda` expression by using an unbound method instead. For example, @@ -856,7 +857,7 @@ Here are all of the changes that Python 2.4 makes to the core Python language. age, resulting in a list sorted by age where people with the same age are in name-sorted order. - (All changes to :meth:`sort` contributed by Raymond Hettinger.) + (All changes to :meth:`~list.sort` contributed by Raymond Hettinger.) * There is a new built-in function ``sorted(iterable)`` that works like the in-place :meth:`list.sort` method but can be used in expressions. The @@ -891,8 +892,8 @@ Here are all of the changes that Python 2.4 makes to the core Python language. (Contributed by Raymond Hettinger.) -* Integer operations will no longer trigger an :exc:`OverflowWarning`. The - :exc:`OverflowWarning` warning will disappear in Python 2.5. +* Integer operations will no longer trigger an :exc:`!OverflowWarning`. The + :exc:`!OverflowWarning` warning will disappear in Python 2.5. * The interpreter gained a new switch, :option:`-m`, that takes a name, searches for the corresponding module on ``sys.path``, and runs the module as a script. @@ -904,7 +905,7 @@ Here are all of the changes that Python 2.4 makes to the core Python language. for the *locals* parameter. Previously this had to be a regular Python dictionary. (Contributed by Raymond Hettinger.) -* The :func:`zip` built-in function and :func:`itertools.izip` now return an +* The :func:`zip` built-in function and :func:`!itertools.izip` now return an empty list if called with no arguments. Previously they raised a :exc:`TypeError` exception. This makes them more suitable for use with variable length argument lists:: @@ -935,8 +936,8 @@ Optimizations * The inner loops for list and tuple slicing were optimized and now run about one-third faster. The inner loops for dictionaries were also optimized, - resulting in performance boosts for :meth:`keys`, :meth:`values`, :meth:`items`, - :meth:`iterkeys`, :meth:`itervalues`, and :meth:`iteritems`. (Contributed by + resulting in performance boosts for :meth:`~dict.keys`, :meth:`~dict.values`, :meth:`~dict.items`, + :meth:`!iterkeys`, :meth:`!itervalues`, and :meth:`!iteritems`. (Contributed by Raymond Hettinger.) * The machinery for growing and shrinking lists was optimized for speed and for @@ -948,11 +949,11 @@ Optimizations * :func:`list`, :func:`tuple`, :func:`map`, :func:`filter`, and :func:`zip` now run several times faster with non-sequence arguments that supply a - :meth:`__len__` method. (Contributed by Raymond Hettinger.) + :meth:`~object.__len__` method. (Contributed by Raymond Hettinger.) -* The methods :meth:`list.__getitem__`, :meth:`dict.__getitem__`, and - :meth:`dict.__contains__` are now implemented as :class:`method_descriptor` - objects rather than :class:`wrapper_descriptor` objects. This form of access +* The methods :meth:`!list.__getitem__`, :meth:`!dict.__getitem__`, and + :meth:`!dict.__contains__` are now implemented as :class:`!method_descriptor` + objects rather than :class:`!wrapper_descriptor` objects. This form of access doubles their performance and makes them more suitable for use as arguments to functionals: ``map(mydict.__getitem__, keylist)``. (Contributed by Raymond Hettinger.) @@ -968,7 +969,7 @@ Optimizations * String concatenations in statements of the form ``s = s + "abc"`` and ``s += "abc"`` are now performed more efficiently in certain circumstances. This optimization won't be present in other Python implementations such as Jython, so - you shouldn't rely on it; using the :meth:`join` method of strings is still + you shouldn't rely on it; using the :meth:`~str.join` method of strings is still recommended when you want to efficiently glue a large number of strings together. (Contributed by Armin Rigo.) @@ -1023,13 +1024,13 @@ complete list of changes, or look through the CVS logs for all the details. PCTP-154, and TIS-620. * The UTF-8 and UTF-16 codecs now cope better with receiving partial input. - Previously the :class:`StreamReader` class would try to read more data, making - it impossible to resume decoding from the stream. The :meth:`read` method will + Previously the :class:`~codecs.StreamReader` class would try to read more data, making + it impossible to resume decoding from the stream. The :meth:`~codecs.StreamReader.read` method will now return as much data as it can and future calls will resume decoding where previous ones left off. (Implemented by Walter Dörwald.) * There is a new :mod:`collections` module for various specialized collection - datatypes. Currently it contains just one type, :class:`deque`, a double-ended + datatypes. Currently it contains just one type, :class:`~collections.deque`, a double-ended queue that supports efficiently adding and removing elements from either end:: @@ -1048,7 +1049,7 @@ complete list of changes, or look through the CVS logs for all the details. >>> 'h' in d # search the deque True - Several modules, such as the :mod:`Queue` and :mod:`threading` modules, now take + Several modules, such as the :mod:`queue` and :mod:`threading` modules, now take advantage of :class:`collections.deque` for improved performance. (Contributed by Raymond Hettinger.) @@ -1058,49 +1059,49 @@ complete list of changes, or look through the CVS logs for all the details. isn't a string. (Contributed by John Belmonte and David Goodger.) * The :mod:`curses` module now supports the ncurses extension - :func:`use_default_colors`. On platforms where the terminal supports + :func:`~curses.use_default_colors`. On platforms where the terminal supports transparency, this makes it possible to use a transparent background. (Contributed by Jörg Lehmann.) -* The :mod:`difflib` module now includes an :class:`HtmlDiff` class that creates +* The :mod:`difflib` module now includes an :class:`~difflib.HtmlDiff` class that creates an HTML table showing a side by side comparison of two versions of a text. (Contributed by Dan Gass.) * The :mod:`email` package was updated to version 3.0, which dropped various deprecated APIs and removes support for Python versions earlier than 2.3. The 3.0 version of the package uses a new incremental parser for MIME messages, - available in the :mod:`email.FeedParser` module. The new parser doesn't require + available in the :mod:`!email.FeedParser` module. The new parser doesn't require reading the entire message into memory, and doesn't raise exceptions if a - message is malformed; instead it records any problems in the :attr:`defect` + message is malformed; instead it records any problems in the :attr:`!defect` attribute of the message. (Developed by Anthony Baxter, Barry Warsaw, Thomas Wouters, and others.) * The :mod:`heapq` module has been converted to C. The resulting tenfold improvement in speed makes the module suitable for handling high volumes of - data. In addition, the module has two new functions :func:`nlargest` and - :func:`nsmallest` that use heaps to find the N largest or smallest values in a + data. In addition, the module has two new functions :func:`~heapq.nlargest` and + :func:`~heapq.nsmallest` that use heaps to find the N largest or smallest values in a dataset without the expense of a full sort. (Contributed by Raymond Hettinger.) * The :mod:`httplib <http>` module now contains constants for HTTP status codes defined in various HTTP-related RFC documents. Constants have names such as - :const:`OK`, :const:`CREATED`, :const:`CONTINUE`, and - :const:`MOVED_PERMANENTLY`; use pydoc to get a full list. (Contributed by + :const:`!OK`, :const:`!CREATED`, :const:`!CONTINUE`, and + :const:`!MOVED_PERMANENTLY`; use pydoc to get a full list. (Contributed by Andrew Eland.) * The :mod:`imaplib` module now supports IMAP's THREAD command (contributed by - Yves Dionne) and new :meth:`deleteacl` and :meth:`myrights` methods (contributed - by Arnaud Mazin). + Yves Dionne) and new :meth:`~imaplib.IMAP4.deleteacl` and + :meth:`~imaplib.IMAP4.myrights` methods (contributed by Arnaud Mazin). * The :mod:`itertools` module gained a ``groupby(iterable[, *func*])`` function. *iterable* is something that can be iterated over to return a stream of elements, and the optional *func* parameter is a function that takes an element and returns a key value; if omitted, the key is simply the element - itself. :func:`groupby` then groups the elements into subsequences which have + itself. :func:`~itertools.groupby` then groups the elements into subsequences which have matching values of the key, and returns a series of 2-tuples containing the key value and an iterator over the subsequence. Here's an example to make this clearer. The *key* function simply returns - whether a number is even or odd, so the result of :func:`groupby` is to return + whether a number is even or odd, so the result of :func:`~itertools.groupby` is to return consecutive runs of odd or even numbers. :: >>> import itertools @@ -1115,8 +1116,8 @@ complete list of changes, or look through the CVS logs for all the details. 0 [12, 14] >>> - :func:`groupby` is typically used with sorted input. The logic for - :func:`groupby` is similar to the Unix ``uniq`` filter which makes it handy for + :func:`~itertools.groupby` is typically used with sorted input. The logic for + :func:`~itertools.groupby` is similar to the Unix ``uniq`` filter which makes it handy for eliminating, counting, or identifying duplicate elements:: >>> word = 'abracadabra' @@ -1153,22 +1154,22 @@ complete list of changes, or look through the CVS logs for all the details. >>> list(i2) # Run the second iterator to exhaustion [1, 2, 3] - Note that :func:`tee` has to keep copies of the values returned by the + Note that :func:`~itertools.tee` has to keep copies of the values returned by the iterator; in the worst case, it may need to keep all of them. This should therefore be used carefully if the leading iterator can run far ahead of the trailing iterator in a long stream of inputs. If the separation is large, then you might as well use :func:`list` instead. When the iterators track closely - with one another, :func:`tee` is ideal. Possible applications include + with one another, :func:`~itertools.tee` is ideal. Possible applications include bookmarking, windowing, or lookahead iterators. (Contributed by Raymond Hettinger.) * A number of functions were added to the :mod:`locale` module, such as - :func:`bind_textdomain_codeset` to specify a particular encoding and a family of + :func:`~locale.bind_textdomain_codeset` to specify a particular encoding and a family of :func:`!l\*gettext` functions that return messages in the chosen encoding. (Contributed by Gustavo Niemeyer.) * Some keyword arguments were added to the :mod:`logging` package's - :func:`basicConfig` function to simplify log configuration. The default + :func:`~logging.basicConfig` function to simplify log configuration. The default behavior is to log messages to standard error, but various keyword arguments can be specified to log to a particular file, change the logging format, or set the logging level. For example:: @@ -1179,10 +1180,10 @@ complete list of changes, or look through the CVS logs for all the details. format='%(levelname):%(process):%(thread):%(message)') Other additions to the :mod:`logging` package include a ``log(level, msg)`` - convenience method, as well as a :class:`TimedRotatingFileHandler` class that + convenience method, as well as a :class:`~logging.handlers.TimedRotatingFileHandler` class that rotates its log files at a timed interval. The module already had - :class:`RotatingFileHandler`, which rotated logs once the file exceeded a - certain size. Both classes derive from a new :class:`BaseRotatingHandler` class + :class:`~logging.handlers.RotatingFileHandler`, which rotated logs once the file exceeded a + certain size. Both classes derive from a new :class:`~logging.handlers.BaseRotatingHandler` class that can be used to implement other rotating handlers. (Changes implemented by Vinay Sajip.) @@ -1192,8 +1193,8 @@ complete list of changes, or look through the CVS logs for all the details. effect is to make :file:`.pyc` files significantly smaller. (Contributed by Martin von Löwis.) -* The :mod:`!nntplib` module's :class:`NNTP` class gained :meth:`description` and - :meth:`descriptions` methods to retrieve newsgroup descriptions for a single +* The :mod:`!nntplib` module's :class:`!NNTP` class gained :meth:`!description` and + :meth:`!descriptions` methods to retrieve newsgroup descriptions for a single group or for a range of groups. (Contributed by Jürgen A. Erhard.) * Two new functions were added to the :mod:`operator` module, @@ -1235,7 +1236,7 @@ complete list of changes, or look through the CVS logs for all the details. *path* is a symlink that points to a destination that doesn't exist. (Contributed by Beni Cherniavsky.) -* A new :func:`getsid` function was added to the :mod:`posix` module that +* A new :func:`~os.getsid` function was added to the :mod:`posix` module that underlies the :mod:`os` module. (Contributed by J. Raynor.) * The :mod:`poplib` module now supports POP over SSL. (Contributed by Hector @@ -1245,8 +1246,8 @@ complete list of changes, or look through the CVS logs for all the details. by Nick Bastin.) * The :mod:`random` module has a new method called ``getrandbits(N)`` that - returns a long integer *N* bits in length. The existing :meth:`randrange` - method now uses :meth:`getrandbits` where appropriate, making generation of + returns a long integer *N* bits in length. The existing :meth:`~random.randrange` + method now uses :meth:`~random.getrandbits` where appropriate, making generation of arbitrarily large random numbers more efficient. (Contributed by Raymond Hettinger.) @@ -1269,24 +1270,24 @@ complete list of changes, or look through the CVS logs for all the details. * The :mod:`signal` module now performs tighter error-checking on the parameters to the :func:`signal.signal` function. For example, you can't set a handler on - the :const:`SIGKILL` signal; previous versions of Python would quietly accept + the :const:`~signal.SIGKILL` signal; previous versions of Python would quietly accept this, but 2.4 will raise a :exc:`RuntimeError` exception. -* Two new functions were added to the :mod:`socket` module. :func:`socketpair` +* Two new functions were added to the :mod:`socket` module. :func:`~socket.socketpair` returns a pair of connected sockets and ``getservbyport(port)`` looks up the service name for a given port number. (Contributed by Dave Cole and Barry Warsaw.) -* The :func:`sys.exitfunc` function has been deprecated. Code should be using +* The :func:`!sys.exitfunc` function has been deprecated. Code should be using the existing :mod:`atexit` module, which correctly handles calling multiple exit - functions. Eventually :func:`sys.exitfunc` will become a purely internal + functions. Eventually :func:`!sys.exitfunc` will become a purely internal interface, accessed only by :mod:`atexit`. * The :mod:`tarfile` module now generates GNU-format tar files by default. (Contributed by Lars Gustäbel.) * The :mod:`threading` module now has an elegantly simple way to support - thread-local data. The module contains a :class:`local` class whose attribute + thread-local data. The module contains a :class:`~threading.local` class whose attribute values are local to different threads. :: import threading @@ -1295,8 +1296,8 @@ complete list of changes, or look through the CVS logs for all the details. data.number = 42 data.url = ('www.python.org', 80) - Other threads can assign and retrieve their own values for the :attr:`number` - and :attr:`url` attributes. You can subclass :class:`local` to initialize + Other threads can assign and retrieve their own values for the :attr:`!number` + and :attr:`!url` attributes. You can subclass :class:`~threading.local` to initialize attributes or to add methods. (Contributed by Jim Fulton.) * The :mod:`timeit` module now automatically disables periodic garbage @@ -1312,7 +1313,7 @@ complete list of changes, or look through the CVS logs for all the details. transmitting multiple XML-RPC calls in a single HTTP operation. (Contributed by Brian Quinlan.) -* The :mod:`mpz`, :mod:`rotor`, and :mod:`xreadlines` modules have been +* The :mod:`!mpz`, :mod:`!rotor`, and :mod:`!xreadlines` modules have been removed. .. ====================================================================== @@ -1336,7 +1337,7 @@ use the Mozilla or Lynx cookie files, and one that stores cookies in the same format as the Perl libwww library. :mod:`urllib2 <urllib.request>` has been changed to interact with :mod:`cookielib <http.cookiejar>`: -:class:`HTTPCookieProcessor` manages a cookie jar that is used when accessing +:class:`~urllib.request.HTTPCookieProcessor` manages a cookie jar that is used when accessing URLs. This module was contributed by John J. Lee. @@ -1352,7 +1353,7 @@ Loper and Tim Peters. Testing can still be as simple as running :func:`doctest.testmod`, but the refactorings allow customizing the module's operation in various ways -The new :class:`DocTestFinder` class extracts the tests from a given object's +The new :class:`~doctest.DocTestFinder` class extracts the tests from a given object's docstrings:: def f (x, y): @@ -1368,7 +1369,7 @@ docstrings:: # Get list of DocTest instances tests = finder.find(f) -The new :class:`DocTestRunner` class then runs individual tests and can produce +The new :class:`~doctest.DocTestRunner` class then runs individual tests and can produce a summary of the results:: runner = doctest.DocTestRunner() @@ -1385,10 +1386,10 @@ The above example produces the following output:: 2 passed and 0 failed. Test passed. -:class:`DocTestRunner` uses an instance of the :class:`OutputChecker` class to +:class:`~doctest.DocTestRunner` uses an instance of the :class:`~doctest.OutputChecker` class to compare the expected output with the actual output. This class takes a number of different flags that customize its behaviour; ambitious users can also write -a completely new subclass of :class:`OutputChecker`. +a completely new subclass of :class:`~doctest.OutputChecker`. The default output checker provides a number of handy features. For example, with the :const:`doctest.ELLIPSIS` option flag, an ellipsis (``...``) in the @@ -1465,7 +1466,7 @@ Some of the changes to Python's build process and to the C API are: lookups without masking exceptions raised during the look-up process. (Contributed by Raymond Hettinger.) -* The :c:expr:`Py_IS_NAN(X)` macro returns 1 if its float or double argument +* The :c:macro:`Py_IS_NAN` macro returns 1 if its float or double argument *X* is a NaN. (Contributed by Tim Peters.) * C code can avoid unnecessary locking by using the new @@ -1479,7 +1480,7 @@ Some of the changes to Python's build process and to the C API are: * A new method flag, :c:macro:`METH_COEXIST`, allows a function defined in slots to co-exist with a :c:type:`PyCFunction` having the same name. This can halve - the access time for a method such as :meth:`set.__contains__`. (Contributed by + the access time for a method such as :meth:`!set.__contains__`. (Contributed by Raymond Hettinger.) * Python can now be built with additional profiling for the interpreter itself, @@ -1493,7 +1494,7 @@ Some of the changes to Python's build process and to the C API are: register". (Contributed by Jeremy Hylton.) * The :c:type:`!tracebackobject` type has been renamed to - :c:type:`PyTracebackObject`. + :c:type:`!PyTracebackObject`. .. ====================================================================== @@ -1517,14 +1518,14 @@ code: trigger a :exc:`FutureWarning` and return a value limited to 32 or 64 bits; instead they return a long integer. -* Integer operations will no longer trigger an :exc:`OverflowWarning`. The - :exc:`OverflowWarning` warning will disappear in Python 2.5. +* Integer operations will no longer trigger an :exc:`!OverflowWarning`. The + :exc:`!OverflowWarning` warning will disappear in Python 2.5. -* The :func:`zip` built-in function and :func:`itertools.izip` now return an +* The :func:`zip` built-in function and :func:`!itertools.izip` now return an empty list instead of raising a :exc:`TypeError` exception if called with no arguments. -* You can no longer compare the :class:`date` and :class:`~datetime.datetime` instances +* You can no longer compare the :class:`~datetime.date` and :class:`~datetime.datetime` instances provided by the :mod:`datetime` module. Two instances of different classes will now always be unequal, and relative comparisons (``<``, ``>``) will raise a :exc:`TypeError`. @@ -1532,7 +1533,8 @@ code: * :func:`!dircache.listdir` now passes exceptions to the caller instead of returning empty lists. -* :func:`LexicalHandler.startDTD` used to receive the public and system IDs in +* :meth:`LexicalHandler.startDTD <xml.sax.handler.LexicalHandler.startDTD>` + used to receive the public and system IDs in the wrong order. This has been corrected; applications relying on the wrong order need to be fixed. @@ -1547,9 +1549,9 @@ code: * :const:`None` is now a constant; code that binds a new value to the name ``None`` is now a syntax error. -* The :func:`signals.signal` function now raises a :exc:`RuntimeError` exception +* The :func:`signal.signal` function now raises a :exc:`RuntimeError` exception for certain illegal values; previously these errors would pass silently. For - example, you can no longer set a handler on the :const:`SIGKILL` signal. + example, you can no longer set a handler on the :const:`~signal.SIGKILL` signal. .. ====================================================================== From b7e6f9bb85582e08e4610d4bc86b0c74d664a8d9 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 10 Jul 2026 13:37:10 +0200 Subject: [PATCH 649/818] [3.15] gh-153444: Fix compile warning in `Modules/_interpchannelsmodule.c` (GH-153445) (#153447) gh-153444: Fix compile warning in `Modules/_interpchannelsmodule.c` (GH-153445) (cherry picked from commit 33678dc79f00059aff09ac88f188ef2192031a85) Co-authored-by: sobolevn <mail@sobolevn.me> --- Modules/_interpchannelsmodule.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Modules/_interpchannelsmodule.c b/Modules/_interpchannelsmodule.c index 358d51cf13f1af..7b31b1f0c85d26 100644 --- a/Modules/_interpchannelsmodule.c +++ b/Modules/_interpchannelsmodule.c @@ -2935,7 +2935,8 @@ channelsmod_create(PyObject *self, PyObject *args, PyObject *kwds) int64_t cid = channel_create(&_globals.channels, defaults); if (cid < 0) { - (void)handle_channel_error(cid, self, cid); + // Negative `cid` can't be too big for a downcast: + (void)handle_channel_error((int)cid, self, cid); return NULL; } module_state *state = get_module_state(self); From 73f534c4adb64243fded8f94c9cd4768ce0a6046 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 10 Jul 2026 14:36:44 +0200 Subject: [PATCH 650/818] [3.15] gh-153438: Update NuGet download URL (GH-153482) (GH-153509) gh-153438: Update NuGet download URL (GH-153482) (cherry picked from commit 106eb532ea3b243423e62a702719e9d3c0e40c16) Co-authored-by: Harjoth Khara <harjoth.khara@gmail.com> --- Doc/using/windows.rst | 6 +++--- .../Build/2026-07-09-22-45-00.gh-issue-153438.Qr7N2p.rst | 2 ++ PCbuild/find_python.bat | 2 +- Tools/msi/get_externals.bat | 2 +- 4 files changed, 7 insertions(+), 5 deletions(-) create mode 100644 Misc/NEWS.d/next/Build/2026-07-09-22-45-00.gh-issue-153438.Qr7N2p.rst diff --git a/Doc/using/windows.rst b/Doc/using/windows.rst index 5b715d4614dad8..f75cf5b66c4388 100644 --- a/Doc/using/windows.rst +++ b/Doc/using/windows.rst @@ -1174,9 +1174,9 @@ on using nuget. What follows is a summary that is sufficient for Python developers. The ``nuget.exe`` command line tool may be downloaded directly from -``https://aka.ms/nugetclidl``, for example, using curl or PowerShell. With the -tool, the latest version of Python for 64-bit or 32-bit machines is installed -using:: +``https://dist.nuget.org/win-x86-commandline/latest/nuget.exe``, for example, +using curl or PowerShell. With the tool, the latest version of Python for +64-bit or 32-bit machines is installed using:: nuget.exe install python -ExcludeVersion -OutputDirectory . nuget.exe install pythonx86 -ExcludeVersion -OutputDirectory . diff --git a/Misc/NEWS.d/next/Build/2026-07-09-22-45-00.gh-issue-153438.Qr7N2p.rst b/Misc/NEWS.d/next/Build/2026-07-09-22-45-00.gh-issue-153438.Qr7N2p.rst new file mode 100644 index 00000000000000..edab8e6ba7b259 --- /dev/null +++ b/Misc/NEWS.d/next/Build/2026-07-09-22-45-00.gh-issue-153438.Qr7N2p.rst @@ -0,0 +1,2 @@ +Update Windows build and installer tooling and documentation to use the +current download URL for ``nuget.exe``. diff --git a/PCbuild/find_python.bat b/PCbuild/find_python.bat index deec9541cf0559..4824e89de41d69 100644 --- a/PCbuild/find_python.bat +++ b/PCbuild/find_python.bat @@ -55,7 +55,7 @@ @set _Py_HOST_PYTHON=%HOST_PYTHON% @if "%_Py_HOST_PYTHON%"=="" set _Py_HOST_PYTHON=py @if "%_Py_NUGET%"=="" (set _Py_NUGET=%_Py_EXTERNALS_DIR%\nuget.exe) -@if "%_Py_NUGET_URL%"=="" (set _Py_NUGET_URL=https://aka.ms/nugetclidl) +@if "%_Py_NUGET_URL%"=="" (set _Py_NUGET_URL=https://dist.nuget.org/win-x86-commandline/latest/nuget.exe) @if NOT exist "%_Py_NUGET%" ( @if not "%_Py_Quiet%"=="1" @echo Downloading nuget... @rem NB: Must use single quotes around NUGET here, NOT double! diff --git a/Tools/msi/get_externals.bat b/Tools/msi/get_externals.bat index f6602ce9588ff4..c7c7e9f470bc25 100644 --- a/Tools/msi/get_externals.bat +++ b/Tools/msi/get_externals.bat @@ -6,7 +6,7 @@ set HERE=%~dp0 if "%PCBUILD%"=="" (set PCBUILD=%HERE%..\..\PCbuild\) if "%EXTERNALS_DIR%"=="" (set EXTERNALS_DIR=%HERE%..\..\externals\windows-installer) if "%NUGET%"=="" (set NUGET=%EXTERNALS_DIR%\..\nuget.exe) -if "%NUGET_URL%"=="" (set NUGET_URL=https://aka.ms/nugetclidl) +if "%NUGET_URL%"=="" (set NUGET_URL=https://dist.nuget.org/win-x86-commandline/latest/nuget.exe) set DO_FETCH=true set DO_CLEAN=false From da999e638c03a05ed2b0f8a828f4013c7f9179bd Mon Sep 17 00:00:00 2001 From: Victor Stinner <vstinner@python.org> Date: Fri, 10 Jul 2026 17:18:14 +0200 Subject: [PATCH 651/818] [3.15] gh-152785: Upgrade Ubuntu from 24.04 to 26.04 in GitHub Actions (#152717) (#153416) gh-152785: Upgrade Ubuntu from 24.04 to 26.04 in GitHub Actions (#152717) * Replace "ubuntu-24.04" with "ubuntu-26.04". * Replace "ubuntu-latest" with "ubuntu-26.04" for Cross build Linux. * Replace "ubuntu-latest" with "ubuntu-slim" for small workloads. * Update ".github/actionlint.yaml" to allow "ubuntu-26.04" and "ubuntu-26.04-arm" images. * Install Ubuntu libmpdec-dev package, rather than installing libmpdec from source (tarball). * No longer run https://apt.llvm.org/llvm.sh, since ubuntu-26.04 provides clang-21 by default. (cherry picked from commit 4c79929705eb31959a6f4071cc34583de0737a28) Co-authored-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> --- .github/actionlint.yaml | 7 ++++++ .github/workflows/add-issue-header.yml | 2 +- .github/workflows/build.yml | 22 +++++++++---------- .github/workflows/jit.yml | 14 +++++------- .../workflows/new-bugs-announce-notifier.yml | 2 +- .github/workflows/posix-deps-apt.sh | 20 +++-------------- .github/workflows/require-pr-label.yml | 4 ++-- .github/workflows/reusable-docs.yml | 2 +- .github/workflows/reusable-emscripten.yml | 2 +- .github/workflows/reusable-san.yml | 11 ++-------- .github/workflows/reusable-ubuntu.yml | 2 +- .github/workflows/reusable-wasi.yml | 2 +- .github/workflows/stale.yml | 2 +- .github/workflows/tail-call.yml | 9 ++++---- .github/workflows/verify-expat.yml | 2 +- 15 files changed, 43 insertions(+), 60 deletions(-) diff --git a/.github/actionlint.yaml b/.github/actionlint.yaml index eacfff24889021..61ee08db9919bb 100644 --- a/.github/actionlint.yaml +++ b/.github/actionlint.yaml @@ -1,5 +1,12 @@ config-variables: null +# Pending release of actionlint > 1.7.12 for ubuntu-26.04* support: +# https://github.com/rhysd/actionlint/pull/683 +self-hosted-runner: + labels: + - ubuntu-26.04 + - ubuntu-26.04-arm + paths: .github/workflows/**/*.yml: ignore: diff --git a/.github/workflows/add-issue-header.yml b/.github/workflows/add-issue-header.yml index 4c25976b9c24f7..55eb6bf33b8128 100644 --- a/.github/workflows/add-issue-header.yml +++ b/.github/workflows/add-issue-header.yml @@ -17,7 +17,7 @@ permissions: jobs: add-header: - runs-on: ubuntu-latest + runs-on: ubuntu-slim permissions: issues: write timeout-minutes: 5 diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1203355512e5be..20753ef5601538 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -100,7 +100,7 @@ jobs: name: 'Check if Autoconf files are up to date' # Don't use ubuntu-latest but a specific version to make the job # reproducible: to get the same tools versions (autoconf, aclocal, ...) - runs-on: ubuntu-24.04 + runs-on: ubuntu-26.04 container: image: ghcr.io/python/autoconf:2025.01.02.12581854023 timeout-minutes: 60 @@ -143,7 +143,7 @@ jobs: name: 'Check if generated files are up to date' # Don't use ubuntu-latest but a specific version to make the job # reproducible: to get the same tools versions (autoconf, aclocal, ...) - runs-on: ubuntu-24.04 + runs-on: ubuntu-26.04 timeout-minutes: 60 needs: build-context if: needs.build-context.outputs.run-tests == 'true' @@ -286,18 +286,18 @@ jobs: - false - true os: - - ubuntu-24.04 - - ubuntu-24.04-arm + - ubuntu-26.04 + - ubuntu-26.04-arm exclude: # Do not test BOLT with free-threading, to conserve resources - bolt: true free-threading: true # BOLT currently crashes during instrumentation on aarch64 - - os: ubuntu-24.04-arm + - os: ubuntu-26.04-arm bolt: true include: # Enable CPU-intensive tests on ARM (default build only) - - os: ubuntu-24.04-arm + - os: ubuntu-26.04-arm bolt: false free-threading: false test-opts: '-u cpu' @@ -317,7 +317,7 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-24.04] + os: [ubuntu-26.04] ssllib: # See Tools/ssl/make_ssl_data.py for notes on adding a new version ## OpenSSL @@ -393,7 +393,7 @@ jobs: - arch: aarch64 runs-on: macos-26 - arch: x86_64 - runs-on: ubuntu-24.04 + runs-on: ubuntu-26.04 runs-on: ${{ matrix.runs-on }} steps: @@ -440,7 +440,7 @@ jobs: test-hypothesis: name: "Hypothesis tests on Ubuntu" - runs-on: ubuntu-24.04 + runs-on: ubuntu-26.04 timeout-minutes: 60 needs: build-context if: needs.build-context.outputs.run-ubuntu == 'true' @@ -551,7 +551,7 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-24.04] + os: [ubuntu-26.04] env: OPENSSL_VER: 3.5.7 PYTHONSTRICTEXTENSIONBUILD: 1 @@ -615,7 +615,7 @@ jobs: cross-build-linux: name: Cross build Linux - runs-on: ubuntu-latest + runs-on: ubuntu-26.04 timeout-minutes: 60 needs: build-context if: needs.build-context.outputs.run-ubuntu == 'true' diff --git a/.github/workflows/jit.yml b/.github/workflows/jit.yml index 46c08309b8e739..5dec4eb2307101 100644 --- a/.github/workflows/jit.yml +++ b/.github/workflows/jit.yml @@ -29,7 +29,7 @@ env: jobs: interpreter: name: Interpreter (Debug) - runs-on: ubuntu-24.04 + runs-on: ubuntu-26.04 timeout-minutes: 60 steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 @@ -145,9 +145,9 @@ jobs: - false include: - target: x86_64-unknown-linux-gnu/gcc - runner: ubuntu-24.04 + runner: ubuntu-26.04 - target: aarch64-unknown-linux-gnu/gcc - runner: ubuntu-24.04-arm + runner: ubuntu-26.04-arm steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: @@ -160,8 +160,7 @@ jobs: sudo ./.github/workflows/posix-deps-apt.sh - name: Build run: | - sudo bash -c "$(wget -O - https://apt.llvm.org/llvm.sh)" ./llvm.sh ${{ env.LLVM_VERSION }} - export PATH="$(llvm-config-${{ env.LLVM_VERSION }} --bindir):$PATH" + # On ubuntu-26.04 image, clang is clang-21 by default ./configure --enable-experimental-jit ${{ matrix.debug && '--with-pydebug' || '' }} make all --jobs 4 - name: Test @@ -171,7 +170,7 @@ jobs: linux-extras: name: ${{ matrix.name }} - runs-on: ubuntu-24.04 + runs-on: ubuntu-26.04 timeout-minutes: 60 strategy: fail-fast: false @@ -202,8 +201,7 @@ jobs: sudo ./.github/workflows/posix-deps-apt.sh - name: Build run: | - sudo bash -c "$(wget -O - https://apt.llvm.org/llvm.sh)" ./llvm.sh ${{ env.LLVM_VERSION }} - export PATH="$(llvm-config-${{ env.LLVM_VERSION }} --bindir):$PATH" + # On ubuntu-26.04 image, clang is clang-21 by default if [ "${{ matrix.use_clang }}" = "true" ]; then export CC=clang-${{ env.LLVM_VERSION }} fi diff --git a/.github/workflows/new-bugs-announce-notifier.yml b/.github/workflows/new-bugs-announce-notifier.yml index 1267361040c81b..8727be73f9ebd6 100644 --- a/.github/workflows/new-bugs-announce-notifier.yml +++ b/.github/workflows/new-bugs-announce-notifier.yml @@ -10,7 +10,7 @@ permissions: jobs: notify-new-bugs-announce: - runs-on: ubuntu-latest + runs-on: ubuntu-slim permissions: issues: read timeout-minutes: 10 diff --git a/.github/workflows/posix-deps-apt.sh b/.github/workflows/posix-deps-apt.sh index 6201e719ca87de..803204635abfe1 100755 --- a/.github/workflows/posix-deps-apt.sh +++ b/.github/workflows/posix-deps-apt.sh @@ -5,37 +5,23 @@ apt-get -yq --no-install-recommends install \ build-essential \ pkg-config \ cmake \ + curl \ gdb \ lcov \ libb2-dev \ libbz2-dev \ libffi-dev \ - libgdbm-dev \ libgdbm-compat-dev \ + libgdbm-dev \ liblzma-dev \ + libmpdec-dev \ libncurses5-dev \ libreadline6-dev \ libsqlite3-dev \ libssl-dev \ libzstd-dev \ - lzma \ - lzma-dev \ strace \ tk-dev \ uuid-dev \ xvfb \ zlib1g-dev - -# Workaround missing libmpdec-dev on ubuntu 24.04 by building mpdecimal -# from source. ppa:ondrej/php (launchpad.net) are unreliable -# (https://status.canonical.com) so fetch the tarball directly -# from the upstream host. -# https://www.bytereef.org/mpdecimal/ -MPDECIMAL_VERSION=4.0.1 -curl -fsSL "https://www.bytereef.org/software/mpdecimal/releases/mpdecimal-${MPDECIMAL_VERSION}.tar.gz" \ - | tar -xz -C /tmp -(cd "/tmp/mpdecimal-${MPDECIMAL_VERSION}" \ - && ./configure --prefix=/usr/local \ - && make -j"$(nproc)" \ - && make install) -ldconfig diff --git a/.github/workflows/require-pr-label.yml b/.github/workflows/require-pr-label.yml index f3e2666879530f..8af254c10786e1 100644 --- a/.github/workflows/require-pr-label.yml +++ b/.github/workflows/require-pr-label.yml @@ -11,7 +11,7 @@ jobs: label-dnm: name: DO-NOT-MERGE if: github.repository_owner == 'python' - runs-on: ubuntu-latest + runs-on: ubuntu-slim permissions: pull-requests: read timeout-minutes: 10 @@ -28,7 +28,7 @@ jobs: label-reviews: name: Unresolved review if: github.repository_owner == 'python' - runs-on: ubuntu-latest + runs-on: ubuntu-slim permissions: pull-requests: read timeout-minutes: 10 diff --git a/.github/workflows/reusable-docs.yml b/.github/workflows/reusable-docs.yml index 50d61ef20c6594..abc82f5463eb4e 100644 --- a/.github/workflows/reusable-docs.yml +++ b/.github/workflows/reusable-docs.yml @@ -106,7 +106,7 @@ jobs: # Run "doctest" on HEAD as new syntax doesn't exist in the latest stable release doctest: name: 'Doctest' - runs-on: ubuntu-24.04 + runs-on: ubuntu-26.04 timeout-minutes: 60 steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 diff --git a/.github/workflows/reusable-emscripten.yml b/.github/workflows/reusable-emscripten.yml index 38e6dcceb8f47c..c14a41b5682877 100644 --- a/.github/workflows/reusable-emscripten.yml +++ b/.github/workflows/reusable-emscripten.yml @@ -12,7 +12,7 @@ env: jobs: build-emscripten-reusable: name: 'build and test' - runs-on: ubuntu-24.04 + runs-on: ubuntu-26.04 timeout-minutes: 40 steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 diff --git a/.github/workflows/reusable-san.yml b/.github/workflows/reusable-san.yml index 2efa9e781033bd..87a3548377476d 100644 --- a/.github/workflows/reusable-san.yml +++ b/.github/workflows/reusable-san.yml @@ -27,7 +27,7 @@ jobs: && ' (free-threading)' || '' }} - runs-on: ubuntu-24.04 + runs-on: ubuntu-26.04 timeout-minutes: 60 steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 @@ -38,14 +38,7 @@ jobs: - name: Install dependencies run: | sudo ./.github/workflows/posix-deps-apt.sh - # Install clang - wget https://apt.llvm.org/llvm.sh - chmod +x llvm.sh - sudo ./llvm.sh 21 - sudo update-alternatives --install /usr/bin/clang clang /usr/bin/clang-21 100 - sudo update-alternatives --set clang /usr/bin/clang-21 - sudo update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-21 100 - sudo update-alternatives --set clang++ /usr/bin/clang++-21 + # On ubuntu-26.04 image, clang is clang-21 by default echo "CC=clang" >> "$GITHUB_ENV" echo "CXX=clang++" >> "$GITHUB_ENV" - name: TSan option setup diff --git a/.github/workflows/reusable-ubuntu.yml b/.github/workflows/reusable-ubuntu.yml index 564ad024ec1f8a..8de71941c1b115 100644 --- a/.github/workflows/reusable-ubuntu.yml +++ b/.github/workflows/reusable-ubuntu.yml @@ -49,7 +49,7 @@ jobs: - name: Install Clang and BOLT if: ${{ fromJSON(inputs.bolt-optimizations) }} run: | - sudo bash -c "$(wget -O - https://apt.llvm.org/llvm.sh)" ./llvm.sh 21 + # On ubuntu-26.04 image, LLVM is LLVM-21 by default sudo apt-get install --no-install-recommends bolt-21 echo PATH="$(llvm-config-21 --bindir):$PATH" >> $GITHUB_ENV - name: Configure OpenSSL env vars diff --git a/.github/workflows/reusable-wasi.yml b/.github/workflows/reusable-wasi.yml index 4b4888c3844409..2643b438c2a7a8 100644 --- a/.github/workflows/reusable-wasi.yml +++ b/.github/workflows/reusable-wasi.yml @@ -12,7 +12,7 @@ env: jobs: build-wasi-reusable: name: 'build and test' - runs-on: ubuntu-24.04-arm + runs-on: ubuntu-26.04-arm timeout-minutes: 60 env: WASMTIME_VERSION: 38.0.3 diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 01fe5ba8fda8bc..32f7c19f8a4cb7 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -10,7 +10,7 @@ permissions: jobs: stale: if: github.repository_owner == 'python' - runs-on: ubuntu-latest + runs-on: ubuntu-slim permissions: actions: write pull-requests: write diff --git a/.github/workflows/tail-call.yml b/.github/workflows/tail-call.yml index a86a313524605b..c1242a8d79f4bb 100644 --- a/.github/workflows/tail-call.yml +++ b/.github/workflows/tail-call.yml @@ -66,13 +66,13 @@ jobs: matrix: include: - target: x86_64-unknown-linux-gnu/gcc - runner: ubuntu-24.04 + runner: ubuntu-26.04 configure_flags: --with-pydebug - target: x86_64-unknown-linux-gnu/gcc-free-threading - runner: ubuntu-24.04 + runner: ubuntu-26.04 configure_flags: --disable-gil - target: aarch64-unknown-linux-gnu/gcc - runner: ubuntu-24.04-arm + runner: ubuntu-26.04-arm configure_flags: --with-pydebug steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 @@ -83,8 +83,7 @@ jobs: python-version: '3.11' - name: Build run: | - sudo bash -c "$(wget -O - https://apt.llvm.org/llvm.sh)" ./llvm.sh ${{ env.LLVM_VERSION }} - export PATH="$(llvm-config-${{ env.LLVM_VERSION }} --bindir):$PATH" + # On ubuntu-26.04 image, clang is clang-21 by default CC=clang-${{ env.LLVM_VERSION }} ./configure --with-tail-call-interp ${{ matrix.configure_flags }} make all --jobs 4 - name: Test diff --git a/.github/workflows/verify-expat.yml b/.github/workflows/verify-expat.yml index 472a11db2da5fb..158e8f10377cad 100644 --- a/.github/workflows/verify-expat.yml +++ b/.github/workflows/verify-expat.yml @@ -20,7 +20,7 @@ concurrency: jobs: verify: - runs-on: ubuntu-latest + runs-on: ubuntu-slim timeout-minutes: 5 steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 From dc448f3d1a2bfc6ea18e3b5a87f5bd9eb1023964 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 10 Jul 2026 18:46:45 +0200 Subject: [PATCH 652/818] [3.15] gh-153062: Fix a crash iterating itertools.tee on the free-threaded build (gh-153063) (gh-153475) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit itertools.tee branches share a linked list of teedataobject cells. On the free-threaded build, iterating one branch from multiple threads, or iterating sibling branches concurrently, raced on the shared cells and each branch's position, corrupting refcounts and crashing. Lock each teedataobject while reading, extending, or clearing it, and snapshot each branch's position under the tee object's own lock, revalidating before advancing, so the two locks are never nested. Concurrent iteration of one tee is undefined and may raise RuntimeError as documented, but no longer crashes. The free-threading snapshot and revalidation add per-element overhead on the default build, where the GIL already serializes access. Guard that path under Py_GIL_DISABLED so the default build keeps the original iteration and the free-threaded path is unchanged. (cherry picked from commit 6c389c446e487bcb9d09e85de30aa42052990f1c) Co-authored-by: tonghuaroot (童话) <tonghuaroot@gmail.com> Co-authored-by: Neil Schemenauer <nas-github@arctrix.com> --- .../test_free_threading/test_itertools.py | 88 +++++++++++++++++-- ...-07-05-14-30-00.gh-issue-153062.teeFT1.rst | 2 + Modules/itertoolsmodule.c | 82 +++++++++++++++-- 3 files changed, 157 insertions(+), 15 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-07-05-14-30-00.gh-issue-153062.teeFT1.rst diff --git a/Lib/test/test_free_threading/test_itertools.py b/Lib/test/test_free_threading/test_itertools.py index 670d4ca8835e0d..7392bd739acd70 100644 --- a/Lib/test/test_free_threading/test_itertools.py +++ b/Lib/test/test_free_threading/test_itertools.py @@ -1,5 +1,14 @@ import unittest -from itertools import accumulate, batched, chain, combinations_with_replacement, cycle, permutations, zip_longest +from itertools import ( + accumulate, + batched, + chain, + combinations_with_replacement, + cycle, + permutations, + tee, + zip_longest, +) from test.support import threading_helper @@ -15,20 +24,23 @@ def work_iterator(it): class ItertoolsThreading(unittest.TestCase): - @threading_helper.reap_threads def test_accumulate(self): number_of_iterations = 10 for _ in range(number_of_iterations): it = accumulate(tuple(range(40))) - threading_helper.run_concurrently(work_iterator, nthreads=10, args=[it]) + threading_helper.run_concurrently( + work_iterator, nthreads=10, args=[it] + ) @threading_helper.reap_threads def test_batched(self): number_of_iterations = 10 for _ in range(number_of_iterations): it = batched(tuple(range(1000)), 2) - threading_helper.run_concurrently(work_iterator, nthreads=10, args=[it]) + threading_helper.run_concurrently( + work_iterator, nthreads=10, args=[it] + ) @threading_helper.reap_threads def test_cycle(self): @@ -46,28 +58,88 @@ def test_chain(self): number_of_iterations = 10 for _ in range(number_of_iterations): it = chain(*[(1,)] * 200) - threading_helper.run_concurrently(work_iterator, nthreads=6, args=[it]) + threading_helper.run_concurrently( + work_iterator, nthreads=6, args=[it] + ) @threading_helper.reap_threads def test_combinations_with_replacement(self): number_of_iterations = 6 for _ in range(number_of_iterations): it = combinations_with_replacement(tuple(range(2)), 2) - threading_helper.run_concurrently(work_iterator, nthreads=6, args=[it]) + threading_helper.run_concurrently( + work_iterator, nthreads=6, args=[it] + ) @threading_helper.reap_threads def test_permutations(self): number_of_iterations = 6 for _ in range(number_of_iterations): it = permutations(tuple(range(4)), 2) - threading_helper.run_concurrently(work_iterator, nthreads=6, args=[it]) + threading_helper.run_concurrently( + work_iterator, nthreads=6, args=[it] + ) @threading_helper.reap_threads def test_zip_longest(self): number_of_iterations = 10 for _ in range(number_of_iterations): it = zip_longest(list(range(4)), list(range(8)), fillvalue=0) - threading_helper.run_concurrently(work_iterator, nthreads=10, args=[it]) + threading_helper.run_concurrently( + work_iterator, nthreads=10, args=[it] + ) + + +class TestTeeConcurrent(unittest.TestCase): + # itertools.tee branches share a linked list of internal data cells. + # Concurrent iteration must not corrupt that shared state or crash the + # free-threaded build. A crash shows up as the interpreter dying (not as a + # caught exception); tee is documented as not thread-safe, so a + # ``RuntimeError`` from the re-entrancy guard is an allowed outcome and is + # tolerated here. + + def test_same_branch(self): + # Many threads consume the same tee branch. + errors = [] + + def consume(it): + try: + for _ in it: + pass + except RuntimeError: + pass + except Exception as e: + errors.append(e) + + for _ in range(100): + a, _ = tee(iter(range(2000)), 2) + threading_helper.run_concurrently(consume, nthreads=8, args=(a,)) + + self.assertEqual(errors, [], msg=f"unexpected errors: {errors}") + + def test_sibling_branches(self): + # Each thread consumes a different sibling branch of the same tee. + errors = [] + + def make_worker(it): + def consume(): + try: + for _ in it: + pass + except RuntimeError: + pass + except Exception as e: + errors.append(e) + + return consume + + for _ in range(100): + branches = tee(iter(range(4000)), 8) + threading_helper.run_concurrently( + [make_worker(it) for it in branches] + ) + + self.assertEqual(errors, [], msg=f"unexpected errors: {errors}") if __name__ == "__main__": diff --git a/Misc/NEWS.d/next/Library/2026-07-05-14-30-00.gh-issue-153062.teeFT1.rst b/Misc/NEWS.d/next/Library/2026-07-05-14-30-00.gh-issue-153062.teeFT1.rst new file mode 100644 index 00000000000000..ed1aaa15d37bd9 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-05-14-30-00.gh-issue-153062.teeFT1.rst @@ -0,0 +1,2 @@ +Fix a crash when concurrently iterating an :func:`itertools.tee` iterator on +the free-threaded build. diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c index 0dd31dfbc5a346..72bfab1abaf9ca 100644 --- a/Modules/itertoolsmodule.c +++ b/Modules/itertoolsmodule.c @@ -768,13 +768,17 @@ teedataobject_newinternal(itertools_state *state, PyObject *it) static PyObject * teedataobject_jumplink(itertools_state *state, teedataobject *tdo) { + PyObject *link; + Py_BEGIN_CRITICAL_SECTION(tdo); if (tdo->nextlink == NULL) tdo->nextlink = teedataobject_newinternal(state, tdo->it); - return Py_XNewRef(tdo->nextlink); + link = Py_XNewRef(tdo->nextlink); + Py_END_CRITICAL_SECTION(); + return link; } static PyObject * -teedataobject_getitem(teedataobject *tdo, int i) +teedataobject_getitem_lock_held(teedataobject *tdo, int i) { PyObject *value; @@ -800,6 +804,16 @@ teedataobject_getitem(teedataobject *tdo, int i) return Py_NewRef(value); } +static PyObject * +teedataobject_getitem(teedataobject *tdo, int i) +{ + PyObject *result; + Py_BEGIN_CRITICAL_SECTION(tdo); + result = teedataobject_getitem_lock_held(tdo, i); + Py_END_CRITICAL_SECTION(); + return result; +} + static int teedataobject_traverse(PyObject *op, visitproc visit, void * arg) { @@ -819,8 +833,11 @@ teedataobject_safe_decref(PyObject *obj) { while (obj && _PyObject_IsUniquelyReferenced(obj)) { teedataobject *tmp = teedataobject_CAST(obj); - PyObject *nextlink = tmp->nextlink; + PyObject *nextlink; + Py_BEGIN_CRITICAL_SECTION(obj); + nextlink = tmp->nextlink; tmp->nextlink = NULL; + Py_END_CRITICAL_SECTION(); Py_SETREF(obj, nextlink); } Py_XDECREF(obj); @@ -833,11 +850,13 @@ teedataobject_clear(PyObject *op) PyObject *tmp; teedataobject *tdo = teedataobject_CAST(op); + Py_BEGIN_CRITICAL_SECTION(op); Py_CLEAR(tdo->it); for (i=0 ; i<tdo->numread ; i++) Py_CLEAR(tdo->values[i]); tmp = tdo->nextlink; tdo->nextlink = NULL; + Py_END_CRITICAL_SECTION(); teedataobject_safe_decref(tmp); return 0; } @@ -930,20 +949,67 @@ static PyObject * tee_next(PyObject *op) { teeobject *to = teeobject_CAST(op); - PyObject *value, *link; + PyObject *value; +#ifndef Py_GIL_DISABLED + /* The GIL already serializes access, so keep the simple path without the + snapshot and revalidation that the free-threaded build needs. */ if (to->index >= LINKCELLS) { - link = teedataobject_jumplink(to->state, to->dataobj); - if (link == NULL) + PyObject *link = teedataobject_jumplink(to->state, to->dataobj); + if (link == NULL) { return NULL; + } Py_SETREF(to->dataobj, (teedataobject *)link); to->index = 0; } value = teedataobject_getitem(to->dataobj, to->index); - if (value == NULL) + if (value == NULL) { return NULL; + } to->index++; return value; +#else + for (;;) { + teedataobject *dataobj; + int index; + + /* Snapshot the branch position (strong ref to the shared data object) + under the tee lock; the data object is locked separately, not nested, + then the advance is revalidated. */ + Py_BEGIN_CRITICAL_SECTION(op); + dataobj = (teedataobject *)Py_NewRef((PyObject *)to->dataobj); + index = to->index; + Py_END_CRITICAL_SECTION(); + + if (index < LINKCELLS) { + value = teedataobject_getitem(dataobj, index); + if (value != NULL) { + Py_BEGIN_CRITICAL_SECTION(op); + if (to->dataobj == dataobj && to->index == index) { + to->index = index + 1; + } + Py_END_CRITICAL_SECTION(); + } + Py_DECREF(dataobj); + return value; + } + + PyObject *link = teedataobject_jumplink(to->state, dataobj); + if (link == NULL) { + Py_DECREF(dataobj); + return NULL; + } + Py_BEGIN_CRITICAL_SECTION(op); + if (to->dataobj == dataobj) { + Py_SETREF(to->dataobj, (teedataobject *)link); + to->index = 0; + link = NULL; + } + Py_END_CRITICAL_SECTION(); + Py_XDECREF(link); + Py_DECREF(dataobj); + } +#endif } static int @@ -962,8 +1028,10 @@ tee_copy_impl(teeobject *to) if (newto == NULL) { return NULL; } + Py_BEGIN_CRITICAL_SECTION(to); newto->dataobj = (teedataobject *)Py_NewRef(to->dataobj); newto->index = to->index; + Py_END_CRITICAL_SECTION(); newto->weakreflist = NULL; newto->state = to->state; PyObject_GC_Track(newto); From 855c4ed27ffb21ec0ccb39cdd898b86837d6c6bc Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 10 Jul 2026 18:55:15 +0200 Subject: [PATCH 653/818] [3.15] gh-151213: Fix asyncio tools permission requirements link (GH-153493) (GH-153518) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (cherry picked from commit b276b88e385d7785bfc11d87fa56163e984ba699) Co-authored-by: Bartosz Sławecki <bartosz@ilikepython.com> --- Doc/library/asyncio-tools.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/asyncio-tools.rst b/Doc/library/asyncio-tools.rst index 1782640e83f53a..a6353f0618c941 100644 --- a/Doc/library/asyncio-tools.rst +++ b/Doc/library/asyncio-tools.rst @@ -24,7 +24,7 @@ The following commands inspect the process identified by ``PID``: The commands read the target process state without executing any code in it. They are only available on supported platforms and may require permission to -inspect another process. See the :ref:`permission-requirements <permission-requirements>` for details. +inspect another process. See the :ref:`permission requirements <permission-requirements>` for details. .. seealso:: From 3e776ee2a7ea7223d76416c972c29beca83516d4 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 10 Jul 2026 21:27:41 +0200 Subject: [PATCH 654/818] [3.15] gh-152216: Update bundled expat to 2.8.2 (GH-152234) (#153524) gh-152216: Update bundled expat to 2.8.2 (GH-152234) * Update bundled expat to 2.8.2 * `make regen-sbom` * Update download URL * Drop warnings (yay!) (cherry picked from commit c22e9c9daef4d97a3fdf1d41a119947ed46ad937) Co-authored-by: Stan Ulbrych <stan@python.org> --- Makefile.pre.in | 3 + ...-06-25-20-44-20.gh-issue-152216.VxiK5y.rst | 1 + Misc/sbom.spdx.json | 85 +- Modules/expat/expat.h | 2 +- Modules/expat/fallthrough.h | 49 + Modules/expat/memory_sanitizer.h | 51 + Modules/expat/refresh.sh | 9 +- Modules/expat/siphash.h | 15 +- Modules/expat/xcsinc.c | 48 + Modules/expat/xmlparse.c | 1208 +++++++++-------- Modules/expat/xmltok.c | 6 +- Modules/expat/xmltok_impl.c | 21 +- PCbuild/_elementtree.vcxproj | 2 + PCbuild/_elementtree.vcxproj.filters | 6 + PCbuild/pyexpat.vcxproj | 2 + PCbuild/pyexpat.vcxproj.filters | 6 + Tools/build/.warningignore_macos | 4 - 17 files changed, 928 insertions(+), 590 deletions(-) create mode 100644 Misc/NEWS.d/next/Security/2026-06-25-20-44-20.gh-issue-152216.VxiK5y.rst create mode 100644 Modules/expat/fallthrough.h create mode 100644 Modules/expat/memory_sanitizer.h create mode 100644 Modules/expat/xcsinc.c diff --git a/Makefile.pre.in b/Makefile.pre.in index e411160d3ba842..c28207414042a2 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -659,13 +659,16 @@ LIBEXPAT_HEADERS= \ Modules/expat/expat.h \ Modules/expat/expat_config.h \ Modules/expat/expat_external.h \ + Modules/expat/fallthrough.h \ Modules/expat/iasciitab.h \ Modules/expat/internal.h \ Modules/expat/latin1tab.h \ + Modules/expat/memory_sanitizer.h \ Modules/expat/nametab.h \ Modules/expat/pyexpatns.h \ Modules/expat/siphash.h \ Modules/expat/utf8tab.h \ + Modules/expat/xcsinc.c \ Modules/expat/xmlrole.h \ Modules/expat/xmltok.h \ Modules/expat/xmltok_impl.h \ diff --git a/Misc/NEWS.d/next/Security/2026-06-25-20-44-20.gh-issue-152216.VxiK5y.rst b/Misc/NEWS.d/next/Security/2026-06-25-20-44-20.gh-issue-152216.VxiK5y.rst new file mode 100644 index 00000000000000..2769048e001d69 --- /dev/null +++ b/Misc/NEWS.d/next/Security/2026-06-25-20-44-20.gh-issue-152216.VxiK5y.rst @@ -0,0 +1 @@ +Update bundled `libexpat <https://libexpat.github.io/>`_ to version 2.8.2. diff --git a/Misc/sbom.spdx.json b/Misc/sbom.spdx.json index 1eca892fb12ace..2a6d7a6384882d 100644 --- a/Misc/sbom.spdx.json +++ b/Misc/sbom.spdx.json @@ -48,11 +48,11 @@ "checksums": [ { "algorithm": "SHA1", - "checksumValue": "58101ef0951568acadd3117033bef084fea24cc1" + "checksumValue": "00c5e72b384f5c305be613729184ad37bb491238" }, { "algorithm": "SHA256", - "checksumValue": "52d756026bf09befdb211c453e2009a646d6c6b519e6885e971b2550396619fb" + "checksumValue": "eb43180fbdca40e36d9558060e6e654ef4c451ca656ad679e9e1269eb45456b3" } ], "fileName": "Modules/expat/expat.h" @@ -71,6 +71,20 @@ ], "fileName": "Modules/expat/expat_external.h" }, + { + "SPDXID": "SPDXRef-FILE-Modules-expat-fallthrough.h", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "69db5031480c50a1e35a51190bd64fcb816b6caf" + }, + { + "algorithm": "SHA256", + "checksumValue": "3dac2e4fdec819ede1b081ef776f2421c98ab509f69d5647a21d63d651179df2" + } + ], + "fileName": "Modules/expat/fallthrough.h" + }, { "SPDXID": "SPDXRef-FILE-Modules-expat-iasciitab.h", "checksums": [ @@ -113,6 +127,20 @@ ], "fileName": "Modules/expat/latin1tab.h" }, + { + "SPDXID": "SPDXRef-FILE-Modules-expat-memory-sanitizer.h", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "abdf1b9e9642176466ecbb77d5f48e502d01d0d8" + }, + { + "algorithm": "SHA256", + "checksumValue": "10c66f1cf9dc28608d57cb19adc8c7c654800e8b5b1b9be176eaed802deca2d9" + } + ], + "fileName": "Modules/expat/memory_sanitizer.h" + }, { "SPDXID": "SPDXRef-FILE-Modules-expat-nametab.h", "checksums": [ @@ -132,11 +160,11 @@ "checksums": [ { "algorithm": "SHA1", - "checksumValue": "aca27f46d9fd387b63ce7ff2e4f172cad130b39b" + "checksumValue": "6648f9c12a8d6f77a6eab5ef5c7caa976e7549aa" }, { "algorithm": "SHA256", - "checksumValue": "f537add526ecda8389503b7ef45fb52b6217e4dc171dcc3a8dc6903ff6134726" + "checksumValue": "c1be28dd62282e668d4daedfe756edb68b7da165c442202bb06a9e597cd5c289" } ], "fileName": "Modules/expat/siphash.h" @@ -169,16 +197,30 @@ ], "fileName": "Modules/expat/winconfig.h" }, + { + "SPDXID": "SPDXRef-FILE-Modules-expat-xcsinc.c", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "69fa7a25f555164f089fdcf290f3af6a1731621f" + }, + { + "algorithm": "SHA256", + "checksumValue": "071345c5ccfbe2e46a02839331ee60ee20048348b4408964bff48c4355473b9e" + } + ], + "fileName": "Modules/expat/xcsinc.c" + }, { "SPDXID": "SPDXRef-FILE-Modules-expat-xmlparse.c", "checksums": [ { "algorithm": "SHA1", - "checksumValue": "1dad2ab196cdbe37572674c465bd9187fdbe4495" + "checksumValue": "a5a5dd44ee8eeb73f42fa42ca1499cd282ddf6a6" }, { "algorithm": "SHA256", - "checksumValue": "740137e670d2f3b7269364ffb6f60064e6560091850c5d6f2c3bb1b8ca6e3dd1" + "checksumValue": "5d2c99b576744edd9545cefe613e0577617f57e16c86387edc13d45710dc97d2" } ], "fileName": "Modules/expat/xmlparse.c" @@ -216,11 +258,11 @@ "checksums": [ { "algorithm": "SHA1", - "checksumValue": "63e4766a09e63760c6518670509198f8d638f4ad" + "checksumValue": "08dba893b34338e64b66f1044f542aa6760dbab1" }, { "algorithm": "SHA256", - "checksumValue": "0ad3f915f2748dc91bf4e4b4a50cf40bf2c95769d0eca7e3b293a230d82bb779" + "checksumValue": "0c842b1876503e699517994317805dd2298d9e11c94dcc87c2ecb6c2b8e00bc0" } ], "fileName": "Modules/expat/xmltok.c" @@ -244,11 +286,11 @@ "checksums": [ { "algorithm": "SHA1", - "checksumValue": "7756f7c0d3625ae7dde6cf7d386685ffacb57c7e" + "checksumValue": "3ccb9335589c3ff60aae50ac79b2cdac57999bee" }, { "algorithm": "SHA256", - "checksumValue": "a3fe18ff32b21fbcb7c190895c68158404e1b9fb449db6431bc08b261dc03938" + "checksumValue": "94eeaef9ed46d10f80f748924fbf41f950b4859d6f234f61fdb2c8f1a8e77bd1" } ], "fileName": "Modules/expat/xmltok_impl.c" @@ -1730,14 +1772,14 @@ "checksums": [ { "algorithm": "SHA256", - "checksumValue": "a52eb72108be160e190b5cafa5bba8663f1313f2013e26060d1c18e26e31067b" + "checksumValue": "ef7d1994f533c9e7343d6c19f31064fc8ebbcbcaa144be3812b4f43052a05f4c" } ], - "downloadLocation": "https://github.com/libexpat/libexpat/releases/download/R_2_8_1/expat-2.8.1.tar.gz", + "downloadLocation": "https://github.com/libexpat/libexpat/releases/download/R_2_8_2/expat-2.8.2.tar.gz", "externalRefs": [ { "referenceCategory": "SECURITY", - "referenceLocator": "cpe:2.3:a:libexpat_project:libexpat:2.8.1:*:*:*:*:*:*:*", + "referenceLocator": "cpe:2.3:a:libexpat_project:libexpat:2.8.2:*:*:*:*:*:*:*", "referenceType": "cpe23Type" } ], @@ -1745,7 +1787,7 @@ "name": "expat", "originator": "Organization: Expat development team", "primaryPackagePurpose": "SOURCE", - "versionInfo": "2.8.1" + "versionInfo": "2.8.2" }, { "SPDXID": "SPDXRef-PACKAGE-hacl-star", @@ -1840,6 +1882,11 @@ "relationshipType": "CONTAINS", "spdxElementId": "SPDXRef-PACKAGE-expat" }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-expat-fallthrough.h", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-expat" + }, { "relatedSpdxElement": "SPDXRef-FILE-Modules-expat-iasciitab.h", "relationshipType": "CONTAINS", @@ -1855,6 +1902,11 @@ "relationshipType": "CONTAINS", "spdxElementId": "SPDXRef-PACKAGE-expat" }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-expat-memory-sanitizer.h", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-expat" + }, { "relatedSpdxElement": "SPDXRef-FILE-Modules-expat-nametab.h", "relationshipType": "CONTAINS", @@ -1875,6 +1927,11 @@ "relationshipType": "CONTAINS", "spdxElementId": "SPDXRef-PACKAGE-expat" }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-expat-xcsinc.c", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-expat" + }, { "relatedSpdxElement": "SPDXRef-FILE-Modules-expat-xmlparse.c", "relationshipType": "CONTAINS", diff --git a/Modules/expat/expat.h b/Modules/expat/expat.h index ec3f58544cb00d..c493c70441c418 100644 --- a/Modules/expat/expat.h +++ b/Modules/expat/expat.h @@ -1094,7 +1094,7 @@ XML_SetReparseDeferralEnabled(XML_Parser parser, XML_Bool enabled); */ # define XML_MAJOR_VERSION 2 # define XML_MINOR_VERSION 8 -# define XML_MICRO_VERSION 1 +# define XML_MICRO_VERSION 2 # ifdef __cplusplus } diff --git a/Modules/expat/fallthrough.h b/Modules/expat/fallthrough.h new file mode 100644 index 00000000000000..707dbdd44bfe53 --- /dev/null +++ b/Modules/expat/fallthrough.h @@ -0,0 +1,49 @@ +/* + __ __ _ + ___\ \/ /_ __ __ _| |_ + / _ \\ /| '_ \ / _` | __| + | __// \| |_) | (_| | |_ + \___/_/\_\ .__/ \__,_|\__| + |_| XML parser + + Copyright (c) 2026 Nick Begg <nick@stunttruck.net> + Licensed under the MIT license: + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to permit + persons to whom the Software is furnished to do so, subject to the + following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN + NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#ifndef FALLTHROUGH_H +# define FALLTHROUGH_H 1 + +// Explicit fallthrough in switch case to avoid warnings +// with compiler flag -Wimplicit-fallthrough. + +# define EXPAT_FALLTHROUGH \ + do { \ + } while (0) + +# if defined(__has_attribute) +# if __has_attribute(fallthrough) +# undef EXPAT_FALLTHROUGH +# define EXPAT_FALLTHROUGH __attribute__((fallthrough)) +# endif +# endif + +#endif // FALLTHROUGH_H diff --git a/Modules/expat/memory_sanitizer.h b/Modules/expat/memory_sanitizer.h new file mode 100644 index 00000000000000..a8a8006ccded12 --- /dev/null +++ b/Modules/expat/memory_sanitizer.h @@ -0,0 +1,51 @@ +/* + __ __ _ + ___\ \/ /_ __ __ _| |_ + / _ \\ /| '_ \ / _` | __| + | __// \| |_) | (_| | |_ + \___/_/\_\ .__/ \__,_|\__| + |_| XML parser + + Copyright (c) 2026 Matthew Fernandez <matthew.fernandez@gmail.com> + Licensed under the MIT license: + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to permit + persons to whom the Software is furnished to do so, subject to the + following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN + NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#if ! defined(MEMORY_SANITIZER_H) +# define MEMORY_SANITIZER_H 1 + +# if defined(__has_feature) +# if __has_feature(memory_sanitizer) +# include <sanitizer/msan_interface.h> + +// inform Memory Sanitizer that [base, base + extent) is now initialized +# define MSAN_UNPOISON(base, extent) __msan_unpoison((base), (extent)) + +# endif +# endif + +# if ! defined(MSAN_UNPOISON) +# define MSAN_UNPOISON(base, extent) \ + do { \ + } while (0) +# endif + +#endif // ! defined(MEMORY_SANITIZER_H) diff --git a/Modules/expat/refresh.sh b/Modules/expat/refresh.sh index fa3692f9379510..503f562c1862a4 100755 --- a/Modules/expat/refresh.sh +++ b/Modules/expat/refresh.sh @@ -12,9 +12,9 @@ fi # Update this when updating to a new version after verifying that the changes # the update brings in are good. These values are used for verifying the SBOM, too. -expected_libexpat_tag="R_2_8_1" -expected_libexpat_version="2.8.1" -expected_libexpat_sha256="a52eb72108be160e190b5cafa5bba8663f1313f2013e26060d1c18e26e31067b" +expected_libexpat_tag="R_2_8_2" +expected_libexpat_version="2.8.2" +expected_libexpat_sha256="ef7d1994f533c9e7343d6c19f31064fc8ebbcbcaa144be3812b4f43052a05f4c" expat_dir="$(realpath "$(dirname -- "${BASH_SOURCE[0]}")")" cd ${expat_dir} @@ -33,13 +33,16 @@ lib_files=( asciitab.h expat.h expat_external.h + fallthrough.h iasciitab.h internal.h latin1tab.h + memory_sanitizer.h nametab.h siphash.h utf8tab.h winconfig.h + xcsinc.c xmlparse.c xmlrole.c xmlrole.h diff --git a/Modules/expat/siphash.h b/Modules/expat/siphash.h index 04f6f74585b5a2..be216b4006dc84 100644 --- a/Modules/expat/siphash.h +++ b/Modules/expat/siphash.h @@ -100,6 +100,7 @@ #include <stddef.h> /* size_t */ #include <stdint.h> /* uint64_t uint32_t uint8_t */ +#include "fallthrough.h" /* * Workaround to not require a C++11 compiler for using ULL suffix @@ -234,25 +235,25 @@ sip24_final(struct siphash *H) { switch (left) { case 7: b |= (uint64_t)H->buf[6] << 48; - /* fall through */ + EXPAT_FALLTHROUGH; case 6: b |= (uint64_t)H->buf[5] << 40; - /* fall through */ + EXPAT_FALLTHROUGH; case 5: b |= (uint64_t)H->buf[4] << 32; - /* fall through */ + EXPAT_FALLTHROUGH; case 4: b |= (uint64_t)H->buf[3] << 24; - /* fall through */ + EXPAT_FALLTHROUGH; case 3: b |= (uint64_t)H->buf[2] << 16; - /* fall through */ + EXPAT_FALLTHROUGH; case 2: b |= (uint64_t)H->buf[1] << 8; - /* fall through */ + EXPAT_FALLTHROUGH; case 1: b |= (uint64_t)H->buf[0] << 0; - /* fall through */ + EXPAT_FALLTHROUGH; case 0: break; } diff --git a/Modules/expat/xcsinc.c b/Modules/expat/xcsinc.c new file mode 100644 index 00000000000000..3597c2480bc961 --- /dev/null +++ b/Modules/expat/xcsinc.c @@ -0,0 +1,48 @@ +/* This file is included from other .c files! + __ __ _ + ___\ \/ /_ __ __ _| |_ + / _ \\ /| '_ \ / _` | __| + | __// \| |_) | (_| | |_ + \___/_/\_\ .__/ \__,_|\__| + |_| XML parser + + Copyright (c) 2022 Sebastian Pipping <sebastian@pipping.org> + Licensed under the MIT license: + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to permit + persons to whom the Software is furnished to do so, subject to the + following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN + NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +static size_t +xcslen(const XML_Char *s) { +#ifdef XML_UNICODE +# ifdef XML_UNICODE_WCHAR_T + return wcslen(s); +# else + // XML_Char is unsigned short + size_t len = 0; + while (s[len]) { + len++; + } + return len; +# endif +#else + return strlen(s); +#endif +} diff --git a/Modules/expat/xmlparse.c b/Modules/expat/xmlparse.c index 95d346758563ab..d961ebf227e740 100644 --- a/Modules/expat/xmlparse.c +++ b/Modules/expat/xmlparse.c @@ -1,4 +1,4 @@ -/* 75ef4224f81c052e9e5aeea2ac7de75357d2169ff9908e39edc08b9dc3052513 (2.8.1+) +/* 5de44e6750c6cc78818f06ed552f522a1241df0299395250e1792cb339389daf (2.8.2+) __ __ _ ___\ \/ /_ __ __ _| |_ / _ \\ /| '_ \ / _` | __| @@ -47,6 +47,9 @@ Copyright (c) 2026 Rosen Penev <rosenp@gmail.com> Copyright (c) 2026 Francesco Bertolaccini Copyright (c) 2026 Christian Ng <christianrng@berkeley.edu> + Copyright (c) 2026 Nick Begg <nick@stunttruck.net> + Copyright (c) 2026 Kartik Kenchi <netliomax25@gmail.com> + Copyright (c) 2026 Haris Hussain <hextheshadow0x@gmail.com> Licensed under the MIT license: Permission is hereby granted, free of charge, to any person obtaining @@ -90,7 +93,7 @@ #include <stddef.h> #include <string.h> /* memset(), memcpy() */ #include <assert.h> -#include <limits.h> /* INT_MAX, UINT_MAX */ +#include <limits.h> /* INT_MAX, LLONG_MAX, LONG_MAX, UINT_MAX */ #include <stdio.h> /* fprintf */ #include <stdlib.h> /* getenv */ #include <stdint.h> /* SIZE_MAX, uintptr_t */ @@ -114,6 +117,7 @@ #include "ascii.h" #include "expat.h" #include "siphash.h" +#include "xcsinc.c" #if defined(HAVE_ARC4RANDOM) # include "random_arc4random.h" @@ -156,7 +160,7 @@ * Windows >=Vista (rand_s): _WIN32. \ \ If you insist on not using any of these, bypass this error by defining \ - XML_POOR_ENTROPY; you have been warned. \ + XML_POOR_ENTROPY and be vulnerable to hash flooding; you have been warned. \ \ If you have reasons to patch this detection code away or need changes \ to the build system, please open a bug. Thank you! @@ -207,6 +211,12 @@ typedef char ICHAR; #endif +#ifdef XML_LARGE_SIZE +# define XML_INDEX_MAX LLONG_MAX +#else +# define XML_INDEX_MAX LONG_MAX +#endif + /* Round up n to be a multiple of sz, where sz is a power of 2. */ #define ROUND_UP(n, sz) (((n) + ((sz) - 1)) & ~((sz) - 1)) @@ -270,8 +280,8 @@ typedef struct binding { struct binding *prevPrefixBinding; const struct attribute_id *attId; XML_Char *uri; - int uriLen; - int uriAlloc; + size_t uriLen; + size_t uriAlloc; } BINDING; typedef struct prefix { @@ -283,9 +293,9 @@ typedef struct { const XML_Char *str; const XML_Char *localPart; const XML_Char *prefix; - int strLen; - int uriLen; - int prefixLen; + size_t strLen; + size_t uriLen; + size_t prefixLen; } TAG_NAME; /* TAG represents an open element. @@ -384,8 +394,8 @@ typedef struct { const XML_Char *name; PREFIX *prefix; const ATTRIBUTE_ID *idAtt; - int nDefaultAtts; - int allocDefaultAtts; + size_t nDefaultAtts; + size_t allocDefaultAtts; DEFAULT_ATTRIBUTE *defaultAtts; HASH_TABLE defaultAttsNames; } ELEMENT_TYPE; @@ -417,6 +427,7 @@ typedef struct { unsigned scaffCount; int scaffLevel; int *scaffIndex; + size_t scaffIndexSize; } DTD; enum EntityType { @@ -588,6 +599,7 @@ static XML_Char *poolAppend(STRING_POOL *pool, const ENCODING *enc, static XML_Char *poolStoreString(STRING_POOL *pool, const ENCODING *enc, const char *ptr, const char *end); static XML_Bool FASTCALL poolGrow(STRING_POOL *pool); +static bool FASTCALL poolGrowUntil(STRING_POOL *pool, size_t needed); static const XML_Char *FASTCALL poolCopyString(STRING_POOL *pool, const XML_Char *s); static const XML_Char *FASTCALL poolCopyStringNoFinish(STRING_POOL *pool, @@ -642,16 +654,40 @@ static XML_Parser getRootParserOf(XML_Parser parser, static unsigned long getDebugLevel(const char *variableName, unsigned long defaultDebugLevel); +static bool poolAppendChar(STRING_POOL *pool, XML_Char c); + +static bool poolAppendChars(STRING_POOL *pool, const XML_Char *s, size_t len); + #define poolStart(pool) ((pool)->start) #define poolLength(pool) ((pool)->ptr - (pool)->start) #define poolChop(pool) ((void)--(pool->ptr)) #define poolLastChar(pool) (((pool)->ptr)[-1]) #define poolDiscard(pool) ((pool)->ptr = (pool)->start) #define poolFinish(pool) ((pool)->start = (pool)->ptr) -#define poolAppendChar(pool, c) \ - (((pool)->ptr == (pool)->end && ! poolGrow(pool)) \ - ? 0 \ - : ((*((pool)->ptr)++ = c), 1)) + +bool +poolAppendChar(STRING_POOL *pool, XML_Char c) { + if (pool->ptr == pool->end && ! poolGrow(pool)) + return false; + + *(pool->ptr)++ = c; + return true; +} + +bool +poolAppendChars(STRING_POOL *pool, const XML_Char *s, size_t len) { + // Detect and prevent integer overflow + if (len > SIZE_MAX / sizeof(XML_Char)) + return false; + + if (! poolGrowUntil(pool, len)) + return false; + + memcpy(pool->ptr, s, len * sizeof(XML_Char)); + pool->ptr += len; + + return true; +} #if ! defined(XML_TESTING) const @@ -730,11 +766,9 @@ struct XML_ParserStruct { const char *m_eventEndPtr; const char *m_positionPtr; OPEN_INTERNAL_ENTITY *m_openInternalEntities; - OPEN_INTERNAL_ENTITY *m_freeInternalEntities; OPEN_INTERNAL_ENTITY *m_openAttributeEntities; - OPEN_INTERNAL_ENTITY *m_freeAttributeEntities; OPEN_INTERNAL_ENTITY *m_openValueEntities; - OPEN_INTERNAL_ENTITY *m_freeValueEntities; + OPEN_INTERNAL_ENTITY *m_freeEntities; XML_Bool m_defaultExpandInternalEntities; int m_tagLevel; ENTITY *m_declEntity; @@ -754,7 +788,7 @@ struct XML_ParserStruct { TAG *m_freeTagList; BINDING *m_inheritedBindings; BINDING *m_freeBindingList; - int m_attsSize; + size_t m_attsSize; int m_nSpecifiedAtts; int m_idAttIndex; ATTRIBUTE *m_atts; @@ -768,7 +802,7 @@ struct XML_ParserStruct { STRING_POOL m_tempPool; STRING_POOL m_temp2Pool; char *m_groupConnector; - unsigned int m_groupSize; + size_t m_groupSize; XML_Char m_namespaceSeparator; XML_Parser m_parentParser; XML_ParsingStatus m_parsingStatus; @@ -785,6 +819,7 @@ struct XML_ParserStruct { ENTITY_STATS m_entity_stats; #endif XML_Bool m_reenter; + unsigned m_handlerCallDepth; }; #if XML_GE == 1 @@ -1128,6 +1163,23 @@ generate_hash_secret_salt(void) { #endif } +static void +beforeHandler(XML_Parser parser) { + assert(parser->m_handlerCallDepth < UINT_MAX); + parser->m_handlerCallDepth++; +} + +static void +afterHandler(XML_Parser parser) { + assert(parser->m_handlerCallDepth > 0); + parser->m_handlerCallDepth--; +} + +static bool +isCalledFromInsideHandler(XML_Parser parser) { + return parser->m_handlerCallDepth > 0; +} + static enum XML_Error callProcessor(XML_Parser parser, const char *start, const char *end, const char **endPtr) { @@ -1364,9 +1416,7 @@ parserCreate(const XML_Char *encodingName, parser->m_freeBindingList = NULL; parser->m_freeTagList = NULL; - parser->m_freeInternalEntities = NULL; - parser->m_freeAttributeEntities = NULL; - parser->m_freeValueEntities = NULL; + parser->m_freeEntities = NULL; parser->m_groupSize = 0; parser->m_groupConnector = NULL; @@ -1482,6 +1532,7 @@ parserInit(XML_Parser parser, const XML_Char *encodingName) { parser->m_parsingStatus.parsing = XML_INITIALIZED; // Reentry can only be triggered inside m_processor calls parser->m_reenter = XML_FALSE; + parser->m_handlerCallDepth = 0; #ifdef XML_DTD parser->m_isParamEntity = XML_FALSE; parser->m_useForeignDTD = XML_FALSE; @@ -1515,12 +1566,22 @@ moveToFreeBindingList(XML_Parser parser, BINDING *bindings) { } } +/* Moves a list of entities onto the start of another list. */ +static void +moveEntityList(OPEN_INTERNAL_ENTITY **dst, OPEN_INTERNAL_ENTITY **src) { + for (OPEN_INTERNAL_ENTITY *head = *src; head != NULL;) { + OPEN_INTERNAL_ENTITY *const openEntity = head; + head = head->next; + openEntity->next = *dst; + *dst = openEntity; + } +} + XML_Bool XMLCALL XML_ParserReset(XML_Parser parser, const XML_Char *encodingName) { TAG *tStk; - OPEN_INTERNAL_ENTITY *openEntityList; - if (parser == NULL) + if ((parser == NULL) || isCalledFromInsideHandler(parser)) return XML_FALSE; if (parser->m_parentParser) @@ -1535,32 +1596,14 @@ XML_ParserReset(XML_Parser parser, const XML_Char *encodingName) { tag->bindings = NULL; parser->m_freeTagList = tag; } - /* move m_openInternalEntities to m_freeInternalEntities */ - openEntityList = parser->m_openInternalEntities; - while (openEntityList) { - OPEN_INTERNAL_ENTITY *openEntity = openEntityList; - openEntityList = openEntity->next; - openEntity->next = parser->m_freeInternalEntities; - parser->m_freeInternalEntities = openEntity; - } - /* move m_openAttributeEntities to m_freeAttributeEntities (i.e. same task but - * for attributes) */ - openEntityList = parser->m_openAttributeEntities; - while (openEntityList) { - OPEN_INTERNAL_ENTITY *openEntity = openEntityList; - openEntityList = openEntity->next; - openEntity->next = parser->m_freeAttributeEntities; - parser->m_freeAttributeEntities = openEntity; - } - /* move m_openValueEntities to m_freeValueEntities (i.e. same task but - * for value entities) */ - openEntityList = parser->m_openValueEntities; - while (openEntityList) { - OPEN_INTERNAL_ENTITY *openEntity = openEntityList; - openEntityList = openEntity->next; - openEntity->next = parser->m_freeValueEntities; - parser->m_freeValueEntities = openEntity; - } + /* move m_openInternalEntities to m_freeEntities */ + moveEntityList(&parser->m_freeEntities, &parser->m_openInternalEntities); + /* move m_openAttributeEntities to m_freeEntities (i.e. same task but for + * attributes) */ + moveEntityList(&parser->m_freeEntities, &parser->m_openAttributeEntities); + /* move m_openValueEntities to m_freeEntities (i.e. same task but for value + * entities) */ + moveEntityList(&parser->m_freeEntities, &parser->m_openValueEntities); moveToFreeBindingList(parser, parser->m_inheritedBindings); FREE(parser, parser->m_unknownEncodingMem); if (parser->m_unknownEncodingRelease) @@ -1712,11 +1755,6 @@ XML_ExternalEntityParserCreate(XML_Parser oldParser, const XML_Char *context, newDtd = oldDtd; #endif /* XML_DTD */ - /* Note that the magical uses of the pre-processor to make field - access look more like C++ require that `parser' be overwritten - here. This makes this function more painful to follow than it - would be otherwise. - */ if (parser->m_ns) { XML_Char tmp[2] = {parser->m_namespaceSeparator, 0}; parser = parserCreate(encodingName, &parser->m_mem, tmp, newDtd, oldParser); @@ -1806,8 +1844,7 @@ destroyBindings(BINDING *bindings, XML_Parser parser) { void XMLCALL XML_ParserFree(XML_Parser parser) { TAG *tagList; - OPEN_INTERNAL_ENTITY *entityList; - if (parser == NULL) + if ((parser == NULL) || isCalledFromInsideHandler(parser)) return; /* free m_tagStack and m_freeTagList */ tagList = parser->m_tagStack; @@ -1825,48 +1862,35 @@ XML_ParserFree(XML_Parser parser) { destroyBindings(p->bindings, parser); FREE(parser, p); } - /* free m_openInternalEntities and m_freeInternalEntities */ - entityList = parser->m_openInternalEntities; - for (;;) { - OPEN_INTERNAL_ENTITY *openEntity; - if (entityList == NULL) { - if (parser->m_freeInternalEntities == NULL) - break; - entityList = parser->m_freeInternalEntities; - parser->m_freeInternalEntities = NULL; - } - openEntity = entityList; + /* free m_openInternalEntities */ + for (OPEN_INTERNAL_ENTITY *entityList = parser->m_openInternalEntities; + entityList != NULL;) { + OPEN_INTERNAL_ENTITY *const openEntity = entityList; entityList = entityList->next; FREE(parser, openEntity); } - /* free m_openAttributeEntities and m_freeAttributeEntities */ - entityList = parser->m_openAttributeEntities; - for (;;) { - OPEN_INTERNAL_ENTITY *openEntity; - if (entityList == NULL) { - if (parser->m_freeAttributeEntities == NULL) - break; - entityList = parser->m_freeAttributeEntities; - parser->m_freeAttributeEntities = NULL; - } - openEntity = entityList; + /* free m_openAttributeEntities */ + for (OPEN_INTERNAL_ENTITY *entityList = parser->m_openAttributeEntities; + entityList != NULL;) { + OPEN_INTERNAL_ENTITY *const openEntity = entityList; entityList = entityList->next; FREE(parser, openEntity); } - /* free m_openValueEntities and m_freeValueEntities */ - entityList = parser->m_openValueEntities; - for (;;) { - OPEN_INTERNAL_ENTITY *openEntity; - if (entityList == NULL) { - if (parser->m_freeValueEntities == NULL) - break; - entityList = parser->m_freeValueEntities; - parser->m_freeValueEntities = NULL; - } - openEntity = entityList; + /* free m_openValueEntities */ + for (OPEN_INTERNAL_ENTITY *entityList = parser->m_openValueEntities; + entityList != NULL;) { + OPEN_INTERNAL_ENTITY *const openEntity = entityList; entityList = entityList->next; FREE(parser, openEntity); } + /* free m_freeEntities */ + for (OPEN_INTERNAL_ENTITY *entityList = parser->m_freeEntities; + entityList != NULL;) { + OPEN_INTERNAL_ENTITY *const openEntity = entityList; + entityList = entityList->next; + FREE(parser, openEntity); + } + parser->m_freeEntities = NULL; destroyBindings(parser->m_freeBindingList, parser); destroyBindings(parser->m_inheritedBindings, parser); poolDestroy(&parser->m_tempPool); @@ -2263,6 +2287,8 @@ XML_Parse(XML_Parser parser, const char *s, int len, int isFinal) { parser->m_errorCode = XML_ERROR_INVALID_ARGUMENT; return XML_STATUS_ERROR; } + if (isCalledFromInsideHandler(parser)) + return XML_STATUS_ERROR; switch (parser->m_parsingStatus.parsing) { case XML_SUSPENDED: parser->m_errorCode = XML_ERROR_SUSPENDED; @@ -2275,7 +2301,7 @@ XML_Parse(XML_Parser parser, const char *s, int len, int isFinal) { parser->m_errorCode = XML_ERROR_NO_MEMORY; return XML_STATUS_ERROR; } - /* fall through */ + EXPAT_FALLTHROUGH; default: parser->m_parsingStatus.parsing = XML_PARSING; } @@ -2286,7 +2312,7 @@ XML_Parse(XML_Parser parser, const char *s, int len, int isFinal) { int nLeftOver; enum XML_Status result; /* Detect overflow (a+b > MAX <==> b > MAX-a) */ - if ((XML_Size)len > ((XML_Size)-1) / 2 - parser->m_parseEndByteIndex) { + if (len > XML_INDEX_MAX - parser->m_parseEndByteIndex) { parser->m_errorCode = XML_ERROR_NO_MEMORY; parser->m_eventPtr = parser->m_eventEndPtr = NULL; parser->m_processor = errorProcessor; @@ -2317,7 +2343,7 @@ XML_Parse(XML_Parser parser, const char *s, int len, int isFinal) { parser->m_parsingStatus.parsing = XML_FINISHED; return XML_STATUS_OK; } - /* fall through */ + EXPAT_FALLTHROUGH; default: result = XML_STATUS_OK; } @@ -2372,7 +2398,7 @@ XML_ParseBuffer(XML_Parser parser, int len, int isFinal) { const char *start; enum XML_Status result = XML_STATUS_OK; - if (parser == NULL) + if ((parser == NULL) || isCalledFromInsideHandler(parser)) return XML_STATUS_ERROR; if (len < 0) { @@ -2398,11 +2424,19 @@ XML_ParseBuffer(XML_Parser parser, int len, int isFinal) { parser->m_errorCode = XML_ERROR_NO_MEMORY; return XML_STATUS_ERROR; } - /* fall through */ + EXPAT_FALLTHROUGH; default: parser->m_parsingStatus.parsing = XML_PARSING; } + // Detect and avoid integer overflow + if (len > XML_INDEX_MAX - parser->m_parseEndByteIndex) { + parser->m_errorCode = XML_ERROR_NO_MEMORY; + parser->m_eventPtr = parser->m_eventEndPtr = NULL; + parser->m_processor = errorProcessor; + return XML_STATUS_ERROR; + } + start = parser->m_bufferPtr; parser->m_positionPtr = start; parser->m_bufferEnd += len; @@ -2428,6 +2462,7 @@ XML_ParseBuffer(XML_Parser parser, int len, int isFinal) { parser->m_parsingStatus.parsing = XML_FINISHED; return result; } + break; default:; /* should not happen */ } } @@ -2438,9 +2473,32 @@ XML_ParseBuffer(XML_Parser parser, int len, int isFinal) { return result; } +/* Modifies `parser`’s buffer to be backed by `newBuf`. */ +static void +setParserBuffer(XML_Parser parser, char *newBuf, int newBufSize, int keep) { + parser->m_bufferLim = newBuf + newBufSize; + if (parser->m_bufferPtr) { + const int parsing + = (int)EXPAT_SAFE_PTR_DIFF(parser->m_bufferEnd, parser->m_bufferPtr); + memcpy(newBuf, parser->m_bufferPtr - keep, parsing + keep); + // NOTE: We are avoiding FREE(..) here because parser->m_buffer + // is not being allocated with MALLOC(..) but with plain + // .malloc_fcn(..). + parser->m_mem.free_fcn(parser->m_buffer); + parser->m_buffer = newBuf; + parser->m_bufferEnd = newBuf + parsing + keep; + parser->m_bufferPtr = newBuf + keep; + } else { + /* This must be a brand new buffer with no data in it yet */ + parser->m_buffer = newBuf; + parser->m_bufferEnd = newBuf; + parser->m_bufferPtr = newBuf; + } +} + void *XMLCALL XML_GetBuffer(XML_Parser parser, int len) { - if (parser == NULL) + if ((parser == NULL) || isCalledFromInsideHandler(parser)) return NULL; if (len < 0) { parser->m_errorCode = XML_ERROR_NO_MEMORY; @@ -2461,9 +2519,6 @@ XML_GetBuffer(XML_Parser parser, int len) { parser->m_lastBufferRequestSize = len; if (len > EXPAT_SAFE_PTR_DIFF(parser->m_bufferLim, parser->m_bufferEnd) || parser->m_buffer == NULL) { -#if XML_CONTEXT_BYTES > 0 - int keep; -#endif /* XML_CONTEXT_BYTES > 0 */ /* Do not invoke signed arithmetic overflow: */ int neededSize = (int)((unsigned)len + (unsigned)EXPAT_SAFE_PTR_DIFF( @@ -2473,7 +2528,9 @@ XML_GetBuffer(XML_Parser parser, int len) { return NULL; } #if XML_CONTEXT_BYTES > 0 - keep = (int)EXPAT_SAFE_PTR_DIFF(parser->m_bufferPtr, parser->m_buffer); + const int parsed + = (int)EXPAT_SAFE_PTR_DIFF(parser->m_bufferPtr, parser->m_buffer); + int keep = parsed; if (keep > XML_CONTEXT_BYTES) keep = XML_CONTEXT_BYTES; /* Detect and prevent integer overflow */ @@ -2481,16 +2538,16 @@ XML_GetBuffer(XML_Parser parser, int len) { parser->m_errorCode = XML_ERROR_NO_MEMORY; return NULL; } - neededSize += keep; +#else + int keep = 0; #endif /* XML_CONTEXT_BYTES > 0 */ + neededSize += keep; if (parser->m_buffer && parser->m_bufferPtr && neededSize <= EXPAT_SAFE_PTR_DIFF(parser->m_bufferLim, parser->m_buffer)) { #if XML_CONTEXT_BYTES > 0 - if (keep < EXPAT_SAFE_PTR_DIFF(parser->m_bufferPtr, parser->m_buffer)) { - int offset - = (int)EXPAT_SAFE_PTR_DIFF(parser->m_bufferPtr, parser->m_buffer) - - keep; + if (keep < parsed) { + int offset = parsed - keep; /* The buffer pointers cannot be NULL here; we have at least some bytes * in the buffer */ memmove(parser->m_buffer, &parser->m_buffer[offset], @@ -2507,7 +2564,6 @@ XML_GetBuffer(XML_Parser parser, int len) { parser->m_bufferPtr = parser->m_buffer; #endif /* XML_CONTEXT_BYTES > 0 */ } else { - char *newBuf; int bufferSize = (int)EXPAT_SAFE_PTR_DIFF(parser->m_bufferLim, parser->m_buffer); if (bufferSize == 0) @@ -2522,49 +2578,12 @@ XML_GetBuffer(XML_Parser parser, int len) { } // NOTE: We are avoiding MALLOC(..) here to leave limiting // the input size to the application using Expat. - newBuf = parser->m_mem.malloc_fcn(bufferSize); + char *const newBuf = parser->m_mem.malloc_fcn(bufferSize); if (newBuf == NULL) { parser->m_errorCode = XML_ERROR_NO_MEMORY; return NULL; } - parser->m_bufferLim = newBuf + bufferSize; -#if XML_CONTEXT_BYTES > 0 - if (parser->m_bufferPtr) { - memcpy(newBuf, &parser->m_bufferPtr[-keep], - EXPAT_SAFE_PTR_DIFF(parser->m_bufferEnd, parser->m_bufferPtr) - + keep); - // NOTE: We are avoiding FREE(..) here because parser->m_buffer - // is not being allocated with MALLOC(..) but with plain - // .malloc_fcn(..). - parser->m_mem.free_fcn(parser->m_buffer); - parser->m_buffer = newBuf; - parser->m_bufferEnd - = parser->m_buffer - + EXPAT_SAFE_PTR_DIFF(parser->m_bufferEnd, parser->m_bufferPtr) - + keep; - parser->m_bufferPtr = parser->m_buffer + keep; - } else { - /* This must be a brand new buffer with no data in it yet */ - parser->m_bufferEnd = newBuf; - parser->m_bufferPtr = parser->m_buffer = newBuf; - } -#else - if (parser->m_bufferPtr) { - memcpy(newBuf, parser->m_bufferPtr, - EXPAT_SAFE_PTR_DIFF(parser->m_bufferEnd, parser->m_bufferPtr)); - // NOTE: We are avoiding FREE(..) here because parser->m_buffer - // is not being allocated with MALLOC(..) but with plain - // .malloc_fcn(..). - parser->m_mem.free_fcn(parser->m_buffer); - parser->m_bufferEnd - = newBuf - + EXPAT_SAFE_PTR_DIFF(parser->m_bufferEnd, parser->m_bufferPtr); - } else { - /* This must be a brand new buffer with no data in it yet */ - parser->m_bufferEnd = newBuf; - } - parser->m_bufferPtr = parser->m_buffer = newBuf; -#endif /* XML_CONTEXT_BYTES > 0 */ + setParserBuffer(parser, newBuf, bufferSize, keep); } parser->m_eventPtr = parser->m_eventEndPtr = NULL; parser->m_positionPtr = NULL; @@ -2617,7 +2636,7 @@ enum XML_Status XMLCALL XML_ResumeParser(XML_Parser parser) { enum XML_Status result = XML_STATUS_OK; - if (parser == NULL) + if ((parser == NULL) || isCalledFromInsideHandler(parser)) return XML_STATUS_ERROR; if (parser->m_parsingStatus.parsing != XML_SUSPENDED) { parser->m_errorCode = XML_ERROR_NOT_SUSPENDED; @@ -2643,6 +2662,7 @@ XML_ResumeParser(XML_Parser parser) { parser->m_parsingStatus.parsing = XML_FINISHED; return result; } + break; default:; } } @@ -2704,7 +2724,7 @@ XML_GetInputContext(XML_Parser parser, int *offset, int *size) { (void)offset; (void)size; #endif /* XML_CONTEXT_BYTES > 0 */ - return (const char *)0; + return NULL; } XML_Size XMLCALL @@ -3063,7 +3083,7 @@ storeRawNames(XML_Parser parser) { */ rawNameLen = ROUND_UP(tag->rawNameLength, sizeof(XML_Char)); /* Detect and prevent integer overflow. */ - if (rawNameLen > (size_t)INT_MAX - nameLen) + if (rawNameLen > SIZE_MAX - nameLen) return XML_FALSE; bufSize = nameLen + rawNameLen; if (bufSize > (size_t)(tag->bufEnd - tag->buf.raw)) { @@ -3190,7 +3210,7 @@ externalEntityInitProcessor3(XML_Parser parser, const char *start, if (parser->m_reenter) { return XML_ERROR_UNEXPECTED_STATE; // LCOV_EXCL_LINE } - /* Fall through */ + EXPAT_FALLTHROUGH; default: start = next; } @@ -3269,7 +3289,9 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc, *eventEndPP = end; if (parser->m_characterDataHandler) { XML_Char c = 0xA; + beforeHandler(parser); parser->m_characterDataHandler(parser->m_handlerArg, &c, 1); + afterHandler(parser); } else if (parser->m_defaultHandler) reportDefault(parser, enc, s, end); /* We are at the end of the final buffer, should we check for @@ -3322,9 +3344,11 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc, ((char *)&ch) + sizeof(XML_Char), __LINE__, XML_ACCOUNT_ENTITY_EXPANSION); #endif /* XML_GE == 1 */ - if (parser->m_characterDataHandler) + if (parser->m_characterDataHandler) { + beforeHandler(parser); parser->m_characterDataHandler(parser->m_handlerArg, &ch, 1); - else if (parser->m_defaultHandler) + afterHandler(parser); + } else if (parser->m_defaultHandler) reportDefault(parser, enc, s, next); break; } @@ -3344,9 +3368,11 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc, else if (! entity->is_internal) return XML_ERROR_ENTITY_DECLARED_IN_PE; } else if (! entity) { - if (parser->m_skippedEntityHandler) + if (parser->m_skippedEntityHandler) { + beforeHandler(parser); parser->m_skippedEntityHandler(parser->m_handlerArg, name, 0); - else if (parser->m_defaultHandler) + afterHandler(parser); + } else if (parser->m_defaultHandler) reportDefault(parser, enc, s, next); break; } @@ -3357,10 +3383,12 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc, if (entity->textPtr) { enum XML_Error result; if (! parser->m_defaultExpandInternalEntities) { - if (parser->m_skippedEntityHandler) + if (parser->m_skippedEntityHandler) { + beforeHandler(parser); parser->m_skippedEntityHandler(parser->m_handlerArg, entity->name, 0); - else if (parser->m_defaultHandler) + afterHandler(parser); + } else if (parser->m_defaultHandler) reportDefault(parser, enc, s, next); break; } @@ -3374,9 +3402,12 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc, entity->open = XML_FALSE; if (! context) return XML_ERROR_NO_MEMORY; - if (! parser->m_externalEntityRefHandler( - parser->m_externalEntityRefHandlerArg, context, entity->base, - entity->systemId, entity->publicId)) + beforeHandler(parser); + const int status = parser->m_externalEntityRefHandler( + parser->m_externalEntityRefHandlerArg, context, entity->base, + entity->systemId, entity->publicId); + afterHandler(parser); + if (! status) return XML_ERROR_EXTERNAL_ENTITY_HANDLING; poolDiscard(&parser->m_tempPool); } else if (parser->m_defaultHandler) @@ -3384,7 +3415,6 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc, break; } case XML_TOK_START_TAG_NO_ATTS: - /* fall through */ case XML_TOK_START_TAG_WITH_ATTS: { TAG *tag; enum XML_Error result; @@ -3416,11 +3446,10 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc, const char *fromPtr = tag->rawName; toPtr = tag->buf.str; for (;;) { - int convLen; const enum XML_Convert_Result convert_res = XmlConvert(enc, &fromPtr, rawNameEnd, (ICHAR **)&toPtr, (ICHAR *)tag->bufEnd - 1); - convLen = (int)(toPtr - tag->buf.str); + const size_t convLen = (size_t)(toPtr - tag->buf.str); if ((fromPtr >= rawNameEnd) || (convert_res == XML_CONVERT_INPUT_INCOMPLETE)) { tag->name.strLen = convLen; @@ -3445,16 +3474,17 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc, = storeAtts(parser, enc, s, &(tag->name), &(tag->bindings), account); if (result) return result; - if (parser->m_startElementHandler) + if (parser->m_startElementHandler) { + beforeHandler(parser); parser->m_startElementHandler(parser->m_handlerArg, tag->name.str, (const XML_Char **)parser->m_atts); - else if (parser->m_defaultHandler) + afterHandler(parser); + } else if (parser->m_defaultHandler) reportDefault(parser, enc, s, next); poolClear(&parser->m_tempPool); break; } case XML_TOK_EMPTY_ELEMENT_NO_ATTS: - /* fall through */ case XML_TOK_EMPTY_ELEMENT_WITH_ATTS: { const char *rawName = s + enc->minBytesPerChar; enum XML_Error result; @@ -3474,14 +3504,18 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc, } poolFinish(&parser->m_tempPool); if (parser->m_startElementHandler) { + beforeHandler(parser); parser->m_startElementHandler(parser->m_handlerArg, name.str, (const XML_Char **)parser->m_atts); + afterHandler(parser); noElmHandlers = XML_FALSE; } if (parser->m_endElementHandler) { if (parser->m_startElementHandler) *eventPP = *eventEndPP; + beforeHandler(parser); parser->m_endElementHandler(parser->m_handlerArg, name.str); + afterHandler(parser); noElmHandlers = XML_FALSE; } if (noElmHandlers && parser->m_defaultHandler) @@ -3539,14 +3573,19 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc, } *uri = XML_T('\0'); } + beforeHandler(parser); parser->m_endElementHandler(parser->m_handlerArg, tag->name.str); + afterHandler(parser); } else if (parser->m_defaultHandler) reportDefault(parser, enc, s, next); while (tag->bindings) { BINDING *b = tag->bindings; - if (parser->m_endNamespaceDeclHandler) + if (parser->m_endNamespaceDeclHandler) { + beforeHandler(parser); parser->m_endNamespaceDeclHandler(parser->m_handlerArg, b->prefix->name); + afterHandler(parser); + } tag->bindings = tag->bindings->nextTagBinding; b->nextTagBinding = parser->m_freeBindingList; parser->m_freeBindingList = b; @@ -3569,8 +3608,10 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc, return XML_ERROR_BAD_CHAR_REF; if (parser->m_characterDataHandler) { XML_Char buf[XML_ENCODE_MAX]; + beforeHandler(parser); parser->m_characterDataHandler(parser->m_handlerArg, buf, XmlEncode(n, (ICHAR *)buf)); + afterHandler(parser); } else if (parser->m_defaultHandler) reportDefault(parser, enc, s, next); } break; @@ -3579,32 +3620,38 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc, case XML_TOK_DATA_NEWLINE: if (parser->m_characterDataHandler) { XML_Char c = 0xA; + beforeHandler(parser); parser->m_characterDataHandler(parser->m_handlerArg, &c, 1); + afterHandler(parser); } else if (parser->m_defaultHandler) reportDefault(parser, enc, s, next); break; case XML_TOK_CDATA_SECT_OPEN: { enum XML_Error result; - if (parser->m_startCdataSectionHandler) + if (parser->m_startCdataSectionHandler) { + beforeHandler(parser); parser->m_startCdataSectionHandler(parser->m_handlerArg); - /* BEGIN disabled code */ - /* Suppose you doing a transformation on a document that involves - changing only the character data. You set up a defaultHandler - and a characterDataHandler. The defaultHandler simply copies - characters through. The characterDataHandler does the - transformation and writes the characters out escaping them as - necessary. This case will fail to work if we leave out the - following two lines (because & and < inside CDATA sections will - be incorrectly escaped). - - However, now we have a start/endCdataSectionHandler, so it seems - easier to let the user deal with this. - */ - else if ((0) && parser->m_characterDataHandler) + afterHandler(parser); + /* BEGIN disabled code */ + /* Suppose you doing a transformation on a document that involves + changing only the character data. You set up a defaultHandler + and a characterDataHandler. The defaultHandler simply copies + characters through. The characterDataHandler does the + transformation and writes the characters out escaping them as + necessary. This case will fail to work if we leave out the + following two lines (because & and < inside CDATA sections will + be incorrectly escaped). + + However, now we have a start/endCdataSectionHandler, so it seems + easier to let the user deal with this. + */ + } else if ((0) && parser->m_characterDataHandler) { + beforeHandler(parser); parser->m_characterDataHandler(parser->m_handlerArg, parser->m_dataBuf, 0); - /* END disabled code */ - else if (parser->m_defaultHandler) + afterHandler(parser); + /* END disabled code */ + } else if (parser->m_defaultHandler) reportDefault(parser, enc, s, next); result = doCdataSection(parser, enc, &next, end, nextPtr, haveMore, account); @@ -3624,13 +3671,18 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc, if (MUST_CONVERT(enc, s)) { ICHAR *dataPtr = (ICHAR *)parser->m_dataBuf; XmlConvert(enc, &s, end, &dataPtr, (ICHAR *)parser->m_dataBufEnd); + beforeHandler(parser); parser->m_characterDataHandler( parser->m_handlerArg, parser->m_dataBuf, (int)(dataPtr - (ICHAR *)parser->m_dataBuf)); - } else + afterHandler(parser); + } else { + beforeHandler(parser); parser->m_characterDataHandler( parser->m_handlerArg, (const XML_Char *)s, (int)((const XML_Char *)end - (const XML_Char *)s)); + afterHandler(parser); + } } else if (parser->m_defaultHandler) reportDefault(parser, enc, s, end); /* We are at the end of the final buffer, should we check for @@ -3655,16 +3707,21 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc, const enum XML_Convert_Result convert_res = XmlConvert( enc, &s, next, &dataPtr, (ICHAR *)parser->m_dataBufEnd); *eventEndPP = s; + beforeHandler(parser); charDataHandler(parser->m_handlerArg, parser->m_dataBuf, (int)(dataPtr - (ICHAR *)parser->m_dataBuf)); + afterHandler(parser); if ((convert_res == XML_CONVERT_COMPLETED) || (convert_res == XML_CONVERT_INPUT_INCOMPLETE)) break; *eventPP = s; } - } else + } else { + beforeHandler(parser); charDataHandler(parser->m_handlerArg, (const XML_Char *)s, (int)((const XML_Char *)next - (const XML_Char *)s)); + afterHandler(parser); + } } else if (parser->m_defaultHandler) reportDefault(parser, enc, s, next); } break; @@ -3702,7 +3759,7 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc, *nextPtr = next; return XML_ERROR_NONE; } - /* Fall through */ + EXPAT_FALLTHROUGH; default:; *eventPP = s = next; } @@ -3722,8 +3779,11 @@ freeBindings(XML_Parser parser, BINDING *bindings) { /* m_startNamespaceDeclHandler will have been called for this * binding in addBindings(), so call the end handler now. */ - if (parser->m_endNamespaceDeclHandler) + if (parser->m_endNamespaceDeclHandler) { + beforeHandler(parser); parser->m_endNamespaceDeclHandler(parser->m_handlerArg, b->prefix->name); + afterHandler(parser); + } bindings = bindings->nextTagBinding; b->nextTagBinding = parser->m_freeBindingList; @@ -3747,20 +3807,14 @@ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr, TAG_NAME *tagNamePtr, BINDING **bindingsPtr, enum XML_Account account) { DTD *const dtd = parser->m_dtd; /* save one level of indirection */ - ELEMENT_TYPE *elementType; - int nDefaultAtts; - const XML_Char **appAtts; /* the attribute list for the application */ int attIndex = 0; - int prefixLen; - int i; - int n; XML_Char *uri; int nPrefixes = 0; BINDING *binding; const XML_Char *localPart; /* lookup the element type name */ - elementType + ELEMENT_TYPE *elementType = (ELEMENT_TYPE *)lookup(parser, &dtd->elementTypes, tagNamePtr->str, 0); if (! elementType) { const XML_Char *name = poolCopyString(&dtd->pool, tagNamePtr->str); @@ -3775,75 +3829,71 @@ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr, if (parser->m_ns && ! setElementTypePrefix(parser, elementType)) return XML_ERROR_NO_MEMORY; } - nDefaultAtts = elementType->nDefaultAtts; + const size_t nDefaultAtts = elementType->nDefaultAtts; + + /* Detect and prevent integer overflow. */ + if (parser->m_attsSize > (size_t)INT_MAX) + return XML_ERROR_NO_MEMORY; /* get the attributes from the tokenizer */ - n = XmlGetAttributes(enc, attStr, parser->m_attsSize, parser->m_atts); + size_t n = (size_t)XmlGetAttributes(enc, attStr, (int)parser->m_attsSize, + parser->m_atts); /* Detect and prevent integer overflow */ - if (n > INT_MAX - nDefaultAtts) { + if (n > SIZE_MAX - nDefaultAtts) { return XML_ERROR_NO_MEMORY; } if (n + nDefaultAtts > parser->m_attsSize) { - int oldAttsSize = parser->m_attsSize; - ATTRIBUTE *temp; -#ifdef XML_ATTR_INFO - XML_AttrInfo *temp2; -#endif + size_t oldAttsSize = parser->m_attsSize; /* Detect and prevent integer overflow */ - if ((nDefaultAtts > INT_MAX - INIT_ATTS_SIZE) - || (n > INT_MAX - (nDefaultAtts + INIT_ATTS_SIZE))) { + if ((nDefaultAtts > SIZE_MAX - INIT_ATTS_SIZE) + || (n > SIZE_MAX - (nDefaultAtts + INIT_ATTS_SIZE))) { return XML_ERROR_NO_MEMORY; } parser->m_attsSize = n + nDefaultAtts + INIT_ATTS_SIZE; - /* Detect and prevent integer overflow. - * The preprocessor guard addresses the "always false" warning - * from -Wtype-limits on platforms where - * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */ -#if UINT_MAX >= SIZE_MAX - if ((unsigned)parser->m_attsSize > SIZE_MAX / sizeof(ATTRIBUTE)) { + /* Detect and prevent integer overflow. */ + if (parser->m_attsSize > SIZE_MAX / sizeof(ATTRIBUTE)) { parser->m_attsSize = oldAttsSize; return XML_ERROR_NO_MEMORY; } -#endif - temp = REALLOC(parser, parser->m_atts, - parser->m_attsSize * sizeof(ATTRIBUTE)); + ATTRIBUTE *const temp = REALLOC(parser, parser->m_atts, + parser->m_attsSize * sizeof(ATTRIBUTE)); if (temp == NULL) { parser->m_attsSize = oldAttsSize; return XML_ERROR_NO_MEMORY; } parser->m_atts = temp; #ifdef XML_ATTR_INFO - /* Detect and prevent integer overflow. - * The preprocessor guard addresses the "always false" warning - * from -Wtype-limits on platforms where - * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */ -# if UINT_MAX >= SIZE_MAX - if ((unsigned)parser->m_attsSize > SIZE_MAX / sizeof(XML_AttrInfo)) { + /* Detect and prevent integer overflow. */ + if (parser->m_attsSize > SIZE_MAX / sizeof(XML_AttrInfo)) { parser->m_attsSize = oldAttsSize; return XML_ERROR_NO_MEMORY; } -# endif - temp2 = REALLOC(parser, parser->m_attInfo, - parser->m_attsSize * sizeof(XML_AttrInfo)); + XML_AttrInfo *const temp2 = REALLOC( + parser, parser->m_attInfo, parser->m_attsSize * sizeof(XML_AttrInfo)); if (temp2 == NULL) { parser->m_attsSize = oldAttsSize; return XML_ERROR_NO_MEMORY; } parser->m_attInfo = temp2; #endif - if (n > oldAttsSize) - XmlGetAttributes(enc, attStr, n, parser->m_atts); + if (n > oldAttsSize) { + /* Detect and prevent integer overflow. */ + if (n > (size_t)INT_MAX) + return XML_ERROR_NO_MEMORY; + XmlGetAttributes(enc, attStr, (int)n, parser->m_atts); + } } - appAtts = (const XML_Char **)parser->m_atts; - for (i = 0; i < n; i++) { + /* the attribute list for the application */ + const XML_Char **const appAtts = (const XML_Char **)parser->m_atts; + for (size_t i = 0; i < n; i++) { ATTRIBUTE *currAtt = &parser->m_atts[i]; #ifdef XML_ATTR_INFO XML_AttrInfo *currAttInfo = &parser->m_attInfo[i]; @@ -3876,13 +3926,11 @@ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr, (attId->name)[-1] = 1; appAtts[attIndex++] = attId->name; if (! parser->m_atts[i].normalized) { - enum XML_Error result; XML_Bool isCdata = XML_TRUE; /* figure out whether declared as other than CDATA */ if (attId->maybeTokenized) { - int j; - for (j = 0; j < nDefaultAtts; j++) { + for (size_t j = 0; j < nDefaultAtts; j++) { if (attId == elementType->defaultAtts[j].id) { isCdata = elementType->defaultAtts[j].isCdata; break; @@ -3891,7 +3939,7 @@ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr, } /* normalize the attribute value */ - result = storeAttributeValue( + const enum XML_Error result = storeAttributeValue( parser, enc, isCdata, parser->m_atts[i].valuePtr, parser->m_atts[i].valueEnd, &parser->m_tempPool, account); if (result) @@ -3929,7 +3977,7 @@ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr, /* set-up for XML_GetSpecifiedAttributeCount and XML_GetIdAttributeIndex */ parser->m_nSpecifiedAtts = attIndex; if (elementType->idAtt && (elementType->idAtt->name)[-1]) { - for (i = 0; i < attIndex; i += 2) + for (int i = 0; i < attIndex; i += 2) if (appAtts[i] == elementType->idAtt->name) { parser->m_idAttIndex = i; break; @@ -3938,7 +3986,7 @@ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr, parser->m_idAttIndex = -1; /* do attribute defaulting */ - for (i = 0; i < nDefaultAtts; i++) { + for (size_t i = 0; i < nDefaultAtts; i++) { const DEFAULT_ATTRIBUTE *da = elementType->defaultAtts + i; if (! (da->id->name)[-1] && da->value) { if (da->id->prefix) { @@ -3964,7 +4012,7 @@ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr, /* expand prefixed attribute names, check for duplicates, and clear flags that say whether attributes were specified */ - i = 0; + int i = 0; if (nPrefixes) { unsigned int j; /* hash table index */ unsigned long version = parser->m_nsAttsVersion; @@ -3979,7 +4027,6 @@ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr, /* size of hash table must be at least 2 * (# of prefixed attributes) */ if ((nPrefixes << 1) >> parser->m_nsAttsPower) { /* true for m_nsAttsPower = 0 */ - NS_ATT *temp; /* hash table size must also be a power of 2 and >= 8 */ while (nPrefixes >> parser->m_nsAttsPower++) ; @@ -4007,7 +4054,8 @@ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr, } #endif - temp = REALLOC(parser, parser->m_nsAtts, nsAttsSize * sizeof(NS_ATT)); + NS_ATT *const temp + = REALLOC(parser, parser->m_nsAtts, nsAttsSize * sizeof(NS_ATT)); if (! temp) { /* Restore actual size of memory in m_nsAtts */ parser->m_nsAttsPower = oldNsAttsPower; @@ -4028,9 +4076,6 @@ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr, for (; i < attIndex; i += 2) { const XML_Char *s = appAtts[i]; if (s[-1] == 2) { /* prefixed */ - ATTRIBUTE_ID *id; - const BINDING *b; - unsigned long uriHash; struct siphash sip_state; struct sipkey sip_key; @@ -4038,7 +4083,8 @@ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr, sip24_init(&sip_state, &sip_key); ((XML_Char *)s)[-1] = 0; /* clear flag */ - id = (ATTRIBUTE_ID *)lookup(parser, &dtd->attributeIds, s, 0); + ATTRIBUTE_ID *const id + = (ATTRIBUTE_ID *)lookup(parser, &dtd->attributeIds, s, 0); if (! id || ! id->prefix) { /* This code is walking through the appAtts array, dealing * with (in this case) a prefixed attribute name. To be in @@ -4046,7 +4092,7 @@ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr, * has to have passed through the hash table lookup once * already. That implies that an entry for it already * exists, so the lookup above will return a pointer to - * already allocated memory. There is no opportunaity for + * already allocated memory. There is no opportunity for * the allocator to fail, so the condition above cannot be * fulfilled. * @@ -4056,15 +4102,12 @@ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr, */ return XML_ERROR_NO_MEMORY; /* LCOV_EXCL_LINE */ } - b = id->prefix->binding; + const BINDING *const b = id->prefix->binding; if (! b) return XML_ERROR_UNBOUND_PREFIX; - for (j = 0; j < (unsigned int)b->uriLen; j++) { - const XML_Char c = b->uri[j]; - if (! poolAppendChar(&parser->m_tempPool, c)) - return XML_ERROR_NO_MEMORY; - } + if (! poolAppendChars(&parser->m_tempPool, b->uri, b->uriLen)) + return XML_ERROR_NO_MEMORY; sip24_update(&sip_state, b->uri, b->uriLen * sizeof(XML_Char)); @@ -4073,12 +4116,13 @@ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr, sip24_update(&sip_state, s, keylen(s) * sizeof(XML_Char)); - do { /* copies null terminator */ - if (! poolAppendChar(&parser->m_tempPool, *s)) + { + const size_t len = xcslen(s) + /*null terminator*/ 1; + if (! poolAppendChars(&parser->m_tempPool, s, len)) return XML_ERROR_NO_MEMORY; - } while (*s++); + } - uriHash = (unsigned long)sip24_final(&sip_state); + const unsigned long uriHash = (unsigned long)sip24_final(&sip_state); { /* Check hash table for duplicate of expanded name (uriName). Derived from code in lookup(parser, HASH_TABLE *table, ...). @@ -4106,10 +4150,9 @@ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr, if (parser->m_ns_triplets) { /* append namespace separator and prefix */ parser->m_tempPool.ptr[-1] = parser->m_namespaceSeparator; s = b->prefix->name; - do { - if (! poolAppendChar(&parser->m_tempPool, *s)) - return XML_ERROR_NO_MEMORY; - } while (*s++); + const size_t len = xcslen(s) + /*null terminator*/ 1; + if (! poolAppendChars(&parser->m_tempPool, s, len)) + return XML_ERROR_NO_MEMORY; } /* store expanded name in attribute list */ @@ -4152,48 +4195,36 @@ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr, localPart = tagNamePtr->str; } else return XML_ERROR_NONE; - prefixLen = 0; - if (parser->m_ns_triplets && binding->prefix->name) { - while (binding->prefix->name[prefixLen++]) - ; /* prefixLen includes null terminator */ - } + size_t prefixLen = 0; + if (parser->m_ns_triplets && binding->prefix->name) + prefixLen = xcslen(binding->prefix->name) + /*null terminator*/ 1; tagNamePtr->localPart = localPart; tagNamePtr->uriLen = binding->uriLen; tagNamePtr->prefix = binding->prefix->name; tagNamePtr->prefixLen = prefixLen; - for (i = 0; localPart[i++];) - ; /* i includes null terminator */ + + const size_t localPartLen = xcslen(localPart) + /*null terminator*/ 1; /* Detect and prevent integer overflow */ - if (binding->uriLen > INT_MAX - prefixLen - || i > INT_MAX - (binding->uriLen + prefixLen)) { + if (binding->uriLen > SIZE_MAX - prefixLen + || localPartLen > SIZE_MAX - (binding->uriLen + prefixLen)) { return XML_ERROR_NO_MEMORY; } - n = i + binding->uriLen + prefixLen; - if (n > binding->uriAlloc) { - TAG *p; - + const size_t totalLen = localPartLen + binding->uriLen + prefixLen; + if (totalLen > binding->uriAlloc) { /* Detect and prevent integer overflow */ - if (n > INT_MAX - EXPAND_SPARE) { - return XML_ERROR_NO_MEMORY; - } - /* Detect and prevent integer overflow. - * The preprocessor guard addresses the "always false" warning - * from -Wtype-limits on platforms where - * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */ -#if UINT_MAX >= SIZE_MAX - if ((unsigned)(n + EXPAND_SPARE) > SIZE_MAX / sizeof(XML_Char)) { + if (totalLen > SIZE_MAX - EXPAND_SPARE + || totalLen + EXPAND_SPARE > SIZE_MAX / sizeof(XML_Char)) { return XML_ERROR_NO_MEMORY; } -#endif - uri = MALLOC(parser, (n + EXPAND_SPARE) * sizeof(XML_Char)); + uri = MALLOC(parser, (totalLen + EXPAND_SPARE) * sizeof(XML_Char)); if (! uri) return XML_ERROR_NO_MEMORY; - binding->uriAlloc = n + EXPAND_SPARE; + binding->uriAlloc = totalLen + EXPAND_SPARE; memcpy(uri, binding->uri, binding->uriLen * sizeof(XML_Char)); - for (p = parser->m_tagStack; p; p = p->parent) + for (TAG *p = parser->m_tagStack; p; p = p->parent) if (p->name.str == binding->uri) p->name.str = uri; FREE(parser, binding->uri); @@ -4201,10 +4232,14 @@ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr, } /* if m_namespaceSeparator != '\0' then uri includes it already */ uri = binding->uri + binding->uriLen; - memcpy(uri, localPart, i * sizeof(XML_Char)); + /* Detect and prevent integer overflow */ + if (localPartLen > SIZE_MAX / sizeof(XML_Char)) { + return XML_ERROR_NO_MEMORY; + } + memcpy(uri, localPart, localPartLen * sizeof(XML_Char)); /* we always have a namespace separator between localPart and prefix */ if (prefixLen) { - uri += i - 1; + uri += localPartLen - 1; *uri = parser->m_namespaceSeparator; /* replace null terminator */ memcpy(uri + 1, binding->prefix->name, prefixLen * sizeof(XML_Char)); } @@ -4339,7 +4374,7 @@ addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId, ASCII_8, ASCII_SLASH, ASCII_n, ASCII_a, ASCII_m, ASCII_e, ASCII_s, ASCII_p, ASCII_a, ASCII_c, ASCII_e, '\0'}; - static const int xmlLen = (int)sizeof(xmlNamespace) / sizeof(XML_Char) - 1; + static const size_t xmlLen = sizeof(xmlNamespace) / sizeof(XML_Char) - 1; // "http://www.w3.org/2000/xmlns/" static const XML_Char xmlnsNamespace[] = {ASCII_h, ASCII_t, ASCII_t, ASCII_p, ASCII_COLON, ASCII_SLASH, @@ -4347,15 +4382,14 @@ addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId, ASCII_3, ASCII_PERIOD, ASCII_o, ASCII_r, ASCII_g, ASCII_SLASH, ASCII_2, ASCII_0, ASCII_0, ASCII_0, ASCII_SLASH, ASCII_x, ASCII_m, ASCII_l, ASCII_n, ASCII_s, ASCII_SLASH, '\0'}; - static const int xmlnsLen - = (int)sizeof(xmlnsNamespace) / sizeof(XML_Char) - 1; + static const size_t xmlnsLen = sizeof(xmlnsNamespace) / sizeof(XML_Char) - 1; XML_Bool mustBeXML = XML_FALSE; XML_Bool isXML = XML_TRUE; XML_Bool isXMLNS = XML_TRUE; BINDING *b; - int len; + size_t len; /* empty URI is only valid for default namespace per XML NS 1.0 (not 1.1) */ if (*uri == XML_T('\0') && prefix->name) @@ -4374,6 +4408,10 @@ addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId, } for (len = 0; uri[len]; len++) { + /* Detect and prevent integer overflow */ + if (len == SIZE_MAX) { + return XML_ERROR_NO_MEMORY; + } if (isXML && (len > xmlLen || uri[len] != xmlNamespace[len])) isXML = XML_FALSE; @@ -4414,25 +4452,21 @@ addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId, if (isXMLNS) return XML_ERROR_RESERVED_NAMESPACE_URI; - if (parser->m_namespaceSeparator) + if (parser->m_namespaceSeparator) { + /* Detect and prevent integer overflow */ + if (len == SIZE_MAX) { + return XML_ERROR_NO_MEMORY; + } len++; + } if (parser->m_freeBindingList) { b = parser->m_freeBindingList; if (len > b->uriAlloc) { /* Detect and prevent integer overflow */ - if (len > INT_MAX - EXPAND_SPARE) { - return XML_ERROR_NO_MEMORY; - } - - /* Detect and prevent integer overflow. - * The preprocessor guard addresses the "always false" warning - * from -Wtype-limits on platforms where - * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */ -#if UINT_MAX >= SIZE_MAX - if ((unsigned)(len + EXPAND_SPARE) > SIZE_MAX / sizeof(XML_Char)) { + if (len > SIZE_MAX - EXPAND_SPARE + || len + EXPAND_SPARE > SIZE_MAX / sizeof(XML_Char)) { return XML_ERROR_NO_MEMORY; } -#endif XML_Char *temp = REALLOC(parser, b->uri, sizeof(XML_Char) * (len + EXPAND_SPARE)); @@ -4448,18 +4482,10 @@ addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId, return XML_ERROR_NO_MEMORY; /* Detect and prevent integer overflow */ - if (len > INT_MAX - EXPAND_SPARE) { + if (len > SIZE_MAX - EXPAND_SPARE + || len + EXPAND_SPARE > SIZE_MAX / sizeof(XML_Char)) { return XML_ERROR_NO_MEMORY; } - /* Detect and prevent integer overflow. - * The preprocessor guard addresses the "always false" warning - * from -Wtype-limits on platforms where - * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */ -#if UINT_MAX >= SIZE_MAX - if ((unsigned)(len + EXPAND_SPARE) > SIZE_MAX / sizeof(XML_Char)) { - return XML_ERROR_NO_MEMORY; - } -#endif b->uri = MALLOC(parser, sizeof(XML_Char) * (len + EXPAND_SPARE)); if (! b->uri) { @@ -4483,9 +4509,12 @@ addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId, b->nextTagBinding = *bindingsPtr; *bindingsPtr = b; /* if attId == NULL then we are not starting a namespace scope */ - if (attId && parser->m_startNamespaceDeclHandler) + if (attId && parser->m_startNamespaceDeclHandler) { + beforeHandler(parser); parser->m_startNamespaceDeclHandler(parser->m_handlerArg, prefix->name, prefix->binding ? uri : 0); + afterHandler(parser); + } return XML_ERROR_NONE; } @@ -4547,15 +4576,20 @@ doCdataSection(XML_Parser parser, const ENCODING *enc, const char **startPtr, *eventEndPP = next; switch (tok) { case XML_TOK_CDATA_SECT_CLOSE: - if (parser->m_endCdataSectionHandler) + if (parser->m_endCdataSectionHandler) { + beforeHandler(parser); parser->m_endCdataSectionHandler(parser->m_handlerArg); + afterHandler(parser); + } /* BEGIN disabled code */ /* see comment under XML_TOK_CDATA_SECT_OPEN */ - else if ((0) && parser->m_characterDataHandler) + else if ((0) && parser->m_characterDataHandler) { + beforeHandler(parser); parser->m_characterDataHandler(parser->m_handlerArg, parser->m_dataBuf, 0); - /* END disabled code */ - else if (parser->m_defaultHandler) + afterHandler(parser); + /* END disabled code */ + } else if (parser->m_defaultHandler) reportDefault(parser, enc, s, next); *startPtr = next; *nextPtr = next; @@ -4566,7 +4600,9 @@ doCdataSection(XML_Parser parser, const ENCODING *enc, const char **startPtr, case XML_TOK_DATA_NEWLINE: if (parser->m_characterDataHandler) { XML_Char c = 0xA; + beforeHandler(parser); parser->m_characterDataHandler(parser->m_handlerArg, &c, 1); + afterHandler(parser); } else if (parser->m_defaultHandler) reportDefault(parser, enc, s, next); break; @@ -4579,16 +4615,21 @@ doCdataSection(XML_Parser parser, const ENCODING *enc, const char **startPtr, const enum XML_Convert_Result convert_res = XmlConvert( enc, &s, next, &dataPtr, (ICHAR *)parser->m_dataBufEnd); *eventEndPP = next; + beforeHandler(parser); charDataHandler(parser->m_handlerArg, parser->m_dataBuf, (int)(dataPtr - (ICHAR *)parser->m_dataBuf)); + afterHandler(parser); if ((convert_res == XML_CONVERT_COMPLETED) || (convert_res == XML_CONVERT_INPUT_INCOMPLETE)) break; *eventPP = s; } - } else + } else { + beforeHandler(parser); charDataHandler(parser->m_handlerArg, (const XML_Char *)s, (int)((const XML_Char *)next - (const XML_Char *)s)); + afterHandler(parser); + } } else if (parser->m_defaultHandler) reportDefault(parser, enc, s, next); } break; @@ -4633,7 +4674,7 @@ doCdataSection(XML_Parser parser, const ENCODING *enc, const char **startPtr, if (parser->m_reenter) { return XML_ERROR_UNEXPECTED_STATE; // LCOV_EXCL_LINE } - /* Fall through */ + EXPAT_FALLTHROUGH; default:; *eventPP = s = next; } @@ -4827,8 +4868,10 @@ processXmlDecl(XML_Parser parser, int isGeneralTextEntity, const char *s, if (! storedversion) return XML_ERROR_NO_MEMORY; } + beforeHandler(parser); parser->m_xmlDeclHandler(parser->m_handlerArg, storedversion, storedEncName, standalone); + afterHandler(parser); } else if (parser->m_defaultHandler) reportDefault(parser, parser->m_encoding, s, next); if (parser->m_protocolEncodingName == NULL) { @@ -4878,8 +4921,11 @@ handleUnknownEncoding(XML_Parser parser, const XML_Char *encodingName) { info.convert = NULL; info.data = NULL; info.release = NULL; - if (parser->m_unknownEncodingHandler(parser->m_unknownEncodingHandlerData, - encodingName, &info)) { + beforeHandler(parser); + const int status = parser->m_unknownEncodingHandler( + parser->m_unknownEncodingHandlerData, encodingName, &info); + afterHandler(parser); + if (status) { ENCODING *enc; parser->m_unknownEncodingMem = MALLOC(parser, XmlSizeOfUnknownEncoding()); if (! parser->m_unknownEncodingMem) { @@ -5256,9 +5302,11 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end, break; case XML_ROLE_DOCTYPE_INTERNAL_SUBSET: if (parser->m_startDoctypeDeclHandler) { + beforeHandler(parser); parser->m_startDoctypeDeclHandler( parser->m_handlerArg, parser->m_doctypeName, parser->m_doctypeSysid, parser->m_doctypePubid, 1); + afterHandler(parser); parser->m_doctypeName = NULL; poolClear(&parser->m_tempPool); handleDefault = XML_FALSE; @@ -5297,7 +5345,7 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end, handleDefault = XML_FALSE; goto alreadyChecked; } - /* fall through */ + EXPAT_FALLTHROUGH; case XML_ROLE_ENTITY_PUBLIC_ID: if (! XmlIsPublicId(enc, s, next, eventPP)) return XML_ERROR_PUBLICID; @@ -5325,9 +5373,11 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end, } if (parser->m_doctypeName) { + beforeHandler(parser); parser->m_startDoctypeDeclHandler( parser->m_handlerArg, parser->m_doctypeName, parser->m_doctypeSysid, parser->m_doctypePubid, 0); + afterHandler(parser); poolClear(&parser->m_tempPool); handleDefault = XML_FALSE; } @@ -5354,14 +5404,22 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end, if (parser->m_useForeignDTD) entity->base = parser->m_curBase; dtd->paramEntityRead = XML_FALSE; - if (! parser->m_externalEntityRefHandler( - parser->m_externalEntityRefHandlerArg, 0, entity->base, - entity->systemId, entity->publicId)) + beforeHandler(parser); + const int status = parser->m_externalEntityRefHandler( + parser->m_externalEntityRefHandlerArg, 0, entity->base, + entity->systemId, entity->publicId); + afterHandler(parser); + if (! status) return XML_ERROR_EXTERNAL_ENTITY_HANDLING; if (dtd->paramEntityRead) { - if (! dtd->standalone && parser->m_notStandaloneHandler - && ! parser->m_notStandaloneHandler(parser->m_handlerArg)) - return XML_ERROR_NOT_STANDALONE; + if (! dtd->standalone && parser->m_notStandaloneHandler) { + beforeHandler(parser); + const int handlerStatus + = parser->m_notStandaloneHandler(parser->m_handlerArg); + afterHandler(parser); + if (! handlerStatus) + return XML_ERROR_NOT_STANDALONE; + } } /* if we didn't read the foreign DTD then this means that there is no external subset and we must reset dtd->hasParamEntityRefs @@ -5374,7 +5432,9 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end, } #endif /* XML_DTD */ if (parser->m_endDoctypeDeclHandler) { + beforeHandler(parser); parser->m_endDoctypeDeclHandler(parser->m_handlerArg); + afterHandler(parser); handleDefault = XML_FALSE; } break; @@ -5394,14 +5454,22 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end, return XML_ERROR_NO_MEMORY; entity->base = parser->m_curBase; dtd->paramEntityRead = XML_FALSE; - if (! parser->m_externalEntityRefHandler( - parser->m_externalEntityRefHandlerArg, 0, entity->base, - entity->systemId, entity->publicId)) + beforeHandler(parser); + const int status = parser->m_externalEntityRefHandler( + parser->m_externalEntityRefHandlerArg, 0, entity->base, + entity->systemId, entity->publicId); + afterHandler(parser); + if (! status) return XML_ERROR_EXTERNAL_ENTITY_HANDLING; if (dtd->paramEntityRead) { - if (! dtd->standalone && parser->m_notStandaloneHandler - && ! parser->m_notStandaloneHandler(parser->m_handlerArg)) - return XML_ERROR_NOT_STANDALONE; + if (! dtd->standalone && parser->m_notStandaloneHandler) { + beforeHandler(parser); + const int handlerStatus + = parser->m_notStandaloneHandler(parser->m_handlerArg); + afterHandler(parser); + if (! handlerStatus) + return XML_ERROR_NOT_STANDALONE; + } } /* if we didn't read the foreign DTD then this means that there is no external subset and we must reset dtd->hasParamEntityRefs @@ -5494,10 +5562,12 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end, poolFinish(&parser->m_tempPool); } *eventEndPP = s; + beforeHandler(parser); parser->m_attlistDeclHandler( parser->m_handlerArg, parser->m_declElementType->name, parser->m_declAttributeId->name, parser->m_declAttributeType, 0, role == XML_ROLE_REQUIRED_ATTRIBUTE_VALUE); + afterHandler(parser); handleDefault = XML_FALSE; } } @@ -5532,10 +5602,12 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end, poolFinish(&parser->m_tempPool); } *eventEndPP = s; + beforeHandler(parser); parser->m_attlistDeclHandler( parser->m_handlerArg, parser->m_declElementType->name, parser->m_declAttributeId->name, parser->m_declAttributeType, attVal, role == XML_ROLE_FIXED_ATTRIBUTE_VALUE); + afterHandler(parser); poolClear(&parser->m_tempPool); handleDefault = XML_FALSE; } @@ -5550,16 +5622,22 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end, parser, enc, s + enc->minBytesPerChar, next - enc->minBytesPerChar, XML_ACCOUNT_NONE); if (parser->m_declEntity) { + /* Detect and prevent signed integer overflow */ + if ((size_t)poolLength(&dtd->entityValuePool) > (size_t)INT_MAX) { + return XML_ERROR_NO_MEMORY; + } parser->m_declEntity->textPtr = poolStart(&dtd->entityValuePool); parser->m_declEntity->textLen = (int)(poolLength(&dtd->entityValuePool)); poolFinish(&dtd->entityValuePool); if (parser->m_entityDeclHandler) { *eventEndPP = s; + beforeHandler(parser); parser->m_entityDeclHandler( parser->m_handlerArg, parser->m_declEntity->name, parser->m_declEntity->is_param, parser->m_declEntity->textPtr, parser->m_declEntity->textLen, parser->m_curBase, 0, 0, 0); + afterHandler(parser); handleDefault = XML_FALSE; } } else @@ -5577,10 +5655,12 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end, if (parser->m_entityDeclHandler) { *eventEndPP = s; + beforeHandler(parser); parser->m_entityDeclHandler( parser->m_handlerArg, parser->m_declEntity->name, parser->m_declEntity->is_param, parser->m_declEntity->textPtr, parser->m_declEntity->textLen, parser->m_curBase, 0, 0, 0); + afterHandler(parser); handleDefault = XML_FALSE; } } @@ -5611,9 +5691,13 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end, #ifdef XML_DTD && ! parser->m_paramEntityParsing #endif /* XML_DTD */ - && parser->m_notStandaloneHandler - && ! parser->m_notStandaloneHandler(parser->m_handlerArg)) - return XML_ERROR_NOT_STANDALONE; + && parser->m_notStandaloneHandler) { + beforeHandler(parser); + const int status = parser->m_notStandaloneHandler(parser->m_handlerArg); + afterHandler(parser); + if (! status) + return XML_ERROR_NOT_STANDALONE; + } #ifndef XML_DTD break; #else /* XML_DTD */ @@ -5625,7 +5709,7 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end, parser->m_declEntity->publicId = NULL; } #endif /* XML_DTD */ - /* fall through */ + EXPAT_FALLTHROUGH; case XML_ROLE_ENTITY_SYSTEM_ID: if (dtd->keepProcessing && parser->m_declEntity) { parser->m_declEntity->systemId @@ -5656,10 +5740,12 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end, if (dtd->keepProcessing && parser->m_declEntity && parser->m_entityDeclHandler) { *eventEndPP = s; + beforeHandler(parser); parser->m_entityDeclHandler( parser->m_handlerArg, parser->m_declEntity->name, parser->m_declEntity->is_param, 0, 0, parser->m_declEntity->base, parser->m_declEntity->systemId, parser->m_declEntity->publicId, 0); + afterHandler(parser); handleDefault = XML_FALSE; } break; @@ -5672,17 +5758,21 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end, poolFinish(&dtd->pool); if (parser->m_unparsedEntityDeclHandler) { *eventEndPP = s; + beforeHandler(parser); parser->m_unparsedEntityDeclHandler( parser->m_handlerArg, parser->m_declEntity->name, parser->m_declEntity->base, parser->m_declEntity->systemId, parser->m_declEntity->publicId, parser->m_declEntity->notation); + afterHandler(parser); handleDefault = XML_FALSE; } else if (parser->m_entityDeclHandler) { *eventEndPP = s; + beforeHandler(parser); parser->m_entityDeclHandler( parser->m_handlerArg, parser->m_declEntity->name, 0, 0, 0, parser->m_declEntity->base, parser->m_declEntity->systemId, parser->m_declEntity->publicId, parser->m_declEntity->notation); + afterHandler(parser); handleDefault = XML_FALSE; } } @@ -5789,9 +5879,11 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end, if (! systemId) return XML_ERROR_NO_MEMORY; *eventEndPP = s; + beforeHandler(parser); parser->m_notationDeclHandler( parser->m_handlerArg, parser->m_declNotationName, parser->m_curBase, systemId, parser->m_declNotationPublicId); + afterHandler(parser); handleDefault = XML_FALSE; } poolClear(&parser->m_tempPool); @@ -5799,9 +5891,11 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end, case XML_ROLE_NOTATION_NO_SYSTEM_ID: if (parser->m_declNotationPublicId && parser->m_notationDeclHandler) { *eventEndPP = s; + beforeHandler(parser); parser->m_notationDeclHandler( parser->m_handlerArg, parser->m_declNotationName, parser->m_curBase, 0, parser->m_declNotationPublicId); + afterHandler(parser); handleDefault = XML_FALSE; } poolClear(&parser->m_tempPool); @@ -5835,41 +5929,18 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end, case XML_ROLE_GROUP_OPEN: if (parser->m_prologState.level >= parser->m_groupSize) { if (parser->m_groupSize) { - { - /* Detect and prevent integer overflow */ - if (parser->m_groupSize > (unsigned int)(-1) / 2u) { - return XML_ERROR_NO_MEMORY; - } - - char *const new_connector = REALLOC( - parser, parser->m_groupConnector, parser->m_groupSize *= 2); - if (new_connector == NULL) { - parser->m_groupSize /= 2; - return XML_ERROR_NO_MEMORY; - } - parser->m_groupConnector = new_connector; + /* Detect and prevent integer overflow */ + if (parser->m_groupSize > SIZE_MAX / 2) { + return XML_ERROR_NO_MEMORY; } - if (dtd->scaffIndex) { - /* Detect and prevent integer overflow. - * The preprocessor guard addresses the "always false" warning - * from -Wtype-limits on platforms where - * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */ -#if UINT_MAX >= SIZE_MAX - if (parser->m_groupSize > SIZE_MAX / sizeof(int)) { - parser->m_groupSize /= 2; - return XML_ERROR_NO_MEMORY; - } -#endif - - int *const new_scaff_index = REALLOC( - parser, dtd->scaffIndex, parser->m_groupSize * sizeof(int)); - if (new_scaff_index == NULL) { - parser->m_groupSize /= 2; - return XML_ERROR_NO_MEMORY; - } - dtd->scaffIndex = new_scaff_index; + char *const new_connector = REALLOC(parser, parser->m_groupConnector, + parser->m_groupSize *= 2); + if (new_connector == NULL) { + parser->m_groupSize /= 2; + return XML_ERROR_NO_MEMORY; } + parser->m_groupConnector = new_connector; } else { parser->m_groupConnector = MALLOC(parser, parser->m_groupSize = 32); if (! parser->m_groupConnector) { @@ -5884,6 +5955,21 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end, if (myindex < 0) return XML_ERROR_NO_MEMORY; assert(dtd->scaffIndex != NULL); + if ((size_t)dtd->scaffLevel >= dtd->scaffIndexSize) { + /* Detect and prevent integer overflow */ + if (dtd->scaffIndexSize > SIZE_MAX / 2 / sizeof(int)) { + return XML_ERROR_NO_MEMORY; + } + assert(dtd->scaffIndexSize > 0); + const size_t new_size = dtd->scaffIndexSize * 2; + int *const new_scaff_index + = REALLOC(parser, dtd->scaffIndex, new_size * sizeof(int)); + if (new_scaff_index == NULL) { + return XML_ERROR_NO_MEMORY; + } + dtd->scaffIndex = new_scaff_index; + dtd->scaffIndexSize = new_size; + } dtd->scaffIndex[dtd->scaffLevel] = myindex; dtd->scaffLevel++; dtd->scaffold[myindex].type = XML_CTYPE_SEQ; @@ -5964,7 +6050,9 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end, /* cannot report skipped entities in declarations */ if ((role == XML_ROLE_PARAM_ENTITY_REF) && parser->m_skippedEntityHandler) { + beforeHandler(parser); parser->m_skippedEntityHandler(parser->m_handlerArg, name, 1); + afterHandler(parser); handleDefault = XML_FALSE; } break; @@ -5985,9 +6073,12 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end, dtd->paramEntityRead = XML_FALSE; entity->open = XML_TRUE; entityTrackingOnOpen(parser, entity, __LINE__); - if (! parser->m_externalEntityRefHandler( - parser->m_externalEntityRefHandlerArg, 0, entity->base, - entity->systemId, entity->publicId)) { + beforeHandler(parser); + const int status = parser->m_externalEntityRefHandler( + parser->m_externalEntityRefHandlerArg, 0, entity->base, + entity->systemId, entity->publicId); + afterHandler(parser); + if (! status) { entityTrackingOnClose(parser, entity, __LINE__); entity->open = XML_FALSE; return XML_ERROR_EXTERNAL_ENTITY_HANDLING; @@ -6005,9 +6096,13 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end, } } #endif /* XML_DTD */ - if (! dtd->standalone && parser->m_notStandaloneHandler - && ! parser->m_notStandaloneHandler(parser->m_handlerArg)) - return XML_ERROR_NOT_STANDALONE; + if (! dtd->standalone && parser->m_notStandaloneHandler) { + beforeHandler(parser); + const int status = parser->m_notStandaloneHandler(parser->m_handlerArg); + afterHandler(parser); + if (! status) + return XML_ERROR_NOT_STANDALONE; + } break; /* Element declaration stuff */ @@ -6042,8 +6137,10 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end, content->type = ((role == XML_ROLE_CONTENT_ANY) ? XML_CTYPE_ANY : XML_CTYPE_EMPTY); *eventEndPP = s; + beforeHandler(parser); parser->m_elementDeclHandler( parser->m_handlerArg, parser->m_declElementType->name, content); + afterHandler(parser); handleDefault = XML_FALSE; } dtd->in_eldecl = XML_FALSE; @@ -6087,9 +6184,7 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end, return XML_ERROR_NO_MEMORY; name = el->name; dtd->scaffold[myindex].name = name; - nameLen = 0; - while (name[nameLen++]) - ; + nameLen = xcslen(name) + /*null terminator*/ 1; /* Detect and prevent integer overflow */ if (nameLen > UINT_MAX - dtd->contentStringLen) { @@ -6125,8 +6220,10 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end, if (! model) return XML_ERROR_NO_MEMORY; *eventEndPP = s; + beforeHandler(parser); parser->m_elementDeclHandler( parser->m_handlerArg, parser->m_declElementType->name, model); + afterHandler(parser); } dtd->in_eldecl = XML_FALSE; dtd->contentStringLen = 0; @@ -6188,7 +6285,7 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end, *nextPtr = next; return XML_ERROR_NONE; } - /* Fall through */ + EXPAT_FALLTHROUGH; default: s = next; tok = XmlPrologTok(enc, s, end, &next); @@ -6268,7 +6365,7 @@ epilogProcessor(XML_Parser parser, const char *s, const char *end, if (parser->m_reenter) { return XML_ERROR_UNEXPECTED_STATE; // LCOV_EXCL_LINE } - /* Fall through */ + EXPAT_FALLTHROUGH; default:; parser->m_eventPtr = s = next; } @@ -6278,20 +6375,18 @@ epilogProcessor(XML_Parser parser, const char *s, const char *end, static enum XML_Error processEntity(XML_Parser parser, ENTITY *entity, XML_Bool betweenDecl, enum EntityType type) { - OPEN_INTERNAL_ENTITY *openEntity, **openEntityList, **freeEntityList; + OPEN_INTERNAL_ENTITY *openEntity, **openEntityList; + OPEN_INTERNAL_ENTITY **const freeEntityList = &parser->m_freeEntities; switch (type) { case ENTITY_INTERNAL: parser->m_processor = internalEntityProcessor; openEntityList = &parser->m_openInternalEntities; - freeEntityList = &parser->m_freeInternalEntities; break; case ENTITY_ATTRIBUTE: openEntityList = &parser->m_openAttributeEntities; - freeEntityList = &parser->m_freeAttributeEntities; break; case ENTITY_VALUE: openEntityList = &parser->m_openValueEntities; - freeEntityList = &parser->m_freeValueEntities; break; /* default case serves merely as a safety net in case of a * wrong entityType. Therefore we exclude the following lines @@ -6408,8 +6503,8 @@ internalEntityProcessor(XML_Parser parser, const char *s, const char *end, parser->m_openInternalEntities = parser->m_openInternalEntities->next; /* put openEntity back in list of free instances */ - openEntity->next = parser->m_freeInternalEntities; - parser->m_freeInternalEntities = openEntity; + openEntity->next = parser->m_freeEntities; + parser->m_freeEntities = openEntity; if (parser->m_openInternalEntities == NULL) { parser->m_processor = entity->is_param ? prologProcessor : contentProcessor; @@ -6485,8 +6580,8 @@ storeAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata, parser->m_openAttributeEntities = parser->m_openAttributeEntities->next; /* put openEntity back in list of free instances */ - openEntity->next = parser->m_freeAttributeEntities; - parser->m_freeAttributeEntities = openEntity; + openEntity->next = parser->m_freeEntities; + parser->m_freeEntities = openEntity; } // Break if an error occurred or there is nothing left to process @@ -6539,7 +6634,6 @@ appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata, return XML_ERROR_INVALID_TOKEN; case XML_TOK_CHAR_REF: { XML_Char buf[XML_ENCODE_MAX]; - int i; int n = XmlCharRefNumber(enc, ptr); if (n < 0) { if (enc == parser->m_encoding) @@ -6559,10 +6653,9 @@ appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata, * XmlEncode() is never passed a value it might return an * error for. */ - for (i = 0; i < n; i++) { - if (! poolAppendChar(pool, buf[i])) - return XML_ERROR_NO_MEMORY; - } + + if (! poolAppendChars(pool, buf, n)) + return XML_ERROR_NO_MEMORY; } break; case XML_TOK_DATA_CHARS: if (! poolAppend(pool, enc, ptr, next)) @@ -6570,7 +6663,7 @@ appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata, break; case XML_TOK_TRAILING_CR: next = ptr + enc->minBytesPerChar; - /* fall through */ + EXPAT_FALLTHROUGH; case XML_TOK_ATTRIBUTE_VALUE_S: case XML_TOK_DATA_NEWLINE: if (! isCdata && (poolLength(pool) == 0 || poolLastChar(pool) == 0x20)) @@ -6624,8 +6717,11 @@ appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata, } else if (! entity) { /* Cannot report skipped entity here - see comments on parser->m_skippedEntityHandler. - if (parser->m_skippedEntityHandler) + if (parser->m_skippedEntityHandler) { + beforeHandler(parser); parser->m_skippedEntityHandler(parser->m_handlerArg, name, 0); + afterHandler(parser); + } */ /* Cannot call the default handler because this would be out of sync with the call to the startElementHandler. @@ -6758,8 +6854,11 @@ storeEntityValue(XML_Parser parser, const ENCODING *enc, /* not a well-formedness error - see XML 1.0: WFC Entity Declared */ /* cannot report skipped entity here - see comments on parser->m_skippedEntityHandler - if (parser->m_skippedEntityHandler) + if (parser->m_skippedEntityHandler) { + beforeHandler(parser); parser->m_skippedEntityHandler(parser->m_handlerArg, name, 0); + afterHandler(parser); + } */ dtd->keepProcessing = dtd->standalone; goto endEntityValue; @@ -6775,9 +6874,12 @@ storeEntityValue(XML_Parser parser, const ENCODING *enc, dtd->paramEntityRead = XML_FALSE; entity->open = XML_TRUE; entityTrackingOnOpen(parser, entity, __LINE__); - if (! parser->m_externalEntityRefHandler( - parser->m_externalEntityRefHandlerArg, 0, entity->base, - entity->systemId, entity->publicId)) { + beforeHandler(parser); + const int status = parser->m_externalEntityRefHandler( + parser->m_externalEntityRefHandlerArg, 0, entity->base, + entity->systemId, entity->publicId); + afterHandler(parser); + if (! status) { entityTrackingOnClose(parser, entity, __LINE__); entity->open = XML_FALSE; result = XML_ERROR_EXTERNAL_ENTITY_HANDLING; @@ -6813,17 +6915,15 @@ storeEntityValue(XML_Parser parser, const ENCODING *enc, break; case XML_TOK_TRAILING_CR: next = entityTextPtr + enc->minBytesPerChar; - /* fall through */ + EXPAT_FALLTHROUGH; case XML_TOK_DATA_NEWLINE: - if (pool->end == pool->ptr && ! poolGrow(pool)) { + if (! poolAppendChar(pool, 0xA)) { result = XML_ERROR_NO_MEMORY; goto endEntityValue; } - *(pool->ptr)++ = 0xA; break; case XML_TOK_CHAR_REF: { XML_Char buf[XML_ENCODE_MAX]; - int i; int n = XmlCharRefNumber(enc, entityTextPtr); if (n < 0) { if (enc == parser->m_encoding) @@ -6841,12 +6941,9 @@ storeEntityValue(XML_Parser parser, const ENCODING *enc, * XmlEncode() is never passed a value it might return an * error for. */ - for (i = 0; i < n; i++) { - if (pool->end == pool->ptr && ! poolGrow(pool)) { - result = XML_ERROR_NO_MEMORY; - goto endEntityValue; - } - *(pool->ptr)++ = buf[i]; + if (! poolAppendChars(pool, buf, n)) { + result = XML_ERROR_NO_MEMORY; + goto endEntityValue; } } break; case XML_TOK_PARTIAL: @@ -6943,8 +7040,8 @@ callStoreEntityValue(XML_Parser parser, const ENCODING *enc, parser->m_openValueEntities = parser->m_openValueEntities->next; /* put openEntity back in list of free instances */ - openEntity->next = parser->m_freeValueEntities; - parser->m_freeValueEntities = openEntity; + openEntity->next = parser->m_freeEntities; + parser->m_freeEntities = openEntity; } // Break if an error occurred or there is nothing left to process @@ -6974,6 +7071,11 @@ storeSelfEntityValue(XML_Parser parser, ENTITY *entity) { return XML_ERROR_NO_MEMORY; } + /* Detect and prevent signed integer overflow */ + if ((size_t)poolLength(pool) > (size_t)INT_MAX) { + poolDiscard(pool); + return XML_ERROR_NO_MEMORY; + } entity->textPtr = poolStart(pool); entity->textLen = (int)(poolLength(pool)); poolFinish(pool); @@ -7026,7 +7128,9 @@ reportProcessingInstruction(XML_Parser parser, const ENCODING *enc, if (! data) return 0; normalizeLines(data); + beforeHandler(parser); parser->m_processingInstructionHandler(parser->m_handlerArg, target, data); + afterHandler(parser); poolClear(&parser->m_tempPool); return 1; } @@ -7046,7 +7150,9 @@ reportComment(XML_Parser parser, const ENCODING *enc, const char *start, if (! data) return 0; normalizeLines(data); + beforeHandler(parser); parser->m_commentHandler(parser->m_handlerArg, data); + afterHandler(parser); poolClear(&parser->m_tempPool); return 1; } @@ -7087,15 +7193,20 @@ reportDefault(XML_Parser parser, const ENCODING *enc, const char *s, convert_res = XmlConvert(enc, &s, end, &dataPtr, (ICHAR *)parser->m_dataBufEnd); *eventEndPP = s; + beforeHandler(parser); parser->m_defaultHandler(parser->m_handlerArg, parser->m_dataBuf, (int)(dataPtr - (ICHAR *)parser->m_dataBuf)); + afterHandler(parser); *eventPP = s; } while ((convert_res != XML_CONVERT_COMPLETED) && (convert_res != XML_CONVERT_INPUT_INCOMPLETE)); - } else + } else { + beforeHandler(parser); parser->m_defaultHandler( parser->m_handlerArg, (const XML_Char *)s, (int)((const XML_Char *)end - (const XML_Char *)s)); + afterHandler(parser); + } } static int @@ -7106,48 +7217,34 @@ defineAttribute(ELEMENT_TYPE *type, ATTRIBUTE_ID *attId, XML_Bool isCdata, /* The handling of default attributes gets messed up if we have a default which duplicates a non-default. */ NAMED *const nameFound - = (NAMED *)lookup(parser, &(type->defaultAttsNames), attId->name, 0); + = lookup(parser, &(type->defaultAttsNames), attId->name, 0); if (nameFound) return 1; if (isId && ! type->idAtt && ! attId->xmlns) type->idAtt = attId; } if (type->nDefaultAtts == type->allocDefaultAtts) { - if (type->allocDefaultAtts == 0) { - type->allocDefaultAtts = 8; - type->defaultAtts - = MALLOC(parser, type->allocDefaultAtts * sizeof(DEFAULT_ATTRIBUTE)); - if (! type->defaultAtts) { - type->allocDefaultAtts = 0; - return 0; - } - } else { - DEFAULT_ATTRIBUTE *temp; - - /* Detect and prevent integer overflow */ - if (type->allocDefaultAtts > INT_MAX / 2) { - return 0; - } - - int count = type->allocDefaultAtts * 2; + /* Detect and prevent integer overflow */ + if (type->allocDefaultAtts > SIZE_MAX / 2) { + return 0; + } - /* Detect and prevent integer overflow. - * The preprocessor guard addresses the "always false" warning - * from -Wtype-limits on platforms where - * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */ -#if UINT_MAX >= SIZE_MAX - if ((unsigned)count > SIZE_MAX / sizeof(DEFAULT_ATTRIBUTE)) { - return 0; - } -#endif + size_t count = type->allocDefaultAtts * 2; + if (count == 0) { + count = 8; + } - temp = REALLOC(parser, type->defaultAtts, - (count * sizeof(DEFAULT_ATTRIBUTE))); - if (temp == NULL) - return 0; - type->allocDefaultAtts = count; - type->defaultAtts = temp; + /* Detect and prevent integer overflow. */ + if (count > SIZE_MAX / sizeof(DEFAULT_ATTRIBUTE)) { + return 0; } + + DEFAULT_ATTRIBUTE *const temp = REALLOC( + parser, type->defaultAtts, (count * sizeof(DEFAULT_ATTRIBUTE))); + if (temp == NULL) + return 0; + type->allocDefaultAtts = count; + type->defaultAtts = temp; } att = type->defaultAtts + type->nDefaultAtts; att->id = attId; @@ -7156,8 +7253,8 @@ defineAttribute(ELEMENT_TYPE *type, ATTRIBUTE_ID *attId, XML_Bool isCdata, if (! isCdata) attId->maybeTokenized = XML_TRUE; - NAMED *const nameAddedOrFound = (NAMED *)lookup( - parser, &(type->defaultAttsNames), attId->name, sizeof(NAMED)); + NAMED *const nameAddedOrFound + = lookup(parser, &(type->defaultAttsNames), attId->name, sizeof(NAMED)); if (! nameAddedOrFound) return 0; @@ -7230,13 +7327,14 @@ getAttributeId(XML_Parser parser, const ENCODING *enc, const char *start, } else { int i; for (i = 0; name[i]; i++) { + /* Detect and prevent signed integer overflow */ + if (i == INT_MAX) { + return NULL; + } /* attributes without prefix are *not* in the default namespace */ if (name[i] == XML_T(ASCII_COLON)) { - int j; - for (j = 0; j < i; j++) { - if (! poolAppendChar(&dtd->pool, name[j])) - return NULL; - } + if (! poolAppendChars(&dtd->pool, name, i)) + return NULL; if (! poolAppendChar(&dtd->pool, XML_T('\0'))) return NULL; id->prefix = (PREFIX *)lookup(parser, &dtd->prefixes, @@ -7264,46 +7362,39 @@ getContext(XML_Parser parser) { XML_Bool needSep = XML_FALSE; if (dtd->defaultPrefix.binding) { - int i; - int len; if (! poolAppendChar(&parser->m_tempPool, XML_T(ASCII_EQUALS))) return NULL; - len = dtd->defaultPrefix.binding->uriLen; + size_t len = dtd->defaultPrefix.binding->uriLen; if (parser->m_namespaceSeparator) len--; - for (i = 0; i < len; i++) { - if (! poolAppendChar(&parser->m_tempPool, - dtd->defaultPrefix.binding->uri[i])) { - /* Because of memory caching, I don't believe this line can be - * executed. - * - * This is part of a loop copying the default prefix binding - * URI into the parser's temporary string pool. Previously, - * that URI was copied into the same string pool, with a - * terminating NUL character, as part of setContext(). When - * the pool was cleared, that leaves a block definitely big - * enough to hold the URI on the free block list of the pool. - * The URI copy in getContext() therefore cannot run out of - * memory. - * - * If the pool is used between the setContext() and - * getContext() calls, the worst it can do is leave a bigger - * block on the front of the free list. Given that this is - * all somewhat inobvious and program logic can be changed, we - * don't delete the line but we do exclude it from the test - * coverage statistics. - */ - return NULL; /* LCOV_EXCL_LINE */ - } + if (! poolAppendChars(&parser->m_tempPool, dtd->defaultPrefix.binding->uri, + len)) { + /* Because of memory caching, I don't believe this line can be + * executed. + * + * This is part of a loop copying the default prefix binding + * URI into the parser's temporary string pool. Previously, + * that URI was copied into the same string pool, with a + * terminating NUL character, as part of setContext(). When + * the pool was cleared, that leaves a block definitely big + * enough to hold the URI on the free block list of the pool. + * The URI copy in getContext() therefore cannot run out of + * memory. + * + * If the pool is used between the setContext() and + * getContext() calls, the worst it can do is leave a bigger + * block on the front of the free list. Given that this is + * all somewhat inobvious and program logic can be changed, we + * don't delete the line but we do exclude it from the test + * coverage statistics. + */ + return NULL; /* LCOV_EXCL_LINE */ } needSep = XML_TRUE; } hashTableIterInit(&iter, &(dtd->prefixes)); for (;;) { - int i; - int len; - const XML_Char *s; PREFIX *prefix = (PREFIX *)hashTableIterNext(&iter); if (! prefix) break; @@ -7318,23 +7409,21 @@ getContext(XML_Parser parser) { } if (needSep && ! poolAppendChar(&parser->m_tempPool, CONTEXT_SEP)) return NULL; - for (s = prefix->name; *s; s++) - if (! poolAppendChar(&parser->m_tempPool, *s)) - return NULL; + if (! poolAppendChars(&parser->m_tempPool, prefix->name, + xcslen(prefix->name))) + return NULL; if (! poolAppendChar(&parser->m_tempPool, XML_T(ASCII_EQUALS))) return NULL; - len = prefix->binding->uriLen; + size_t len = prefix->binding->uriLen; if (parser->m_namespaceSeparator) len--; - for (i = 0; i < len; i++) - if (! poolAppendChar(&parser->m_tempPool, prefix->binding->uri[i])) - return NULL; + if (! poolAppendChars(&parser->m_tempPool, prefix->binding->uri, len)) + return NULL; needSep = XML_TRUE; } hashTableIterInit(&iter, &(dtd->generalEntities)); for (;;) { - const XML_Char *s; ENTITY *e = (ENTITY *)hashTableIterNext(&iter); if (! e) break; @@ -7342,9 +7431,8 @@ getContext(XML_Parser parser) { continue; if (needSep && ! poolAppendChar(&parser->m_tempPool, CONTEXT_SEP)) return NULL; - for (s = e->name; *s; s++) - if (! poolAppendChar(&parser->m_tempPool, *s)) - return 0; + if (! poolAppendChars(&parser->m_tempPool, e->name, xcslen(e->name))) + return NULL; needSep = XML_TRUE; } @@ -7466,6 +7554,7 @@ dtdCreate(XML_Parser parser) { p->in_eldecl = XML_FALSE; p->scaffIndex = NULL; + p->scaffIndexSize = 0; p->scaffold = NULL; p->scaffLevel = 0; p->scaffSize = 0; @@ -7487,8 +7576,7 @@ dtdReset(DTD *p, XML_Parser parser) { if (! e) break; hashTableDestroy(&(e->defaultAttsNames)); - if (e->allocDefaultAtts != 0) - FREE(parser, e->defaultAtts); + FREE(parser, e->defaultAtts); } hashTableClear(&(p->generalEntities)); #ifdef XML_DTD @@ -7507,6 +7595,7 @@ dtdReset(DTD *p, XML_Parser parser) { FREE(parser, p->scaffIndex); p->scaffIndex = NULL; + p->scaffIndexSize = 0; FREE(parser, p->scaffold); p->scaffold = NULL; @@ -7529,8 +7618,7 @@ dtdDestroy(DTD *p, XML_Bool isDocEntity, XML_Parser parser) { if (! e) break; hashTableDestroy(&(e->defaultAttsNames)); - if (e->allocDefaultAtts != 0) - FREE(parser, e->defaultAtts); + FREE(parser, e->defaultAtts); } hashTableDestroy(&(p->generalEntities)); #ifdef XML_DTD @@ -7609,7 +7697,6 @@ dtdCopy(XML_Parser oldParser, DTD *newDtd, const DTD *oldDtd, hashTableIterInit(&iter, &(oldDtd->elementTypes)); for (;;) { - int i; ELEMENT_TYPE *newE; const XML_Char *name; const ELEMENT_TYPE *oldE = (ELEMENT_TYPE *)hashTableIterNext(&iter); @@ -7627,15 +7714,10 @@ dtdCopy(XML_Parser oldParser, DTD *newDtd, const DTD *oldDtd, hashTableInit(&(newE->defaultAttsNames), parser); if (oldE->nDefaultAtts) { - /* Detect and prevent integer overflow. - * The preprocessor guard addresses the "always false" warning - * from -Wtype-limits on platforms where - * sizeof(int) < sizeof(size_t), e.g. on x86_64. */ -#if UINT_MAX >= SIZE_MAX - if ((size_t)oldE->nDefaultAtts > SIZE_MAX / sizeof(DEFAULT_ATTRIBUTE)) { + /* Detect and prevent integer overflow. */ + if (oldE->nDefaultAtts > SIZE_MAX / sizeof(DEFAULT_ATTRIBUTE)) { return 0; } -#endif newE->defaultAtts = MALLOC(parser, oldE->nDefaultAtts * sizeof(DEFAULT_ATTRIBUTE)); if (! newE->defaultAtts) { @@ -7649,7 +7731,7 @@ dtdCopy(XML_Parser oldParser, DTD *newDtd, const DTD *oldDtd, if (oldE->prefix) newE->prefix = (PREFIX *)lookup(oldParser, &(newDtd->prefixes), oldE->prefix->name, 0); - for (i = 0; i < newE->nDefaultAtts; i++) { + for (size_t i = 0; i < newE->nDefaultAtts; i++) { const XML_Char *const attributeName = oldE->defaultAtts[i].id->name; newE->defaultAtts[i].id = (ATTRIBUTE_ID *)lookup( oldParser, &(newDtd->attributeIds), attributeName, 0); @@ -7662,8 +7744,8 @@ dtdCopy(XML_Parser oldParser, DTD *newDtd, const DTD *oldDtd, } else newE->defaultAtts[i].value = NULL; - NAMED *const nameAddedOrFound = (NAMED *)lookup( - parser, &(newE->defaultAttsNames), attributeName, sizeof(NAMED)); + NAMED *const nameAddedOrFound = lookup(parser, &(newE->defaultAttsNames), + attributeName, sizeof(NAMED)); if (! nameAddedOrFound) { return 0; } @@ -7693,6 +7775,7 @@ dtdCopy(XML_Parser oldParser, DTD *newDtd, const DTD *oldDtd, newDtd->scaffSize = oldDtd->scaffSize; newDtd->scaffLevel = oldDtd->scaffLevel; newDtd->scaffIndex = oldDtd->scaffIndex; + newDtd->scaffIndexSize = oldDtd->scaffIndexSize; return 1; } /* End dtdCopy */ @@ -7764,18 +7847,23 @@ copyEntityTable(XML_Parser oldParser, HASH_TABLE *newTable, static XML_Bool FASTCALL keyeq(KEY s1, KEY s2) { +#ifdef XML_UNICODE +# ifdef XML_UNICODE_WCHAR_T + return (wcscmp(s1, s2) == 0) ? XML_TRUE : XML_FALSE; +# else for (; *s1 == *s2; s1++, s2++) if (*s1 == 0) return XML_TRUE; return XML_FALSE; +# endif +#else + return (strcmp(s1, s2) == 0) ? XML_TRUE : XML_FALSE; +#endif } static size_t keylen(KEY s) { - size_t len = 0; - for (; *s; s++, len++) - ; - return len; + return xcslen(s); } static void @@ -7993,10 +8081,8 @@ poolAppend(STRING_POOL *pool, const ENCODING *enc, const char *ptr, static const XML_Char *FASTCALL poolCopyString(STRING_POOL *pool, const XML_Char *s) { - do { - if (! poolAppendChar(pool, *s)) - return NULL; - } while (*s++); + if (! poolAppendChars(pool, s, xcslen(s) + /*null terminator*/ 1)) + return NULL; s = pool->start; poolFinish(pool); return s; @@ -8035,10 +8121,8 @@ poolCopyStringN(STRING_POOL *pool, const XML_Char *s, int n) { */ return NULL; /* LCOV_EXCL_LINE */ } - for (; n > 0; --n, s++) { - if (! poolAppendChar(pool, *s)) - return NULL; - } + if (n > 0 && ! poolAppendChars(pool, s, n)) + return NULL; s = pool->start; poolFinish(pool); return s; @@ -8046,11 +8130,8 @@ poolCopyStringN(STRING_POOL *pool, const XML_Char *s, int n) { static const XML_Char *FASTCALL poolAppendString(STRING_POOL *pool, const XML_Char *s) { - while (*s) { - if (! poolAppendChar(pool, *s)) - return NULL; - s++; - } + if (! poolAppendChars(pool, s, xcslen(s))) + return NULL; return pool->start; } @@ -8059,9 +8140,8 @@ poolStoreString(STRING_POOL *pool, const ENCODING *enc, const char *ptr, const char *end) { if (! poolAppend(pool, enc, ptr, end)) return NULL; - if (pool->ptr == pool->end && ! poolGrow(pool)) + if (! poolAppendChar(pool, 0)) return NULL; - *(pool->ptr)++ = 0; return pool->start; } @@ -8196,6 +8276,19 @@ poolGrow(STRING_POOL *pool) { return XML_TRUE; } +static bool FASTCALL +poolGrowUntil(STRING_POOL *pool, size_t needed) { + for (;;) { + const size_t available = pool->end - pool->ptr; + if (available >= needed) { + return true; + } + if (! poolGrow(pool)) { + return false; + } + } +} + static int FASTCALL nextScaffoldPart(XML_Parser parser) { DTD *const dtd = parser->m_dtd; /* save one level of indirection */ @@ -8203,18 +8296,14 @@ nextScaffoldPart(XML_Parser parser) { int next; if (! dtd->scaffIndex) { - /* Detect and prevent integer overflow. - * The preprocessor guard addresses the "always false" warning - * from -Wtype-limits on platforms where - * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */ -#if UINT_MAX >= SIZE_MAX + /* Detect and prevent integer overflow. */ if (parser->m_groupSize > SIZE_MAX / sizeof(int)) { return -1; } -#endif dtd->scaffIndex = MALLOC(parser, parser->m_groupSize * sizeof(int)); if (! dtd->scaffIndex) return -1; + dtd->scaffIndexSize = parser->m_groupSize; dtd->scaffIndex[0] = 0; } @@ -8375,12 +8464,21 @@ build_model(XML_Parser parser) { const XML_Char *src; dest->name = str; src = dtd->scaffold[src_node].name; - for (;;) { - *str++ = *src; - if (! *src) - break; - src++; + + const size_t nameLen = xcslen(src) + /* null terminator*/ 1; + + // Detect and prevent integer overflow + if (nameLen > SIZE_MAX / sizeof(XML_Char)) { + // NOTE: We are avoiding FREE(..) here because the model + // is not being allocated with MALLOC(..) but with plain + // .malloc_fcn(..). + parser->m_mem.free_fcn(ret); + return NULL; } + + memcpy(str, src, nameLen * sizeof(XML_Char)); + str += nameLen; + dest->numchildren = 0; dest->children = NULL; } else { @@ -8427,22 +8525,24 @@ getElementType(XML_Parser parser, const ENCODING *enc, const char *ptr, static XML_Char * copyString(const XML_Char *s, XML_Parser parser) { - size_t charsRequired = 0; - XML_Char *result; - /* First determine how long the string is */ - while (s[charsRequired] != 0) { - charsRequired++; - } - /* Include the terminator */ - charsRequired++; + const size_t charsRequired = xcslen(s) + /*null terminator*/ 1; + + /* Detect and prevent integer overflow */ + if (charsRequired > SIZE_MAX / sizeof(XML_Char)) + return NULL; + + const size_t bytesRequired = charsRequired * sizeof(XML_Char); /* Now allocate space for the copy */ - result = MALLOC(parser, charsRequired * sizeof(XML_Char)); + XML_Char *const result = MALLOC(parser, bytesRequired); + if (result == NULL) return NULL; + /* Copy the original into place */ - memcpy(result, s, charsRequired * sizeof(XML_Char)); + memcpy(result, s, bytesRequired); + return result; } @@ -8609,15 +8709,25 @@ entityTrackingReportStats(XML_Parser rootParser, ENTITY *entity, const char *const entityName = entity->name; # endif + const bool limitingWanted = rootParser->m_entity_stats.debugLevel < 2; + const int maxLimitedDepth = 10; // somewhat arbitrary + const int candidateIndentDepth + = (int)rootParser->m_entity_stats.currentDepth - 1; + const bool limitingNeeded + = limitingWanted && (candidateIndentDepth > maxLimitedDepth); + const char *const ellipisOrEmpty = limitingNeeded ? " [..] " : ""; + const int indentDepth + = limitingNeeded ? (maxLimitedDepth - /* make space for ellipis */ 2) + : candidateIndentDepth; + fprintf( stderr, - "expat: Entities(%p): Count %9u, depth %2u/%2u %*s%s%s; %s length %d (xmlparse.c:%d)\n", + "expat: Entities(%p): Count %9u, depth %2u/%2u %*s%s%s%s; %s length %d (xmlparse.c:%d)\n", (void *)rootParser, rootParser->m_entity_stats.countEverOpened, rootParser->m_entity_stats.currentDepth, - rootParser->m_entity_stats.maximumDepthSeen, - ((int)rootParser->m_entity_stats.currentDepth - 1) * 2, "", - entity->is_param ? "%" : "&", entityName, action, entity->textLen, - sourceLine); + rootParser->m_entity_stats.maximumDepthSeen, indentDepth * 2, "", + ellipisOrEmpty, entity->is_param ? "%" : "&", entityName, action, + entity->textLen, sourceLine); } static void diff --git a/Modules/expat/xmltok.c b/Modules/expat/xmltok.c index 32cd5f147e9322..387c6e44a25f80 100644 --- a/Modules/expat/xmltok.c +++ b/Modules/expat/xmltok.c @@ -25,6 +25,7 @@ Copyright (c) 2022 Sean McBride <sean@rogue-research.com> Copyright (c) 2023 Hanno Böck <hanno@gentoo.org> Copyright (c) 2025 Alfonso Gregory <gfunni234@gmail.com> + Copyright (c) 2026 Nick Begg <nick@stunttruck.net> Licensed under the MIT license: Permission is hereby granted, free of charge, to any person obtaining @@ -58,6 +59,7 @@ #endif #include "internal.h" +#include "fallthrough.h" #include "xmltok.h" #include "nametab.h" @@ -641,7 +643,7 @@ unicode_byte_type(char hi, char lo) { *(*toP)++ = lo; \ break; \ } \ - /* fall through */ \ + EXPAT_FALLTHROUGH; \ case 0x1: \ case 0x2: \ case 0x3: \ @@ -1557,7 +1559,7 @@ initScan(const ENCODING *const *encodingTable, const INIT_ENCODING *enc, case 0xEF: /* possibly first byte of UTF-8 BOM */ if (INIT_ENC_INDEX(enc) == ISO_8859_1_ENC && state == XML_CONTENT_STATE) break; - /* fall through */ + EXPAT_FALLTHROUGH; case 0x00: case 0x3C: return XML_TOK_PARTIAL; diff --git a/Modules/expat/xmltok_impl.c b/Modules/expat/xmltok_impl.c index 239a2d06c4512c..eae11bdd968aee 100644 --- a/Modules/expat/xmltok_impl.c +++ b/Modules/expat/xmltok_impl.c @@ -17,6 +17,7 @@ Copyright (c) 2019 David Loffredo <loffredo@steptools.com> Copyright (c) 2020 Boris Kolpackov <boris@codesynthesis.com> Copyright (c) 2022 Martin Ettl <ettl.martin78@googlemail.com> + Copyright (c) 2026 Nick Begg <nick@stunttruck.net> Licensed under the MIT license: Permission is hereby granted, free of charge, to any person obtaining @@ -83,7 +84,7 @@ *nextTokPtr = ptr; \ return XML_TOK_INVALID; \ } \ - /* fall through */ \ + EXPAT_FALLTHROUGH; \ case BT_NMSTRT: \ case BT_HEX: \ case BT_DIGIT: \ @@ -112,7 +113,7 @@ *nextTokPtr = ptr; \ return XML_TOK_INVALID; \ } \ - /* fall through */ \ + EXPAT_FALLTHROUGH; \ case BT_NMSTRT: \ case BT_HEX: \ ptr += MINBPC(enc); \ @@ -209,7 +210,7 @@ PREFIX(scanDecl)(const ENCODING *enc, const char *ptr, const char *end, *nextTokPtr = ptr; return XML_TOK_INVALID; } - /* fall through */ + EXPAT_FALLTHROUGH; case BT_S: case BT_CR: case BT_LF: @@ -323,7 +324,7 @@ PREFIX(scanPi)(const ENCODING *enc, const char *ptr, const char *end, *nextTokPtr = ptr + MINBPC(enc); return tok; } - /* fall through */ + EXPAT_FALLTHROUGH; default: *nextTokPtr = ptr; return XML_TOK_INVALID; @@ -615,7 +616,7 @@ PREFIX(scanAtts)(const ENCODING *enc, const char *ptr, const char *end, return XML_TOK_INVALID; } } - /* fall through */ + EXPAT_FALLTHROUGH; case BT_EQUALS: { int open; # ifdef XML_NS @@ -898,7 +899,7 @@ PREFIX(contentTok)(const ENCODING *enc, const char *ptr, const char *end, return XML_TOK_INVALID; } } - /* fall through */ + EXPAT_FALLTHROUGH; case BT_AMP: case BT_LT: case BT_NONXML: @@ -1059,7 +1060,7 @@ PREFIX(prologTok)(const ENCODING *enc, const char *ptr, const char *end, /* indicate that this might be part of a CR/LF pair */ return -XML_TOK_PROLOG_S; } - /* fall through */ + EXPAT_FALLTHROUGH; case BT_S: case BT_LF: for (;;) { @@ -1074,7 +1075,7 @@ PREFIX(prologTok)(const ENCODING *enc, const char *ptr, const char *end, /* don't split CR/LF pair */ if (ptr + MINBPC(enc) != end) break; - /* fall through */ + EXPAT_FALLTHROUGH; default: *nextTokPtr = ptr; return XML_TOK_PROLOG_S; @@ -1189,7 +1190,7 @@ PREFIX(prologTok)(const ENCODING *enc, const char *ptr, const char *end, tok = XML_TOK_NMTOKEN; break; } - /* fall through */ + EXPAT_FALLTHROUGH; default: *nextTokPtr = ptr; return XML_TOK_INVALID; @@ -1484,7 +1485,7 @@ PREFIX(isPublicId)(const ENCODING *enc, const char *ptr, const char *end, case BT_NMSTRT: if (! (BYTE_TO_ASCII(enc, ptr) & ~0x7f)) break; - /* fall through */ + EXPAT_FALLTHROUGH; default: switch (BYTE_TO_ASCII(enc, ptr)) { case 0x24: /* $ */ diff --git a/PCbuild/_elementtree.vcxproj b/PCbuild/_elementtree.vcxproj index 3eb9c89bcb6740..46e34a5ea82d5d 100644 --- a/PCbuild/_elementtree.vcxproj +++ b/PCbuild/_elementtree.vcxproj @@ -103,9 +103,11 @@ <ClInclude Include="..\Modules\expat\expat.h" /> <ClInclude Include="..\Modules\expat\expat_config.h" /> <ClInclude Include="..\Modules\expat\expat_external.h" /> + <ClInclude Include="..\Modules\expat\fallthrough.h" /> <ClInclude Include="..\Modules\expat\iasciitab.h" /> <ClInclude Include="..\Modules\expat\internal.h" /> <ClInclude Include="..\Modules\expat\latin1tab.h" /> + <ClInclude Include="..\Modules\expat\memory_sanitizer.h" /> <ClInclude Include="..\Modules\expat\nametab.h" /> <ClInclude Include="..\Modules\expat\pyexpatns.h" /> <ClInclude Include="..\Modules\expat\utf8tab.h" /> diff --git a/PCbuild/_elementtree.vcxproj.filters b/PCbuild/_elementtree.vcxproj.filters index a5368024ccebfd..f6b55d8ff82a68 100644 --- a/PCbuild/_elementtree.vcxproj.filters +++ b/PCbuild/_elementtree.vcxproj.filters @@ -33,6 +33,9 @@ <ClInclude Include="..\Modules\expat\expat_external.h"> <Filter>Header Files\expat</Filter> </ClInclude> + <ClInclude Include="..\Modules\expat\fallthrough.h"> + <Filter>Header Files\expat</Filter> + </ClInclude> <ClInclude Include="..\Modules\expat\iasciitab.h"> <Filter>Header Files\expat</Filter> </ClInclude> @@ -42,6 +45,9 @@ <ClInclude Include="..\Modules\expat\latin1tab.h"> <Filter>Header Files\expat</Filter> </ClInclude> + <ClInclude Include="..\Modules\expat\memory_sanitizer.h"> + <Filter>Header Files\expat</Filter> + </ClInclude> <ClInclude Include="..\Modules\expat\nametab.h"> <Filter>Header Files\expat</Filter> </ClInclude> diff --git a/PCbuild/pyexpat.vcxproj b/PCbuild/pyexpat.vcxproj index 8e0f5f6311220a..8a60ee15eb41bf 100644 --- a/PCbuild/pyexpat.vcxproj +++ b/PCbuild/pyexpat.vcxproj @@ -95,6 +95,8 @@ </ClCompile> </ItemDefinitionGroup> <ItemGroup> + <ClInclude Include="..\Modules\expat\fallthrough.h" /> + <ClInclude Include="..\Modules\expat\memory_sanitizer.h" /> <ClInclude Include="..\Modules\expat\xmlrole.h" /> <ClInclude Include="..\Modules\expat\xmltok.h" /> </ItemGroup> diff --git a/PCbuild/pyexpat.vcxproj.filters b/PCbuild/pyexpat.vcxproj.filters index fd22fc8c477df0..230531033fccd8 100644 --- a/PCbuild/pyexpat.vcxproj.filters +++ b/PCbuild/pyexpat.vcxproj.filters @@ -12,6 +12,12 @@ </Filter> </ItemGroup> <ItemGroup> + <ClInclude Include="..\Modules\expat\fallthrough.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\Modules\expat\memory_sanitizer.h"> + <Filter>Header Files</Filter> + </ClInclude> <ClInclude Include="..\Modules\expat\xmlrole.h"> <Filter>Header Files</Filter> </ClInclude> diff --git a/Tools/build/.warningignore_macos b/Tools/build/.warningignore_macos index d7b62bc6a43ba6..67f50119db7310 100644 --- a/Tools/build/.warningignore_macos +++ b/Tools/build/.warningignore_macos @@ -3,7 +3,3 @@ # Keep lines sorted lexicographically to help avoid merge conflicts. # Format example: # /path/to/file (number of warnings in file) -Modules/expat/siphash.h 7 -Modules/expat/xmlparse.c 13 -Modules/expat/xmltok.c 3 -Modules/expat/xmltok_impl.c 26 From ae42632ed4bf6d8ff912060b383915955928cb7a Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka <storchaka@gmail.com> Date: Sat, 11 Jul 2026 08:22:20 +0300 Subject: [PATCH 655/818] [3.15] gh-153333: Read tkinter profile scripts with the source file's encoding (GH-153334) (GH-153541) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tk.readprofile ran the user's ~/.CLASS.py and ~/.BASE.py scripts with exec(open(path).read()), decoding them with the locale encoding. Read them in binary mode so exec() honors each script's own coding cookie. (cherry picked from commit bac73b0f4ea475cbfb11f41579129c9d07075c34) Co-authored-by: tonghuaroot (童话) <tonghuaroot@gmail.com> --- Lib/test/test_tkinter/test_misc.py | 21 +++++++++++++++++++ Lib/tkinter/__init__.py | 6 ++++-- ...-07-08-21-15-00.gh-issue-153333.Kp3mZq.rst | 3 +++ 3 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-07-08-21-15-00.gh-issue-153333.Kp3mZq.rst diff --git a/Lib/test/test_tkinter/test_misc.py b/Lib/test/test_tkinter/test_misc.py index 698ba818029fe8..285a5d0938d2de 100644 --- a/Lib/test/test_tkinter/test_misc.py +++ b/Lib/test/test_tkinter/test_misc.py @@ -1,5 +1,6 @@ import collections.abc import functools +import os import platform import sys import textwrap @@ -755,6 +756,26 @@ def test_iterable_protocol(self): class TkTest(AbstractTkTest, unittest.TestCase): + def test_readprofile(self): + # gh-153333: profile scripts are decoded with their own coding cookie, + # not the locale encoding. Two cookies so no locale can mask the bug. + profiles = { + '.RpClass.py': ('latin-1', "self._rp_latin1 = 'caf\xe9'"), + '.rpbase.py': ('utf-8', "self._rp_utf8 = 'caf\xe9'"), + } + self.addCleanup(self.root.__dict__.pop, '_rp_latin1', None) + self.addCleanup(self.root.__dict__.pop, '_rp_utf8', None) + with (os_helper.temp_dir() as home, + os_helper.EnvironmentVarGuard() as env): + env['HOME'] = home + for filename, (encoding, body) in profiles.items(): + script = '# -*- coding: %s -*-\n%s\n' % (encoding, body) + with open(os.path.join(home, filename), 'wb') as f: + f.write(script.encode(encoding)) + self.root.readprofile('rpbase', 'RpClass') + self.assertEqual(self.root._rp_latin1, 'caf\xe9') + self.assertEqual(self.root._rp_utf8, 'caf\xe9') + def test_className(self): # The className argument sets the class of the root window. Tk # title-cases it: the first letter is upper-cased, the rest lower-cased. diff --git a/Lib/tkinter/__init__.py b/Lib/tkinter/__init__.py index 7189471ee3fa0e..3b693bc72f5723 100644 --- a/Lib/tkinter/__init__.py +++ b/Lib/tkinter/__init__.py @@ -2639,11 +2639,13 @@ def readprofile(self, baseName, className): if os.path.isfile(class_tcl): self.tk.call('source', class_tcl) if os.path.isfile(class_py): - exec(open(class_py).read(), dir) + with open(class_py, 'rb') as f: + exec(f.read(), dir) if os.path.isfile(base_tcl): self.tk.call('source', base_tcl) if os.path.isfile(base_py): - exec(open(base_py).read(), dir) + with open(base_py, 'rb') as f: + exec(f.read(), dir) def report_callback_exception(self, exc, val, tb): """Report callback exception on sys.stderr. diff --git a/Misc/NEWS.d/next/Library/2026-07-08-21-15-00.gh-issue-153333.Kp3mZq.rst b/Misc/NEWS.d/next/Library/2026-07-08-21-15-00.gh-issue-153333.Kp3mZq.rst new file mode 100644 index 00000000000000..6fcbd590d0d9d3 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-08-21-15-00.gh-issue-153333.Kp3mZq.rst @@ -0,0 +1,3 @@ +The ``readprofile`` method of :class:`tkinter.Tk` now reads the user's +profile scripts using the encoding declared in the file, instead of the +locale encoding. From 43e621e0d3817c4b34e414c9aae618f0a9292c29 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 11 Jul 2026 10:21:01 +0200 Subject: [PATCH 656/818] [3.15] gh-88647: Fix tkinter config() docs for synonym options (GH-153544) (GH-153545) (cherry picked from commit d52cfd2a0ec4423ed94bda640deefdfcf053bd8e) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --- Doc/library/tkinter.rst | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/Doc/library/tkinter.rst b/Doc/library/tkinter.rst index 7ac2e033cea88c..f28e6706e22cbb 100644 --- a/Doc/library/tkinter.rst +++ b/Doc/library/tkinter.rst @@ -539,11 +539,8 @@ arguments, or by calling the :meth:`~Misc.keys` method on that widget. The return value of these calls is a dictionary whose key is the name of the option as a string (for example, ``'relief'``) and whose values are 5-tuples. -Some options, like ``bg`` are synonyms for common options with long names -(``bg`` is shorthand for "background"). Passing the ``config()`` method the name -of a shorthand option will return a 2-tuple, not 5-tuple. The 2-tuple passed -back will contain the name of the synonym and the "real" option (such as -``('bg', 'background')``). +Some options, like ``bg``, are synonyms for common options with long names +(``bg`` is shorthand for "background"). +-------+---------------------------------+--------------+ | Index | Meaning | Example | From 2aa59283922e5148664604f2e94cc134723ae272 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 11 Jul 2026 12:17:25 +0200 Subject: [PATCH 657/818] [3.15] gh-86726: Fix and improve tkinter documentation and docstrings (GH-153549) (GH-153551) Correct inaccurate return-type and option descriptions in the tkinter reference, and add missing module and class docstrings. (cherry picked from commit 77cb7560c07feed0d5b144c0c1735e1620c96f51) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --- Doc/library/dialog.rst | 25 ++++++++++++------------- Doc/library/tkinter.messagebox.rst | 4 +--- Doc/library/tkinter.rst | 15 ++++++++------- Doc/library/tkinter.ttk.rst | 15 +++++++++++---- Lib/tkinter/__init__.py | 4 ++-- Lib/tkinter/colorchooser.py | 2 ++ Lib/tkinter/commondialog.py | 2 ++ Lib/tkinter/dialog.py | 7 ++++++- Lib/tkinter/font.py | 2 ++ Lib/tkinter/messagebox.py | 2 ++ Lib/tkinter/simpledialog.py | 2 +- 11 files changed, 49 insertions(+), 31 deletions(-) diff --git a/Doc/library/dialog.rst b/Doc/library/dialog.rst index 384a1eacc2d7cc..c50232f1d029cd 100644 --- a/Doc/library/dialog.rst +++ b/Doc/library/dialog.rst @@ -175,19 +175,16 @@ specific value. .. class:: Open(master=None, **options) SaveAs(master=None, **options) + Directory(master=None, **options) - The above two classes provide native dialog windows for saving and loading - files. + The above three classes provide native dialog windows for loading and saving + files and for selecting a directory. **Convenience classes** The below classes are used for creating file/directory windows from scratch. These do not emulate the native look-and-feel of the platform. -.. class:: Directory(master=None, **options) - - Create a dialog prompting the user to select a directory. - .. note:: The *FileDialog* class should be subclassed for custom event handling and behaviour. @@ -311,23 +308,25 @@ the classic (non-themed) Tk widgets. .. data:: DIALOG_ICON - The name of the default bitmap (``'questhead'``) displayed by a - :class:`Dialog`. + The name of a bitmap (``'questhead'``) suitable for use as the *bitmap* + of a :class:`Dialog`. .. class:: Dialog(master=None, cnf={}, **kw) Display a modal dialog box built from the classic (non-themed) Tk widgets and wait for the user to press one of its buttons. - The options, given through *cnf* or as keyword arguments, include *title* - (the window title), *text* (the message), *bitmap* (an icon, - :data:`DIALOG_ICON` by default), *default* (the index of the default button) - and *strings* (the sequence of button labels). + The options, given through *cnf* or as keyword arguments, are all required: + *title* (the window title), *text* (the message), *bitmap* (the name of a + bitmap icon, such as :data:`DIALOG_ICON`), *default* (the index of the + default button) and *strings* (the sequence of button labels). After construction, the :attr:`!num` attribute holds the index of the button the user pressed. .. method:: destroy() - Destroy the dialog window. + Do nothing. + The dialog window is destroyed automatically before the constructor + returns, so there is nothing left for this method to do. .. seealso:: diff --git a/Doc/library/tkinter.messagebox.rst b/Doc/library/tkinter.messagebox.rst index 7fd561ade2f8bc..47fe680bac9107 100644 --- a/Doc/library/tkinter.messagebox.rst +++ b/Doc/library/tkinter.messagebox.rst @@ -13,9 +13,7 @@ a variety of convenience methods for commonly used configurations. The message boxes are modal: each blocks until the user responds, then returns a value that depends on the function. The ``show*`` functions and :meth:`Message.show` return the symbolic name of -the button the user pressed, as a string (such as :data:`OK` or :data:`YES`), -while the ``ask*`` functions return a :class:`bool` or ``None`` (see each -function below). +the button the user pressed, as a string (such as :data:`OK` or :data:`YES`). Common message box styles and layouts include but are not limited to: .. figure:: tk_msg.png diff --git a/Doc/library/tkinter.rst b/Doc/library/tkinter.rst index f28e6706e22cbb..ce68f0389b9c30 100644 --- a/Doc/library/tkinter.rst +++ b/Doc/library/tkinter.rst @@ -2280,8 +2280,8 @@ Base and mixin classes If all four arguments are given, the window manager keeps the ratio between ``minNumer/minDenom`` and ``maxNumer/maxDenom``; passing empty strings removes any existing restriction. - With no arguments, return a tuple of the four current values, or an empty - string if no aspect restriction is in effect. + With no arguments, return a tuple of the four current values, or ``None`` + if no aspect restriction is in effect. :meth:`wm_aspect` is an alias of :meth:`!aspect`. .. method:: wm_attributes(*args, return_python_dict=False, **kwargs) @@ -2506,8 +2506,8 @@ Base and mixin classes window's internally requested size, and *widthInc* and *heightInc* are the pixel sizes of a horizontal and vertical grid unit. Empty strings turn off gridded management. - With no arguments, return a tuple of the four current values, or an empty - string if the window is not gridded. + With no arguments, return a tuple of the four current values, or ``None`` + if the window is not gridded. :meth:`wm_grid` is an alias of :meth:`!grid`. Not to be confused with the grid geometry manager :meth:`Grid.grid`. @@ -2602,8 +2602,8 @@ Base and mixin classes Set or query a hint to the window manager about where the window's icon should be positioned. Empty strings cancel an existing hint. - With no arguments, return a tuple of the two current values, or an empty - string if no hint is in effect. + With no arguments, return a tuple of the two current values, or ``None`` + if no hint is in effect. :meth:`wm_iconposition` is an alias of :meth:`!iconposition`. .. method:: wm_iconwindow(pathName=None) @@ -2672,7 +2672,8 @@ Base and mixin classes When this flag is set, the window is ignored by the window manager: it is not reparented into a decorative frame and the user cannot manipulate it through the usual window manager controls. - With no argument, return a boolean indicating whether the flag is set. + With no argument, return a boolean indicating whether the flag is set, + or ``None`` if it has not been set. The flag is reliably honored only when the window is first mapped or remapped from the withdrawn state. :meth:`wm_overrideredirect` is an alias of :meth:`!overrideredirect`. diff --git a/Doc/library/tkinter.ttk.rst b/Doc/library/tkinter.ttk.rst index 13fead3e65ece7..54066625e82c06 100644 --- a/Doc/library/tkinter.ttk.rst +++ b/Doc/library/tkinter.ttk.rst @@ -42,8 +42,9 @@ To override the basic Tk widgets, the import should follow the Tk import:: That code causes several :mod:`!tkinter.ttk` widgets (:class:`Button`, :class:`Checkbutton`, :class:`Entry`, :class:`Frame`, :class:`Label`, -:class:`LabelFrame`, :class:`Menubutton`, :class:`PanedWindow`, -:class:`Radiobutton`, :class:`Scale` and :class:`Scrollbar`) to +:class:`LabelFrame`, :class:`Menubutton`, :class:`OptionMenu`, +:class:`PanedWindow`, :class:`Radiobutton`, :class:`Scale`, +:class:`Scrollbar` and :class:`Spinbox`) to automatically replace the Tk widgets. This has the direct benefit of using the new widgets which gives a better look @@ -1039,6 +1040,9 @@ ttk.Treeview The minimum width of the column in pixels. The treeview widget will not make the column any smaller than specified by this option when the widget is resized or the user drags a column. + *separator*: ``True``/``False`` + Specifies whether a column separator should be drawn to the right of + the column. *stretch*: ``True``/``False`` Specifies whether the column's width should be adjusted when the widget is resized. @@ -1752,8 +1756,11 @@ and inherits the common methods of :class:`Widget`. display in the menu. A *command* keyword argument may be given to specify a callable that is invoked with the selected value whenever the selection changes; the *style* - keyword argument sets the style used by the underlying menubutton; and the - *name* keyword argument sets the Tk widget name. + keyword argument sets the style used by the underlying menubutton; the + *direction* keyword argument sets where the menu is posted relative to the + menubutton (one of ``'above'``, ``'below'`` (the default), ``'left'``, + ``'right'`` or ``'flush'``); and the *name* keyword argument sets the Tk + widget name. .. method:: set_menu(default=None, *values) diff --git a/Lib/tkinter/__init__.py b/Lib/tkinter/__init__.py index 3b693bc72f5723..63b08b3e82d4da 100644 --- a/Lib/tkinter/__init__.py +++ b/Lib/tkinter/__init__.py @@ -3,7 +3,7 @@ Tkinter provides classes which allow the display, positioning and control of widgets. Toplevel widgets are Tk and Toplevel. Other widgets are Frame, Label, Entry, Text, Canvas, Button, Radiobutton, -Checkbutton, Scale, Listbox, Scrollbar, OptionMenu, Spinbox +Checkbutton, Scale, Listbox, Scrollbar, OptionMenu, Spinbox, LabelFrame and PanedWindow. Properties of the widgets are specified with keyword arguments. @@ -2436,7 +2436,7 @@ def wm_iconphoto(self, default=False, *args): # new in Tk 8.5 def wm_iconposition(self, x=None, y=None): """Set the position of the icon of this widget to X and Y. Return - a tuple of the current values of X and X if None is given.""" + a tuple of the current values of X and Y if None is given.""" return self._getints(self.tk.call( 'wm', 'iconposition', self._w, x, y)) diff --git a/Lib/tkinter/colorchooser.py b/Lib/tkinter/colorchooser.py index e2fb69dba92763..4085bde1637a79 100644 --- a/Lib/tkinter/colorchooser.py +++ b/Lib/tkinter/colorchooser.py @@ -1,3 +1,5 @@ +"""Interface to the native Tk color selection dialog.""" + # tk common color chooser dialogue # # this module provides an interface to the native color dialogue diff --git a/Lib/tkinter/commondialog.py b/Lib/tkinter/commondialog.py index 86f5387e001bf2..408cedc345def6 100644 --- a/Lib/tkinter/commondialog.py +++ b/Lib/tkinter/commondialog.py @@ -1,3 +1,5 @@ +"""Base class for the Tk common dialogs.""" + # base class for tk common dialogues # # this module provides a base class for accessing the common diff --git a/Lib/tkinter/dialog.py b/Lib/tkinter/dialog.py index 36ae6c277cb66a..ef005af0d5a19c 100644 --- a/Lib/tkinter/dialog.py +++ b/Lib/tkinter/dialog.py @@ -1,5 +1,7 @@ # dialog.py -- Tkinter interface to the tk_dialog script. +"""Classic Tk dialog box, wrapping the tk_dialog script.""" + from tkinter import _cnfmerge, Widget, TclError, Button, Pack __all__ = ["Dialog"] @@ -8,6 +10,8 @@ class Dialog(Widget): + """A modal dialog box built from the classic (non-themed) Tk widgets.""" + def __init__(self, master=None, cnf={}, **kw): cnf = _cnfmerge((cnf, kw)) self.widgetName = '__dialog__' @@ -21,7 +25,8 @@ def __init__(self, master=None, cnf={}, **kw): try: Widget.destroy(self) except TclError: pass - def destroy(self): pass + def destroy(self): + """Do nothing; the dialog window is already destroyed.""" def _test(): diff --git a/Lib/tkinter/font.py b/Lib/tkinter/font.py index 1face04279af7f..2bbdbd560436af 100644 --- a/Lib/tkinter/font.py +++ b/Lib/tkinter/font.py @@ -1,3 +1,5 @@ +"""Utilities to help work with fonts in Tkinter.""" + # Tkinter font wrapper # # written by Fredrik Lundh, February 1998 diff --git a/Lib/tkinter/messagebox.py b/Lib/tkinter/messagebox.py index dd2816cffb1140..f6848142a9aff6 100644 --- a/Lib/tkinter/messagebox.py +++ b/Lib/tkinter/messagebox.py @@ -1,3 +1,5 @@ +"""Interface to the standard Tk message boxes.""" + # tk common message boxes # # this module provides an interface to the native message boxes diff --git a/Lib/tkinter/simpledialog.py b/Lib/tkinter/simpledialog.py index 4f9eb44f034677..b9710a98ed0b92 100644 --- a/Lib/tkinter/simpledialog.py +++ b/Lib/tkinter/simpledialog.py @@ -8,7 +8,7 @@ # fredrik@pythonware.com # http://www.pythonware.com # -"""This modules handles dialog boxes. +"""This module handles dialog boxes. It contains the following public symbols: From bb0720fb783e0ce493720ef4144f600290663ded Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 11 Jul 2026 12:18:38 +0200 Subject: [PATCH 658/818] [3.15] gh-86726: Note that the ttk Treeview separator column option needs Tk 9.0 (GH-153556) (GH-153558) (cherry picked from commit 9ca892717eaa66f3fba231f00dc5bce355f6f34c) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --- Doc/library/tkinter.ttk.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/tkinter.ttk.rst b/Doc/library/tkinter.ttk.rst index 54066625e82c06..77703eff26412e 100644 --- a/Doc/library/tkinter.ttk.rst +++ b/Doc/library/tkinter.ttk.rst @@ -884,8 +884,8 @@ This widget accepts the following specific options: The *selectmode* option gained the values ``"single"`` and ``"multiple"``; the new widget options *selecttype* (``"item"`` or ``"cell"`` selection), *striped* (zebra-striped rows), and *titlecolumns* / *titleitems* (columns - or rows frozen against scrolling) were introduced; and items gained a - *hidden* option. + or rows frozen against scrolling) were introduced; the column *separator* + option was added; and items gained a *hidden* option. Tk 9.1 added the *rowheight* and *headingheight* options. From 487ac27295cab7c81a4afa06a4b49159d70835d3 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 11 Jul 2026 12:22:02 +0200 Subject: [PATCH 659/818] [3.15] gh-126877: Fix the configure check for Tcl/Tk with optimizing compilers (GH-153543) (GH-153553) The check assigned the addresses of Tcl_Init() and Tk_Init() to unused variables, which optimizing compilers can eliminate, so it linked even when the libraries were missing. Call the functions instead. (cherry picked from commit ff0a9ae269fa38c21f01bdea1a7ff5d439c4f681) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --- .../next/Build/2026-07-11-07-26-16.gh-issue-126877.Zt7Kq2.rst | 2 ++ configure | 4 ++-- configure.ac | 4 ++-- 3 files changed, 6 insertions(+), 4 deletions(-) create mode 100644 Misc/NEWS.d/next/Build/2026-07-11-07-26-16.gh-issue-126877.Zt7Kq2.rst diff --git a/Misc/NEWS.d/next/Build/2026-07-11-07-26-16.gh-issue-126877.Zt7Kq2.rst b/Misc/NEWS.d/next/Build/2026-07-11-07-26-16.gh-issue-126877.Zt7Kq2.rst new file mode 100644 index 00000000000000..1d7d4fad886c56 --- /dev/null +++ b/Misc/NEWS.d/next/Build/2026-07-11-07-26-16.gh-issue-126877.Zt7Kq2.rst @@ -0,0 +1,2 @@ +Fix the :program:`configure` check for Tcl/Tk which could wrongly succeed +with optimizing compilers when the libraries are missing. diff --git a/configure b/configure index 90f026976d0e54..08a7c663ce0a9c 100755 --- a/configure +++ b/configure @@ -17800,8 +17800,8 @@ int main (void) { - void *x1 = Tcl_Init; - void *x2 = Tk_Init; + Tcl_Init(NULL); + Tk_Init(NULL); ; return 0; diff --git a/configure.ac b/configure.ac index bdb94d6d280338..ead82d6da0b545 100644 --- a/configure.ac +++ b/configure.ac @@ -4643,8 +4643,8 @@ WITH_SAVE_ENV([ # error "Tk older than 8.5.12 not supported" #endif ], [ - void *x1 = Tcl_Init; - void *x2 = Tk_Init; + Tcl_Init(NULL); + Tk_Init(NULL); ]) ], [ have_tcltk=yes From f237c8610f4e802f3f72a92d72ac2ddd8956de64 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 11 Jul 2026 14:46:14 +0200 Subject: [PATCH 660/818] [3.15] gh-152614: Add raises to `QueueShutDown` in `asyncio.Queue.put_no_wait` and `asyncio.Queue.get_nowait` documentation methods (GH-152681) (#153565) gh-152614: Add raises to `QueueShutDown` in `asyncio.Queue.put_no_wait` and `asyncio.Queue.get_nowait` documentation methods (GH-152681) (cherry picked from commit d1a5b54abaca2b443c7642ef3a7be8e1cd077ae3) Co-authored-by: Duprat <yduprat@gmail.com> --- Doc/library/asyncio-queue.rst | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Doc/library/asyncio-queue.rst b/Doc/library/asyncio-queue.rst index a9735ae80652df..5e3f531f4e482e 100644 --- a/Doc/library/asyncio-queue.rst +++ b/Doc/library/asyncio-queue.rst @@ -71,6 +71,8 @@ Queue Return an item if one is immediately available, else raise :exc:`QueueEmpty`. + Raises :exc:`QueueShutDown` if the queue has been shut down and is empty. + .. method:: join() :async: @@ -96,6 +98,8 @@ Queue If no free slot is immediately available, raise :exc:`QueueFull`. + Raises :exc:`QueueShutDown` if the queue has been shut down. + .. method:: qsize() Return the number of items in the queue. @@ -188,8 +192,9 @@ Exceptions .. exception:: QueueShutDown - Exception raised when :meth:`~Queue.put` or :meth:`~Queue.get` is - called on a queue which has been shut down. + Exception raised when :meth:`~Queue.put`, :meth:`~Queue.put_nowait`, + :meth:`~Queue.get` or :meth:`~Queue.get_nowait` is called + on a queue which has been shut down. .. versionadded:: 3.13 From 8ac2fcbee70a33b53fef88519714238f3b6782f7 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 11 Jul 2026 15:41:09 +0200 Subject: [PATCH 661/818] [3.15] gh-151292: Change `total_samples:u32` in the binary format to `total_samples:u64` (GH-153425) (#153436) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gh-151292: Change `total_samples:u32` in the binary format to `total_samples:u64` (GH-153425) (cherry picked from commit 1d196507e6496aab072e741e03d3565142a681ae) Co-authored-by: Maurycy Pawłowski-Wieroński <maurycy@maurycy.com> --- .../test_binary_format.py | 33 ++++++++++++++++--- ...-07-09-15-18-23.gh-issue-151292.f4NQSW.rst | 5 +++ Modules/_remote_debugging/binary_io.h | 6 ++-- Modules/_remote_debugging/binary_io_reader.c | 15 +++++---- Modules/_remote_debugging/binary_io_writer.c | 6 ---- Modules/_remote_debugging/module.c | 8 ++--- 6 files changed, 49 insertions(+), 24 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-07-09-15-18-23.gh-issue-151292.f4NQSW.rst diff --git a/Lib/test/test_profiling/test_sampling_profiler/test_binary_format.py b/Lib/test/test_profiling/test_sampling_profiler/test_binary_format.py index 5dff58498a4a15..e4963dca9c9663 100644 --- a/Lib/test/test_profiling/test_sampling_profiler/test_binary_format.py +++ b/Lib/test/test_profiling/test_sampling_profiler/test_binary_format.py @@ -999,9 +999,9 @@ class TestBinaryFormatValidation(BinaryFormatTestBase): """Tests for malformed binary files.""" HDR_OFF_SAMPLES = 28 - HDR_OFF_THREADS = 32 - HDR_OFF_STR_TABLE = 36 - HDR_OFF_FRAME_TABLE = 44 + HDR_OFF_THREADS = 36 + HDR_OFF_STR_TABLE = 40 + HDR_OFF_FRAME_TABLE = 48 FILE_HEADER_PLACEHOLDER_SIZE = 64 FILE_FOOTER_SIZE = 32 FTR_OFF_STRINGS = 0 @@ -1039,7 +1039,7 @@ def test_replay_rejects_sample_count_mismatch(self): with open(filename, "r+b") as raw: raw.seek(self.HDR_OFF_SAMPLES) - raw.write(struct.pack("=I", 2)) + raw.write(struct.pack("=Q", 2)) with BinaryReader(filename) as reader: self.assertEqual(reader.get_info()["sample_count"], 2) @@ -1149,6 +1149,31 @@ def test_open_accepts_frame_count_at_capacity_boundary(self): f"possible {max_frames}", ) + def test_sample_count_reads_full_64_bits(self): + """sample_count values requiring the upper 32 bits decode correctly.""" + filename = self.create_binary_file([], compression="none") + big_count = 0x1_0002_0003 + + with open(filename, "r+b") as raw: + raw.seek(self.HDR_OFF_SAMPLES) + raw.write(struct.pack("=Q", big_count)) + + with BinaryReader(filename) as reader: + self.assertEqual(reader.get_info()["sample_count"], big_count) + + def test_sample_count_boundary_values(self): + """Values above the old u32 ceiling decode fine.""" + filename = self.create_binary_file([], compression="none") + + for value in (0xFFFFFFFF - 1, 0xFFFFFFFF, 0xFFFFFFFF + 1): + with self.subTest(value=value): + with open(filename, "r+b") as raw: + raw.seek(self.HDR_OFF_SAMPLES) + raw.write(struct.pack("=Q", value)) + + with BinaryReader(filename) as reader: + self.assertEqual(reader.get_info()["sample_count"], value) + class TestBinaryEncodings(BinaryFormatTestBase): """Tests specifically targeting different stack encodings.""" diff --git a/Misc/NEWS.d/next/Library/2026-07-09-15-18-23.gh-issue-151292.f4NQSW.rst b/Misc/NEWS.d/next/Library/2026-07-09-15-18-23.gh-issue-151292.f4NQSW.rst new file mode 100644 index 00000000000000..4165893fc47457 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-09-15-18-23.gh-issue-151292.f4NQSW.rst @@ -0,0 +1,5 @@ +Store the sample count in :mod:`profiling.sampling` binary format, as a +64-bit integer, widening from previously used 32-bit integer. This breaks +the existing recordings. Long or thread-heavy profiling sessions will no +longer fail because of :exc:`OverflowError`. Patch by Maurycy +Pawłowski-Wieroński. diff --git a/Modules/_remote_debugging/binary_io.h b/Modules/_remote_debugging/binary_io.h index 9696bea1cabd86..8c34668ab15ae7 100644 --- a/Modules/_remote_debugging/binary_io.h +++ b/Modules/_remote_debugging/binary_io.h @@ -50,7 +50,7 @@ extern "C" { #define HDR_OFF_INTERVAL (HDR_OFF_START_TIME + HDR_SIZE_START_TIME) #define HDR_SIZE_INTERVAL 8 #define HDR_OFF_SAMPLES (HDR_OFF_INTERVAL + HDR_SIZE_INTERVAL) -#define HDR_SIZE_SAMPLES 4 +#define HDR_SIZE_SAMPLES 8 #define HDR_OFF_THREADS (HDR_OFF_SAMPLES + HDR_SIZE_SAMPLES) #define HDR_SIZE_THREADS 4 #define HDR_OFF_STR_TABLE (HDR_OFF_THREADS + HDR_SIZE_THREADS) @@ -260,7 +260,7 @@ typedef struct { /* Metadata */ uint64_t start_time_us; uint64_t sample_interval_us; - uint32_t total_samples; + uint64_t total_samples; /* String hash table: PyObject* -> uint32_t index */ _Py_hashtable_t *string_hash; @@ -326,7 +326,7 @@ typedef struct { int needs_swap; /* Non-zero if file was written on different-endian system */ uint64_t start_time_us; uint64_t sample_interval_us; - uint32_t sample_count; + uint64_t sample_count; uint32_t thread_count; uint64_t string_table_offset; uint64_t frame_table_offset; diff --git a/Modules/_remote_debugging/binary_io_reader.c b/Modules/_remote_debugging/binary_io_reader.c index 73c4f5b6250d89..07352f94cc805d 100644 --- a/Modules/_remote_debugging/binary_io_reader.c +++ b/Modules/_remote_debugging/binary_io_reader.c @@ -83,7 +83,8 @@ reader_parse_header(BinaryReader *reader, const uint8_t *data, size_t file_size) /* Read header fields with byte-swapping if needed */ uint64_t start_time_us, sample_interval_us, string_table_offset, frame_table_offset; - uint32_t sample_count, thread_count, compression_type; + uint64_t sample_count; + uint32_t thread_count, compression_type; memcpy(&start_time_us, &data[HDR_OFF_START_TIME], HDR_SIZE_START_TIME); memcpy(&sample_interval_us, &data[HDR_OFF_INTERVAL], HDR_SIZE_INTERVAL); @@ -95,7 +96,7 @@ reader_parse_header(BinaryReader *reader, const uint8_t *data, size_t file_size) reader->start_time_us = SWAP64_IF(reader->needs_swap, start_time_us); reader->sample_interval_us = SWAP64_IF(reader->needs_swap, sample_interval_us); - reader->sample_count = SWAP32_IF(reader->needs_swap, sample_count); + reader->sample_count = SWAP64_IF(reader->needs_swap, sample_count); reader->thread_count = SWAP32_IF(reader->needs_swap, thread_count); reader->string_table_offset = SWAP64_IF(reader->needs_swap, string_table_offset); reader->frame_table_offset = SWAP64_IF(reader->needs_swap, frame_table_offset); @@ -993,10 +994,10 @@ emit_batch(RemoteDebuggingState *state, PyObject *collector, /* Helper to invoke progress callback, returns -1 on error */ static inline int -invoke_progress_callback(PyObject *callback, Py_ssize_t current, uint32_t total) +invoke_progress_callback(PyObject *callback, Py_ssize_t current, uint64_t total) { if (callback && callback != Py_None) { - PyObject *result = PyObject_CallFunction(callback, "nI", current, total); + PyObject *result = PyObject_CallFunction(callback, "nK", current, (unsigned long long)total); if (result) { Py_DECREF(result); } else { @@ -1248,8 +1249,8 @@ binary_reader_replay(BinaryReader *reader, PyObject *collector, PyObject *progre if ((uint64_t)replayed != reader->sample_count) { PyErr_Format(PyExc_ValueError, - "Sample count mismatch: header declares %u samples but replay decoded %zd", - reader->sample_count, replayed); + "Sample count mismatch: header declares %llu samples but replay decoded %zd", + (unsigned long long)reader->sample_count, replayed); return -1; } @@ -1270,7 +1271,7 @@ binary_reader_get_info(BinaryReader *reader) return NULL; } return Py_BuildValue( - "{s:I, s:N, s:K, s:K, s:I, s:I, s:I, s:I, s:i}", + "{s:I, s:N, s:K, s:K, s:K, s:I, s:I, s:I, s:i}", "version", BINARY_FORMAT_VERSION, "python_version", py_version, "start_time_us", reader->start_time_us, diff --git a/Modules/_remote_debugging/binary_io_writer.c b/Modules/_remote_debugging/binary_io_writer.c index 5d300103ff16f8..e2ac40d96b39be 100644 --- a/Modules/_remote_debugging/binary_io_writer.c +++ b/Modules/_remote_debugging/binary_io_writer.c @@ -924,12 +924,6 @@ static int process_thread_sample(BinaryWriter *writer, PyObject *thread_info, uint32_t interpreter_id, uint64_t timestamp_us) { - if (writer->total_samples >= UINT32_MAX) { - PyErr_SetString(PyExc_OverflowError, - "too many samples for binary format"); - return -1; - } - PyObject *thread_id_obj = PyStructSequence_GET_ITEM(thread_info, 0); PyObject *status_obj = PyStructSequence_GET_ITEM(thread_info, 1); PyObject *frame_list = PyStructSequence_GET_ITEM(thread_info, 2); diff --git a/Modules/_remote_debugging/module.c b/Modules/_remote_debugging/module.c index 62d5315f361fa8..adafee97a94ada 100644 --- a/Modules/_remote_debugging/module.c +++ b/Modules/_remote_debugging/module.c @@ -14,7 +14,7 @@ typedef struct { PyObject_HEAD BinaryWriter *writer; - uint32_t cached_total_samples; /* Preserved after finalize */ + uint64_t cached_total_samples; /* Preserved after finalize */ } BinaryWriterObject; typedef struct { @@ -1916,9 +1916,9 @@ BinaryWriter_get_total_samples(PyObject *op, void *closure) BinaryWriterObject *self = BinaryWriter_CAST(op); if (!self->writer) { /* Use cached value after finalize/close */ - return PyLong_FromUnsignedLong(self->cached_total_samples); + return PyLong_FromUnsignedLongLong(self->cached_total_samples); } - return PyLong_FromUnsignedLong(self->writer->total_samples); + return PyLong_FromUnsignedLongLong(self->writer->total_samples); } static PyGetSetDef BinaryWriter_getset[] = { @@ -2141,7 +2141,7 @@ BinaryReader_get_sample_count(BinaryReaderObject *self, void *closure) if (!self->reader) { return PyLong_FromLong(0); } - return PyLong_FromUnsignedLong(self->reader->sample_count); + return PyLong_FromUnsignedLongLong(self->reader->sample_count); } static PyObject * From a3a6203da29c96a6816c7819daa9985fe1f64dfb Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 11 Jul 2026 20:19:00 +0200 Subject: [PATCH 662/818] [3.15] gh-153293: Clear opcode statistics in the live profiler's reset_stats() (GH-153295) (#153586) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gh-153293: Clear opcode statistics in the live profiler's reset_stats() (GH-153295) (cherry picked from commit 43b0e01b5098c9e796957c10a992d8e6e95e0ae1) Co-authored-by: Łukasz <lukaszlapinski7@gmail.com> --- Lib/profiling/sampling/live_collector/collector.py | 1 + .../test_sampling_profiler/test_live_collector_interaction.py | 2 ++ .../next/Library/2026-07-07-22-06-52.gh-issue-153293.0DvYdc.rst | 2 ++ 3 files changed, 5 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2026-07-07-22-06-52.gh-issue-153293.0DvYdc.rst diff --git a/Lib/profiling/sampling/live_collector/collector.py b/Lib/profiling/sampling/live_collector/collector.py index a53cfc6b719a10..c5bd0178f2636b 100644 --- a/Lib/profiling/sampling/live_collector/collector.py +++ b/Lib/profiling/sampling/live_collector/collector.py @@ -705,6 +705,7 @@ def build_stats_list(self): def reset_stats(self): """Reset all collected statistics.""" self.result.clear() + self.opcode_stats.clear() self.per_thread_data.clear() self.thread_ids.clear() self.view_mode = "ALL" diff --git a/Lib/test/test_profiling/test_sampling_profiler/test_live_collector_interaction.py b/Lib/test/test_profiling/test_sampling_profiler/test_live_collector_interaction.py index baf478133fc665..6dfdb9a192e03a 100644 --- a/Lib/test/test_profiling/test_sampling_profiler/test_live_collector_interaction.py +++ b/Lib/test/test_profiling/test_sampling_profiler/test_live_collector_interaction.py @@ -99,6 +99,7 @@ def test_reset_stats(self): "cumulative_calls": 75, "total_rec_calls": 0, } + self.collector.opcode_stats[("test.py", 1, "func")][100] = 5 # Reset self.collector.reset_stats() @@ -107,6 +108,7 @@ def test_reset_stats(self): self.assertEqual(self.collector.successful_samples, 0) self.assertEqual(self.collector.failed_samples, 0) self.assertEqual(len(self.collector.result), 0) + self.assertEqual(len(self.collector.opcode_stats), 0) def test_increase_refresh_rate(self): """Test increasing refresh rate (faster updates).""" diff --git a/Misc/NEWS.d/next/Library/2026-07-07-22-06-52.gh-issue-153293.0DvYdc.rst b/Misc/NEWS.d/next/Library/2026-07-07-22-06-52.gh-issue-153293.0DvYdc.rst new file mode 100644 index 00000000000000..ac358bb7fc0a50 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-07-22-06-52.gh-issue-153293.0DvYdc.rst @@ -0,0 +1,2 @@ +Fix the live sampling profiler TUI keeping stale aggregated opcode +statistics after a stats reset. From 1a9359dcea1f3db1c54bd51fa30ddcafe0ad654a Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 11 Jul 2026 23:20:38 +0200 Subject: [PATCH 663/818] [3.15] gh-102591: Document that urlcleanup resets the global opener (GH-153562) (#153588) gh-102591: Document that urlcleanup resets the global opener (GH-153562) (cherry picked from commit bbd1f2f9e0354f91c5d3c4eb3eb53657265dcc77) Co-authored-by: Taeknology <20297177+Taeknology@users.noreply.github.com> Co-authored-by: Senthil Kumaran <senthil@python.org> --- Doc/library/urllib.request.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Doc/library/urllib.request.rst b/Doc/library/urllib.request.rst index 03518d49d437ce..95e4d2627c8b23 100644 --- a/Doc/library/urllib.request.rst +++ b/Doc/library/urllib.request.rst @@ -1486,7 +1486,8 @@ some point in the future. .. function:: urlcleanup() Cleans up temporary files that may have been left behind by previous - calls to :func:`urlretrieve`. + calls to :func:`urlretrieve`. It also resets the default global opener + installed by :func:`install_opener`. :mod:`!urllib.request` Restrictions From b3144d91448f3b4e36f36d73046839aaf40a46d4 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 12 Jul 2026 00:26:16 +0200 Subject: [PATCH 664/818] [3.15] gh-152132: Close stderr_copy in test_api.test_run (GH-153591) (#153595) gh-152132: Close stderr_copy in test_api.test_run (GH-153591) Previously, the test was leaking a file descriptor. (cherry picked from commit 0023d5b23df09f18425fea9b9c54a37ba050d5cf) Co-authored-by: Victor Stinner <vstinner@python.org> --- Lib/test/test_capi/test_run.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/Lib/test/test_capi/test_run.py b/Lib/test/test_capi/test_run.py index 14f9833f63a4fb..7796c589b557c7 100644 --- a/Lib/test/test_capi/test_run.py +++ b/Lib/test/test_capi/test_run.py @@ -310,13 +310,15 @@ def check_run_interactive(self, run, encode_filename, use_loop=False): # supported". In this case, run the test without redirecting # stderr to a temporary file. self._check_run_interactive(run, encode_filename, use_loop) - else: - with tempfile.TemporaryFile() as tmp: - try: - os.dup2(tmp.fileno(), STDERR_FD) - self._check_run_interactive(run, encode_filename, use_loop) - finally: - os.dup2(stderr_copy, STDERR_FD) + return + + with tempfile.TemporaryFile() as tmp: + try: + os.dup2(tmp.fileno(), STDERR_FD) + self._check_run_interactive(run, encode_filename, use_loop) + finally: + os.dup2(stderr_copy, STDERR_FD) + os.close(stderr_copy) def test_run_interactiveone(self): # Test PyRun_InteractiveOne() From d419b0245d712656ee71e6c1883e46195e5e7ef9 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 12 Jul 2026 13:23:56 +0200 Subject: [PATCH 665/818] [3.15] gh-90431: Document cancellation behavior of asyncio.wait() and asyncio.as_completed() (GH-153616) (#153617) gh-90431: Document cancellation behavior of asyncio.wait() and asyncio.as_completed() (GH-153616) (cherry picked from commit dd2faeb33d5fa0d2635b91ece6eaebd34c61408c) Co-authored-by: Kumar Aditya <kumaraditya@python.org> --- Doc/library/asyncio-task.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Doc/library/asyncio-task.rst b/Doc/library/asyncio-task.rst index 64f0810777e41b..d0cd241e42db26 100644 --- a/Doc/library/asyncio-task.rst +++ b/Doc/library/asyncio-task.rst @@ -924,6 +924,9 @@ Waiting primitives Unlike :func:`~asyncio.wait_for`, ``wait()`` does not cancel the futures when a timeout occurs. + If ``wait()`` is cancelled, the futures in *aws* are not cancelled + and continue to run. + .. versionchanged:: 3.10 Removed the *loop* parameter. @@ -981,6 +984,10 @@ Waiting primitives are done. This is raised by the ``async for`` loop during asynchronous iteration or by the coroutines yielded during plain iteration. + ``as_completed()`` does not cancel the tasks running the supplied + awaitables: if a timeout occurs or the iteration is cancelled, the + remaining tasks continue to run. + .. versionchanged:: 3.10 Removed the *loop* parameter. From 7d8783bd9fa48eed4046fb1ab0d3e4618d52b5f0 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 13 Jul 2026 04:51:38 +0200 Subject: [PATCH 666/818] [3.15] gh-153037: Make ZstdFile.__next__ raise io.UnsupportedOperation on non-readable files (GH-153045) (#153638) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gh-153037: Make ZstdFile.__next__ raise io.UnsupportedOperation on non-readable files (GH-153045) Make `ZstdFile.__next__` raise `io.UnsupportedOperation` on non-readable files, consistent with other compression modules. (cherry picked from commit ed716551e13d1e46a5cd17955657d64b8824626a) Co-authored-by: Łukasz <lukaszlapinski7@gmail.com> --- Lib/compression/zstd/_zstdfile.py | 1 + Lib/test/test_zstd.py | 2 ++ .../Library/2026-07-04-20-28-51.gh-issue-153037.XUSp_g.rst | 3 +++ 3 files changed, 6 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2026-07-04-20-28-51.gh-issue-153037.XUSp_g.rst diff --git a/Lib/compression/zstd/_zstdfile.py b/Lib/compression/zstd/_zstdfile.py index 8d3358152e9a88..c4477244e8327f 100644 --- a/Lib/compression/zstd/_zstdfile.py +++ b/Lib/compression/zstd/_zstdfile.py @@ -246,6 +246,7 @@ def peek(self, size=-1): return self._buffer.peek(size) def __next__(self): + self._check_can_read() if ret := self._buffer.readline(): return ret raise StopIteration diff --git a/Lib/test/test_zstd.py b/Lib/test/test_zstd.py index 6358cc78739cd9..9225c42e0e711a 100644 --- a/Lib/test/test_zstd.py +++ b/Lib/test/test_zstd.py @@ -2373,6 +2373,8 @@ def read(self, size): f.read(100) with self.assertRaises(io.UnsupportedOperation): f.seek(100) + with self.assertRaises(io.UnsupportedOperation): + next(iter(f)) self.assertEqual(f.closed, True) with self.assertRaises(ValueError): f.readable() diff --git a/Misc/NEWS.d/next/Library/2026-07-04-20-28-51.gh-issue-153037.XUSp_g.rst b/Misc/NEWS.d/next/Library/2026-07-04-20-28-51.gh-issue-153037.XUSp_g.rst new file mode 100644 index 00000000000000..cbfc62f7518470 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-04-20-28-51.gh-issue-153037.XUSp_g.rst @@ -0,0 +1,3 @@ +Fix :class:`~compression.zstd.ZstdFile` raising :exc:`AttributeError` +instead of :exc:`io.UnsupportedOperation` when iterating over a file that +is not open for reading. From 91084886e5a39de4bb34673463b141cfcb32235a Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 13 Jul 2026 10:01:30 +0200 Subject: [PATCH 667/818] [3.15] gh-148286: Fix UB in `ZstdDecompressor.unused_data` when a frame is decompressed in one call (GH-153258) (#153644) (cherry picked from commit adebb68153346043c0671fa5725d269c32cc40e4) Co-authored-by: Stan Ulbrych <stan@python.org> Co-authored-by: Emma Smith <emma@emmatyping.dev> --- .../2026-07-07-13-31-52.gh-issue-148286.-qu-em.rst | 3 +++ Modules/_zstd/decompressor.c | 11 ++++++++--- Tools/ubsan/suppressions.txt | 3 --- 3 files changed, 11 insertions(+), 6 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-07-07-13-31-52.gh-issue-148286.-qu-em.rst diff --git a/Misc/NEWS.d/next/Library/2026-07-07-13-31-52.gh-issue-148286.-qu-em.rst b/Misc/NEWS.d/next/Library/2026-07-07-13-31-52.gh-issue-148286.-qu-em.rst new file mode 100644 index 00000000000000..60cd49020c954a --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-07-13-31-52.gh-issue-148286.-qu-em.rst @@ -0,0 +1,3 @@ +Fix undefined behavior in +:attr:`compression.zstd.ZstdDecompressor.unused_data` when a complete frame +was decompressed in a single call. diff --git a/Modules/_zstd/decompressor.c b/Modules/_zstd/decompressor.c index cb95ba89eb650a..ca9ea7e3b8f99b 100644 --- a/Modules/_zstd/decompressor.c +++ b/Modules/_zstd/decompressor.c @@ -594,9 +594,14 @@ _zstd_ZstdDecompressor_unused_data_get_impl(ZstdDecompressor *self) } else { if (self->unused_data == NULL) { - self->unused_data = PyBytes_FromStringAndSize( - self->input_buffer + self->in_begin, - self->in_end - self->in_begin); + if (self->input_buffer == NULL) { + self->unused_data = Py_GetConstant(Py_CONSTANT_EMPTY_BYTES); + } + else { + self->unused_data = PyBytes_FromStringAndSize( + self->input_buffer + self->in_begin, + self->in_end - self->in_begin); + } ret = self->unused_data; Py_XINCREF(ret); } diff --git a/Tools/ubsan/suppressions.txt b/Tools/ubsan/suppressions.txt index e3679bc421f420..2b9ad49ebf1eef 100644 --- a/Tools/ubsan/suppressions.txt +++ b/Tools/ubsan/suppressions.txt @@ -15,8 +15,5 @@ shift-base:Modules/_ctypes/cfield.c # Modules/_ctypes/cfield.c:640:1: runtime error: signed integer overflow: -2147483648 - 1 cannot be represented in type 'int' signed-integer-overflow:Modules/_ctypes/cfield.c -# Modules/_zstd/decompressor.c:598:56: runtime error: applying non-zero offset 18446744073709551615 to null pointer -pointer-overflow:Modules/_zstd/decompressor.c - # Modules/_io/stringio.c:350:24: runtime error: addition of unsigned offset to 0x7fd01ec25850 overflowed to 0x7fd01ec2584c pointer-overflow:Modules/_io/stringio.c From 9efded46646ae25de8e8c6fdef85f2f7d188dfd3 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 13 Jul 2026 12:09:39 +0200 Subject: [PATCH 668/818] [3.15] gh-89696: Fix `loop.sock_connect` docs on address resolution (GH-153651) (#153652) gh-89696: Fix `loop.sock_connect` docs on address resolution (GH-153651) (cherry picked from commit 1fece4457032382947c7c2a5c9e95dc106ca7a7d) Co-authored-by: Kumar Aditya <kumaraditya@python.org> --- Doc/library/asyncio-eventloop.rst | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/Doc/library/asyncio-eventloop.rst b/Doc/library/asyncio-eventloop.rst index 79c9516cda2d60..865f5e3be39a86 100644 --- a/Doc/library/asyncio-eventloop.rst +++ b/Doc/library/asyncio-eventloop.rst @@ -1156,12 +1156,21 @@ convenient. *sock* must be a non-blocking socket. + With :class:`SelectorEventLoop`, *address* does not need to be resolved: + for :const:`~socket.AF_INET` and :const:`~socket.AF_INET6` sockets, + ``sock_connect`` first checks whether *address* is already resolved by + calling :func:`socket.inet_pton`, and uses :meth:`loop.getaddrinfo` to + resolve it if it is not. + + :class:`ProactorEventLoop`, the default event loop on Windows, does not + resolve *address*. The host must already be a numeric IP address; passing + a host name raises :exc:`OSError`. Resolve the address with + :meth:`loop.getaddrinfo` first, or use :meth:`loop.create_connection`, + which resolves the address on every platform. + .. versionchanged:: 3.5.2 - ``address`` no longer needs to be resolved. ``sock_connect`` - will try to check if the *address* is already resolved by calling - :func:`socket.inet_pton`. If not, - :meth:`loop.getaddrinfo` will be used to resolve the - *address*. + With :class:`SelectorEventLoop`, ``address`` no longer needs to be + resolved. .. seealso:: From b772f4d1a62f14fce72193581f1e5e32252d8fed Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 13 Jul 2026 21:42:00 +0200 Subject: [PATCH 669/818] [3.15] gh-152405: Do not expose the internal mapping when rich-comparing `MappingProxyType` objects (GH-152483) (#153670) gh-152405: Do not expose the internal mapping when rich-comparing `MappingProxyType` objects (GH-152483) (cherry picked from commit 701a7c5408f689b26c46ed7ed13879375fa82959) Co-authored-by: sobolevn <mail@sobolevn.me> --- Lib/test/test_types.py | 121 ++++++++++++++++-- ...-06-28-14-39-05.gh-issue-152405.-_3YRo.rst | 5 + Objects/descrobject.c | 23 +++- 3 files changed, 138 insertions(+), 11 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-28-14-39-05.gh-issue-152405.-_3YRo.rst diff --git a/Lib/test/test_types.py b/Lib/test/test_types.py index 2084b30d71ff6c..53e0289b10feef 100644 --- a/Lib/test/test_types.py +++ b/Lib/test/test_types.py @@ -8,7 +8,7 @@ from test.support.import_helper import import_fresh_module import collections.abc -from collections import namedtuple, UserDict +from collections import namedtuple, UserDict, OrderedDict import copy import _datetime import gc @@ -1391,26 +1391,127 @@ def __hash__(self): view = self.mappingproxy(mapping) self.assertEqual(hash(view), hash(mapping)) - def test_richcompare(self): - mp1 = self.mappingproxy({'a': 1}) - mp1_2 = self.mappingproxy({'a': 1}) - mp2 = self.mappingproxy({'a': 2}) + def check_richcompare(self, mapping_type): + data1 = mapping_type({'a': 1}) + data2 = mapping_type({'a': 2}) + mp1 = self.mappingproxy(data1) + copy1 = self.mappingproxy(data1) + mp2 = self.mappingproxy(data2) + + self.assertTrue(mp1 == data1) + self.assertTrue(data1 == mp1) + self.assertTrue(copy1 == data1) + + self.assertTrue(mp1 == copy1) + self.assertFalse(mp1 != copy1) - self.assertTrue(mp1 == mp1_2) - self.assertFalse(mp1 != mp1_2) self.assertFalse(mp1 == mp2) self.assertTrue(mp1 != mp2) + self.assertFalse(mp2 == data1) + self.assertTrue(mp2 != data1) + self.assertTrue(data1 != mp2) msg = "not supported between instances of 'mappingproxy' and 'mappingproxy'" - with self.assertRaisesRegex(TypeError, msg): mp1 > mp2 with self.assertRaisesRegex(TypeError, msg): - mp1 < mp1_2 + mp1 < copy1 with self.assertRaisesRegex(TypeError, msg): mp2 >= mp2 with self.assertRaisesRegex(TypeError, msg): - mp1_2 <= mp1 + copy1 <= mp1 + + if mapping_type.__module__ == 'collections': + mapping_name = f'{mapping_type.__module__}.{mapping_type.__name__}' + else: + mapping_name = mapping_type.__name__ + with self.assertRaisesRegex( + TypeError, + f"not supported between instances of 'mappingproxy' and '{mapping_name}'", + ): + copy1 <= data1 + + class Evil: + def __eq__(self, other): + return other + + result = (mp1 == Evil()) + self.assertIs(type(result), mapping_type) + if mapping_type == dict: + # Evil.__eq__() gets a copy of the mapping + self.assertEqual(result, data1) + else: + self.assertIs(result, data1) + + def test_richcompare_dict(self): + self.check_richcompare(dict) + + def test_richcompare_custom_mapping(self): + class CustomMapping(collections.abc.Mapping): + def __init__(self, data): + self._data = data + + def __getitem__(self, key): + return self._data[key] + + def __iter__(self): + return iter(self._data) + + def __len__(self): + return len(self._data) + + def __contains__(self, item): + return item in self._data + + self.check_richcompare(CustomMapping) + + class CustomMapping2(CustomMapping): + def __eq__(self, other): + return ( + isinstance(other, CustomMapping) + and self._data == other._data + ) + + mp1 = self.mappingproxy(CustomMapping({'a': 1})) + self.assertEqual(mp1, CustomMapping2({'a': 1})) + self.assertNotEqual(CustomMapping2({'a': 1}), mp1) + + def test_richcompare_odict(self): + self.check_richcompare(OrderedDict) + + def test_richcompare_frozendict(self): + self.check_richcompare(frozendict) + + def test_richcompare_evil(self): + # This test used to mutate the list dictionary, + # but MappingProxyType now creates a copy to call `__eq__`: + # https://github.com/python/cpython/issues/152405 + key = "__mappingproxy_crash_key__" + + class Evil: + def __eq__(self, other): + other[key] = 1 + return other + + # Checks that it does not mutate the internals of `MappingProxyType`: + dc = {} + leaked = self.mappingproxy(dc) == Evil() + self.assertIs(type(leaked), dict) + self.assertIn(key, leaked) + self.assertNotIn(key, dc) + + # Exposes the internals of `MappingProxyType` via richcompare: + leaked = vars(list) == Evil() + self.assertIs(type(leaked), dict) + self.assertIn(key, leaked) + name = "__mappingproxy_crash_probe__" + leaked[name] = lambda self: "probe" + self.assertIn(name, leaked) + self.assertNotHasAttr(list, key) + self.assertNotHasAttr(list, name) # it used to return `True` + del leaked[name] + self.assertNotIn(name, leaked) + self.assertNotHasAttr(list, name) # it used to crash class ClassCreationTests(unittest.TestCase): diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-28-14-39-05.gh-issue-152405.-_3YRo.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-28-14-39-05.gh-issue-152405.-_3YRo.rst new file mode 100644 index 00000000000000..d7c473ce171d4b --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-28-14-39-05.gh-issue-152405.-_3YRo.rst @@ -0,0 +1,5 @@ +Do not expose the internal mapping of :class:`types.MappingProxyType` +when performing rich-compare operations with non-stdlib types. +Previously, it was possible to mutate the internal mapping of a proxy there. +Now we pass not the original :class:`dict` instance, but its copy, +when dealing with custom types. diff --git a/Objects/descrobject.c b/Objects/descrobject.c index 30444b7d677424..cfcafb56d46cc3 100644 --- a/Objects/descrobject.c +++ b/Objects/descrobject.c @@ -1232,8 +1232,29 @@ mappingproxy_traverse(PyObject *self, visitproc visit, void *arg) static PyObject * mappingproxy_richcompare(PyObject *self, PyObject *w, int op) { - mappingproxyobject *v = (mappingproxyobject *)self; if (op == Py_EQ || op == Py_NE) { + mappingproxyobject *v = (mappingproxyobject *)self; + // We have to guard the mutable `dict` instances, because it can + // otherwise mutate the type's `__dict__` entries and cause crashes. + // But, do not create copies on known types like `OrderedDict` + // or immutable types like `frozendict` + // for memory optimization. See gh-152405 for the details. + if ( + PyDict_CheckExact(v->mapping) && + !(PyAnyDict_CheckExact(w) || + Py_TYPE(w) == &PyDictProxy_Type || + PyODict_CheckExact(w)) + ) { + // So, instead we send a copy: + PyObject *copy = PyDict_Copy(v->mapping); + if (copy == NULL) { + return NULL; + } + PyObject *res = PyObject_RichCompare(copy, w, op); + Py_DECREF(copy); + return res; + } + // Otherwise we are free to share the mapping directly: return PyObject_RichCompare(v->mapping, w, op); } Py_RETURN_NOTIMPLEMENTED; From a442c8945906ad0e600088a2bedb2fa00ba0b8a3 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 14 Jul 2026 01:13:23 +0200 Subject: [PATCH 670/818] [3.15] gh-153631: Move to `macos-26` runner for iOS (GH-153632) (#153673) Switches iOS CI to use the macos-26 runner, and makes a small change to the iOS build script to improve build stability. xcodebuild doesn't guarantee that the CoreSimulatorService is running before starting a simulator. If the service isn't running, xcodebuild reports that no simulators are available, and fails to start the test app. However, simctl blocks until the simulator is available, and simctl is used to evaluate the default simulator. So - the iOS build script now unconditionally determines the default simulator, even if a specific simulator is requested. (cherry picked from commit 2dc1a91af801ea896e21f6c6e6cc41f57e8268d9) Co-authored-by: Russell Keith-Magee <russell@keith-magee.com> --- .github/workflows/build.yml | 13 ++----------- Platforms/Apple/testbed/__main__.py | 8 +++++++- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 20753ef5601538..f15dc9f7e17878 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -408,23 +408,14 @@ jobs: needs: build-context if: needs.build-context.outputs.run-ios == 'true' timeout-minutes: 60 - runs-on: macos-14 + runs-on: macos-26 steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - # GitHub recommends explicitly selecting the desired Xcode version: - # https://github.com/actions/runner-images/issues/12541#issuecomment-3083850140 - # This became a necessity as a result of - # https://github.com/actions/runner-images/issues/12541 and - # https://github.com/actions/runner-images/issues/12751. - - name: Select Xcode version - run: | - sudo xcode-select --switch /Applications/Xcode_15.4.app - - name: Build and test - run: python3 Platforms/Apple ci iOS --fast-ci --simulator 'iPhone SE (3rd generation),OS=17.5' + run: python3 Platforms/Apple ci iOS --fast-ci build-emscripten: name: 'Emscripten' diff --git a/Platforms/Apple/testbed/__main__.py b/Platforms/Apple/testbed/__main__.py index b3eed38571d970..797b522678f9d7 100644 --- a/Platforms/Apple/testbed/__main__.py +++ b/Platforms/Apple/testbed/__main__.py @@ -271,8 +271,14 @@ def run_testbed( update_test_plan(location, platform, args) print(" done.") + # xcodebuild doesn't guarantee that the CoreSimulatorService daemon is + # running prior to using a simulator, but calling `xcrun simctl list` does. + # Determining the default simulator that *would* be used is a cheap action; + # so use that as a way to ensure that the CoreSimulatorService daemon is + # running. + default_simulator = select_simulator_device(platform) if simulator is None: - simulator = select_simulator_device(platform) + simulator = default_simulator print(f"Running test on {simulator}") xcode_test( From 35975878e60874407548539897b03e72ba28c61c Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 14 Jul 2026 09:24:56 +0200 Subject: [PATCH 671/818] [3.15] gh-141510: Update `marshal` module comment with `frozendict` support (GH-153655) (#153681) gh-141510: Update `marshal` module comment with `frozendict` support (GH-153655) (cherry picked from commit 37571ea82a0f8e39ad0c0b2012f23aa149dd238f) Co-authored-by: sobolevn <mail@sobolevn.me> --- Python/marshal.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Python/marshal.c b/Python/marshal.c index 9688d426419c2f..25353f6e689624 100644 --- a/Python/marshal.c +++ b/Python/marshal.c @@ -1,8 +1,8 @@ /* Write Python objects to files and read them back. This is primarily intended for writing and reading compiled Python code, - even though dicts, lists, sets and frozensets, not commonly seen in - code objects, are supported. + even though dicts and frozendicts, lists, sets and frozensets, + not commonly seen in code objects, are supported. Version 3 of this protocol properly supports circular links and sharing. */ From 3e99c701622eb48bf8b5d1afc0e0eed16d268287 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 14 Jul 2026 09:49:02 +0200 Subject: [PATCH 672/818] [3.15] gh-153658: Fix sqlite3 iterdump() for table names containing a single quote (GH-153659) (#153682) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (cherry picked from commit 2fc3c4d47dff722758c76686f657d5ecdd922551) Co-authored-by: tonghuaroot (童话) <tonghuaroot@gmail.com> --- Lib/sqlite3/dump.py | 13 +++++++++---- Lib/test/test_sqlite3/test_dump.py | 18 ++++++++++++++++++ ...6-07-13-10-27-08.gh-issue-153658.A6o4n5.rst | 2 ++ 3 files changed, 29 insertions(+), 4 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-07-13-10-27-08.gh-issue-153658.A6o4n5.rst diff --git a/Lib/sqlite3/dump.py b/Lib/sqlite3/dump.py index 57e6a3b4f1e6eb..95e14a6655ef17 100644 --- a/Lib/sqlite3/dump.py +++ b/Lib/sqlite3/dump.py @@ -11,8 +11,12 @@ def _quote_name(name): return '"{0}"'.format(name.replace('"', '""')) +def _escape_single_quotes(value): + return value.replace("'", "''") + + def _quote_value(value): - return "'{0}'".format(value.replace("'", "''")) + return "'{0}'".format(_escape_single_quotes(value)) def _iterdump(connection, *, filter=None): @@ -80,11 +84,12 @@ def _iterdump(connection, *, filter=None): table_name_ident = _quote_name(table_name) res = cu.execute(f'PRAGMA table_info({table_name_ident})') column_names = [str(table_info[1]) for table_info in res.fetchall()] - q = "SELECT 'INSERT INTO {0} VALUES('{1}')' FROM {0};".format( - table_name_ident, + q = "SELECT 'INSERT INTO {0} VALUES('{1}')' FROM {2};".format( + _escape_single_quotes(table_name_ident), "','".join( "||quote({0})||".format(_quote_name(col)) for col in column_names - ) + ), + table_name_ident, ) query_res = cu.execute(q) for row in query_res: diff --git a/Lib/test/test_sqlite3/test_dump.py b/Lib/test/test_sqlite3/test_dump.py index e18a207e9f6494..7841b610cd222a 100644 --- a/Lib/test/test_sqlite3/test_dump.py +++ b/Lib/test/test_sqlite3/test_dump.py @@ -56,6 +56,24 @@ def test_table_dump(self): [self.assertEqual(expected_sqls[i], actual_sqls[i]) for i in range(len(expected_sqls))] + def test_dump_single_quote_in_identifier(self): + # A single quote in a table or column name must not break the dump. + self.cu.execute("""CREATE TABLE "a'b" ("c'd" text);""") + self.cu.execute("""INSERT INTO "a'b" VALUES('x''y');""") + expected = [ + "BEGIN TRANSACTION;", + """CREATE TABLE "a'b" ("c'd" text);""", + """INSERT INTO "a'b" VALUES('x''y');""", + "COMMIT;", + ] + actual = list(self.cx.iterdump()) + self.assertEqual(expected, actual) + # The dump restores into a fresh database. + with memory_database() as cx2: + cx2.executescript("".join(actual)) + row = cx2.execute("""SELECT "c'd" FROM "a'b";""").fetchone() + self.assertEqual(row[0], "x'y") + def test_table_dump_filter(self): all_table_sqls = [ """CREATE TABLE "some_table_2" ("id_1" INTEGER);""", diff --git a/Misc/NEWS.d/next/Library/2026-07-13-10-27-08.gh-issue-153658.A6o4n5.rst b/Misc/NEWS.d/next/Library/2026-07-13-10-27-08.gh-issue-153658.A6o4n5.rst new file mode 100644 index 00000000000000..06385bb7754b12 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-13-10-27-08.gh-issue-153658.A6o4n5.rst @@ -0,0 +1,2 @@ +Fix :meth:`sqlite3.Connection.iterdump` raising :exc:`sqlite3.OperationalError` +when a table name contains a single quote. Patch by tonghuaroot. From 9465c849d9f33a9bdda413bf813e8abc7881b006 Mon Sep 17 00:00:00 2001 From: Kumar Aditya <kumaraditya@python.org> Date: Tue, 14 Jul 2026 13:38:43 +0530 Subject: [PATCH 673/818] [3.15] gh-71019: document which objects connect_read_pipe/connect_write_pipe accept and add tests (GH-153660) (#153685) gh-71019: document which objects connect_read_pipe/connect_write_pipe accept and add tests (GH-153660) (cherry picked from commit 7fb315b0cd53277c6191b4bfd8019f999d49f1f0) --- Doc/library/asyncio-eventloop.rst | 35 +++++- Doc/library/asyncio-platforms.rst | 9 ++ Lib/asyncio/proactor_events.py | 6 +- Lib/test/test_asyncio/test_events.py | 96 ++++++++++++++++ Lib/test/test_asyncio/test_windows_events.py | 109 +++++++++++++++++++ 5 files changed, 248 insertions(+), 7 deletions(-) diff --git a/Doc/library/asyncio-eventloop.rst b/Doc/library/asyncio-eventloop.rst index 865f5e3be39a86..1caecb1c143a23 100644 --- a/Doc/library/asyncio-eventloop.rst +++ b/Doc/library/asyncio-eventloop.rst @@ -1274,7 +1274,9 @@ Working with pipes *protocol_factory* must be a callable returning an :ref:`asyncio protocol <asyncio-protocol>` implementation. - *pipe* is a :term:`file-like object <file object>`. + *pipe* is a :term:`file-like object <file object>`. See + :ref:`Supported pipe objects <asyncio-pipe-objects>` for the objects + supported as *pipe*. Return pair ``(transport, protocol)``, where *transport* supports the :class:`ReadTransport` interface and *protocol* is an object @@ -1291,7 +1293,9 @@ Working with pipes *protocol_factory* must be a callable returning an :ref:`asyncio protocol <asyncio-protocol>` implementation. - *pipe* is :term:`file-like object <file object>`. + *pipe* is a :term:`file-like object <file object>`. See + :ref:`Supported pipe objects <asyncio-pipe-objects>` for the objects + supported as *pipe*. Return pair ``(transport, protocol)``, where *transport* supports :class:`WriteTransport` interface and *protocol* is an object @@ -1300,6 +1304,33 @@ Working with pipes With :class:`SelectorEventLoop` event loop, the *pipe* is set to non-blocking mode. +.. _asyncio-pipe-objects: + +.. rubric:: Supported pipe objects + +These methods only work with objects the operating system can poll for +readiness or perform overlapped I/O on. Regular files on disk are **not** +supported on any platform. There is no asynchronous file I/O in asyncio; +use :meth:`loop.run_in_executor` to read and write regular files without +blocking the event loop. + +On Unix, with :class:`SelectorEventLoop`, *pipe* must wrap one of the +following: + +* a pipe, such as an end of an :func:`os.pipe` pair or a FIFO created with + :func:`os.mkfifo`; +* a socket; +* a character device, such as a terminal. + +On Windows, where only :class:`ProactorEventLoop` implements these methods, +*pipe* must wrap a handle opened for overlapped I/O (that is, created with the +``FILE_FLAG_OVERLAPPED`` flag), since the handle has to be associated with an +I/O completion port. Handles that were not opened for overlapped I/O are +rejected. In particular, the standard streams (:data:`sys.stdin`, +:data:`sys.stdout` and :data:`sys.stderr`), console handles, and the pipes +created by :func:`os.pipe` are **not** opened for overlapped I/O and therefore +cannot be used with these methods. + .. note:: :class:`SelectorEventLoop` does not support the above methods on diff --git a/Doc/library/asyncio-platforms.rst b/Doc/library/asyncio-platforms.rst index a2a3114ad6e4c5..0b7c17a2c58479 100644 --- a/Doc/library/asyncio-platforms.rst +++ b/Doc/library/asyncio-platforms.rst @@ -19,6 +19,11 @@ All Platforms * :meth:`loop.add_reader` and :meth:`loop.add_writer` cannot be used to monitor file I/O. +* :meth:`loop.connect_read_pipe` and :meth:`loop.connect_write_pipe` + cannot be used with regular files. See :ref:`Supported pipe objects + <asyncio-pipe-objects>` for the objects that are accepted on each + platform. + Windows ======= @@ -62,6 +67,10 @@ All event loops on Windows do not support the following methods: * The :meth:`loop.add_reader` and :meth:`loop.add_writer` methods are not supported. +* :meth:`loop.connect_read_pipe` and :meth:`loop.connect_write_pipe` only + accept a handle opened for overlapped I/O. + See :ref:`Supported pipe objects <asyncio-pipe-objects>` for which objects are supported. + The resolution of the monotonic clock on Windows is usually around 15.6 milliseconds. The best resolution is 0.5 milliseconds. The resolution depends on the hardware (availability of `HPET diff --git a/Lib/asyncio/proactor_events.py b/Lib/asyncio/proactor_events.py index cf2902b4c76559..f18a7fe5855815 100644 --- a/Lib/asyncio/proactor_events.py +++ b/Lib/asyncio/proactor_events.py @@ -62,6 +62,7 @@ def __init__(self, loop, sock, protocol, waiter=None, self._closing = False # Set when close() called. self._called_connection_lost = False self._eof_written = False + self._empty_waiter = None if self._server is not None: self._server._attach(self) self._loop.call_soon(self._protocol.connection_made, self) @@ -331,10 +332,6 @@ class _ProactorBaseWritePipeTransport(_ProactorBasePipeTransport, _start_tls_compatible = True - def __init__(self, *args, **kw): - super().__init__(*args, **kw) - self._empty_waiter = None - def write(self, data): if not isinstance(data, (bytes, bytearray, memoryview)): raise TypeError( @@ -465,7 +462,6 @@ class _ProactorDatagramTransport(_ProactorBasePipeTransport, def __init__(self, loop, sock, protocol, address=None, waiter=None, extra=None): self._address = address - self._empty_waiter = None self._buffer_size = 0 # We don't need to call _protocol.connection_made() since our base # constructor does it for us. diff --git a/Lib/test/test_asyncio/test_events.py b/Lib/test/test_asyncio/test_events.py index 919d543b0329e9..43d1fb1047e7e4 100644 --- a/Lib/test/test_asyncio/test_events.py +++ b/Lib/test/test_asyncio/test_events.py @@ -33,6 +33,7 @@ from multiprocessing.util import _cleanup_tests as multiprocessing_cleanup_tests from test.test_asyncio import utils as test_utils from test import support +from test.support import os_helper from test.support import socket_helper from test.support import threading_helper from test.support import ALWAYS_EQ, LARGEST, SMALLEST @@ -3172,5 +3173,100 @@ def test_get_loop(self): events.AbstractServer().get_loop() +@unittest.skipIf(sys.platform == 'win32', 'Unix pipe transport semantics') +class UnixPipeObjectSupportTests(unittest.TestCase): + def setUp(self): + super().setUp() + self.loop = asyncio.SelectorEventLoop() + self.addCleanup(self.loop.close) + + def check_accepted(self, connect, pipeobj): + lost = self.loop.create_future() + + class Proto(asyncio.Protocol): + def connection_lost(self, exc): + if not lost.done(): + lost.set_result(exc) + + async def run(): + transport, protocol = await connect(Proto, pipeobj) + self.assertIsInstance(protocol, Proto) + self.assertFalse(pipeobj.closed) + transport.close() + self.assertIsNone(await lost) + + self.loop.run_until_complete(run()) + self.assertTrue(pipeobj.closed) + + def check_rejected(self, connect, pipeobj): + self.addCleanup(pipeobj.close) + with self.assertRaisesRegex(ValueError, 'Pipe transport is'): + self.loop.run_until_complete(connect(asyncio.Protocol, pipeobj)) + + def test_read_pipe(self): + rfd, wfd = os.pipe() + self.addCleanup(os.close, wfd) + self.check_accepted(self.loop.connect_read_pipe, open(rfd, 'rb', 0)) + + def test_write_pipe(self): + rfd, wfd = os.pipe() + self.addCleanup(os.close, rfd) + self.check_accepted(self.loop.connect_write_pipe, open(wfd, 'wb', 0)) + + def test_read_fifo(self): + path = os_helper.TESTFN + os.mkfifo(path) + self.addCleanup(os_helper.unlink, path) + rfd = os.open(path, os.O_RDONLY | os.O_NONBLOCK) + wfd = os.open(path, os.O_WRONLY) + self.addCleanup(os.close, wfd) + self.check_accepted(self.loop.connect_read_pipe, open(rfd, 'rb', 0)) + + def test_write_fifo(self): + path = os_helper.TESTFN + os.mkfifo(path) + self.addCleanup(os_helper.unlink, path) + rfd = os.open(path, os.O_RDONLY | os.O_NONBLOCK) + self.addCleanup(os.close, rfd) + wfd = os.open(path, os.O_WRONLY) + self.check_accepted(self.loop.connect_write_pipe, open(wfd, 'wb', 0)) + + def test_read_socket(self): + rsock, wsock = socket.socketpair() + self.addCleanup(wsock.close) + self.check_accepted(self.loop.connect_read_pipe, + open(rsock.detach(), 'rb', 0)) + + def test_write_socket(self): + rsock, wsock = socket.socketpair() + self.addCleanup(rsock.close) + self.check_accepted(self.loop.connect_write_pipe, + open(wsock.detach(), 'wb', 0)) + + @unittest.skipUnless(hasattr(os, 'openpty'), 'need os.openpty()') + def test_read_character_device(self): + master, slave = os.openpty() + self.addCleanup(os.close, slave) + self.check_accepted(self.loop.connect_read_pipe, open(master, 'rb', 0)) + + @unittest.skipUnless(hasattr(os, 'openpty'), 'need os.openpty()') + def test_write_character_device(self): + master, slave = os.openpty() + self.addCleanup(os.close, master) + self.check_accepted(self.loop.connect_write_pipe, open(slave, 'wb', 0)) + + def test_read_regular_file(self): + self.addCleanup(os_helper.unlink, os_helper.TESTFN) + with open(os_helper.TESTFN, 'wb') as f: + f.write(b'spam') + self.check_rejected(self.loop.connect_read_pipe, + open(os_helper.TESTFN, 'rb', 0)) + + def test_write_regular_file(self): + self.addCleanup(os_helper.unlink, os_helper.TESTFN) + self.check_rejected(self.loop.connect_write_pipe, + open(os_helper.TESTFN, 'wb', 0)) + + if __name__ == '__main__': unittest.main() diff --git a/Lib/test/test_asyncio/test_windows_events.py b/Lib/test/test_asyncio/test_windows_events.py index 0af3368627afca..4a85b1a09ee0e2 100644 --- a/Lib/test/test_asyncio/test_windows_events.py +++ b/Lib/test/test_asyncio/test_windows_events.py @@ -5,6 +5,7 @@ import time import threading import unittest +import warnings from unittest import mock if sys.platform != 'win32': @@ -15,6 +16,9 @@ import asyncio from asyncio import windows_events +from asyncio import windows_utils +from test import support +from test.support import os_helper from test.test_asyncio import utils as test_utils @@ -359,5 +363,110 @@ async def main(): asyncio.events._set_event_loop_policy(old_policy) +class ProactorPipeObjectSupportTests(unittest.TestCase): + + def setUp(self): + super().setUp() + self.loop = asyncio.ProactorEventLoop() + self.addCleanup(self.loop.close) + self.errors = [] + self.loop.set_exception_handler( + lambda loop, context: self.errors.append(context)) + + def check_read_rejected(self, pipe): + self.addCleanup(pipe.close) + lost = self.loop.create_future() + + class Proto(asyncio.Protocol): + def connection_lost(self, exc): + if not lost.done(): + lost.set_result(exc) + + async def run(): + transport, _ = await self.loop.connect_read_pipe(Proto, pipe) + exc = await lost + transport.close() + return exc + + exc = self.loop.run_until_complete(run()) + self.assertIsInstance(exc, OSError) + + def check_write_rejected(self, pipe): + self.addCleanup(pipe.close) + with warnings.catch_warnings(): + warnings.simplefilter('ignore', ResourceWarning) + with self.assertRaises(OSError): + self.loop.run_until_complete( + self.loop.connect_write_pipe(asyncio.BaseProtocol, pipe)) + support.gc_collect() + + def check_accepted(self, rpipe, wpipe): + self.addCleanup(rpipe.close) + self.addCleanup(wpipe.close) + + chunks = [] + lost = self.loop.create_future() + + class ReadProto(asyncio.Protocol): + def data_received(self, data): + chunks.append(data) + + def connection_lost(self, exc): + if not lost.done(): + lost.set_result(exc) + + async def run(): + rtransport, _ = await self.loop.connect_read_pipe(ReadProto, rpipe) + wtransport, _ = await self.loop.connect_write_pipe( + asyncio.BaseProtocol, wpipe) + wtransport.write(b'spam') + wtransport.close() + await lost + rtransport.close() + + self.loop.run_until_complete(run()) + self.assertEqual(b''.join(chunks), b'spam') + self.assertFalse(self.errors) + + def test_overlapped_pipe(self): + rhandle, whandle = windows_utils.pipe(duplex=True, overlapped=(True, True)) + self.check_accepted(windows_utils.PipeHandle(rhandle), + windows_utils.PipeHandle(whandle)) + + def test_socketpair(self): + rsock, wsock = socket.socketpair() + self.check_accepted(rsock, wsock) + + def test_read_non_overlapped_pipe(self): + rhandle, whandle = windows_utils.pipe(overlapped=(False, False)) + self.addCleanup(windows_utils.PipeHandle(whandle).close) + self.check_read_rejected(windows_utils.PipeHandle(rhandle)) + + def test_write_non_overlapped_pipe(self): + rhandle, whandle = windows_utils.pipe(overlapped=(False, False)) + self.addCleanup(windows_utils.PipeHandle(rhandle).close) + self.check_write_rejected(windows_utils.PipeHandle(whandle)) + + def test_read_regular_file(self): + self.addCleanup(os_helper.unlink, os_helper.TESTFN) + with open(os_helper.TESTFN, 'wb') as f: + f.write(b'spam') + self.check_read_rejected(open(os_helper.TESTFN, 'rb', 0)) + + def test_write_regular_file(self): + self.addCleanup(os_helper.unlink, os_helper.TESTFN) + self.check_write_rejected(open(os_helper.TESTFN, 'wb', 0)) + + def test_read_os_pipe(self): + rfd, wfd = os.pipe() + self.addCleanup(os.close, wfd) + self.check_read_rejected(open(rfd, 'rb', 0)) + + def test_write_os_pipe(self): + rfd, wfd = os.pipe() + self.addCleanup(os.close, rfd) + self.check_write_rejected(open(wfd, 'wb', 0)) + + if __name__ == '__main__': unittest.main() From edbc1fe09f046ccbe885051d93cf65d253ba0867 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 14 Jul 2026 18:52:23 +0200 Subject: [PATCH 674/818] [3.15] gh-151912: Fix segfault in `type()` with NULL `tp_new` metaclasses (GH-151916) (#153707) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gh-151912: Fix segfault in `type()` with NULL `tp_new` metaclasses (GH-151916) (cherry picked from commit f160f16373f9ea3f636bc5cd6fb4be7e150bb27f) Co-authored-by: Santhosh .I 🦇 <santhoshilaiyaraja2006@gmail.com> --- Lib/test/test_descr.py | 9 +++++++++ .../2026-06-22-14-48-22.gh-issue-151912.YcxfnU.rst | 1 + Objects/typeobject.c | 7 +++++++ 3 files changed, 17 insertions(+) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-22-14-48-22.gh-issue-151912.YcxfnU.rst diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py index 8a8e70214e27ae..ba504119d294fd 100644 --- a/Lib/test/test_descr.py +++ b/Lib/test/test_descr.py @@ -815,6 +815,15 @@ class X(C, int()): class X(int(), C): pass + @unittest.skipIf(_testcapi is None, 'need the _testcapi module') + def test_type_with_null_new_metaclass(self): + metaclass = _testcapi.HeapCTypeMetaclassNullNew + base = _testcapi.pytype_fromspec_meta(metaclass) + + # Exercise type_new's metaclass selection path, not a direct call. + with self.assertRaisesRegex(TypeError, r"cannot create '.*' instances"): + type("Derived", (base,), {}) + def test_module_subclasses(self): # Testing Python subclass of module... log = [] diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-22-14-48-22.gh-issue-151912.YcxfnU.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-22-14-48-22.gh-issue-151912.YcxfnU.rst new file mode 100644 index 00000000000000..07b73949b438a3 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-22-14-48-22.gh-issue-151912.YcxfnU.rst @@ -0,0 +1 @@ +Fixed a crash in ``type()`` when selecting a metaclass whose ``tp_new`` slot is ``NULL``. Such metaclasses are now rejected with ``TypeError`` instead of causing a NULL pointer dereference. diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 969ae450013a31..f763f9f5eba58f 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -5026,6 +5026,13 @@ type_new_get_bases(type_new_ctx *ctx, PyObject **type) if (winner != ctx->metatype) { if (winner->tp_new != type_new) { + /* Check if tp_new is NULL (cannot instantiate this type) */ + if (winner->tp_new == NULL) { + PyErr_Format(PyExc_TypeError, + "cannot create '%.400s' instances", + winner->tp_name); + return -1; + } /* Pass it to the winner */ *type = winner->tp_new(winner, ctx->args, ctx->kwds); if (*type == NULL) { From bec166a05302c972d7fe731e60ba3eb9da4d64c3 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 14 Jul 2026 23:41:48 +0200 Subject: [PATCH 675/818] [3.15] gh-148488: Clarify the company/tag separator in the py -V docs (GH-153427) (GH-153721) gh-148488: Clarify the company/tag separator in the py -V docs (GH-153427) (cherry picked from commit 54976e1482578d742d4e611741a7995650e8ae6b) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> --- Doc/using/windows.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Doc/using/windows.rst b/Doc/using/windows.rst index f75cf5b66c4388..e48de587598e5f 100644 --- a/Doc/using/windows.rst +++ b/Doc/using/windows.rst @@ -162,7 +162,9 @@ omitted in cases where the tag refers to an official release and starts with $> py -V:3-arm64 ... Runtimes from other distributors may require the *company* to be included as -well. This should be separated from the tag by a slash, and may be a prefix. +well. +It should be separated from the tag by a slash (either ``/`` or ``\``), +and may be shortened to any prefix of its full value. Specifying the company is optional when it is ``PythonCore``, and specifying the tag is optional (but not the slash) when you want the latest release from a specific company. From f58e5824796a175adb6b2c0bd21ff63ef062e980 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 15 Jul 2026 00:55:51 +0200 Subject: [PATCH 676/818] [3.15] gh-153695: Fix sqlite3.Row.__hash__ with an unhashable value (GH-153696) (#153723) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gh-153695: Fix sqlite3.Row.__hash__ with an unhashable value (GH-153696) (cherry picked from commit b704b647b2295924ebaf8d20ddf88925095039bb) Co-authored-by: tonghuaroot (童话) <tonghuaroot@gmail.com> --- Lib/test/test_sqlite3/test_factory.py | 11 +++++++++++ .../2026-07-14-19-45-21.gh-issue-153695.UYdZJZ.rst | 2 ++ Modules/_sqlite/row.c | 10 +++++++++- 3 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2026-07-14-19-45-21.gh-issue-153695.UYdZJZ.rst diff --git a/Lib/test/test_sqlite3/test_factory.py b/Lib/test/test_sqlite3/test_factory.py index a9abeab3193688..b9b18fdee87226 100644 --- a/Lib/test/test_sqlite3/test_factory.py +++ b/Lib/test/test_sqlite3/test_factory.py @@ -239,6 +239,17 @@ def test_sqlite_row_hash_cmp(self): self.assertEqual(hash(row_1), hash(row_2)) + def test_sqlite_row_hash_unhashable(self): + # An unhashable value must raise TypeError, not SystemError. + sqlite.register_converter("LST", lambda b: [1, 2, 3]) + self.addCleanup(sqlite.converters.pop, "LST", None) + with memory_database(detect_types=sqlite.PARSE_DECLTYPES) as con: + con.row_factory = sqlite.Row + con.execute("create table t(x LST)") + con.execute("insert into t values(?)", (b"x",)) + row = con.execute("select x from t").fetchone() + self.assertRaisesRegex(TypeError, "unhashable", hash, row) + def test_sqlite_row_as_sequence(self): # Checks if the row object can act like a sequence. row = self.con.execute("select 1 as a, 2 as b").fetchone() diff --git a/Misc/NEWS.d/next/Library/2026-07-14-19-45-21.gh-issue-153695.UYdZJZ.rst b/Misc/NEWS.d/next/Library/2026-07-14-19-45-21.gh-issue-153695.UYdZJZ.rst new file mode 100644 index 00000000000000..43d7feebf97d6f --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-14-19-45-21.gh-issue-153695.UYdZJZ.rst @@ -0,0 +1,2 @@ +Hashing a :class:`sqlite3.Row` that contains an unhashable value now raises +:exc:`TypeError` instead of :exc:`SystemError`. Patch by tonghuaroot. diff --git a/Modules/_sqlite/row.c b/Modules/_sqlite/row.c index 94565a01d18f24..8646f591ef5169 100644 --- a/Modules/_sqlite/row.c +++ b/Modules/_sqlite/row.c @@ -232,7 +232,15 @@ static Py_hash_t pysqlite_row_hash(PyObject *op) { pysqlite_Row *self = _pysqlite_Row_CAST(op); - return PyObject_Hash(self->description) ^ PyObject_Hash(self->data); + Py_hash_t hash_description = PyObject_Hash(self->description); + if (hash_description == -1) { + return -1; + } + Py_hash_t hash_data = PyObject_Hash(self->data); + if (hash_data == -1) { + return -1; + } + return hash_description ^ hash_data; } static PyObject * From 28c0653215e191ca3fc843201d1a0972ae39f300 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 15 Jul 2026 03:44:18 +0200 Subject: [PATCH 677/818] [3.15] gh-153313: Run Emscripten PyRepl test in CI (GH-153701) (#153727) Adds the PyRepl test to the Github CI configuration for Emscripten. (cherry picked from commit 1b3914ab3d29bba00effe3d58145498efcbeca93) Co-authored-by: Hood Chatham <roberthoodchatham@gmail.com> --- .github/workflows/reusable-emscripten.yml | 2 ++ .../emscripten/browser_test/package-lock.json | 26 +++++++++---------- .../emscripten/browser_test/package.json | 4 +-- Platforms/emscripten/browser_test/run_test.sh | 12 +++++---- 4 files changed, 24 insertions(+), 20 deletions(-) diff --git a/.github/workflows/reusable-emscripten.yml b/.github/workflows/reusable-emscripten.yml index c14a41b5682877..b15169164572b4 100644 --- a/.github/workflows/reusable-emscripten.yml +++ b/.github/workflows/reusable-emscripten.yml @@ -77,3 +77,5 @@ jobs: run: python3 Platforms/emscripten pythoninfo-host - name: "Test" run: python3 Platforms/emscripten run --test + - name: "Test Repl" + run: Platforms/emscripten/browser_test/run_test.sh diff --git a/Platforms/emscripten/browser_test/package-lock.json b/Platforms/emscripten/browser_test/package-lock.json index 978aea0147bc28..67acfba9daf62e 100644 --- a/Platforms/emscripten/browser_test/package-lock.json +++ b/Platforms/emscripten/browser_test/package-lock.json @@ -9,11 +9,11 @@ "version": "1.0.0", "license": "ISC", "dependencies": { - "@playwright/test": "^1.54.1", + "@playwright/test": "^1.61.1", "@types/node": "^24.12.0", "get-port-cli": "^3.0.0", "http-server": "^14.1.1", - "playwright": "^1.54.1" + "playwright": "^1.61.1" } }, "node_modules/@babel/code-frame": { @@ -40,12 +40,12 @@ } }, "node_modules/@playwright/test": { - "version": "1.58.2", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.58.2.tgz", - "integrity": "sha512-akea+6bHYBBfA9uQqSYmlJXn61cTa+jbO87xVLCWbTqbWadRVmhxlXATaOjOgcBaWU4ePo0wB41KMFv3o35IXA==", + "version": "1.61.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.61.1.tgz", + "integrity": "sha512-8nKv6+0RJSL9FE4jYOEGXnPeM/Hg12qZpmqzZjRh3qM0Y7c3z1mrOTfFLids72RDQYVh9WpLEfR5WdpNX4fkig==", "license": "Apache-2.0", "dependencies": { - "playwright": "1.58.2" + "playwright": "1.61.1" }, "bin": { "playwright": "cli.js" @@ -892,12 +892,12 @@ "license": "ISC" }, "node_modules/playwright": { - "version": "1.58.2", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.58.2.tgz", - "integrity": "sha512-vA30H8Nvkq/cPBnNw4Q8TWz1EJyqgpuinBcHET0YVJVFldr8JDNiU9LaWAE1KqSkRYazuaBhTpB5ZzShOezQ6A==", + "version": "1.61.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.61.1.tgz", + "integrity": "sha512-DWnY5o3YbLWK4GovuAVwpqL+1VwGNdUGrRr++8j8PtQQzvAVZUIMjKQ90fY689sEJZJBbZVw1rXaOKSTitkzPQ==", "license": "Apache-2.0", "dependencies": { - "playwright-core": "1.58.2" + "playwright-core": "1.61.1" }, "bin": { "playwright": "cli.js" @@ -910,9 +910,9 @@ } }, "node_modules/playwright-core": { - "version": "1.58.2", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.58.2.tgz", - "integrity": "sha512-yZkEtftgwS8CsfYo7nm0KE8jsvm6i/PTgVtB8DL726wNf6H2IMsDuxCpJj59KDaxCtSnrWan2AeDqM7JBaultg==", + "version": "1.61.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.61.1.tgz", + "integrity": "sha512-h7Qlt6m4REp25qvIdvbDtVmD4LqVXfpRxhORv9L0jzETM05p4fuPJ3dKyuSXQxDSbXnmS79HAgi9589lGSpLkg==", "license": "Apache-2.0", "bin": { "playwright-core": "cli.js" diff --git a/Platforms/emscripten/browser_test/package.json b/Platforms/emscripten/browser_test/package.json index 540c9b8034e7c7..fc8e1ce33975ef 100644 --- a/Platforms/emscripten/browser_test/package.json +++ b/Platforms/emscripten/browser_test/package.json @@ -10,10 +10,10 @@ "license": "ISC", "description": "", "dependencies": { - "@playwright/test": "^1.54.1", + "@playwright/test": "^1.61.1", "@types/node": "^24.12.0", "get-port-cli": "^3.0.0", "http-server": "^14.1.1", - "playwright": "^1.54.1" + "playwright": "^1.61.1" } } diff --git a/Platforms/emscripten/browser_test/run_test.sh b/Platforms/emscripten/browser_test/run_test.sh index cc89b3a91607ed..da6e24cba2e3c9 100755 --- a/Platforms/emscripten/browser_test/run_test.sh +++ b/Platforms/emscripten/browser_test/run_test.sh @@ -2,10 +2,12 @@ set -euo pipefail cd "$(dirname "$0")" rm -f test_log.txt -echo "Installing node packages" | tee test_log.txt +echo "Installing node packages" | tee -a test_log.txt npm ci >> test_log.txt 2>&1 -echo "Installing playwright browsers" | tee test_log.txt +echo "Installing playwright browsers" | tee -a test_log.txt npx playwright install 2>> test_log.txt -export PORT=$(npx get-port-cli) -echo "Running tests with webserver on port $PORT" | tee test_log.txt -CI=1 npx playwright test | tee test_log.txt +# Disable color so FORCE_COLOR=1 (set in CI) doesn't wrap the port number in +# ANSI escape codes, which would produce an invalid baseURL in Playwright. +export PORT=$(FORCE_COLOR=0 npx get-port-cli) +echo "Running tests with webserver on port $PORT" | tee -a test_log.txt +CI=1 npx playwright test | tee -a test_log.txt From 29cb75dc109cfb4a57061ea8525cbc379101ae25 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 15 Jul 2026 05:34:53 +0200 Subject: [PATCH 678/818] [3.15] Remove duplicate button_ok code in idlelib.textview (GH-153733) (#153734) Remove duplicate button_ok code in idlelib.textview (GH-153733) (cherry picked from commit c5530cc836595aed61cbd0504c92e4d8fb996ed0) Co-authored-by: Terry Jan Reedy <tjreedy@udel.edu> --- Lib/idlelib/textview.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/Lib/idlelib/textview.py b/Lib/idlelib/textview.py index 0f719a06883ad7..b326331efa7f9a 100644 --- a/Lib/idlelib/textview.py +++ b/Lib/idlelib/textview.py @@ -92,10 +92,10 @@ def __init__(self, parent, contents, wrap='word'): color_config(text) text.focus_set() - self.button_ok = button_ok = Button( + self.button_ok = Button( self, text='Close', command=self.ok, takefocus=False) self.textframe.pack(side='top', expand=True, fill='both') - button_ok.pack(side='bottom') + self.button_ok.pack(side='bottom') def ok(self, event=None): """Dismiss text viewer dialog.""" @@ -127,10 +127,8 @@ def __init__(self, parent, title, contents, modal=True, wrap=WORD, self.geometry(f'=750x500+{x}+{y}') self.title(title) - self.viewframe = ViewFrame(self, contents, wrap=wrap) self.protocol("WM_DELETE_WINDOW", self.ok) - self.button_ok = Button(self, text='Close', - command=self.ok, takefocus=False) + self.viewframe = ViewFrame(self, contents, wrap=wrap) self.viewframe.pack(side='top', expand=True, fill='both') self.is_modal = modal From accfc342e792d461eecf6bcbdd242f126822f325 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 15 Jul 2026 05:37:16 +0200 Subject: [PATCH 679/818] [3.15] gh-153716: Harden ttk/tkinter GUI tests against display scaling (GH-153717) (GH-153737) Compute probe coordinates from each widget's own realized geometry instead of hardcoding pixels such as (5, 5) or width - 5, which land on a different element, or miss it entirely, at a high display scaling. (cherry picked from commit 87411d0742f070b1424c08b41cf3af49d377b215) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --- Lib/test/test_tkinter/test_widgets.py | 10 +- Lib/test/test_ttk/test_widgets.py | 134 ++++++++++++++++---------- 2 files changed, 91 insertions(+), 53 deletions(-) diff --git a/Lib/test/test_tkinter/test_widgets.py b/Lib/test/test_tkinter/test_widgets.py index efd9beed71a88b..14c06ee913dc8a 100644 --- a/Lib/test/test_tkinter/test_widgets.py +++ b/Lib/test/test_tkinter/test_widgets.py @@ -2017,9 +2017,13 @@ def test_configure_to(self): def test_identify(self): widget = self.create() widget.pack() - widget.update_idletasks() - self.assertIn(widget.identify(5, 5), - ('slider', 'trough1', 'trough2', '')) + # Probe a point on the trough centreline (Scale.coords()) rather than + # a fixed pixel: (5, 5) lies outside the trough and always identifies + # as '', so it would not actually exercise identify(). + if wait_until_mapped(widget): + x, y = widget.coords() + self.assertIn(widget.identify(int(x), int(y)), + ('slider', 'trough1', 'trough2')) self.assertRaises(TclError, widget.identify, 'a', 'b') diff --git a/Lib/test/test_ttk/test_widgets.py b/Lib/test/test_ttk/test_widgets.py index 787c96cfd77cbf..53bcd5ed2aab1b 100644 --- a/Lib/test/test_ttk/test_widgets.py +++ b/Lib/test/test_ttk/test_widgets.py @@ -357,6 +357,19 @@ def setUp(self): def create(self, **kwargs): return ttk.Entry(self.root, **kwargs) + def _arrow_x(self, widget, y, arrow): + # Return an x coordinate on the up/down *arrow* element in row y, + # found by scanning inward from the right edge of the widget. A + # fixed inset such as width - 5 lands in the arrow element's + # right-hand border, which scales with the display scaling, so at a + # high DPI identify() there returns 'field' instead of the arrow. + self.assertTrue(wait_until_mapped(widget, full_size=True)) + width = widget.winfo_width() + for x in range(width - 1, width // 2, -1): + if widget.identify(x, y).endswith(arrow): + return x + self.fail(f'no {arrow} found in row {y}') + def test_configure_invalidcommand(self): widget = self.create() self.checkCommandParam(widget, 'invalidcommand') @@ -391,7 +404,12 @@ def test_identify(self): # Identifying the element under a point requires the widget to be # mapped with a real size; the rest of the checks do not. if wait_until_mapped(self.entry): - self.assertIn(self.entry.identify(5, 5), self.IDENTIFY_AS) + # Probe the centre of the widget: a fixed pixel such as (5, 5) + # lands in the field at a normal scaling but in the surrounding + # padding at a high DPI. + x = self.entry.winfo_width() // 2 + y = self.entry.winfo_height() // 2 + self.assertIn(self.entry.identify(x, y), self.IDENTIFY_AS) self.assertEqual(self.entry.identify(-1, -1), "") self.assertRaises(tkinter.TclError, self.entry.identify, None, 5) @@ -492,10 +510,11 @@ def test_configure_height(self): self.checkParams(widget, 'height', 100, 101.2, 102.6, -100, 0, '1i') def _show_drop_down_listbox(self): - width = self.combo.winfo_width() - x, y = width - 5, 5 + y = 5 if sys.platform != 'darwin': # there's no down arrow on macOS - self.assertRegex(self.combo.identify(x, y), r'.*downarrow\z') + x = self._arrow_x(self.combo, y, 'downarrow') + else: + x = self.combo.winfo_width() - 5 self.combo.event_generate('<Button-1>', x=x, y=y) self.combo.event_generate('<ButtonRelease-1>', x=x, y=y) @@ -1068,21 +1087,15 @@ def test_tab_identifiers(self): self.nb.pack() self.nb.update() - if sys.platform == 'darwin': - tb_idx = "@20,5" - else: - tb_idx = "@5,5" - self.assertEqual(self.nb.tab(tb_idx), self.nb.tab('current')) - - for i in range(5, 100, 5): - try: - if self.nb.tab('@%d, 5' % i, text=None) == 'a': - break - except tkinter.TclError: - pass + # Address a tab by a point taken from Tk's own geometry rather than a + # fixed pixel, which can land on a different tab or miss the tabs + # entirely (e.g. on Aqua the tabs are inset) as the display scaling + # changes. + x, y = self._tab_point(self.nb.index('current')) + self.assertEqual(self.nb.tab(f'@{x},{y}'), self.nb.tab('current')) - else: - self.fail("Tab with text 'a' not found") + x, y = self._tab_point(self.nb.index(self.child1)) + self.assertEqual(self.nb.tab(f'@{x},{y}', text=None), 'a') def test_add_and_hidden(self): self.assertRaises(tkinter.TclError, self.nb.hide, -1) @@ -1212,23 +1225,43 @@ def test_configure_tabs(self): self.assertEqual(self.nb.tabs(), ()) + def _tab_point(self, index): + # Return a window coordinate that really lies on tab *index*, taken + # from Tk's own geometry (ttk::notebook index @x,y), so that it is + # correct regardless of the theme, platform and display scaling. A + # fixed pixel such as (5, 5) can land on a different tab element + # depending on the DPI, or miss the tabs entirely (e.g. on Aqua the + # tabs are inset), which would make a click there test nothing. + self.assertTrue(wait_until_mapped(self.nb, full_size=True)) + w, h = self.nb.winfo_width(), self.nb.winfo_height() + # The selected pane fills the widget except for the tab strip, so skip + # that large tab-free region instead of querying every pixel in it. + pane = self.nb.nametowidget(self.nb.select()) + px, py = pane.winfo_x(), pane.winfo_y() + pw, ph = pane.winfo_width(), pane.winfo_height() + for y in range(h): + inside_y = py <= y < py + ph + for x in range(w): + if inside_y and px <= x < px + pw: + continue + try: + if self.nb.index(f'@{x},{y}') == index: + return x, y + except TclError: + continue + self.fail(f'no point found on tab {index}') + def test_traversal(self): self.nb.pack() self.nb.update() - self.nb.select(0) + # A mouse click selects the tab it lands on. + self.nb.select(1) + self.assertEqual(self.nb.select(), str(self.child2)) + simulate_mouse_click(self.nb, *self._tab_point(0)) + self.assertEqual(self.nb.select(), str(self.child1)) - if sys.platform == 'darwin': - focus_identify_as = '' - elif sys.platform == 'win32': - focus_identify_as = 'focus' - else: - focus_identify_as = 'focus' if tk_version < (8, 7) else 'padding' - # identify() at (5, 5) needs the tab realized there; under focus - # contention the mapped size can lag, so wait for the full size. - if wait_until_mapped(self.nb, full_size=True): - self.assertEqual(self.nb.identify(5, 5), focus_identify_as) - simulate_mouse_click(self.nb, 5, 5) + # Control-Tab and Shift-Control-Tab traverse the tabs. self.nb.focus_force() self.nb.event_generate('<Control-Tab>') self.assertEqual(self.nb.select(), str(self.child2)) @@ -1243,21 +1276,25 @@ def test_traversal(self): self.nb.tab(self.child2, text='e', underline=0) self.nb.enable_traversal() self.nb.focus_force() - if wait_until_mapped(self.nb, full_size=True): - self.assertEqual(self.nb.identify(5, 5), focus_identify_as) - simulate_mouse_click(self.nb, 5, 5) - # on macOS Emacs-style keyboard shortcuts are region-dependent; - # let's use the regular arrow keys instead + + # A click still selects the tab it lands on after enable_traversal(). + self.nb.select(1) + self.assertEqual(self.nb.select(), str(self.child2)) + simulate_mouse_click(self.nb, *self._tab_point(0)) + self.assertEqual(self.nb.select(), str(self.child1)) + + # Mnemonics traverse the tabs (macOS uses region-dependent + # Emacs-style shortcuts, so use the regular arrow keys there). if sys.platform == 'darwin': begin = '<Left>' end = '<Right>' else: begin = '<Alt-a>' end = '<Alt-e>' - self.nb.event_generate(begin) - self.assertEqual(self.nb.select(), str(self.child1)) self.nb.event_generate(end) self.assertEqual(self.nb.select(), str(self.child2)) + self.nb.event_generate(begin) + self.assertEqual(self.nb.select(), str(self.child1)) @add_configure_tests(IntegerSizeTests, StandardTtkOptionsTests) @@ -1283,22 +1320,16 @@ def create(self, **kwargs): def _click_increment_arrow(self): self.require_mapped(self.spin) - width = self.spin.winfo_width() - height = self.spin.winfo_height() - x = width - 5 - y = height//2 - 5 - self.assertRegex(self.spin.identify(x, y), r'.*uparrow\z') + y = self.spin.winfo_height()//2 - 5 + x = self._arrow_x(self.spin, y, 'uparrow') self.spin.event_generate('<ButtonPress-1>', x=x, y=y) self.spin.event_generate('<ButtonRelease-1>', x=x, y=y) self.spin.update_idletasks() def _click_decrement_arrow(self): self.require_mapped(self.spin) - width = self.spin.winfo_width() - height = self.spin.winfo_height() - x = width - 5 - y = height//2 + 4 - self.assertRegex(self.spin.identify(x, y), r'.*downarrow\z') + y = self.spin.winfo_height()//2 + 4 + x = self._arrow_x(self.spin, y, 'downarrow') self.spin.event_generate('<ButtonPress-1>', x=x, y=y) self.spin.event_generate('<ButtonRelease-1>', x=x, y=y) self.spin.update_idletasks() @@ -2068,14 +2099,17 @@ def test_tag_bind(self): self.tv.pack() self.tv.update() + # Find the y coordinate of each item. Scan the whole height of the + # widget rather than a fixed pixel range, since the row height grows + # with the display scaling. pos_y = set() found = set() - for i in range(0, 100, 10): + for y in range(self.tv.winfo_height()): if len(found) == 2: # item1 and item2 already found break - item_id = self.tv.identify_row(i) + item_id = self.tv.identify_row(y) if item_id and item_id not in found: - pos_y.add(i) + pos_y.add(y) found.add(item_id) self.assertEqual(len(pos_y), 2) # item1 and item2 y pos From 12682355a43849b19ddf851cdd4f5c922804cfa8 Mon Sep 17 00:00:00 2001 From: Neil Schemenauer <nas-github@arctrix.com> Date: Wed, 15 Jul 2026 01:28:12 -0700 Subject: [PATCH 680/818] [3.15] gh-149816: Fix UAF in Modules/_pickle.c (GH-150024) (#153718) (cherry picked from commit d095ceb0f420a22353271a8adaf5a83433d018e5) Co-authored-by: Alexey Katsman <alex2007508@gmail.com> Co-authored-by: Gregory P. Smith <68491+gpshead@users.noreply.github.com> --- Lib/test/test_free_threading/test_pickle.py | 34 +++++++++++++++++++ ...-05-18-12-42-31.gh-issue-149816.F98iME.rst | 2 ++ Modules/_pickle.c | 29 +++++++++++----- 3 files changed, 57 insertions(+), 8 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-05-18-12-42-31.gh-issue-149816.F98iME.rst diff --git a/Lib/test/test_free_threading/test_pickle.py b/Lib/test/test_free_threading/test_pickle.py index 85a644dc72ecb4..45ea1bf5f26465 100644 --- a/Lib/test/test_free_threading/test_pickle.py +++ b/Lib/test/test_free_threading/test_pickle.py @@ -40,5 +40,39 @@ def mutator(): with threading_helper.start_threads(threads): pass + def test_pickle_dumps_with_concurrent_list_mutations(self): + # gh-149816: Pickling a list while another thread mutates it + # used to be a UAF in free-threaded mode. batch_list_exact() + # used PyList_GET_ITEM (borrowed) followed by Py_INCREF, and a + # concurrent replace/pop could free the item between those two + # operations. + shared = [list(range(20)) for _ in range(50)] + + def dumper(): + for _ in range(1000): + try: + pickle.dumps(shared) + except (RuntimeError, IndexError): + pass + + def mutator(): + for i in range(1000): + idx = i % 50 + shared[idx] = list(range(i % 20)) + if i % 10 == 0: + try: + shared.pop() + except IndexError: + pass + shared.append([i]) + + threads = [] + for _ in range(10): + threads.append(threading.Thread(target=dumper)) + threads.append(threading.Thread(target=mutator)) + + with threading_helper.start_threads(threads): + pass + if __name__ == "__main__": unittest.main() diff --git a/Misc/NEWS.d/next/Library/2026-05-18-12-42-31.gh-issue-149816.F98iME.rst b/Misc/NEWS.d/next/Library/2026-05-18-12-42-31.gh-issue-149816.F98iME.rst new file mode 100644 index 00000000000000..21e3ae0df57621 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-05-18-12-42-31.gh-issue-149816.F98iME.rst @@ -0,0 +1,2 @@ +Fix a potential use after free condition in :func:`pickle.dumps` in free-threaded +mode when serializing lists. diff --git a/Modules/_pickle.c b/Modules/_pickle.c index 6219706f903159..a5595be251a738 100644 --- a/Modules/_pickle.c +++ b/Modules/_pickle.c @@ -3191,7 +3191,7 @@ static int batch_list_exact(PickleState *state, PicklerObject *self, PyObject *obj) { PyObject *item = NULL; - Py_ssize_t this_batch, total; + Py_ssize_t this_batch, total, list_size; const char append_op = APPEND; const char appends_op = APPENDS; @@ -3200,14 +3200,18 @@ batch_list_exact(PickleState *state, PicklerObject *self, PyObject *obj) assert(obj != NULL); assert(self->proto > 0); assert(PyList_CheckExact(obj)); - assert(PyList_GET_SIZE(obj)); + + list_size = PyList_GET_SIZE(obj); /* Write in batches of BATCHSIZE. */ total = 0; do { - if (PyList_GET_SIZE(obj) - total == 1) { - item = PyList_GET_ITEM(obj, total); - Py_INCREF(item); + if (list_size - total == 1) { + item = PyList_GetItemRef(obj, total); + if (item == NULL) { + _PyErr_FormatNote("when serializing %T item %zd", obj, total); + return -1; + } int err = save(state, self, item, 0); Py_DECREF(item); if (err < 0) { @@ -3222,8 +3226,11 @@ batch_list_exact(PickleState *state, PicklerObject *self, PyObject *obj) if (_Pickler_Write(self, &mark_op, 1) < 0) return -1; while (total < PyList_GET_SIZE(obj)) { - item = PyList_GET_ITEM(obj, total); - Py_INCREF(item); + item = PyList_GetItemRef(obj, total); + if (item == NULL) { + _PyErr_FormatNote("when serializing %T item %zd", obj, total); + return -1; + } int err = save(state, self, item, 0); Py_DECREF(item); if (err < 0) { @@ -3236,8 +3243,14 @@ batch_list_exact(PickleState *state, PicklerObject *self, PyObject *obj) } if (_Pickler_Write(self, &appends_op, 1) < 0) return -1; + if (PyList_GET_SIZE(obj) != list_size) { + PyErr_Format( + PyExc_RuntimeError, + "list changed size during iteration"); + return -1; + } - } while (total < PyList_GET_SIZE(obj)); + } while (total < list_size); return 0; } From 29e733ac31ea21c4d62f4e61bca61234cb6b0827 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 15 Jul 2026 11:46:49 +0200 Subject: [PATCH 681/818] [3.15] gh-71086: Document negative offset support in struct.pack_into() and unpack_from() (GH-153650) (GH-153699) (cherry picked from commit 1706d14a2a1f009f786b8d7599e53c168b0392e0) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --- Doc/library/struct.rst | 2 ++ Modules/_struct.c | 24 +++++++++++++----------- Modules/clinic/_struct.c.h | 18 ++++++++++-------- 3 files changed, 25 insertions(+), 19 deletions(-) diff --git a/Doc/library/struct.rst b/Doc/library/struct.rst index ef535e3ca6e882..6a128a610f3aad 100644 --- a/Doc/library/struct.rst +++ b/Doc/library/struct.rst @@ -68,6 +68,7 @@ The module defines the following exception and functions: Pack the values *v1*, *v2*, ... according to the format string *format* and write the packed bytes into the writable buffer *buffer* starting at position *offset*. Note that *offset* is a required argument. + A negative *offset* counts from the end of *buffer*. .. function:: unpack(format, buffer) @@ -84,6 +85,7 @@ The module defines the following exception and functions: string *format*. The result is a tuple even if it contains exactly one item. The buffer's size in bytes, starting at position *offset*, must be at least the size required by the format, as reflected by :func:`calcsize`. + A negative *offset* counts from the end of *buffer*. .. function:: iter_unpack(format, buffer) diff --git a/Modules/_struct.c b/Modules/_struct.c index 8c611a708d02a9..5b5ca4f9527693 100644 --- a/Modules/_struct.c +++ b/Modules/_struct.c @@ -2127,14 +2127,14 @@ Return a tuple containing unpacked values. Values are unpacked according to the struct format string. The buffer's size in bytes, starting at position offset, must be at -least the struct size. See help(struct) for more on format -strings. +least the struct size. A negative offset counts from the end of +the buffer. See help(struct) for more on format strings. [clinic start generated code]*/ static PyObject * Struct_unpack_from_impl(PyStructObject *self, Py_buffer *buffer, Py_ssize_t offset) -/*[clinic end generated code: output=57fac875e0977316 input=57cfcf84c088faa4]*/ +/*[clinic end generated code: output=57fac875e0977316 input=49b7c90dd8faeb97]*/ { _structmodulestate *state = get_struct_state_structinst(self); ENSURE_STRUCT_IS_READY(self); @@ -2468,15 +2468,16 @@ Pack values and write the packed bytes into the buffer. Pack the provided values according to the struct format string and write the packed bytes into the writable buffer starting at -offset. Note that the offset is a required argument. See -help(struct) for more on format strings. +offset. Note that the offset is a required argument. A negative +offset counts from the end of the buffer. See help(struct) for +more on format strings. [clinic start generated code]*/ static PyObject * Struct_pack_into_impl(PyStructObject *self, Py_buffer *buffer, Py_ssize_t offset, PyObject * const *values, Py_ssize_t values_length) -/*[clinic end generated code: output=aa9d9a93f5f8f77b input=9d842a368ee14245]*/ +/*[clinic end generated code: output=aa9d9a93f5f8f77b input=a2b8749e3843f01b]*/ { _structmodulestate *state = get_struct_state_structinst(self); @@ -2706,15 +2707,15 @@ Pack values and write the packed bytes into the buffer. Pack the provided values according to the format string and write the packed bytes into the writable buffer starting at offset. Note that the -offset is a required argument. See help(struct) for more on format -strings. +offset is a required argument. A negative offset counts from the end of +the buffer. See help(struct) for more on format strings. [clinic start generated code]*/ static PyObject * pack_into_impl(PyObject *module, PyStructObject *s_object, Py_buffer *buffer, Py_ssize_t offset, PyObject * const *values, Py_ssize_t values_length) -/*[clinic end generated code: output=e8bf7d422b2088ef input=086867c0f5d8a8e4]*/ +/*[clinic end generated code: output=e8bf7d422b2088ef input=548c35c57db7436a]*/ { return Struct_pack_into_impl(s_object, buffer, offset, values, values_length); @@ -2752,14 +2753,15 @@ unpack_from Return a tuple containing values unpacked according to the format string. -The buffer's size, minus offset, must be at least calcsize(format). See +The buffer must contain at least calcsize(format) bytes starting at +offset. A negative offset counts from the end of the buffer. See help(struct) for more on format strings. [clinic start generated code]*/ static PyObject * unpack_from_impl(PyObject *module, PyStructObject *s_object, Py_buffer *buffer, Py_ssize_t offset) -/*[clinic end generated code: output=1042631674c6e0d3 input=3e46619756fb0293]*/ +/*[clinic end generated code: output=1042631674c6e0d3 input=fb755400a7a47a51]*/ { return Struct_unpack_from_impl(s_object, buffer, offset); } diff --git a/Modules/clinic/_struct.c.h b/Modules/clinic/_struct.c.h index e75698e3ed00cc..22fec68a4e9ee6 100644 --- a/Modules/clinic/_struct.c.h +++ b/Modules/clinic/_struct.c.h @@ -173,8 +173,8 @@ PyDoc_STRVAR(Struct_unpack_from__doc__, "\n" "Values are unpacked according to the struct format string. The\n" "buffer\'s size in bytes, starting at position offset, must be at\n" -"least the struct size. See help(struct) for more on format\n" -"strings."); +"least the struct size. A negative offset counts from the end of\n" +"the buffer. See help(struct) for more on format strings."); #define STRUCT_UNPACK_FROM_METHODDEF \ {"unpack_from", _PyCFunction_CAST(Struct_unpack_from), METH_FASTCALL|METH_KEYWORDS, Struct_unpack_from__doc__}, @@ -319,8 +319,9 @@ PyDoc_STRVAR(Struct_pack_into__doc__, "\n" "Pack the provided values according to the struct format string\n" "and write the packed bytes into the writable buffer starting at\n" -"offset. Note that the offset is a required argument. See\n" -"help(struct) for more on format strings."); +"offset. Note that the offset is a required argument. A negative\n" +"offset counts from the end of the buffer. See help(struct) for\n" +"more on format strings."); #define STRUCT_PACK_INTO_METHODDEF \ {"pack_into", _PyCFunction_CAST(Struct_pack_into), METH_FASTCALL, Struct_pack_into__doc__}, @@ -490,8 +491,8 @@ PyDoc_STRVAR(pack_into__doc__, "\n" "Pack the provided values according to the format string and write the\n" "packed bytes into the writable buffer starting at offset. Note that the\n" -"offset is a required argument. See help(struct) for more on format\n" -"strings."); +"offset is a required argument. A negative offset counts from the end of\n" +"the buffer. See help(struct) for more on format strings."); #define PACK_INTO_METHODDEF \ {"pack_into", _PyCFunction_CAST(pack_into), METH_FASTCALL, pack_into__doc__}, @@ -598,7 +599,8 @@ PyDoc_STRVAR(unpack_from__doc__, "\n" "Return a tuple containing values unpacked according to the format string.\n" "\n" -"The buffer\'s size, minus offset, must be at least calcsize(format). See\n" +"The buffer must contain at least calcsize(format) bytes starting at\n" +"offset. A negative offset counts from the end of the buffer. See\n" "help(struct) for more on format strings."); #define UNPACK_FROM_METHODDEF \ @@ -724,4 +726,4 @@ iter_unpack(PyObject *module, PyObject *const *args, Py_ssize_t nargs) return return_value; } -/*[clinic end generated code: output=0f417d43a2a387c8 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=021b89d2d3c3c225 input=a9049054013a1b77]*/ From 22eff887f7565d24b6ba54bc147672d3ecdd8cf7 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka <storchaka@gmail.com> Date: Wed, 15 Jul 2026 12:48:33 +0300 Subject: [PATCH 682/818] [3.15] gh-93417: Improve test_mimetypes (GH-150725) (GH-153748) * Separate tests for module-level API and for the MimeTypes class. * Add tests for mimetypes.init() and MimeTypes() with knownfiles and with explicitly passed files. (cherry picked from commit b23646adf1f484d6ee61ea04529b48443508715a) --- Lib/test/mime.types2 | 3 + Lib/test/test_mimetypes.py | 353 +++++++++++++++++++++---------------- 2 files changed, 203 insertions(+), 153 deletions(-) create mode 100644 Lib/test/mime.types2 diff --git a/Lib/test/mime.types2 b/Lib/test/mime.types2 new file mode 100644 index 00000000000000..b05c318d1c05c2 --- /dev/null +++ b/Lib/test/mime.types2 @@ -0,0 +1,3 @@ +# MIME type Extensions +testing/test2 test test2 +testing/test3 test test3 diff --git a/Lib/test/test_mimetypes.py b/Lib/test/test_mimetypes.py index b49f05c66fcfbe..f0851431a2724e 100644 --- a/Lib/test/test_mimetypes.py +++ b/Lib/test/test_mimetypes.py @@ -31,50 +31,11 @@ def tearDownModule(): mimetypes.knownfiles = knownfiles -class MimeTypesTestCase(unittest.TestCase): +class MimeTypesModuleTestCase(unittest.TestCase): def setUp(self): - self.db = mimetypes.MimeTypes() - - def test_case_sensitivity(self): - eq = self.assertEqual - eq(self.db.guess_file_type("foobar.html"), ("text/html", None)) - eq(self.db.guess_type("scheme:foobar.html"), ("text/html", None)) - eq(self.db.guess_file_type("foobar.HTML"), ("text/html", None)) - eq(self.db.guess_type("scheme:foobar.HTML"), ("text/html", None)) - eq(self.db.guess_file_type("foobar.tgz"), ("application/x-tar", "gzip")) - eq(self.db.guess_type("scheme:foobar.tgz"), ("application/x-tar", "gzip")) - eq(self.db.guess_file_type("foobar.TGZ"), ("application/x-tar", "gzip")) - eq(self.db.guess_type("scheme:foobar.TGZ"), ("application/x-tar", "gzip")) - eq(self.db.guess_file_type("foobar.tar.Z"), ("application/x-tar", "compress")) - eq(self.db.guess_type("scheme:foobar.tar.Z"), ("application/x-tar", "compress")) - eq(self.db.guess_file_type("foobar.tar.z"), (None, None)) - eq(self.db.guess_type("scheme:foobar.tar.z"), (None, None)) - - def test_default_data(self): - eq = self.assertEqual - eq(self.db.guess_file_type("foo.html"), ("text/html", None)) - eq(self.db.guess_file_type("foo.HTML"), ("text/html", None)) - eq(self.db.guess_file_type("foo.tgz"), ("application/x-tar", "gzip")) - eq(self.db.guess_file_type("foo.tar.gz"), ("application/x-tar", "gzip")) - eq(self.db.guess_file_type("foo.tar.Z"), ("application/x-tar", "compress")) - eq(self.db.guess_file_type("foo.tar.bz2"), ("application/x-tar", "bzip2")) - eq(self.db.guess_file_type("foo.tar.xz"), ("application/x-tar", "xz")) - - def test_data_urls(self): - eq = self.assertEqual - guess_type = self.db.guess_type - eq(guess_type("data:invalidDataWithoutComma"), (None, None)) - eq(guess_type("data:,thisIsTextPlain"), ("text/plain", None)) - eq(guess_type("data:;base64,thisIsTextPlain"), ("text/plain", None)) - eq(guess_type("data:text/x-foo,thisIsTextXFoo"), ("text/x-foo", None)) - - def test_file_parsing(self): - eq = self.assertEqual - sio = io.StringIO("x-application/x-unittest pyunit\n") - self.db.readfp(sio) - eq(self.db.guess_file_type("foo.pyunit"), - ("x-application/x-unittest", None)) - eq(self.db.guess_extension("x-application/x-unittest"), ".pyunit") + mimetypes.inited = False + mimetypes._default_mime_types() + mimetypes._db = None def test_read_mime_types(self): eq = self.assertEqual @@ -109,100 +70,6 @@ def test_read_mime_types(self): mock_open.assert_called_with(filename, encoding='utf-8') eq(mime_dict[".Français"], "application/no-mans-land") - def test_non_standard_types(self): - eq = self.assertEqual - # First try strict - eq(self.db.guess_file_type('foo.xul', strict=True), (None, None)) - # And then non-strict - eq(self.db.guess_file_type('foo.xul', strict=False), ('text/xul', None)) - eq(self.db.guess_file_type('foo.XUL', strict=False), ('text/xul', None)) - eq(self.db.guess_file_type('foo.invalid', strict=False), (None, None)) - eq(self.db.guess_extension('image/jpeg', strict=False), '.jpg') - eq(self.db.guess_extension('image/JPEG', strict=False), '.jpg') - - def test_filename_with_url_delimiters(self): - # bpo-38449: URL delimiters cases should be handled also. - # They would have different mime types if interpreted as URL as - # compared to when interpreted as filename because of the semicolon. - eq = self.assertEqual - gzip_expected = ('application/x-tar', 'gzip') - for name in ( - ';1.tar.gz', - '?1.tar.gz', - '#1.tar.gz', - '#1#.tar.gz', - ';1#.tar.gz', - ';&1=123;?.tar.gz', - '?k1=v1&k2=v2.tar.gz', - ): - for prefix in ('', '/', '\\', - 'c:', 'c:/', 'c:\\', 'c:/d/', 'c:\\d\\', - '//share/server/', '\\\\share\\server\\'): - path = prefix + name - with self.subTest(path=path): - eq(self.db.guess_file_type(path), gzip_expected) - eq(self.db.guess_type(path), gzip_expected) - expected = (None, None) if os.name == 'nt' else gzip_expected - for prefix in ('//', '\\\\', '//share/', '\\\\share\\'): - path = prefix + name - with self.subTest(path=path): - eq(self.db.guess_file_type(path), expected) - eq(self.db.guess_type(path), expected) - eq(self.db.guess_file_type(r" \"\`;b&b&c |.tar.gz"), gzip_expected) - eq(self.db.guess_type(r" \"\`;b&b&c |.tar.gz"), gzip_expected) - - eq(self.db.guess_file_type(r'foo/.tar.gz'), (None, 'gzip')) - eq(self.db.guess_type(r'foo/.tar.gz'), (None, 'gzip')) - expected = (None, 'gzip') if os.name == 'nt' else gzip_expected - eq(self.db.guess_file_type(r'foo\.tar.gz'), expected) - eq(self.db.guess_type(r'foo\.tar.gz'), expected) - eq(self.db.guess_type(r'scheme:foo\.tar.gz'), gzip_expected) - - def test_url(self): - result = self.db.guess_type('http://example.com/host.html') - result = self.db.guess_type('http://host.html') - msg = 'URL only has a host name, not a file' - self.assertSequenceEqual(result, (None, None), msg) - result = self.db.guess_type('http://example.com/host.html') - msg = 'Should be text/html' - self.assertSequenceEqual(result, ('text/html', None), msg) - result = self.db.guess_type('http://example.com/host.html#x.tar') - self.assertSequenceEqual(result, ('text/html', None)) - result = self.db.guess_type('http://example.com/host.html?q=x.tar') - self.assertSequenceEqual(result, ('text/html', None)) - - def test_guess_all_types(self): - # First try strict. Use a set here for testing the results because if - # test_urllib2 is run before test_mimetypes, global state is modified - # such that the 'all' set will have more items in it. - all = self.db.guess_all_extensions('text/plain', strict=True) - self.assertTrue(set(all) >= {'.bat', '.c', '.h', '.ksh', '.pl', '.txt'}) - self.assertEqual(len(set(all)), len(all)) # no duplicates - # And now non-strict - all = self.db.guess_all_extensions('image/jpeg', strict=False) - self.assertEqual(all, ['.jpg', '.jpe', '.jpeg']) - # And now for no hits - all = self.db.guess_all_extensions('image/jpg', strict=True) - self.assertEqual(all, []) - # And now for type existing in both strict and non-strict mappings. - self.db.add_type('test-type', '.strict-ext') - self.db.add_type('test-type', '.non-strict-ext', strict=False) - all = self.db.guess_all_extensions('test-type', strict=False) - self.assertEqual(all, ['.strict-ext', '.non-strict-ext']) - all = self.db.guess_all_extensions('test-type') - self.assertEqual(all, ['.strict-ext']) - # Test that changing the result list does not affect the global state - all.append('.no-such-ext') - all = self.db.guess_all_extensions('test-type') - self.assertNotIn('.no-such-ext', all) - - def test_encoding(self): - filename = support.findfile("mime.types") - mimes = mimetypes.MimeTypes([filename]) - exts = mimes.guess_all_extensions('application/vnd.geocube+xml', - strict=True) - self.assertEqual(exts, ['.g3', '.g\xb3']) - def test_init_reinitializes(self): # Issue 4936: make sure an init starts clean # First, put some poison into the types table @@ -341,6 +208,202 @@ def test_init_stability(self): self.assertEqual(types_map, mimetypes.types_map) self.assertEqual(common_types, mimetypes.common_types) + def test_init_files(self): + guess_file_type = mimetypes.guess_file_type + self.assertEqual(guess_file_type("file.test2")[0], None) + + filename = support.findfile("mime.types2") + mimetypes.init([filename]) + self.assertEqual(guess_file_type("file.test2")[0], "testing/test2") + + mimetypes.init() + self.assertEqual(guess_file_type("file.test2")[0], None) + + def test_init_knownfiles(self): + guess_file_type = mimetypes.guess_file_type + self.assertEqual(guess_file_type("file.test2")[0], None) + + filename = support.findfile("mime.types2") + mimetypes.knownfiles = [filename, "non-existent"] + self.addCleanup(mimetypes.knownfiles.clear) + + mimetypes.init() + self.assertEqual(guess_file_type("file.test2")[0], "testing/test2") + + def test_added_types_are_used(self): + mimetypes.add_type('testing/default-type', '') + mime_type, _ = mimetypes.guess_type('') + self.assertEqual(mime_type, 'testing/default-type') + + mime_type, _ = mimetypes.guess_type('test.myext') + self.assertEqual(mime_type, None) + + mimetypes.add_type('testing/type', '.myext') + mime_type, _ = mimetypes.guess_type('test.myext') + self.assertEqual(mime_type, 'testing/type') + + def test_add_type_with_undotted_extension_deprecated(self): + with self.assertWarns(DeprecationWarning): + mimetypes.add_type("testing/type", "undotted") + + +class MimeTypesClassTestCase(unittest.TestCase): + def setUp(self): + self.db = mimetypes.MimeTypes() + + def test_init_files(self): + guess_file_type = self.db.guess_file_type + self.assertEqual(guess_file_type("file.test2")[0], None) + + filename = support.findfile("mime.types2") + db = mimetypes.MimeTypes([filename]) + guess_file_type = db.guess_file_type + self.assertEqual(guess_file_type("file.test2")[0], "testing/test2") + + def test_init_knownfiles(self): + filename = support.findfile("mime.types2") + mimetypes.knownfiles = [filename, "non-existent"] + self.addCleanup(mimetypes.knownfiles.clear) + + db = mimetypes.MimeTypes() + guess_file_type = db.guess_file_type + self.assertEqual(guess_file_type("file.test2")[0], None) + + def test_case_sensitivity(self): + eq = self.assertEqual + eq(self.db.guess_file_type("foobar.html"), ("text/html", None)) + eq(self.db.guess_type("scheme:foobar.html"), ("text/html", None)) + eq(self.db.guess_file_type("foobar.HTML"), ("text/html", None)) + eq(self.db.guess_type("scheme:foobar.HTML"), ("text/html", None)) + eq(self.db.guess_file_type("foobar.tgz"), ("application/x-tar", "gzip")) + eq(self.db.guess_type("scheme:foobar.tgz"), ("application/x-tar", "gzip")) + eq(self.db.guess_file_type("foobar.TGZ"), ("application/x-tar", "gzip")) + eq(self.db.guess_type("scheme:foobar.TGZ"), ("application/x-tar", "gzip")) + eq(self.db.guess_file_type("foobar.tar.Z"), ("application/x-tar", "compress")) + eq(self.db.guess_type("scheme:foobar.tar.Z"), ("application/x-tar", "compress")) + eq(self.db.guess_file_type("foobar.tar.z"), (None, None)) + eq(self.db.guess_type("scheme:foobar.tar.z"), (None, None)) + + def test_default_data(self): + eq = self.assertEqual + eq(self.db.guess_file_type("foo.html"), ("text/html", None)) + eq(self.db.guess_file_type("foo.HTML"), ("text/html", None)) + eq(self.db.guess_file_type("foo.tgz"), ("application/x-tar", "gzip")) + eq(self.db.guess_file_type("foo.tar.gz"), ("application/x-tar", "gzip")) + eq(self.db.guess_file_type("foo.tar.Z"), ("application/x-tar", "compress")) + eq(self.db.guess_file_type("foo.tar.bz2"), ("application/x-tar", "bzip2")) + eq(self.db.guess_file_type("foo.tar.xz"), ("application/x-tar", "xz")) + + def test_data_urls(self): + eq = self.assertEqual + guess_type = self.db.guess_type + eq(guess_type("data:invalidDataWithoutComma"), (None, None)) + eq(guess_type("data:,thisIsTextPlain"), ("text/plain", None)) + eq(guess_type("data:;base64,thisIsTextPlain"), ("text/plain", None)) + eq(guess_type("data:text/x-foo,thisIsTextXFoo"), ("text/x-foo", None)) + + def test_file_parsing(self): + eq = self.assertEqual + sio = io.StringIO("x-application/x-unittest pyunit\n") + self.db.readfp(sio) + eq(self.db.guess_file_type("foo.pyunit"), + ("x-application/x-unittest", None)) + eq(self.db.guess_extension("x-application/x-unittest"), ".pyunit") + + def test_non_standard_types(self): + eq = self.assertEqual + # First try strict + eq(self.db.guess_file_type('foo.xul', strict=True), (None, None)) + # And then non-strict + eq(self.db.guess_file_type('foo.xul', strict=False), ('text/xul', None)) + eq(self.db.guess_file_type('foo.XUL', strict=False), ('text/xul', None)) + eq(self.db.guess_file_type('foo.invalid', strict=False), (None, None)) + eq(self.db.guess_extension('image/jpeg', strict=False), '.jpg') + eq(self.db.guess_extension('image/JPEG', strict=False), '.jpg') + + def test_filename_with_url_delimiters(self): + # bpo-38449: URL delimiters cases should be handled also. + # They would have different mime types if interpreted as URL as + # compared to when interpreted as filename because of the semicolon. + eq = self.assertEqual + gzip_expected = ('application/x-tar', 'gzip') + for name in ( + ';1.tar.gz', + '?1.tar.gz', + '#1.tar.gz', + '#1#.tar.gz', + ';1#.tar.gz', + ';&1=123;?.tar.gz', + '?k1=v1&k2=v2.tar.gz', + ): + for prefix in ('', '/', '\\', + 'c:', 'c:/', 'c:\\', 'c:/d/', 'c:\\d\\', + '//share/server/', '\\\\share\\server\\'): + path = prefix + name + with self.subTest(path=path): + eq(self.db.guess_file_type(path), gzip_expected) + eq(self.db.guess_type(path), gzip_expected) + expected = (None, None) if os.name == 'nt' else gzip_expected + for prefix in ('//', '\\\\', '//share/', '\\\\share\\'): + path = prefix + name + with self.subTest(path=path): + eq(self.db.guess_file_type(path), expected) + eq(self.db.guess_type(path), expected) + eq(self.db.guess_file_type(r" \"\`;b&b&c |.tar.gz"), gzip_expected) + eq(self.db.guess_type(r" \"\`;b&b&c |.tar.gz"), gzip_expected) + + eq(self.db.guess_file_type(r'foo/.tar.gz'), (None, 'gzip')) + eq(self.db.guess_type(r'foo/.tar.gz'), (None, 'gzip')) + expected = (None, 'gzip') if os.name == 'nt' else gzip_expected + eq(self.db.guess_file_type(r'foo\.tar.gz'), expected) + eq(self.db.guess_type(r'foo\.tar.gz'), expected) + eq(self.db.guess_type(r'scheme:foo\.tar.gz'), gzip_expected) + + def test_url(self): + result = self.db.guess_type('http://example.com/host.html') + result = self.db.guess_type('http://host.html') + msg = 'URL only has a host name, not a file' + self.assertSequenceEqual(result, (None, None), msg) + result = self.db.guess_type('http://example.com/host.html') + msg = 'Should be text/html' + self.assertSequenceEqual(result, ('text/html', None), msg) + result = self.db.guess_type('http://example.com/host.html#x.tar') + self.assertSequenceEqual(result, ('text/html', None)) + result = self.db.guess_type('http://example.com/host.html?q=x.tar') + self.assertSequenceEqual(result, ('text/html', None)) + + def test_guess_all_types(self): + # First try strict. Use a set here for testing the results because if + # test_urllib2 is run before test_mimetypes, global state is modified + # such that the 'all' set will have more items in it. + all = self.db.guess_all_extensions('text/plain', strict=True) + self.assertTrue(set(all) >= {'.bat', '.c', '.h', '.ksh', '.pl', '.txt'}) + self.assertEqual(len(set(all)), len(all)) # no duplicates + # And now non-strict + all = self.db.guess_all_extensions('image/jpeg', strict=False) + self.assertEqual(all, ['.jpg', '.jpe', '.jpeg']) + # And now for no hits + all = self.db.guess_all_extensions('image/jpg', strict=True) + self.assertEqual(all, []) + # And now for type existing in both strict and non-strict mappings. + self.db.add_type('test-type', '.strict-ext') + self.db.add_type('test-type', '.non-strict-ext', strict=False) + all = self.db.guess_all_extensions('test-type', strict=False) + self.assertEqual(all, ['.strict-ext', '.non-strict-ext']) + all = self.db.guess_all_extensions('test-type') + self.assertEqual(all, ['.strict-ext']) + # Test that changing the result list does not affect the global state + all.append('.no-such-ext') + all = self.db.guess_all_extensions('test-type') + self.assertNotIn('.no-such-ext', all) + + def test_encoding(self): + filename = support.findfile("mime.types") + mimes = mimetypes.MimeTypes([filename]) + exts = mimes.guess_all_extensions('application/vnd.geocube+xml', + strict=True) + self.assertEqual(exts, ['.g3', '.g\xb3']) + def test_path_like_ob(self): filename = "LICENSE.txt" filepath = os_helper.FakePath(filename) @@ -378,22 +441,6 @@ def test_keywords_args_api(self): self.assertEqual(self.db.guess_all_extensions( type='image/jpeg', strict=True), ['.jpg', '.jpe', '.jpeg']) - def test_added_types_are_used(self): - mimetypes.add_type('testing/default-type', '') - mime_type, _ = mimetypes.guess_type('') - self.assertEqual(mime_type, 'testing/default-type') - - mime_type, _ = mimetypes.guess_type('test.myext') - self.assertEqual(mime_type, None) - - mimetypes.add_type('testing/type', '.myext') - mime_type, _ = mimetypes.guess_type('test.myext') - self.assertEqual(mime_type, 'testing/type') - - def test_add_type_with_undotted_extension_deprecated(self): - with self.assertWarns(DeprecationWarning): - mimetypes.add_type("testing/type", "undotted") - @unittest.skipUnless(sys.platform.startswith("win"), "Windows only") class Win32MimeTypesTestCase(unittest.TestCase): From 5125584767c48e32aef07c4d8f9a29a85e1a03b3 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 15 Jul 2026 12:42:48 +0200 Subject: [PATCH 683/818] [3.15] gh-150858: fix data race while changing `__qualname__` of a type object(GH-150859) (#153747) gh-150858: fix data race while changing `__qualname__` of a type object(GH-150859) (cherry picked from commit 1ec6596828b0db4317d85afa85e1f68a3551a07e) Co-authored-by: Thomas Kowalski <thom.kowa@gmail.com> --- .../2026-06-03-16-27-00.gh-issue-150858.j2dSkD.rst | 1 + Objects/typeobject.c | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-03-16-27-00.gh-issue-150858.j2dSkD.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-03-16-27-00.gh-issue-150858.j2dSkD.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-03-16-27-00.gh-issue-150858.j2dSkD.rst new file mode 100644 index 00000000000000..dcb932bf320629 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-03-16-27-00.gh-issue-150858.j2dSkD.rst @@ -0,0 +1 @@ +Fix a data race while changing ``__qualname__`` of a type concurrently on free-threaded builds. diff --git a/Objects/typeobject.c b/Objects/typeobject.c index f763f9f5eba58f..8108e8e92731da 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -1594,7 +1594,12 @@ type_set_qualname(PyObject *tp, PyObject *value, void *context) } et = (PyHeapTypeObject*)type; - Py_SETREF(et->ht_qualname, Py_NewRef(value)); + PyInterpreterState *interp = _PyInterpreterState_GET(); + _PyEval_StopTheWorld(interp); + PyObject *old_qualname = et->ht_qualname; + et->ht_qualname = Py_NewRef(value); + _PyEval_StartTheWorld(interp); + Py_DECREF(old_qualname); return 0; } From 25eb043ebae331199e5cc6bc6b32583dca82994a Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 15 Jul 2026 12:44:37 +0200 Subject: [PATCH 684/818] [3.15] gh-144774: Add critical section in `BaseException.__setstate__` (GH-150578) (#153746) gh-144774: Add critical section in `BaseException.__setstate__` (GH-150578) (cherry picked from commit f586fd9e304e6747fdebe2477355beb059724571) Co-authored-by: Brij Kapadia <97006829+brijkapadia@users.noreply.github.com> --- Lib/test/test_free_threading/test_exceptions.py | 16 ++++++++++++++++ ...026-05-29-17-51-11.gh-issue-144774.jPcixe.rst | 1 + Objects/clinic/exceptions.c.h | 4 ++-- Objects/exceptions.c | 4 ++-- 4 files changed, 21 insertions(+), 4 deletions(-) create mode 100644 Lib/test/test_free_threading/test_exceptions.py create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-05-29-17-51-11.gh-issue-144774.jPcixe.rst diff --git a/Lib/test/test_free_threading/test_exceptions.py b/Lib/test/test_free_threading/test_exceptions.py new file mode 100644 index 00000000000000..61146f29c7868e --- /dev/null +++ b/Lib/test/test_free_threading/test_exceptions.py @@ -0,0 +1,16 @@ +import unittest +import copy + +from test.support import threading_helper + +threading_helper.requires_working_threading(module=True) +class ExceptionTests(unittest.TestCase): + def test_setstate_data_race(self): + E = Exception() + + def func(): + for i in range(100): + setattr(E, 'x', i) + copy.copy(E) + + threading_helper.run_concurrently(func, nthreads=4) diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-29-17-51-11.gh-issue-144774.jPcixe.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-29-17-51-11.gh-issue-144774.jPcixe.rst new file mode 100644 index 00000000000000..3dd117e7d3c350 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-29-17-51-11.gh-issue-144774.jPcixe.rst @@ -0,0 +1 @@ +Fix data race in :class:`BaseException` when an exception is copied while being mutated. diff --git a/Objects/clinic/exceptions.c.h b/Objects/clinic/exceptions.c.h index 9baac8b1cc660b..5047a673e579c6 100644 --- a/Objects/clinic/exceptions.c.h +++ b/Objects/clinic/exceptions.c.h @@ -44,7 +44,7 @@ BaseException___setstate__(PyObject *self, PyObject *state) { PyObject *return_value = NULL; - Py_BEGIN_CRITICAL_SECTION(self); + Py_BEGIN_CRITICAL_SECTION(state); return_value = BaseException___setstate___impl((PyBaseExceptionObject *)self, state); Py_END_CRITICAL_SECTION(); @@ -380,4 +380,4 @@ BaseExceptionGroup_subgroup(PyObject *self, PyObject *matcher_value) return return_value; } -/*[clinic end generated code: output=fcf70b3b71f3d14a input=a9049054013a1b77]*/ +/*[clinic end generated code: output=e63b88d0443b4f92 input=a9049054013a1b77]*/ diff --git a/Objects/exceptions.c b/Objects/exceptions.c index 7b97d9e99431c3..149595e64cec14 100644 --- a/Objects/exceptions.c +++ b/Objects/exceptions.c @@ -225,7 +225,7 @@ BaseException___reduce___impl(PyBaseExceptionObject *self) */ /*[clinic input] -@critical_section +@critical_section state BaseException.__setstate__ state: object / @@ -233,7 +233,7 @@ BaseException.__setstate__ static PyObject * BaseException___setstate___impl(PyBaseExceptionObject *self, PyObject *state) -/*[clinic end generated code: output=f3834889950453ab input=5524b61cfe9b9856]*/ +/*[clinic end generated code: output=f3834889950453ab input=f9b1aea70382cdb6]*/ { PyObject *d_key, *d_value; Py_ssize_t i = 0; From 04baaae20ce5f8ae7bfdaee294e0871b377474b1 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 15 Jul 2026 18:27:37 +0200 Subject: [PATCH 685/818] [3.15] gh-153550: Modernize the older prose sections of the tkinter documentation (GH-153647) (GH-153773) Refresh the narrative "Tkinter life preserver" and "Handy reference" sections to match the overhauled reference (gh-86726 and gh-153549). * Rework "The packer" into a general "Geometry management" section covering grid, pack and place, and cross-link it with the Grid, Pack and Place reference classes. * Rework "The window manager" and "Coupling widget variables", replacing the dated App(Frame) examples with direct Tk() and ttk examples. * Replace page-number citations to Ousterhout's book with links to the relevant Tk man pages. * Modernize the tkinter.ttk front matter and its Tcl/Tk links, and add cross-references between the two documents. * Reconcile the "Packer options" and "Tk option data types" lists with the reference, and fill in the empty Entry index list. * Fix the malformed target-selection list in tkinter.dnd. (cherry picked from commit 93beea7e5a3c5a03253e6812a06f2497505aeb30) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --- Doc/library/tkinter.dnd.rst | 19 ++- Doc/library/tkinter.rst | 318 +++++++++++++++++++++--------------- Doc/library/tkinter.ttk.rst | 45 +++-- 3 files changed, 225 insertions(+), 157 deletions(-) diff --git a/Doc/library/tkinter.dnd.rst b/Doc/library/tkinter.dnd.rst index ba267c0e3840fe..adb9d839505b21 100644 --- a/Doc/library/tkinter.dnd.rst +++ b/Doc/library/tkinter.dnd.rst @@ -16,21 +16,22 @@ a single application, within the same window or between windows. To enable an object to be dragged, you must create an event binding for it that starts the drag-and-drop process. Typically, you bind a ButtonPress event to a callback function that you write (see :ref:`Bindings-and-Events`). The function should -call :func:`dnd_start`, where 'source' is the object to be dragged, and 'event' +call :func:`dnd_start`, where *source* is the object to be dragged, and *event* is the event that invoked the call (the argument to your callback function). Selection of a target object occurs as follows: -#. Top-down search of area under mouse for target widget +#. Top-down search of the area under the mouse for a target widget: - * Target widget should have a callable *dnd_accept* attribute - * If *dnd_accept* is not present or returns ``None``, search moves to parent widget - * If no target widget is found, then the target object is ``None`` + * the target widget should have a callable *dnd_accept* attribute; + * if *dnd_accept* is not present or returns ``None``, + the search moves to the parent widget; + * if no target widget is found, the target object is ``None``. -2. Call to *<old_target>.dnd_leave(source, event)* -#. Call to *<new_target>.dnd_enter(source, event)* -#. Call to *<target>.dnd_commit(source, event)* to notify of drop -#. Call to *<source>.dnd_end(target, event)* to signal end of drag-and-drop +#. Call to ``<old_target>.dnd_leave(source, event)``. +#. Call to ``<new_target>.dnd_enter(source, event)``. +#. Call to ``<target>.dnd_commit(source, event)`` to notify of the drop. +#. Call to ``<source>.dnd_end(target, event)`` to signal the end of drag-and-drop. .. class:: DndHandler(source, event) diff --git a/Doc/library/tkinter.rst b/Doc/library/tkinter.rst index ce68f0389b9c30..489218dfb4d44d 100644 --- a/Doc/library/tkinter.rst +++ b/Doc/library/tkinter.rst @@ -35,7 +35,8 @@ details that are unchanged. .. note:: Tcl/Tk 8.5 (2007) introduced a modern set of themed user interface components - along with a new API to use them. Both old and new APIs are still available. + along with a new API to use them (see :mod:`tkinter.ttk`). + Both old and new APIs are still available. Most documentation you will find online still uses the old API and can be woefully outdated. @@ -519,6 +520,17 @@ Use the config() method to update multiple attrs subsequent to object creation fred.config(fg="red", bg="blue") +.. note:: + + The ``fg`` and ``bg`` options used here, + and other options that control a widget's appearance, + belong to the classic :mod:`!tkinter` widgets. + The themed :mod:`tkinter.ttk` widgets recommended in the introduction + do not accept them; + style a themed widget through the :class:`ttk.Style <tkinter.ttk.Style>` + class instead. + The three ways of setting an option shown above apply to both widget sets. + For a complete explanation of a given option and its behavior, see the Tk man pages for the widget in question. @@ -567,65 +579,84 @@ their values. This is meant only as an example. .. _pack-the-packer: +.. _tkinter-geometry-management: +.. _the-packer: +.. _packer-options: -The packer -^^^^^^^^^^ - -.. index:: single: packing (widgets) - -The packer is one of Tk's geometry-management mechanisms. Geometry managers -are used to specify the relative positioning of widgets within their container. -In contrast to the more cumbersome *placer* (which is -used less commonly, and we do not cover here), the packer takes qualitative -relationship specification - *above*, *to the left of*, *filling*, etc - and -works everything out to determine the exact placement coordinates for you. +Geometry management +^^^^^^^^^^^^^^^^^^^ -The size of any container widget is determined by the size of the "content widgets" -inside. The packer is used to control where content widgets appear inside the -container into which they are packed. You can pack widgets into frames, and frames -into other frames, in order to achieve the kind of layout you desire. -Additionally, the arrangement is dynamically adjusted to accommodate incremental -changes to the configuration, once it is packed. +.. index:: + single: geometry management (widgets) + single: packing (widgets) + +Creating a widget does not display it. +A widget appears only after it has been handed to a *geometry manager*, +which works out its size and position inside its container +and keeps the layout up to date as the container is resized or its content changes. +Forgetting to call a geometry manager is a common early mistake: +the widget is created, but nothing shows up. + +Tk provides three geometry managers. +Each is inherited by every widget, so any widget can be managed by any of them +(but see the warning below about the incompatibility of grid and pack). +The choice depends on the kind of layout you want. + +:meth:`grid <Grid.grid_configure>` + Arranges widgets in a two-dimensional table of rows and columns. + It is the most flexible manager and the one to reach for by default: + layouts that would otherwise need several nested frames can often be + expressed as a single grid, + and rows and columns can be told how to absorb extra space. -Note that widgets do not appear until they have had their geometry specified -with a geometry manager. -It's a common early mistake to leave out the geometry specification, and then -be surprised when the widget is created but nothing appears. -A widget will appear only after it has had, for example, the packer's -:meth:`~Pack.pack` method applied to it. + :: -The pack() method can be called with keyword-option/value pairs that control -where the widget is to appear within its container, and how it is to behave when -the main application window is resized. Here are some examples:: + ttk.Label(frm, text="Name:").grid(column=0, row=0, sticky="w") + ttk.Entry(frm).grid(column=1, row=0) + ttk.Button(frm, text="OK").grid(column=1, row=1, sticky="e") - fred.pack() # defaults to side = "top" - fred.pack(side="left") - fred.pack(expand=1) +:meth:`pack <Pack.pack_configure>` + Stacks widgets against one side of their container + -- ``"top"`` (the default), ``"bottom"``, ``"left"`` or ``"right"`` -- + and can make them fill or expand into the space that is left. + It is convenient for simple arrangements, + such as a single row or column of widgets + or a content area framed by a toolbar and a status bar. + :: -Packer options -^^^^^^^^^^^^^^ + toolbar.pack(side="top", fill="x") + status.pack(side="bottom", fill="x") + body.pack(side="left", expand=True, fill="both") -For more extensive information on the packer and the options that it can take, -see the man pages and page 183 of John Ousterhout's book. +:meth:`place <Place.place_configure>` + Positions each widget at an explicit spot, + given either as absolute screen distances or as a fraction of the container's size. + It offers the most control but the least automatic behavior, and is used the least; + it suits special cases such as overlapping widgets or precise custom layouts. -anchor - Anchor type. Denotes where the packer is to place each content in its parcel. + :: -expand - boolean, ``0`` or ``1``. + background.place(x=0, y=0, relwidth=1.0, relheight=1.0) + badge.place(relx=1.0, rely=0.0, anchor="ne") -fill - Legal values: ``'x'``, ``'y'``, ``'both'``, ``'none'``. +Layouts are built up by nesting: +grid or pack widgets, including frames, inside a frame or toplevel. +Toplevels are managed by the OS window manager. +Classic and themed :mod:`tkinter.ttk` widgets can be managed interchangeably. -ipadx and ipady - A distance - designating internal padding on each side of the content. +.. warning:: -padx and pady - A distance - designating external padding on each side of the content. + Do not apply :meth:`!pack` and :meth:`!grid` to two widgets that share the same container. + The two managers negotiate sizes in incompatible ways, + and the application can hang as they repeatedly resize the container against each other. + To combine them, keep each manager's widgets in a separate frame. -side - Legal values are: ``'left'``, ``'right'``, ``'top'``, ``'bottom'``. +The full set of options accepted by each manager, with their values and defaults, +is documented under :meth:`Grid.grid_configure`, :meth:`Pack.pack_configure` +and :meth:`Place.place_configure`; +see also the :manpage:`grid(3tk)`, :manpage:`pack(3tk)` and :manpage:`place(3tk)` +man pages. .. _coupling-widget-variables: @@ -633,105 +664,98 @@ side Coupling widget variables ^^^^^^^^^^^^^^^^^^^^^^^^^ -The current-value setting of some widgets (like text entry widgets) can be -connected directly to application variables by using special options. These -options are ``variable``, ``textvariable``, ``onvalue``, ``offvalue``, and -``value``. This connection works both ways: if the variable changes for any -reason, the widget it's connected to will be updated to reflect the new value. - -Unfortunately, in the current implementation of :mod:`!tkinter` it is not -possible to hand over an arbitrary Python variable to a widget through a -``variable`` or ``textvariable`` option. The only kinds of variables for which -this works are variables that are subclassed from a class called Variable, -defined in :mod:`!tkinter`. - -There are many useful subclasses of Variable already defined: -:class:`StringVar`, :class:`IntVar`, :class:`DoubleVar`, and -:class:`BooleanVar`. -To read the current value of such a variable, call the :meth:`~Variable.get` -method on it, and to change its value you call the :meth:`!set` method. -If you follow this protocol, the widget will always track the value of the -variable, with no further intervention on your part. - -Keep a reference to the variable for as long as a widget uses it, for example -by storing it as an attribute (see :class:`Variable`). +Some widgets can tie their current value directly to a program variable, +so that the two stay in sync. +Options such as ``variable``, ``textvariable``, ``value``, ``onvalue`` and +``offvalue`` set up this connection: +when the user changes the widget the variable is updated, +and when the variable is set the widget redraws to match. + +A widget can be linked only to a :class:`Variable` object, +not to an ordinary Python variable. +This is not a limitation of :mod:`!tkinter` +but a consequence of how the two languages differ: +the link relies on Tcl being notified every time the value changes, +and Python offers no way to react when a plain variable is reassigned. +A :class:`Variable` sidesteps this by keeping its value inside the Tcl interpreter +and exposing it through explicit :meth:`~Variable.get` and :meth:`~Variable.set` methods. + +Ready-made subclasses cover the common types: +:class:`StringVar`, :class:`IntVar`, :class:`DoubleVar` and :class:`BooleanVar`. +Pass one as a widget's ``textvariable`` (or ``variable``) option, +then read and update it with :meth:`~Variable.get` and :meth:`~Variable.set`; +the widget tracks it with no further work on your part. + +Keep a reference to the variable for as long as the widget uses it +-- for example by storing it as an attribute. +A :class:`Variable` that is garbage collected removes its underlying Tcl variable, +breaking the connection to the widget (see :class:`Variable`). For example:: import tkinter as tk + from tkinter import ttk - class App(tk.Frame): - def __init__(self, master): - super().__init__(master) - self.pack() + root = tk.Tk() - self.entrythingy = tk.Entry() - self.entrythingy.pack() + # Create the application variable and give it an initial value. + contents = tk.StringVar(value="this is a variable") - # Create the application variable. - self.contents = tk.StringVar() - # Set it to some value. - self.contents.set("this is a variable") - # Tell the entry widget to watch this variable. - self.entrythingy["textvariable"] = self.contents + # Tell the entry widget to track the variable. + entry = ttk.Entry(root, textvariable=contents) + entry.pack() - # Define a callback for when the user hits return. - # It prints the current value of the variable. - self.entrythingy.bind('<Key-Return>', - self.print_contents) + # Print the current value whenever the user presses Return. + def print_contents(event): + print("The current entry content is:", contents.get()) - def print_contents(self, event): - print("Hi. The current entry content is:", - self.contents.get()) + entry.bind("<Return>", print_contents) - root = tk.Tk() - myapp = App(root) - myapp.mainloop() + # Setting the variable from the program updates the entry through the + # same link. + def clear(): + contents.set("") + + ttk.Button(root, text="Clear", command=clear).pack() + + root.mainloop() + +.. _tkinter-window-manager: The window manager ^^^^^^^^^^^^^^^^^^ .. index:: single: window manager (widgets) -In Tk, there is a utility command, ``wm``, for interacting with the window -manager. Options to the ``wm`` command allow you to control things like titles, -placement, icon bitmaps, and the like. In :mod:`!tkinter`, these commands have -been implemented as methods on the :class:`Wm` class. Toplevel widgets are -subclassed from the :class:`Wm` class, and so can call the :class:`Wm` methods -directly. - -To get at the toplevel window that contains a given widget, you can often just -refer to the widget's :attr:`~Tk.master`. -Of course if the widget has been packed inside of a frame, the :attr:`!master` -won't represent a toplevel window. -To get at the toplevel window that contains an arbitrary widget, you can call -the :meth:`~Misc.winfo_toplevel` method. -There is also a :meth:`!_root` method; it begins with an underscore to denote -the fact that this function is part of the implementation, and not an interface -to Tk functionality. -It returns the application's root window rather than the nearest enclosing -toplevel. - -Here are some examples of typical usage:: +The *window manager* is the part of the desktop responsible for the title bar, +border and controls drawn around each top-level window, +and for such things as its title, position, size and icon. +Tk gives access to these through the :class:`Wm` mixin, +which is inherited by the :class:`Tk` root window and by every :class:`Toplevel`. +You therefore call the window-manager methods directly on a top-level window. +Each has a short name and an equivalent ``wm_``-prefixed name, +for example :meth:`~Wm.title` and :meth:`~Wm.wm_title`. + +These methods act on the top-level window +whether its content is built from the classic widgets or the themed :mod:`tkinter.ttk` widgets. +To reach the top-level window containing an arbitrary widget, +call its :meth:`~Misc.winfo_toplevel` method. + +For example:: import tkinter as tk + from tkinter import ttk - class App(tk.Frame): - def __init__(self, master=None): - super().__init__(master) - self.pack() + root = tk.Tk() + root.title("My Application") + root.geometry("640x480") + root.minsize(320, 240) - # create the application - myapp = App() + ttk.Label(root, text="Hello").pack(padx=20, pady=20) - # - # here are method calls to the window manager class - # - myapp.master.title("My Do-Nothing Application") - myapp.master.maxsize(1000, 400) + root.mainloop() - # start the program - myapp.mainloop() +See :class:`Wm` for the full set of window-manager methods. .. _Tk-option-data-types: @@ -741,6 +765,9 @@ Tk option data types .. index:: single: Tk Option Data Types +Many widget options documented in the reference +accept values of a small number of common types, described here. + anchor Legal values are points of the compass: ``"n"``, ``"ne"``, ``"e"``, ``"se"``, ``"s"``, ``"sw"``, ``"w"``, ``"nw"``, and also ``"center"``. @@ -766,7 +793,8 @@ color Colors can be given as the names of X colors in the rgb.txt file, or as strings representing RGB values in 4 bit: ``"#RGB"``, 8 bit: ``"#RRGGBB"``, 12 bit: ``"#RRRGGGBBB"``, or 16 bit: ``"#RRRRGGGGBBBB"`` ranges, where R,G,B here - represent any legal hex digit. See page 160 of Ousterhout's book for details. + represent any legal hex digit. See the :manpage:`colors(3tk)` man page for + the list of named colors. cursor The name of the mouse cursor to display while the pointer is over the widget. @@ -841,8 +869,7 @@ sequence ``<modifier-modifier-type-detail>`` form (for example ``"<Enter>"`` or ``"<Control-Button-1>"``); application-defined virtual events use double angle brackets, as in ``"<<Paste>>"``. (See the - :manpage:`bind(3tk)` man page, and page 201 of John Ousterhout's book, - :title-reference:`Tcl and the Tk Toolkit (2nd edition)`, for details). + :manpage:`bind(3tk)` man page for details.) func is a Python function, taking one argument, to be invoked when the event occurs. @@ -914,9 +941,32 @@ point at a specific place in a Text widget, or to particular characters in an Entry widget, or to particular menu items in a Menu widget. Entry widget indexes (index, view index, etc.) - Entry widgets have options that refer to character positions in the text being - displayed. You can use these :mod:`!tkinter` functions to access these special - points in text widgets: + Entry widgets have methods and options that refer to character positions + in the text being displayed. + Anytime an index is needed, you may pass in: + + * an integer which refers to the numeric position of a character, + counted from the beginning of the text, starting with 0; + + * the string ``"anchor"``, + which refers to the anchor point of the selection, + set with the widget's selection methods; + + * the string ``"end"``, + which refers to the position just after the last character; + + * the string ``"insert"``, + which refers to the character just after the insertion cursor; + + * the strings ``"sel.first"`` and ``"sel.last"``, + which refer to the first character in the selection + and the position just after the last + (it is an error to use these if there is no selection); + + * a string consisting of ``@`` followed by an integer, as in ``"@6"``, + where the integer is interpreted as an x pixel coordinate + in the entry's coordinate system, + selecting the character spanning that point. Text widget indexes The index notation for Text widgets is very rich and is best described in the Tk @@ -934,8 +984,9 @@ Menu indexes (menu.invoke(), menu.entryconfig(), etc.) * the string ``"last"`` which refers to the last menu item; - * An integer preceded by ``@``, as in ``@6``, where the integer is interpreted - as a y pixel coordinate in the menu's coordinate system; + * a string consisting of ``@`` followed by an integer, as in ``"@6"``, where + the integer is interpreted as a y pixel coordinate in the menu's coordinate + system; * the string ``"none"``, which indicates no menu entry at all, most often used with menu.activate() to deactivate all entries, and finally, @@ -2270,6 +2321,7 @@ Base and mixin classes available on every top-level window. Each method has two equivalent spellings: a short name and a ``wm_``-prefixed name (for example, :meth:`title` and :meth:`wm_title`). + See also :ref:`tkinter-window-manager`. .. method:: wm_aspect(minNumer=None, minDenom=None, maxNumer=None, maxDenom=None) :no-typesetting: @@ -2803,7 +2855,7 @@ Base and mixin classes The :class:`!Pack` mix-in is inherited by all widgets (through :class:`Widget`) and provides the methods for managing a widget with the *pack* geometry manager. - See also :ref:`pack-the-packer`. + See also :ref:`tkinter-geometry-management`. .. note:: @@ -2935,6 +2987,7 @@ Base and mixin classes their container. The :class:`!Place` mix-in is inherited by all widgets (through :class:`Widget`). + See also :ref:`tkinter-geometry-management`. .. method:: configure(cnf={}, **kw) :no-typesetting: @@ -3027,6 +3080,7 @@ Base and mixin classes columns within their container. The :class:`!Grid` mix-in is inherited by all widgets (through :class:`Widget`). + See also :ref:`tkinter-geometry-management`. .. method:: configure(cnf={}, **kw) :no-typesetting: diff --git a/Doc/library/tkinter.ttk.rst b/Doc/library/tkinter.ttk.rst index 77703eff26412e..e5c48ac62ef084 100644 --- a/Doc/library/tkinter.ttk.rst +++ b/Doc/library/tkinter.ttk.rst @@ -11,21 +11,28 @@ -------------- The :mod:`!tkinter.ttk` module provides access to the Tk themed widget set, -introduced in Tk 8.5. It provides additional benefits including anti-aliased font -rendering under X11 and window transparency (requiring a composition -window manager on X11). +introduced in Tk 8.5. +Its widgets adapt their appearance to the platform's native theme, +giving an application a better and more consistent look and feel +than the classic :mod:`tkinter` widgets, whose appearance is fixed. The basic idea for :mod:`!tkinter.ttk` is to separate, to the extent possible, the code implementing a widget's behavior from the code implementing its appearance. +Ttk widgets are used just like the classic :mod:`tkinter` widgets +and share the same machinery: +the widget hierarchy, the geometry managers, variable coupling and event binding. +Those foundational concepts are covered in the :mod:`tkinter` documentation +and are not repeated here. + .. versionadded:: 3.1 .. seealso:: - `Tk Widget Styling Support <https://core.tcl.tk/tips/doc/trunk/tip/48.md>`_ - A document introducing theming support for Tk + `Tk Widget Styling Support (TIP #48) <https://tip.tcl-lang.org/48.html>`_ + The Tcl Improvement Proposal that introduced the themed widget styling engine. Using Ttk @@ -47,21 +54,22 @@ That code causes several :mod:`!tkinter.ttk` widgets (:class:`Button`, :class:`Scrollbar` and :class:`Spinbox`) to automatically replace the Tk widgets. +.. note:: + + Overriding the classic widgets with ``from tkinter.ttk import *`` + is convenient for adapting existing code, + but new code is usually clearer if it imports the module + as ``from tkinter import ttk`` and refers to the themed widgets explicitly, + such as ``ttk.Button``. + This has the direct benefit of using the new widgets which gives a better look and feel across platforms; however, the replacement widgets are not completely compatible. -The main difference is that widget options such as "fg", "bg" and others +The main difference is that widget options such as ``fg``, ``bg`` and others related to widget styling are no longer present in Ttk widgets. Instead, use the :class:`ttk.Style <Style>` class for improved styling effects. -.. seealso:: - - `Converting existing applications to use Tile widgets <https://tktable.sourceforge.net/tile/doc/converting.txt>`_ - A monograph (using Tcl terminology) about differences typically - encountered when moving applications to use the new widgets. - - Ttk widgets ----------- @@ -71,7 +79,7 @@ Ttk comes with 18 widgets, twelve of which already existed in tkinter: :class:`Radiobutton`, :class:`Scale`, :class:`Scrollbar`, and :class:`Spinbox`. The other six are new: :class:`Combobox`, :class:`Notebook`, :class:`Progressbar`, :class:`Separator`, :class:`Sizegrip` and -:class:`Treeview`. And all them are subclasses of :class:`Widget`. +:class:`Treeview`. All of them are subclasses of :class:`Widget`. Using the Ttk widgets gives the application an improved look and feel. As discussed above, there are differences in how the styling is coded. @@ -1325,8 +1333,13 @@ If you don't know the class name of a widget, use the method .. seealso:: - `Tcl'2004 conference presentation <https://tktable.sourceforge.net/tile/tile-tcl2004.pdf>`_ - This document explains how the theme engine works + `Introduction to the Tk theme engine <https://www.tcl-lang.org/man/tcl9.0/TkCmd/ttk_intro.html>`_ + The ``ttk::intro`` man page explains how the theme engine works. + + `The Tile Widget Set <https://tktable.sourceforge.net/tile/tile-tcl2004.pdf>`_ + Joe English's 2004 paper introducing the theme engine + (then the separate *Tile* extension), + with diagrams of how elements and layouts make up a widget's appearance. .. class:: Style From fd4c7a8d4d46c9b7db920a6b766d367ab22e6a1c Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 15 Jul 2026 20:15:24 +0200 Subject: [PATCH 686/818] [3.15] gh-153630: Add `str.remove{prefix,suffix}()` to the `str` method summary (GH-153629) (#153778) (cherry picked from commit b4662e8e3b60a264486130a171047c7381f993f0) Co-authored-by: darida12321 <73121369+darida12321@users.noreply.github.com> Co-authored-by: Stan Ulbrych <stan@python.org> --- Doc/library/stdtypes.rst | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index 92c89bfc46af2e..5a87ddb1d50156 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -1720,7 +1720,11 @@ category. | | :meth:`str.strip` | :meth:`bytes.strip` | | +--------------------+----------------------+----------------------+----------------------------+ | | :meth:`str.lstrip` | :meth:`str.rstrip` | :meth:`bytes.lstrip` | :meth:`bytes.rstrip` | -+--------------------------+--------------------+----------------------+----------------------+----------------------------+ +| +--------------------+----------------------+----------------------+----------------------------+ +| | :meth:`str.removeprefix` | :meth:`bytes.removeprefix` | +| +-------------------------------------------+---------------------------------------------------+ +| | :meth:`str.removesuffix` | :meth:`bytes.removesuffix` | ++--------------------------+-------------------------------------------+---------------------------------------------------+ | Translation and Encoding | :meth:`str.translate` | :meth:`bytes.translate` | | +-------------------------------------------+---------------------------------------------------+ | | :meth:`str.maketrans` | :meth:`bytes.maketrans` | From 6d6f526866426160307dbc06edf7e2666fea85fa Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 16 Jul 2026 08:07:57 +0200 Subject: [PATCH 687/818] [3.15] gh-150411: fix `gc_generation.count` race in free-threading (GH-150413) (#153788) gh-150411: fix `gc_generation.count` race in free-threading (GH-150413) (cherry picked from commit 12af26d17e4343c1f4ea3a1019bcc34ee76671c3) Co-authored-by: Edward Xu <xuxiangad@gmail.com> --- Lib/test/test_free_threading/test_gc.py | 29 +++++++++++++++++++ ...-05-26-00-06-30.gh-issue-150411.u-d-_5.rst | 2 ++ Modules/gcmodule.c | 2 +- 3 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-05-26-00-06-30.gh-issue-150411.u-d-_5.rst diff --git a/Lib/test/test_free_threading/test_gc.py b/Lib/test/test_free_threading/test_gc.py index cc1888dae48bc0..39901023450940 100644 --- a/Lib/test/test_free_threading/test_gc.py +++ b/Lib/test/test_free_threading/test_gc.py @@ -124,6 +124,35 @@ def setter(): finally: gc.set_threshold(*current_threshold) + def test_get_count(self): + class CyclicReference: + def __init__(self): + self.ref = self + + NUM_ALLOCATORS = 7 + NUM_READERS = 1 + NUM_THREADS = NUM_ALLOCATORS + NUM_READERS + NUM_ITERS = 1000 + + barrier = threading.Barrier(NUM_THREADS) + + def allocator(): + barrier.wait() + for _ in range(NUM_ITERS): + CyclicReference() + + + def reader(): + barrier.wait() + for _ in range(NUM_ITERS): + gc.get_count() + + threads = [Thread(target=allocator) for _ in range(NUM_ALLOCATORS)] + threads.extend(Thread(target=reader) for _ in range(NUM_READERS)) + + with threading_helper.start_threads(threads): + pass + if __name__ == "__main__": unittest.main() diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-26-00-06-30.gh-issue-150411.u-d-_5.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-26-00-06-30.gh-issue-150411.u-d-_5.rst new file mode 100644 index 00000000000000..5b19a4fff5ddc7 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-26-00-06-30.gh-issue-150411.u-d-_5.rst @@ -0,0 +1,2 @@ +Fix a data race in the free-threaded build when :func:`gc.get_count` reads +the young generation allocation count while another thread updates it. diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c index 8762e592b25810..0093995441e390 100644 --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -233,7 +233,7 @@ gc_get_count_impl(PyObject *module) gcstate->generations[2].count); #else return Py_BuildValue("(iii)", - gcstate->young.count, + _Py_atomic_load_int_relaxed(&gcstate->young.count), gcstate->old[0].count, gcstate->old[1].count); #endif From 9fcebd38b5f8f733ed74b9724477381617f19711 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 16 Jul 2026 12:23:07 +0200 Subject: [PATCH 688/818] [3.15] gh-151644: Fix data race in sys.setdlopenflags/getdlopenflags under free-threading (gh-151768) (#153790) gh-151644: Fix data race in sys.setdlopenflags/getdlopenflags under free-threading (gh-151768) In free-threading builds, concurrent calls to sys.getdlopenflags() and sys.setdlopenflags() race on interp->imports.dlopenflags. Fix by using FT_ATOMIC_LOAD_INT_RELAXED / FT_ATOMIC_STORE_INT_RELAXED in _PyImport_GetDLOpenFlags and _PyImport_SetDLOpenFlags, consistent with how analogous interpreter-state integer fields (lazy_imports_mode, pystats_enabled) are protected. Relaxed ordering is correct here: dlopenflags is a standalone config integer with no ordering relationship to other memory. (cherry picked from commit cde31ec135905472f1137dddcc8227af2430d89c) Co-authored-by: Jiucheng(Oliver) <git.jiucheng@gmail.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> --- Lib/test/test_free_threading/test_sys.py | 21 +++++++++++++++++++ ...-06-18-00-00-00.gh-issue-151644.5cFffN.rst | 4 ++++ Python/import.c | 4 ++-- 3 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-18-00-00-00.gh-issue-151644.5cFffN.rst diff --git a/Lib/test/test_free_threading/test_sys.py b/Lib/test/test_free_threading/test_sys.py index 37b53bd723fd76..271fdd13c62b66 100644 --- a/Lib/test/test_free_threading/test_sys.py +++ b/Lib/test/test_free_threading/test_sys.py @@ -4,6 +4,27 @@ class SysModuleTest(unittest.TestCase): + @unittest.skipUnless(hasattr(sys, "setdlopenflags"), + "test needs sys.setdlopenflags()") + def test_dlopenflags_concurrent(self): + # gh-151644: getdlopenflags() and setdlopenflags() must be safe to + # call concurrently in free-threaded builds. + original = sys.getdlopenflags() + self.addCleanup(sys.setdlopenflags, original) + + # Use a small set of known-valid flag values to avoid integer overflow. + flag_values = [1, 2, 256, 257] + + def worker(worker_id): + for i in range(20_000): + if worker_id % 2 == 0: + sys.getdlopenflags() + else: + sys.setdlopenflags(flag_values[worker_id % len(flag_values)]) + + workers = [lambda i=i: worker(i) for i in range(6)] + threading_helper.run_concurrently(workers) + def test_int_max_str_digits_thread(self): # gh-151218: Check that it's safe to call get_int_max_str_digits() and # set_int_max_str_digits() in parallel. Previously, this test triggered diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-18-00-00-00.gh-issue-151644.5cFffN.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-18-00-00-00.gh-issue-151644.5cFffN.rst new file mode 100644 index 00000000000000..ff5058e14b42f1 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-18-00-00-00.gh-issue-151644.5cFffN.rst @@ -0,0 +1,4 @@ +Fix a data race in :func:`sys.setdlopenflags` and :func:`sys.getdlopenflags` +when called concurrently in the free-threaded build. The underlying +``_PyImport_GetDLOpenFlags`` and ``_PyImport_SetDLOpenFlags`` functions now +use atomic load/store operations. diff --git a/Python/import.c b/Python/import.c index 2c975295f9b5d3..a47b2383e99d5f 100644 --- a/Python/import.c +++ b/Python/import.c @@ -911,13 +911,13 @@ _PyImport_SwapPackageContext(const char *newcontext) int _PyImport_GetDLOpenFlags(PyInterpreterState *interp) { - return DLOPENFLAGS(interp); + return FT_ATOMIC_LOAD_INT_RELAXED(DLOPENFLAGS(interp)); } void _PyImport_SetDLOpenFlags(PyInterpreterState *interp, int new_val) { - DLOPENFLAGS(interp) = new_val; + FT_ATOMIC_STORE_INT_RELAXED(DLOPENFLAGS(interp), new_val); } #endif // HAVE_DLOPEN From 38c3f112c383d1f61a3e2d2d4ff589a5ca570944 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 16 Jul 2026 20:59:43 +0200 Subject: [PATCH 689/818] [3.15] gh-149162: Use _Py_LOCK_DONT_DETACH in intern_common (gh-149164) (gh-153814) Avoids potential deadlocks with C++ static local initialization in extensions that call PyUnicode_InternFromString during one-time initialization. (cherry picked from commit f62050d65743f0c895f7e6d665936c4e86aa39d5) Co-authored-by: Sam Gross <colesbury@gmail.com> --- .../2026-04-29-15-10-59.gh-issue-149162.BPPyrq.rst | 3 +++ Objects/unicodeobject.c | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-04-29-15-10-59.gh-issue-149162.BPPyrq.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-04-29-15-10-59.gh-issue-149162.BPPyrq.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-04-29-15-10-59.gh-issue-149162.BPPyrq.rst new file mode 100644 index 00000000000000..b4c443ecee07ad --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-04-29-15-10-59.gh-issue-149162.BPPyrq.rst @@ -0,0 +1,3 @@ +Fix a potential deadlock in :c:func:`PyUnicode_InternFromString` and other +interning functions in the :term:`free-threaded build` when called from C++ +static local initializers. diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 18523c2dfde77e..c3a1beee0c8a5e 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -14344,7 +14344,7 @@ intern_common(PyInterpreterState *interp, PyObject *s /* stolen */, } #endif - FT_MUTEX_LOCK(INTERN_MUTEX); + FT_MUTEX_LOCK_FLAGS(INTERN_MUTEX, _Py_LOCK_DONT_DETACH); PyObject *t; { int res = PyDict_SetDefaultRef(interned, s, s, &t); From 21ab8eb5a87852c8336e18fb912073a4e4ac0c19 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 17 Jul 2026 10:23:01 +0200 Subject: [PATCH 690/818] [3.15] gh-85943: Fix BytesWarning in the struct format cache under -bb (GH-153627) (GH-153834) Normalize bytes format strings to str before using them as the cache key, so that equal str and bytes formats no longer collide and get compared. (cherry picked from commit 190d2ffbb969ad571fd12d4988b37519091194d5) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --- Lib/test/test_struct.py | 10 +++++++ ...6-07-12-00-00-00.gh-issue-85943.8f906e.rst | 4 +++ Modules/_struct.c | 26 ++++++++++++++++--- 3 files changed, 36 insertions(+), 4 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-07-12-00-00-00.gh-issue-85943.8f906e.rst diff --git a/Lib/test/test_struct.py b/Lib/test/test_struct.py index edd85df633fc3b..934012784de1af 100644 --- a/Lib/test/test_struct.py +++ b/Lib/test/test_struct.py @@ -181,6 +181,16 @@ def test_calcsize(self): self.assertGreaterEqual(struct.calcsize('n'), struct.calcsize('i')) self.assertGreaterEqual(struct.calcsize('n'), struct.calcsize('P')) + def test_cache_bytes_vs_str_bb(self): + # Mixing str and bytes formats must not raise BytesWarning under -bb. + code = ( + 'import struct\n' + 'struct.calcsize(b"!d"); struct.calcsize("!d")\n' + 'struct.calcsize(">d"); struct.calcsize(b">d")\n' + 'struct.Struct(b"i"); struct.Struct("i")\n' + ) + assert_python_ok('-bb', '-c', code) + def test_integers(self): # Integer tests (bBhHiIlLqQnN). import binascii diff --git a/Misc/NEWS.d/next/Library/2026-07-12-00-00-00.gh-issue-85943.8f906e.rst b/Misc/NEWS.d/next/Library/2026-07-12-00-00-00.gh-issue-85943.8f906e.rst new file mode 100644 index 00000000000000..0a93bf2e7b803e --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-12-00-00-00.gh-issue-85943.8f906e.rst @@ -0,0 +1,4 @@ +Fix :mod:`struct` functions raising :exc:`BytesWarning` under the ``-bb`` +command line option when a :class:`str` format is used after an equal +:class:`bytes` format (or vice versa). The internal format cache no longer +mixes :class:`str` and :class:`bytes` keys. diff --git a/Modules/_struct.c b/Modules/_struct.c index 5b5ca4f9527693..41068a321b61f5 100644 --- a/Modules/_struct.c +++ b/Modules/_struct.c @@ -2613,7 +2613,8 @@ static PyType_Spec PyStructType_spec = { static int cache_struct_converter(PyObject *module, PyObject *fmt, PyStructObject **ptr) { - PyObject * s_object; + PyObject *s_object; + PyObject *key; _structmodulestate *state = get_struct_state(module); if (fmt == NULL) { @@ -2621,24 +2622,41 @@ cache_struct_converter(PyObject *module, PyObject *fmt, PyStructObject **ptr) return 1; } - if (PyDict_GetItemRef(state->cache, fmt, &s_object) < 0) { + /* Use a str cache key: an equal str and bytes would collide and be + compared, raising BytesWarning under -bb. */ + if (PyBytes_Check(fmt)) { + key = PyUnicode_DecodeASCII(PyBytes_AS_STRING(fmt), + PyBytes_GET_SIZE(fmt), "surrogateescape"); + if (key == NULL) { + return 0; + } + } + else { + key = Py_NewRef(fmt); + } + + if (PyDict_GetItemRef(state->cache, key, &s_object) < 0) { + Py_DECREF(key); return 0; } if (s_object != NULL) { + Py_DECREF(key); *ptr = PyStructObject_CAST(s_object); return Py_CLEANUP_SUPPORTED; } - s_object = PyObject_CallOneArg(state->PyStructType, fmt); + s_object = PyObject_CallOneArg(state->PyStructType, key); if (s_object != NULL) { if (PyDict_GET_SIZE(state->cache) >= MAXCACHE) PyDict_Clear(state->cache); /* Attempt to cache the result */ - if (PyDict_SetItem(state->cache, fmt, s_object) == -1) + if (PyDict_SetItem(state->cache, key, s_object) == -1) PyErr_Clear(); + Py_DECREF(key); *ptr = (PyStructObject *)s_object; return Py_CLEANUP_SUPPORTED; } + Py_DECREF(key); return 0; } From 9f85842ee7dc014b960f45e6744e3384f94af12c Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 17 Jul 2026 17:51:40 +0200 Subject: [PATCH 691/818] [3.15] Shut down leaked executors in `test_interpreter_pool` (GH-153780) (#153847) (cherry picked from commit 8ca85b5bc5a888b8329915aff0ceb34de9373546) Co-authored-by: Stan Ulbrych <stan@python.org> --- .../test_interpreter_pool.py | 68 +++++++++---------- 1 file changed, 33 insertions(+), 35 deletions(-) diff --git a/Lib/test/test_concurrent_futures/test_interpreter_pool.py b/Lib/test/test_concurrent_futures/test_interpreter_pool.py index 7241fcc4b1e74d..5ae6563ef23ee3 100644 --- a/Lib/test/test_concurrent_futures/test_interpreter_pool.py +++ b/Lib/test/test_concurrent_futures/test_interpreter_pool.py @@ -129,12 +129,12 @@ def test_init_script(self): """ os.write(w, b'\0') - executor = self.executor_type(initializer=initscript) - before_init = os.read(r, 100) - fut = executor.submit(script) - after_init = read_msg(r) - fut.result() - after_run = read_msg(r) + with self.executor_type(initializer=initscript) as executor: + before_init = os.read(r, 100) + fut = executor.submit(script) + after_init = read_msg(r) + fut.result() + after_run = read_msg(r) self.assertEqual(before_init, b'\0') self.assertEqual(after_init, msg1) @@ -150,11 +150,11 @@ def test_init_func(self): r, w = self.pipe() os.write(w, b'\0') - executor = self.executor_type( - initializer=write_msg, initargs=(w, msg)) - before = os.read(r, 100) - executor.submit(mul, 10, 10) - after = read_msg(r) + with self.executor_type( + initializer=write_msg, initargs=(w, msg)) as executor: + before = os.read(r, 100) + executor.submit(mul, 10, 10) + after = read_msg(r) self.assertEqual(before, b'\0') self.assertEqual(after, msg) @@ -260,11 +260,10 @@ def test_submit_script(self): import os os.write({w}, __name__.encode('utf-8') + b'\\0') """ - executor = self.executor_type() - - fut = executor.submit(script) - res = fut.result() - after = read_msg(r) + with self.executor_type() as executor: + fut = executor.submit(script) + res = fut.result() + after = read_msg(r) self.assertEqual(after, b'__main__') self.assertIs(res, None) @@ -278,25 +277,24 @@ def task2(): spam += 1 return spam - executor = self.executor_type() - - fut = executor.submit(task1) - with self.assertRaises(_interpreters.NotShareableError): - fut.result() + with self.executor_type() as executor: + fut = executor.submit(task1) + with self.assertRaises(_interpreters.NotShareableError): + fut.result() - fut = executor.submit(task2) - with self.assertRaises(_interpreters.NotShareableError): - fut.result() + fut = executor.submit(task2) + with self.assertRaises(_interpreters.NotShareableError): + fut.result() def test_submit_local_instance(self): class Spam: def __init__(self): self.value = True - executor = self.executor_type() - fut = executor.submit(Spam) - with self.assertRaises(_interpreters.NotShareableError): - fut.result() + with self.executor_type() as executor: + fut = executor.submit(Spam) + with self.assertRaises(_interpreters.NotShareableError): + fut.result() def test_submit_instance_method(self): class Spam: @@ -304,15 +302,15 @@ def run(self): return True spam = Spam() - executor = self.executor_type() - fut = executor.submit(spam.run) - with self.assertRaises(_interpreters.NotShareableError): - fut.result() + with self.executor_type() as executor: + fut = executor.submit(spam.run) + with self.assertRaises(_interpreters.NotShareableError): + fut.result() def test_submit_func_globals(self): - executor = self.executor_type() - fut = executor.submit(get_current_name) - name = fut.result() + with self.executor_type() as executor: + fut = executor.submit(get_current_name) + name = fut.result() self.assertEqual(name, __name__) self.assertNotEqual(name, '__main__') From 0be137da9dbc8d4d710e47051c6c1a9bd5e37ef7 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 17 Jul 2026 20:59:46 +0200 Subject: [PATCH 692/818] [3.15] gh-153853: Fix parameter name of calendar.setfirstweekday() in docs (GH-153851) (#153859) gh-153853: Fix parameter name of calendar.setfirstweekday() in docs (GH-153851) (cherry picked from commit 1736526023a3e616d1530815880bb3b28e3433c3) Co-authored-by: Ibrahim Shaqqou <101660458+IbrahimShaqqou@users.noreply.github.com> --- Doc/library/calendar.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/calendar.rst b/Doc/library/calendar.rst index 31faa8c4fb43dc..60cd214b450101 100644 --- a/Doc/library/calendar.rst +++ b/Doc/library/calendar.rst @@ -365,7 +365,7 @@ interpreted as prescribed by the ISO 8601 standard. Year 0 is 1 BC, year -1 is For simple text calendars this module provides the following functions. -.. function:: setfirstweekday(weekday) +.. function:: setfirstweekday(firstweekday) Sets the weekday (``0`` is Monday, ``6`` is Sunday) to start each week. The values :const:`MONDAY`, :const:`TUESDAY`, :const:`WEDNESDAY`, :const:`THURSDAY`, From fefc0b4e84a7852fd5c72625465cdfa25376e403 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 17 Jul 2026 22:37:49 +0200 Subject: [PATCH 693/818] [3.15] gh-151669: Normalize symlink targets in tarfile.TarFile.gettarinfo() (GH-151671) (#153517) Co-authored-by: Daniele Nicolodi <daniele@grinta.net> --- Doc/whatsnew/3.15.rst | 3 +++ Lib/tarfile.py | 2 +- Lib/test/test_tarfile.py | 16 ++++++++++++++++ ...026-06-24-23-28-42.gh-issue-151669.tPUavQ.rst | 3 +++ 4 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2026-06-24-23-28-42.gh-issue-151669.tPUavQ.rst diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst index bad9e2d8dff37f..ae75d14a3088ba 100644 --- a/Doc/whatsnew/3.15.rst +++ b/Doc/whatsnew/3.15.rst @@ -1541,6 +1541,9 @@ tarfile now replace slashes with backslashes in symlink targets on Windows to prevent creation of corrupted links. (Contributed by Christoph Walcher in :gh:`57911`.) +* :func:`~tarfile.TarFile.gettarinfo` now replaces backslashes with slashes in + symlink targets on Windows to conform to the tar format standard. (Contributed + by Daniele Nicolodi in :gh:`151669`.) threading diff --git a/Lib/tarfile.py b/Lib/tarfile.py index 8c058357f114ad..fe28ea68cfd132 100644 --- a/Lib/tarfile.py +++ b/Lib/tarfile.py @@ -2275,7 +2275,7 @@ def gettarinfo(self, name=None, arcname=None, fileobj=None): type = FIFOTYPE elif stat.S_ISLNK(stmd): type = SYMTYPE - linkname = os.readlink(name) + linkname = os.readlink(name).replace(os.sep, "/") elif stat.S_ISCHR(stmd): type = CHRTYPE elif stat.S_ISBLK(stmd): diff --git a/Lib/test/test_tarfile.py b/Lib/test/test_tarfile.py index 9615547fc22dfa..2c6f0da7887f53 100644 --- a/Lib/test/test_tarfile.py +++ b/Lib/test/test_tarfile.py @@ -1647,6 +1647,22 @@ def test_symlink_size(self): finally: os_helper.unlink(path) + @os_helper.skip_unless_symlink + def test_symlink_target_normalization(self): + # Test for gh-151669. + path = os.path.join(TEMPDIR, "symlink") + target = "subdir/link/target" + os.symlink(target.replace("/", os.sep), path) + try: + tar = tarfile.open(tmpname, self.mode) + try: + tarinfo = tar.gettarinfo(path) + self.assertEqual(tarinfo.linkname, target) + finally: + tar.close() + finally: + os_helper.unlink(path) + def test_add_self(self): # Test for #1257255. dstname = os.path.abspath(tmpname) diff --git a/Misc/NEWS.d/next/Library/2026-06-24-23-28-42.gh-issue-151669.tPUavQ.rst b/Misc/NEWS.d/next/Library/2026-06-24-23-28-42.gh-issue-151669.tPUavQ.rst new file mode 100644 index 00000000000000..d8e4850ba94e14 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-24-23-28-42.gh-issue-151669.tPUavQ.rst @@ -0,0 +1,3 @@ +On Windows, when populating tar archives from filesystem content, to +conform to the tar format standard, backslashes in symlink targets are +be replaced by slashes. From ec8cfecf1e0aea0b1725408a8f543196f852b503 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 18 Jul 2026 00:14:43 +0200 Subject: [PATCH 694/818] [3.15] gh-152023: Update macOS installer builds to SQLite 3.53.3 (GH-153867) (#153869) Enable median() and percentile() functions. (cherry picked from commit 34f109db9579fe5f597d8b00653e905b40590410) Co-authored-by: Ned Deily <nad@python.org> --- Mac/BuildScript/build-installer.py | 7 ++++--- .../macOS/2026-07-17-23-20-27.gh-issue-152023.QAAgdj.rst | 2 ++ 2 files changed, 6 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/macOS/2026-07-17-23-20-27.gh-issue-152023.QAAgdj.rst diff --git a/Mac/BuildScript/build-installer.py b/Mac/BuildScript/build-installer.py index 9c060f3ea15632..7b43873af48801 100755 --- a/Mac/BuildScript/build-installer.py +++ b/Mac/BuildScript/build-installer.py @@ -359,13 +359,14 @@ def library_recipes(): ), ), dict( - name="SQLite 3.53.2", - url="https://www.sqlite.org/2026/sqlite-autoconf-3530200.tar.gz", - checksum="588ad51949419a56ebe81fe56193d510c559eb94c9a57748387860b5d3069316", + name="SQLite 3.53.3", + url="https://www.sqlite.org/2026/sqlite-autoconf-3530300.tar.gz", + checksum="c917d7db16648ec95f714974ace5e5dcf46b7dc70e26600a0a102a3141125db0", extra_cflags=('-Os ' '-DSQLITE_ENABLE_FTS5 ' '-DSQLITE_ENABLE_FTS4 ' '-DSQLITE_ENABLE_FTS3_PARENTHESIS ' + '-DSQLITE_ENABLE_PERCENTILE ' '-DSQLITE_ENABLE_RTREE ' '-DSQLITE_OMIT_AUTOINIT ' '-DSQLITE_TCL=0 ' diff --git a/Misc/NEWS.d/next/macOS/2026-07-17-23-20-27.gh-issue-152023.QAAgdj.rst b/Misc/NEWS.d/next/macOS/2026-07-17-23-20-27.gh-issue-152023.QAAgdj.rst new file mode 100644 index 00000000000000..afabb3d5224970 --- /dev/null +++ b/Misc/NEWS.d/next/macOS/2026-07-17-23-20-27.gh-issue-152023.QAAgdj.rst @@ -0,0 +1,2 @@ +Update macOS installer builds to SQLite 3.53.3. Enable median() and +percentile() functions. From d87949b72b32529753e8fbd9f8be41914ce0a558 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 18 Jul 2026 00:40:46 +0200 Subject: [PATCH 695/818] [3.15] gh-124111: Update macOS installer to use Tcl/Tk 9.0.4. (GH-153868) (#153871) cherry picked from commit d478cf81f770168e3fb512ce110a88774f04f549) Co-authored-by: Ned Deily <nad@python.org> --- Mac/BuildScript/build-installer.py | 6 +++--- .../macOS/2026-07-17-23-35-36.gh-issue-124111.dmM4lk.rst | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/macOS/2026-07-17-23-35-36.gh-issue-124111.dmM4lk.rst diff --git a/Mac/BuildScript/build-installer.py b/Mac/BuildScript/build-installer.py index 7b43873af48801..d2fa6dd069e378 100755 --- a/Mac/BuildScript/build-installer.py +++ b/Mac/BuildScript/build-installer.py @@ -264,10 +264,10 @@ def library_recipes(): tk_patches = ['backport_gh71383_fix.patch', 'tk868_on_10_8_10_9.patch', 'backport_gh110950_fix.patch'] else: - tcl_tk_ver='9.0.3' - tcl_checksum='2537ba0c86112c8c953f7c09d33f134dd45c0fb3a71f2d7f7691fd301d2c33a6' + tcl_tk_ver='9.0.4' + tcl_checksum='d0aed49230bc02a65c1e0229e65f34590a4b037ec40d546f32573b467f7551ea' - tk_checksum='bf344efadb618babb7933f69275620f72454d1c8220130da93e3f7feb0efbf9b' + tk_checksum='d7a146d2917eb8b5cc95276dbf0e3d03c7464d2b19c1675357857c989301dbb4' tk_patches = [] diff --git a/Misc/NEWS.d/next/macOS/2026-07-17-23-35-36.gh-issue-124111.dmM4lk.rst b/Misc/NEWS.d/next/macOS/2026-07-17-23-35-36.gh-issue-124111.dmM4lk.rst new file mode 100644 index 00000000000000..48ab66407831a8 --- /dev/null +++ b/Misc/NEWS.d/next/macOS/2026-07-17-23-35-36.gh-issue-124111.dmM4lk.rst @@ -0,0 +1 @@ +Update macOS installer to use Tcl/Tk 9.0.4. From 4d74b76ed2534dfe74e085bcc0c86b2212838c6b Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 18 Jul 2026 02:01:13 +0200 Subject: [PATCH 696/818] [3.15] gh-153872: Update macOS installer ReadMe files for 3.15. (GH-153875) (#153876) (cherry picked from commit 16d0c89b875c520cf5af9da5ba4db133358f742f) Co-authored-by: Ned Deily <nad@python.org> --- Mac/BuildScript/resources/License.rtf | 11 +++--- Mac/BuildScript/resources/ReadMe.rtf | 49 ++++++++++++++++----------- Mac/BuildScript/resources/Welcome.rtf | 6 +--- 3 files changed, 38 insertions(+), 28 deletions(-) diff --git a/Mac/BuildScript/resources/License.rtf b/Mac/BuildScript/resources/License.rtf index b5cb8ec41c86e2..8fed71829073fe 100644 --- a/Mac/BuildScript/resources/License.rtf +++ b/Mac/BuildScript/resources/License.rtf @@ -16,7 +16,7 @@ Python was created in the early 1990s by Guido van Rossum at Stichting Mathemati \ In 1995, Guido continued his work on Python at the Corporation for National Research Initiatives (CNRI, see https://www.cnri.reston.va.us) in Reston, Virginia where he released several versions of the software.\ \ -In May 2000, Guido and the Python core development team moved to BeOpen.com to form the BeOpen PythonLabs team. In October of the same year, the PythonLabs team moved to Digital Creations (now Zope Corporation, see https://www.zope.dev). In 2001, the Python Software Foundation (PSF, see https://www.python.org/psf/) was formed, a non-profit organization created specifically to own Python-related Intellectual Property. Zope Corporation is a sponsoring member of the PSF.\ +In May 2000, Guido and the Python core development team moved to BeOpen.com to form the BeOpen PythonLabs team. In October of the same year, the PythonLabs team moved to Digital Creations, which became Zope Corporation. In 2001, the Python Software Foundation (PSF, see https://www.python.org/psf/) was formed, a non-profit organization created specifically to own Python-related Intellectual Property. Zope Corporation was a sponsoring member of the PSF.\ \ All Python releases are Open Source (see https://opensource.org for the Open Source Definition). Historically, most, but not all, Python releases have also been GPL-compatible; the table below summarizes the various releases.\ \ @@ -29,7 +29,7 @@ All Python releases are Open Source (see https://opensource.org for the Open Sou 1.3 thru 1.5.2 1.2 1995-1999 CNRI yes\ 1.6 1.5.2 2000 CNRI no\ 2.0 1.6 2000 BeOpen.com no\ -1.6.1 1.6 2001 CNRI no\ +1.6.1 1.6 2001 CNRI yes\ 2.1 2.0+1.6.1 2001 PSF no\ 2.0.1 2.0+1.6.1 2001 PSF yes\ 2.1.1 2.1+2.0.1 2001 PSF yes\ @@ -39,8 +39,11 @@ All Python releases are Open Source (see https://opensource.org for the Open Sou \f1 \ -\f0\b Note: -\f1\b0 GPL-compatible doesn't mean that we're distributing Python under the GPL. All Python licenses, unlike the GPL, let you distribute a modified version without making your changes open source. The GPL-compatible licenses make it possible to combine Python with other software that is released under the GPL; the others don't.\ +\f0\b Notes: +\f1\b0 \ +(1) GPL-compatible doesn't mean that we're distributing Python under the GPL. All Python licenses, unlike the GPL, let you distribute a modified version without making your changes open source. The GPL-compatible licenses make it possible to combine Python with other software that is released under the GPL; the others don't.\ +\ +(2) According to Richard Stallman, 1.6.1 is not GPL-compatible, because its license has a choice of law clause. According to CNRI, however, Stallman's lawyer has told CNRI's lawyer that 1.6.1 is "not incompatible" with the GPL.\ \ Thanks to the many outside volunteers who have worked under Guido's direction to make these releases possible.\ \ diff --git a/Mac/BuildScript/resources/ReadMe.rtf b/Mac/BuildScript/resources/ReadMe.rtf index d81bcd5c745baa..d19b542b7e6c5a 100644 --- a/Mac/BuildScript/resources/ReadMe.rtf +++ b/Mac/BuildScript/resources/ReadMe.rtf @@ -1,32 +1,26 @@ -{\rtf1\ansi\ansicpg1252\cocoartf2761 +{\rtf1\ansi\ansicpg1252\cocoartf2870 \cocoatextscaling0\cocoaplatform0{\fonttbl\f0\fswiss\fcharset0 Helvetica;\f1\fswiss\fcharset0 Helvetica-Bold;\f2\fswiss\fcharset0 Helvetica-Oblique; \f3\fmodern\fcharset0 CourierNewPSMT;\f4\fmodern\fcharset0 Courier;} {\colortbl;\red255\green255\blue255;} {\*\expandedcolortbl;;} -\margl1440\margr1440\vieww13380\viewh14580\viewkind0 +\margl1440\margr1440\vieww15140\viewh15740\viewkind0 \pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural\partightenfactor0 \f0\fs24 \cf0 This package will install Python $FULL_VERSION for macOS $MACOSX_DEPLOYMENT_TARGET for the following architecture(s): $ARCHITECTURES.\ \ -\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\partightenfactor0 - -\f1\b \cf0 NOTE: -\f0\b0 This is a beta preview of Python 3.13.0, the next feature release of Python 3. It is not intended for production use.\ -\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural\partightenfactor0 -\cf0 \ \pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural\partightenfactor0 \f1\b \cf0 \ul \ulc0 Certificate verification and OpenSSL\ \f0\b0 \ulnone \ -This package includes its own private copy of OpenSSL 3.5. The trust certificates in system and user keychains managed by the +This package includes its own private copy of OpenSSL 3. The trust certificates in system and user keychains managed by the \f2\i Keychain Access \f0\i0 application and the \f2\i security \f0\i0 command line utility are not used as defaults by the Python \f3 ssl \f0 module. A sample command script is included in -\f3 /Applications/Python 3.13 +\f3 /Applications/Python 3.15 \f0 to install a curated bundle of default root certificates from the third-party \f3 certifi \f0 package ({\field{\*\fldinst{HYPERLINK "https://pypi.org/project/certifi/"}}{\fldrslt https://pypi.org/project/certifi/}}). Double-click on @@ -42,18 +36,34 @@ The bundled \f0\b0 \ulnone \ You can control some aspects of what is installed by this package. To see the options, click on the -\f4 Customize -\f0 button in the -\f4 Installation Type -\f0 step of the macOS installer app. Click on a package name in the list shown to see more information about that option,\ - \ +\f1\b Customize +\f0\b0 button in the +\f1\b Installation Type +\f0\b0 step of the macOS installer app. Click on a package name in the list shown to see more information about that option.\ +\ + +\f1\b \ul Free-threading support\ + +\f0\b0 \ulnone \ +This installer package can optionally install an additional build of Python 3.15 that supports the free-threading feature (running with the +\f1\b global interpreter lock +\f0\b0 disabled).\ +\ +See {\field{\*\fldinst{HYPERLINK "https://docs.python.org/3.15/using/mac.html"}}{\fldrslt the macOS section of the Python Setup and Usage document}}, the release notice, and the {\field{\*\fldinst{HYPERLINK "https://docs.python.org/3.15/whatsnew/3.15.html"}}{\fldrslt 3.15 What's New document}} for more information. As of Python 3.15, free-threading support is installed by default.\ +\ + +\f1\b \ul Just-in-time compiler support\ + +\f0\b0 \ulnone \ +As of Python 3.14, this installer package includes support for the experimental just-in-time (JIT) compiler feature. See the {\field{\*\fldinst{HYPERLINK "https://docs.python.org/dev/whatsnew/3.14.html#binary-releases-for-the-experimental-just-in-time-compiler"}}{\fldrslt 3.14 What's New document}} and the release notice for more information. Note that the just-in-time compiler is not available with the optional free-threading build.\ + \ \f1\b \ul Using IDLE or other Tk applications \f0\b0 \ulnone \ \ -This package includes its own private version of Tcl/Tk 8.6. It does not use any system-supplied or third-party supplied versions of Tcl/Tk.\ +This package includes its own private version of Tcl/Tk 9. It does not use any system-supplied or third-party supplied versions of Tcl/Tk.\ \ -Due to new security checks on macOS 10.15 Catalina, when launching IDLE macOS may open a window with a message +Due to security checks introduced with macOS 10.15 Catalina, when launching IDLE, macOS may open a window with a message \f1\b "Python" would like to access files in your Documents folder \f0\b0 . This is normal as IDLE uses your \f1\b Documents @@ -69,7 +79,7 @@ Due to new security checks on macOS 10.15 Catalina, when launching IDLE macOS ma \f1\b \ul Apple Silicon Mac support\ \f0\b0 \ulnone \ -On Apple Silicon Macs, it is possible to run Python either with native ARM64 code or under Intel 64 emulation using Rosetta2. This option might be useful for testing or if binary wheels are not yet available with native ARM64 binaries. To easily force Python to run in emulation mode, invoke it from a command line shell with the +On Apple Silicon Macs, it is possible to run Python either with native ARM64 code or under Intel 64 emulation using Rosetta 2. This option might be useful for testing or if binary wheels are not yet available with native ARM64 binaries. To easily force Python to run in emulation mode, invoke it from a command line shell with the \f4 python3-intel64 \f0 command instead of just \f4 python3 @@ -84,4 +94,5 @@ For other changes in this release, see the \f0\i0 section in the {\field{\*\fldinst{HYPERLINK "https://www.python.org/doc/"}}{\fldrslt Documentation Set}} for this release and its \f2\i Release Notes \f0\i0 link at {\field{\*\fldinst{HYPERLINK "https://www.python.org/downloads/"}}{\fldrslt https://www.python.org/downloads/}}.\ -} \ No newline at end of file +} + diff --git a/Mac/BuildScript/resources/Welcome.rtf b/Mac/BuildScript/resources/Welcome.rtf index 49d6e22286be26..0855124934e25c 100644 --- a/Mac/BuildScript/resources/Welcome.rtf +++ b/Mac/BuildScript/resources/Welcome.rtf @@ -1,4 +1,4 @@ -{\rtf1\ansi\ansicpg1252\cocoartf2761 +{\rtf1\ansi\ansicpg1252\cocoartf2870 \cocoascreenfonts1\cocoatextscaling0\cocoaplatform0{\fonttbl\f0\fswiss\fcharset0 Helvetica;\f1\fswiss\fcharset0 Helvetica-Bold;\f2\fmodern\fcharset0 CourierNewPSMT; } {\colortbl;\red255\green255\blue255;} @@ -23,8 +23,4 @@ At the end of this install, click on \f2 Install Certificates \f0 to install a set of current SSL root certificates.\ -\ - -\f1\b NOTE: -\f0\b0 This is a beta test preview of Python 3.13.0, the next feature release of Python 3. It is not intended for production use.\ } \ No newline at end of file From c642dc83cc6da32f255b1537959b10f320ceff92 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 18 Jul 2026 09:21:46 +0200 Subject: [PATCH 697/818] [3.15] gh-150583: Fix zstd compression level with digested ZstdDict (GH-150586) (#153883) gh-150583: Fix zstd compression level with digested ZstdDict (GH-150586) (cherry picked from commit 0983642c966d9c536416101e99b7d2b085483847) Co-authored-by: Rogdham <3994389+Rogdham@users.noreply.github.com> --- .../next/Library/2026-06-03-19-35-32.gh-issue-150583.dedI24.rst | 2 ++ Modules/_zstd/compressor.c | 1 + 2 files changed, 3 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2026-06-03-19-35-32.gh-issue-150583.dedI24.rst diff --git a/Misc/NEWS.d/next/Library/2026-06-03-19-35-32.gh-issue-150583.dedI24.rst b/Misc/NEWS.d/next/Library/2026-06-03-19-35-32.gh-issue-150583.dedI24.rst new file mode 100644 index 00000000000000..edb551b3c3c8cb --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-03-19-35-32.gh-issue-150583.dedI24.rst @@ -0,0 +1,2 @@ +Correctly set the default compression level in :mod:`compression.zstd` when passing a digested +dictionary during compression. diff --git a/Modules/_zstd/compressor.c b/Modules/_zstd/compressor.c index b2eb22d9ec8add..894568fce28d0d 100644 --- a/Modules/_zstd/compressor.c +++ b/Modules/_zstd/compressor.c @@ -347,6 +347,7 @@ _zstd_ZstdCompressor_new_impl(PyTypeObject *type, PyObject *level, } self->use_multithread = 0; + self->compression_level = ZSTD_CLEVEL_DEFAULT; self->dict = NULL; self->lock = (PyMutex){0}; From 0a6fa6274a6c0ab38758302e85e1625920dbd2ad Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> Date: Sat, 18 Jul 2026 09:56:32 +0200 Subject: [PATCH 698/818] Python 3.15.0b4 --- Doc/library/concurrent.futures.rst | 2 +- Include/patchlevel.h | 4 +- Lib/pydoc_data/module_docs.py | 2 +- Lib/pydoc_data/topics.py | 633 ++++++- Misc/NEWS.d/3.15.0b4.rst | 1570 +++++++++++++++++ ...-06-28-16-17-55.gh-issue-152502.6SNqMg.rst | 5 - ...-07-01-17-53-00.gh-issue-152769.Kp7mQ2.rst | 4 - ...-07-02-16-25-13.gh-issue-152870.oh9eD1.rst | 4 - ...-07-09-22-45-00.gh-issue-153438.Qr7N2p.rst | 2 - ...-07-11-07-26-16.gh-issue-126877.Zt7Kq2.rst | 2 - ...-07-08-00-38-32.gh-issue-153300.lVoWyR.rst | 3 - ...-07-09-16-46-30.gh-issue-145633.jyNwAs.rst | 2 - ...-07-09-17-33-29.gh-issue-152132.Ma8MJZ.rst | 3 - ...-04-21-15-07-03.gh-issue-148825.AbJzmZ.rst | 1 - ...-04-29-15-10-59.gh-issue-149162.BPPyrq.rst | 3 - ...-05-11-15-58-23.gh-issue-149689.9Ht49z.rst | 2 - ...-05-26-00-06-30.gh-issue-150411.u-d-_5.rst | 2 - ...-05-29-17-51-11.gh-issue-144774.jPcixe.rst | 1 - ...-06-03-16-27-00.gh-issue-150858.j2dSkD.rst | 1 - ...-06-03-21-14-28.gh-issue-150459.qpsCEl.rst | 3 - ...-06-06-20-15-08.gh-issue-151029.A33CKK.rst | 2 - ...-06-17-16-46-07.gh-issue-151126.vhTL0T.rst | 2 - ...-06-18-00-00-00.gh-issue-151644.5cFffN.rst | 4 - ...-06-18-16-00-10.gh-issue-151126.tBqn6I.rst | 3 - ...-06-19-16-40-01.gh-issue-151619.35yyJW.rst | 3 - ...-06-20-10-01-26.gh-issue-151672.K-w7j0.rst | 3 - ...-06-21-16-00-00.gh-issue-151773.mN4kRt.rst | 2 - ...-06-22-14-48-22.gh-issue-151912.YcxfnU.rst | 1 - ...-06-23-12-03-55.gh-issue-151763.K7QfWG.rst | 3 - ...-06-23-19-50-22.gh-issue-152020.DTKXjR.rst | 3 - ...-06-23-23-48-54.gh-issue-151763.Eu8pYQ.rst | 1 - ...-06-24-13-36-31.gh-issue-151722.lWKfE1.rst | 3 - ...-06-25-21-34-15.gh-issue-152228.a6K14K.rst | 2 - ...-06-26-05-49-13.gh-issue-152235.YU20T9.rst | 2 - ...-06-26-22-03-16.gh-issue-152235.ZKWiWk.rst | 3 - ...-06-27-10-05-12.gh-issue-152375.L-ZBk6.rst | 2 - ...-06-28-14-31-03.gh-issue-152492._09Zee.rst | 1 - ...-06-28-14-39-05.gh-issue-152405.-_3YRo.rst | 5 - ...-06-29-23-29-14.gh-issue-152635.O21J0O.rst | 2 - ...-06-30-14-00-00.gh-issue-152682.yId7e5.rst | 3 - ...-07-07-04-16-48.gh-issue-153205.5fE8QZ.rst | 2 - ...-07-08-13-23-11.gh-issue-153298.wvcXxN.rst | 2 - ...6-06-28-06-46-46.gh-issue-85320.Hq2vKn.rst | 4 - ...6-07-01-00-00-00.gh-issue-66331.wMcLaS.rst | 3 - ...-07-01-00-15-58.gh-issue-152728.yxIhMN.rst | 2 - ...6-07-01-12-00-00.gh-issue-71956.rPlAlL.rst | 3 - ...6-07-01-14-00-00.gh-issue-89360.mUlTiC.rst | 3 - ...-07-01-15-00-00.gh-issue-134300.iDlPaT.rst | 3 - ...026-07-01-16-00-00.gh-issue-80504.gReP.rst | 3 - ...6-07-01-17-00-00.gh-issue-65339.oUtTxt.rst | 3 - ...6-07-01-18-00-00.gh-issue-83653.cFgInt.rst | 3 - ...6-07-01-19-00-00.gh-issue-82183.rNsTrt.rst | 3 - ...-06-12-21-31-02.gh-issue-105708.5fFwP8.rst | 1 - ...5-09-05-20-50-35.gh-issue-79638.Y-JfaH.rst | 2 - ...-11-02-05-28-56.gh-issue-115634.JbcNnF.rst | 5 - ...-02-11-16-47-27.gh-issue-140729.2uTPQp.rst | 3 - ...6-03-26-00-00-00.gh-issue-47005.xxc89c.rst | 4 - ...-05-18-12-42-31.gh-issue-149816.F98iME.rst | 2 - ...-05-31-14-39-25.gh-issue-150641.LLIhd1.rst | 2 - ...-06-03-19-35-32.gh-issue-150583.dedI24.rst | 2 - ...-06-06-06-29-17.gh-issue-150994.I2119M.rst | 1 - ...-06-11-06-56-31.gh-issue-150994.gd1wVw.rst | 1 - ...06-12-00-00-00.gh-issue-151416.spawnUA.rst | 5 - ...-06-15-15-32-36.gh-issue-151497.1cfmSV.rst | 4 - ...-06-17-00-00-00.gh-issue-148660.odcopy.rst | 3 - ...-06-17-22-31-57.gh-issue-151613.n0nua1.rst | 3 - ...-06-18-12-48-03.gh-issue-151640.R4c3Fx.rst | 3 - ...-06-18-23-59-46.gh-issue-151596.5ma144.rst | 1 - ...-06-20-21-15-13.gh-issue-151814.OIbgsO.rst | 2 - ...6-06-21-15-50-24.gh-issue-86165.dyac1G.rst | 3 - ...-06-23-13-27-14.gh-issue-126219.kOfv2g.rst | 3 - ...-06-23-17-14-04.gh-issue-127802.nGSxo6.rst | 3 - ...-06-24-10-46-35.gh-issue-152060.f2asrt.rst | 3 - ...-06-24-12-00-00.gh-issue-152052.yBssDE.rst | 2 - ...-06-24-12-00-00.gh-issue-152079.f1tzus.rst | 3 - ...-06-24-16-40-15.gh-issue-151378.iYWa_6.rst | 3 - ...-06-24-22-16-35.gh-issue-105895.hRkuEw.rst | 2 - ...-06-24-23-28-42.gh-issue-151669.tPUavQ.rst | 3 - ...-06-25-01-00-43.gh-issue-151763.wWeHBe.rst | 2 - ...-06-25-07-08-17.gh-issue-152157.dt5Ef0.rst | 3 - ...-06-25-10-07-54.gh-issue-152156.gscPU9.rst | 2 - ...-06-25-12-00-00.gh-issue-152212.Zk7Qm2.rst | 3 - ...-06-25-14-32-42.gh-issue-139145.kT9rmP.rst | 5 - ...-06-25-14-32-43.gh-issue-139816.Lq2vXa.rst | 4 - ...-06-25-20-00-00.gh-issue-151496.kMnT3x.rst | 3 - ...-06-26-12-50-26.gh-issue-152246.MfXMd1.rst | 2 - ...6-06-26-13-10-00.gh-issue-80937.Hq3mNp.rst | 4 - ...-06-26-13-39-11.gh-issue-152248.N2Rmaf.rst | 3 - ...6-06-26-15-00-00.gh-issue-38464.yDPjKH.rst | 3 - ...6-06-26-15-30-00.gh-issue-88758.Qw7nLp.rst | 4 - ...-06-26-15-41-34.gh-issue-152305.WnbbBc.rst | 2 - ...6-06-26-16-30-00.gh-issue-83274.Kx9mQv.rst | 3 - ...6-06-26-23-56-40.gh-issue-71880.782D31.rst | 5 - ...-06-27-12-30-00.gh-issue-133031.Na8Bit.rst | 3 - ...-06-27-17-19-09.gh-issue-151126.huUyOM.rst | 2 - ...6-06-28-11-00-40.gh-issue-78335.Kp3mWq.rst | 4 - ...-06-28-12-45-09.gh-issue-152356.Dr4w2Q.rst | 3 - ...-06-29-01-08-53.gh-issue-110357.QGWdZQ.rst | 6 - ...-06-29-09-45-00.gh-issue-152569.Kf7Lq2.rst | 3 - ...6-06-29-22-16-57.gh-issue-50966.Tq5mLp.rst | 3 - ...6-06-30-12-00-00.gh-issue-40038.qK7mGv.rst | 6 - ...-06-30-13-00-00.gh-issue-151842.OOM31g.rst | 2 - ...-06-30-21-40-00.gh-issue-152502.Kq3Vn7.rst | 5 - ...6-07-01-10-00-00.gh-issue-88574.Kz3wQm.rst | 4 - ...6-07-01-10-30-00.gh-issue-63121.Rm4tZp.rst | 7 - ...-07-01-12-00-00.gh-issue-108280.Nq8vTr.rst | 4 - ...-07-01-12-00-00.gh-issue-152718.pr0f1l.rst | 2 - ...-07-02-12-00-00.gh-issue-152847.PitKqc.rst | 3 - ...-07-02-13-30-00.gh-issue-152849.K9dRvP.rst | 2 - ...-07-02-19-21-15.gh-issue-152068.ThsmJU.rst | 1 - ...-07-02-22-19-53.gh-issue-150880.vPZ7jK.rst | 3 - ...-07-03-14-54-33.gh-issue-152951.u8tPCI.rst | 2 - ...-03-17-29-34.gh-issue-150579.0tLpQukIU.rst | 2 - ...-07-03-18-30-00.gh-issue-119592.mQr3Vx.rst | 11 - ...6-07-03-21-10-00.gh-issue-54930.hq09Er.rst | 5 - ...-07-04-11-14-06.gh-issue-152851.diYvTf.rst | 2 - ...-07-04-13-00-00.gh-issue-135661.CIkADG.rst | 3 - ...-07-04-20-28-51.gh-issue-153037.XUSp_g.rst | 3 - ...-07-05-10-24-30.gh-issue-143921.wQx3Tn.rst | 4 - ...-07-05-12-00-00.gh-issue-153056.tMpLat.rst | 4 - ...-07-05-14-30-00.gh-issue-153062.teeFT1.rst | 2 - ...-07-05-16-09-31.gh-issue-153068.huY9Jh.rst | 2 - ...07-06-12-00-00.gh-issue-153200.isqrtLt.rst | 3 - ...-07-07-02-26-43.gh-issue-153210.LUXIcm.rst | 1 - ...-07-07-13-31-52.gh-issue-148286.-qu-em.rst | 3 - ...-07-07-17-50-54.gh-issue-143990.FoNtCf.rst | 4 - ...-07-07-22-06-52.gh-issue-153293.0DvYdc.rst | 2 - ...-07-08-01-03-17.gh-issue-153292.oHDt3l.rst | 1 - ...-07-08-01-47-15.gh-issue-153083.XbKZCp.rst | 2 - ...-07-08-21-15-00.gh-issue-153333.Kp3mZq.rst | 3 - ...-07-09-00-00-00.gh-issue-153406.vyMmB6.rst | 3 - ...-07-09-14-00-00.gh-issue-153417.Bw7Rq2.rst | 3 - ...-07-09-15-18-23.gh-issue-151292.f4NQSW.rst | 5 - ...6-07-12-00-00-00.gh-issue-85943.8f906e.rst | 4 - ...-07-13-10-27-08.gh-issue-153658.A6o4n5.rst | 2 - ...-07-14-19-45-21.gh-issue-153695.UYdZJZ.rst | 2 - ...-01-16-11-58-19.gh-issue-143927.aviFeG.rst | 2 - ...05-30-00-00-00.gh-issue-150743.httpdos.rst | 7 - ...-06-10-13-08-19.gh-issue-151558.mL74i2.rst | 3 - ...-06-23-13-28-16.gh-issue-151981.xBHEcU.rst | 2 - ...-06-23-14-19-30.gh-issue-151987.8mNIMf.rst | 2 - ...-06-25-20-44-20.gh-issue-152216.VxiK5y.rst | 1 - ...-07-04-17-00-00.gh-issue-153030.RovkP6.rst | 3 - ...-06-16-05-11-38.gh-issue-151096.Kq3Lp9.rst | 2 - ...-06-22-19-45-00.gh-issue-151626.K9pZ2x.rst | 5 - ...-04-21-16-07-11.gh-issue-140146.TAcUHA.rst | 3 - ...-07-17-23-20-27.gh-issue-152023.QAAgdj.rst | 2 - ...-07-17-23-35-36.gh-issue-124111.dmM4lk.rst | 1 - README.rst | 2 +- 149 files changed, 2195 insertions(+), 431 deletions(-) create mode 100644 Misc/NEWS.d/3.15.0b4.rst delete mode 100644 Misc/NEWS.d/next/Build/2026-06-28-16-17-55.gh-issue-152502.6SNqMg.rst delete mode 100644 Misc/NEWS.d/next/Build/2026-07-01-17-53-00.gh-issue-152769.Kp7mQ2.rst delete mode 100644 Misc/NEWS.d/next/Build/2026-07-02-16-25-13.gh-issue-152870.oh9eD1.rst delete mode 100644 Misc/NEWS.d/next/Build/2026-07-09-22-45-00.gh-issue-153438.Qr7N2p.rst delete mode 100644 Misc/NEWS.d/next/Build/2026-07-11-07-26-16.gh-issue-126877.Zt7Kq2.rst delete mode 100644 Misc/NEWS.d/next/C_API/2026-07-08-00-38-32.gh-issue-153300.lVoWyR.rst delete mode 100644 Misc/NEWS.d/next/C_API/2026-07-09-16-46-30.gh-issue-145633.jyNwAs.rst delete mode 100644 Misc/NEWS.d/next/C_API/2026-07-09-17-33-29.gh-issue-152132.Ma8MJZ.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-04-21-15-07-03.gh-issue-148825.AbJzmZ.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-04-29-15-10-59.gh-issue-149162.BPPyrq.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-05-11-15-58-23.gh-issue-149689.9Ht49z.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-05-26-00-06-30.gh-issue-150411.u-d-_5.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-05-29-17-51-11.gh-issue-144774.jPcixe.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-03-16-27-00.gh-issue-150858.j2dSkD.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-03-21-14-28.gh-issue-150459.qpsCEl.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-06-20-15-08.gh-issue-151029.A33CKK.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-17-16-46-07.gh-issue-151126.vhTL0T.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-18-00-00-00.gh-issue-151644.5cFffN.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-18-16-00-10.gh-issue-151126.tBqn6I.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-19-16-40-01.gh-issue-151619.35yyJW.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-20-10-01-26.gh-issue-151672.K-w7j0.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-21-16-00-00.gh-issue-151773.mN4kRt.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-22-14-48-22.gh-issue-151912.YcxfnU.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-23-12-03-55.gh-issue-151763.K7QfWG.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-23-19-50-22.gh-issue-152020.DTKXjR.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-23-23-48-54.gh-issue-151763.Eu8pYQ.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-24-13-36-31.gh-issue-151722.lWKfE1.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-25-21-34-15.gh-issue-152228.a6K14K.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-26-05-49-13.gh-issue-152235.YU20T9.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-26-22-03-16.gh-issue-152235.ZKWiWk.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-27-10-05-12.gh-issue-152375.L-ZBk6.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-28-14-31-03.gh-issue-152492._09Zee.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-28-14-39-05.gh-issue-152405.-_3YRo.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-29-23-29-14.gh-issue-152635.O21J0O.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-30-14-00-00.gh-issue-152682.yId7e5.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-07-07-04-16-48.gh-issue-153205.5fE8QZ.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-07-08-13-23-11.gh-issue-153298.wvcXxN.rst delete mode 100644 Misc/NEWS.d/next/IDLE/2026-06-28-06-46-46.gh-issue-85320.Hq2vKn.rst delete mode 100644 Misc/NEWS.d/next/IDLE/2026-07-01-00-00-00.gh-issue-66331.wMcLaS.rst delete mode 100644 Misc/NEWS.d/next/IDLE/2026-07-01-00-15-58.gh-issue-152728.yxIhMN.rst delete mode 100644 Misc/NEWS.d/next/IDLE/2026-07-01-12-00-00.gh-issue-71956.rPlAlL.rst delete mode 100644 Misc/NEWS.d/next/IDLE/2026-07-01-14-00-00.gh-issue-89360.mUlTiC.rst delete mode 100644 Misc/NEWS.d/next/IDLE/2026-07-01-15-00-00.gh-issue-134300.iDlPaT.rst delete mode 100644 Misc/NEWS.d/next/IDLE/2026-07-01-16-00-00.gh-issue-80504.gReP.rst delete mode 100644 Misc/NEWS.d/next/IDLE/2026-07-01-17-00-00.gh-issue-65339.oUtTxt.rst delete mode 100644 Misc/NEWS.d/next/IDLE/2026-07-01-18-00-00.gh-issue-83653.cFgInt.rst delete mode 100644 Misc/NEWS.d/next/IDLE/2026-07-01-19-00-00.gh-issue-82183.rNsTrt.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-06-12-21-31-02.gh-issue-105708.5fFwP8.rst delete mode 100644 Misc/NEWS.d/next/Library/2025-09-05-20-50-35.gh-issue-79638.Y-JfaH.rst delete mode 100644 Misc/NEWS.d/next/Library/2025-11-02-05-28-56.gh-issue-115634.JbcNnF.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-02-11-16-47-27.gh-issue-140729.2uTPQp.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-03-26-00-00-00.gh-issue-47005.xxc89c.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-05-18-12-42-31.gh-issue-149816.F98iME.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-05-31-14-39-25.gh-issue-150641.LLIhd1.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-06-03-19-35-32.gh-issue-150583.dedI24.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-06-06-06-29-17.gh-issue-150994.I2119M.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-06-11-06-56-31.gh-issue-150994.gd1wVw.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-06-12-00-00-00.gh-issue-151416.spawnUA.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-06-15-15-32-36.gh-issue-151497.1cfmSV.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-06-17-00-00-00.gh-issue-148660.odcopy.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-06-17-22-31-57.gh-issue-151613.n0nua1.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-06-18-12-48-03.gh-issue-151640.R4c3Fx.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-06-18-23-59-46.gh-issue-151596.5ma144.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-06-20-21-15-13.gh-issue-151814.OIbgsO.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-06-21-15-50-24.gh-issue-86165.dyac1G.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-06-23-13-27-14.gh-issue-126219.kOfv2g.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-06-23-17-14-04.gh-issue-127802.nGSxo6.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-06-24-10-46-35.gh-issue-152060.f2asrt.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-06-24-12-00-00.gh-issue-152052.yBssDE.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-06-24-12-00-00.gh-issue-152079.f1tzus.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-06-24-16-40-15.gh-issue-151378.iYWa_6.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-06-24-22-16-35.gh-issue-105895.hRkuEw.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-06-24-23-28-42.gh-issue-151669.tPUavQ.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-06-25-01-00-43.gh-issue-151763.wWeHBe.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-06-25-07-08-17.gh-issue-152157.dt5Ef0.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-06-25-10-07-54.gh-issue-152156.gscPU9.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-06-25-12-00-00.gh-issue-152212.Zk7Qm2.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-06-25-14-32-42.gh-issue-139145.kT9rmP.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-06-25-14-32-43.gh-issue-139816.Lq2vXa.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-06-25-20-00-00.gh-issue-151496.kMnT3x.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-06-26-12-50-26.gh-issue-152246.MfXMd1.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-06-26-13-10-00.gh-issue-80937.Hq3mNp.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-06-26-13-39-11.gh-issue-152248.N2Rmaf.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-06-26-15-00-00.gh-issue-38464.yDPjKH.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-06-26-15-30-00.gh-issue-88758.Qw7nLp.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-06-26-15-41-34.gh-issue-152305.WnbbBc.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-06-26-16-30-00.gh-issue-83274.Kx9mQv.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-06-26-23-56-40.gh-issue-71880.782D31.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-06-27-12-30-00.gh-issue-133031.Na8Bit.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-06-27-17-19-09.gh-issue-151126.huUyOM.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-06-28-11-00-40.gh-issue-78335.Kp3mWq.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-06-28-12-45-09.gh-issue-152356.Dr4w2Q.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-06-29-01-08-53.gh-issue-110357.QGWdZQ.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-06-29-09-45-00.gh-issue-152569.Kf7Lq2.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-06-29-22-16-57.gh-issue-50966.Tq5mLp.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-06-30-12-00-00.gh-issue-40038.qK7mGv.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-06-30-13-00-00.gh-issue-151842.OOM31g.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-06-30-21-40-00.gh-issue-152502.Kq3Vn7.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-07-01-10-00-00.gh-issue-88574.Kz3wQm.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-07-01-10-30-00.gh-issue-63121.Rm4tZp.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-07-01-12-00-00.gh-issue-108280.Nq8vTr.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-07-01-12-00-00.gh-issue-152718.pr0f1l.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-07-02-12-00-00.gh-issue-152847.PitKqc.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-07-02-13-30-00.gh-issue-152849.K9dRvP.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-07-02-19-21-15.gh-issue-152068.ThsmJU.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-07-02-22-19-53.gh-issue-150880.vPZ7jK.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-07-03-14-54-33.gh-issue-152951.u8tPCI.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-07-03-17-29-34.gh-issue-150579.0tLpQukIU.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-07-03-18-30-00.gh-issue-119592.mQr3Vx.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-07-03-21-10-00.gh-issue-54930.hq09Er.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-07-04-11-14-06.gh-issue-152851.diYvTf.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-07-04-13-00-00.gh-issue-135661.CIkADG.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-07-04-20-28-51.gh-issue-153037.XUSp_g.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-07-05-10-24-30.gh-issue-143921.wQx3Tn.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-07-05-12-00-00.gh-issue-153056.tMpLat.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-07-05-14-30-00.gh-issue-153062.teeFT1.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-07-05-16-09-31.gh-issue-153068.huY9Jh.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-07-06-12-00-00.gh-issue-153200.isqrtLt.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-07-07-02-26-43.gh-issue-153210.LUXIcm.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-07-07-13-31-52.gh-issue-148286.-qu-em.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-07-07-17-50-54.gh-issue-143990.FoNtCf.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-07-07-22-06-52.gh-issue-153293.0DvYdc.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-07-08-01-03-17.gh-issue-153292.oHDt3l.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-07-08-01-47-15.gh-issue-153083.XbKZCp.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-07-08-21-15-00.gh-issue-153333.Kp3mZq.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-07-09-00-00-00.gh-issue-153406.vyMmB6.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-07-09-14-00-00.gh-issue-153417.Bw7Rq2.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-07-09-15-18-23.gh-issue-151292.f4NQSW.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-07-12-00-00-00.gh-issue-85943.8f906e.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-07-13-10-27-08.gh-issue-153658.A6o4n5.rst delete mode 100644 Misc/NEWS.d/next/Library/2026-07-14-19-45-21.gh-issue-153695.UYdZJZ.rst delete mode 100644 Misc/NEWS.d/next/Security/2026-01-16-11-58-19.gh-issue-143927.aviFeG.rst delete mode 100644 Misc/NEWS.d/next/Security/2026-05-30-00-00-00.gh-issue-150743.httpdos.rst delete mode 100644 Misc/NEWS.d/next/Security/2026-06-10-13-08-19.gh-issue-151558.mL74i2.rst delete mode 100644 Misc/NEWS.d/next/Security/2026-06-23-13-28-16.gh-issue-151981.xBHEcU.rst delete mode 100644 Misc/NEWS.d/next/Security/2026-06-23-14-19-30.gh-issue-151987.8mNIMf.rst delete mode 100644 Misc/NEWS.d/next/Security/2026-06-25-20-44-20.gh-issue-152216.VxiK5y.rst delete mode 100644 Misc/NEWS.d/next/Security/2026-07-04-17-00-00.gh-issue-153030.RovkP6.rst delete mode 100644 Misc/NEWS.d/next/Tests/2026-06-16-05-11-38.gh-issue-151096.Kq3Lp9.rst delete mode 100644 Misc/NEWS.d/next/Tests/2026-06-22-19-45-00.gh-issue-151626.K9pZ2x.rst delete mode 100644 Misc/NEWS.d/next/Windows/2026-04-21-16-07-11.gh-issue-140146.TAcUHA.rst delete mode 100644 Misc/NEWS.d/next/macOS/2026-07-17-23-20-27.gh-issue-152023.QAAgdj.rst delete mode 100644 Misc/NEWS.d/next/macOS/2026-07-17-23-35-36.gh-issue-124111.dmM4lk.rst diff --git a/Doc/library/concurrent.futures.rst b/Doc/library/concurrent.futures.rst index cadf841b43537e..bf17f0429d7f16 100644 --- a/Doc/library/concurrent.futures.rst +++ b/Doc/library/concurrent.futures.rst @@ -421,7 +421,7 @@ in a REPL or a lambda should not be expected to work. require the *fork* start method for :class:`ProcessPoolExecutor` you must explicitly pass ``mp_context=multiprocessing.get_context("fork")``. - .. versionchanged:: next + .. versionchanged:: 3.15 Fixed a deadlock (:gh:`115634`) where the executor could hang after a worker process exited upon reaching its *max_tasks_per_child* limit while tasks remained queued. diff --git a/Include/patchlevel.h b/Include/patchlevel.h index f597c49cfd398d..425ce233955cfd 100644 --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -24,10 +24,10 @@ #define PY_MINOR_VERSION 15 #define PY_MICRO_VERSION 0 #define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_BETA -#define PY_RELEASE_SERIAL 3 +#define PY_RELEASE_SERIAL 4 /* Version as a string */ -#define PY_VERSION "3.15.0b3+dev" +#define PY_VERSION "3.15.0b4" /*--end constants--*/ diff --git a/Lib/pydoc_data/module_docs.py b/Lib/pydoc_data/module_docs.py index 8611b1e7c47dd1..e10baa0f29cace 100644 --- a/Lib/pydoc_data/module_docs.py +++ b/Lib/pydoc_data/module_docs.py @@ -1,4 +1,4 @@ -# Autogenerated by Sphinx on Tue Jun 23 12:35:44 2026 +# Autogenerated by Sphinx on Sat Jul 18 09:57:06 2026 # as part of the release process. module_docs = { diff --git a/Lib/pydoc_data/topics.py b/Lib/pydoc_data/topics.py index 7016734651125d..72915fa49f2baf 100644 --- a/Lib/pydoc_data/topics.py +++ b/Lib/pydoc_data/topics.py @@ -1,4 +1,4 @@ -# Autogenerated by Sphinx on Tue Jun 23 12:35:44 2026 +# Autogenerated by Sphinx on Sat Jul 18 09:57:06 2026 # as part of the release process. topics = { @@ -2063,12 +2063,12 @@ class with multiple inheritance will raise an error if one of the handler, the outer handler will not handle the exception.) When an exception has been assigned using "as target", it is cleared -at the end of the "except" clause. This is as if +at the end of the "except" clause. This is as if: except E as N: foo -was translated to +was translated to: except E as N: try: @@ -2116,8 +2116,8 @@ class with multiple inheritance will raise an error if one of the type for matching is mandatory in the case of "except*", so "except*:" is a syntax error. The type is interpreted as in the case of "except", but matching is performed on the exceptions contained in the group -that is being handled. An "TypeError" is raised if a matching type is -a subclass of "BaseExceptionGroup", because that would have ambiguous +that is being handled. A "TypeError" is raised if a matching type is a +subclass of "BaseExceptionGroup", because that would have ambiguous semantics. When an exception group is raised in the try block, each "except*" @@ -2132,7 +2132,7 @@ class with multiple inheritance will raise an error if one of the After all "except*" clauses execute, the group of unhandled exceptions is merged with any exceptions that were raised or re-raised from -within "except*" clauses. This merged exception group propagates on.: +within "except*" clauses. This merged exception group propagates on: >>> try: ... raise ExceptionGroup("eg", @@ -3018,7 +3018,7 @@ def func(): pass by appending an item to a list), the default parameter value is in effect modified. This is generally not what was intended. A way around this is to use "None" as the default, and explicitly test for -it in the body of the function, e.g.: +it in the body of the function, for example: def whats_on_the_telly(penguin=None): if penguin is None: @@ -6404,7 +6404,7 @@ def func(): pass by appending an item to a list), the default parameter value is in effect modified. This is generally not what was intended. A way around this is to use "None" as the default, and explicitly test for -it in the body of the function, e.g.: +it in the body of the function, for example: def whats_on_the_telly(penguin=None): if penguin is None: @@ -7335,6 +7335,606 @@ def <lambda>(parameters): The formal grammar for list displays is: list: '[' [flexible_expression_list] ']' +''', + 'match': r'''The "match" statement +********************* + +Added in version 3.10. + +The match statement is used for pattern matching. Syntax: + + match_stmt: 'match' subject_expr ":" NEWLINE INDENT case_block+ DEDENT + subject_expr: flexible_expression "," [flexible_expression_list [',']] + | assignment_expression + case_block: 'case' patterns [guard] ":" suite + +Note: + + This section uses single quotes to denote soft keywords. + +Pattern matching takes a pattern as input (following "case") and a +subject value (following "match"). The pattern (which may contain +subpatterns) is matched against the subject value. The outcomes are: + +* A match success or failure (also termed a pattern success or + failure). + +* Possible binding of matched values to a name. The prerequisites for + this are further discussed below. + +The "match" and "case" keywords are soft keywords. + +See also: + + * **PEP 634** – Structural Pattern Matching: Specification + + * **PEP 636** – Structural Pattern Matching: Tutorial + + +Overview +======== + +Here’s an overview of the logical flow of a match statement: + +1. The subject expression "subject_expr" is evaluated and a resulting + subject value obtained. If the subject expression contains a comma, + a tuple is constructed using the standard rules. + +2. Each pattern in a "case_block" is attempted to match with the + subject value. The specific rules for success or failure are + described below. The match attempt can also bind some or all of the + standalone names within the pattern. The precise pattern binding + rules vary per pattern type and are specified below. **Name + bindings made during a successful pattern match outlive the + executed block and can be used after the match statement**. + + Note: + + During failed pattern matches, some subpatterns may succeed. Do + not rely on bindings being made for a failed match. Conversely, + do not rely on variables remaining unchanged after a failed + match. The exact behavior is dependent on implementation and may + vary. This is an intentional decision made to allow different + implementations to add optimizations. + +3. If the pattern succeeds, the corresponding guard (if present) is + evaluated. In this case all name bindings are guaranteed to have + happened. + + * If the guard evaluates as true or is missing, the "block" inside + "case_block" is executed. + + * Otherwise, the next "case_block" is attempted as described above. + + * If there are no further case blocks, the match statement is + completed. + +Note: + + Users should generally never rely on a pattern being evaluated. + Depending on implementation, the interpreter may cache values or use + other optimizations which skip repeated evaluations. + +A sample match statement: + + >>> flag = False + >>> match (100, 200): + ... case (100, 300): # Mismatch: 200 != 300 + ... print('Case 1') + ... case (100, 200) if flag: # Successful match, but guard fails + ... print('Case 2') + ... case (100, y): # Matches and binds y to 200 + ... print(f'Case 3, y: {y}') + ... case _: # Pattern not attempted + ... print('Case 4, I match anything!') + ... + Case 3, y: 200 + +In this case, "if flag" is a guard. Read more about that in the next +section. + + +Guards +====== + + guard: "if" assignment_expression + +A "guard" (which is part of the "case") must succeed for code inside +the "case" block to execute. It takes the form: "if" followed by an +expression. + +The logical flow of a "case" block with a "guard" follows: + +1. Check that the pattern in the "case" block succeeded. If the + pattern failed, the "guard" is not evaluated and the next "case" + block is checked. + +2. If the pattern succeeded, evaluate the "guard". + + * If the "guard" condition evaluates as true, the case block is + selected. + + * If the "guard" condition evaluates as false, the case block is + not selected. + + * If the "guard" raises an exception during evaluation, the + exception bubbles up. + +Guards are allowed to have side effects as they are expressions. +Guard evaluation must proceed from the first to the last case block, +one at a time, skipping case blocks whose pattern(s) don’t all +succeed. (I.e., guard evaluation must happen in order.) Guard +evaluation must stop once a case block is selected. + + +Irrefutable Case Blocks +======================= + +An irrefutable case block is a match-all case block. A match +statement may have at most one irrefutable case block, and it must be +last. + +A case block is considered irrefutable if it has no guard and its +pattern is irrefutable. A pattern is considered irrefutable if we can +prove from its syntax alone that it will always succeed. Only the +following patterns are irrefutable: + +* AS Patterns whose left-hand side is irrefutable + +* OR Patterns containing at least one irrefutable pattern + +* Capture Patterns + +* Wildcard Patterns + +* parenthesized irrefutable patterns + + +Patterns +======== + +Note: + + This section uses grammar notations beyond standard EBNF: + + * the notation "SEP.RULE+" is shorthand for "RULE (SEP RULE)*" + + * the notation "!RULE" is shorthand for a negative lookahead + assertion + +The top-level syntax for "patterns" is: + + patterns: open_sequence_pattern | pattern + pattern: as_pattern | or_pattern + closed_pattern: | literal_pattern + | capture_pattern + | wildcard_pattern + | value_pattern + | group_pattern + | sequence_pattern + | mapping_pattern + | class_pattern + +The descriptions below will include a description “in simple terms” of +what a pattern does for illustration purposes (credits to Raymond +Hettinger for a document that inspired most of the descriptions). Note +that these descriptions are purely for illustration purposes and **may +not** reflect the underlying implementation. Furthermore, they do not +cover all valid forms. + + +OR Patterns +----------- + +An OR pattern is two or more patterns separated by vertical bars "|". +Syntax: + + or_pattern: "|".closed_pattern+ + +Only the final subpattern may be irrefutable, and each subpattern must +bind the same set of names to avoid ambiguity. + +An OR pattern matches each of its subpatterns in turn to the subject +value, until one succeeds. The OR pattern is then considered +successful. Otherwise, if none of the subpatterns succeed, the OR +pattern fails. + +In simple terms, "P1 | P2 | ..." will try to match "P1", if it fails +it will try to match "P2", succeeding immediately if any succeeds, +failing otherwise. + + +AS Patterns +----------- + +An AS pattern matches an OR pattern on the left of the "as" keyword +against a subject. Syntax: + + as_pattern: or_pattern "as" capture_pattern + +If the OR pattern fails, the AS pattern fails. Otherwise, the AS +pattern binds the subject to the name on the right of the as keyword +and succeeds. "capture_pattern" cannot be a "_". + +In simple terms "P as NAME" will match with "P", and on success it +will set "NAME = <subject>". + + +Literal Patterns +---------------- + +A literal pattern corresponds to most literals in Python. Syntax: + + literal_pattern: signed_number + | signed_number "+" NUMBER + | signed_number "-" NUMBER + | strings + | "None" + | "True" + | "False" + signed_number: ["+" | "-"] NUMBER + +The rule "strings" and the token "NUMBER" are defined in the standard +Python grammar. Triple-quoted strings are supported. Raw strings and +byte strings are supported. f-strings and t-strings are not +supported. + +The forms "signed_number '+' NUMBER" and "signed_number '-' NUMBER" +are for expressing complex numbers; they require a real number on the +left and an imaginary number on the right. E.g. "3 + 4j". + +In simple terms, "LITERAL" will succeed only if "<subject> == +LITERAL". For the singletons "None", "True" and "False", the "is" +operator is used. + + +Capture Patterns +---------------- + +A capture pattern binds the subject value to a name. Syntax: + + capture_pattern: !'_' NAME + +A single underscore "_" is not a capture pattern (this is what "!'_'" +expresses). It is instead treated as a "wildcard_pattern". + +In a given pattern, a given name can only be bound once. E.g. "case +x, x: ..." is invalid while "case [x] | x: ..." is allowed. + +Capture patterns always succeed. The binding follows scoping rules +established by the assignment expression operator in **PEP 572**; the +name becomes a local variable in the closest containing function scope +unless there’s an applicable "global" or "nonlocal" statement. + +In simple terms "NAME" will always succeed and it will set "NAME = +<subject>". + + +Wildcard Patterns +----------------- + +A wildcard pattern always succeeds (matches anything) and binds no +name. Syntax: + + wildcard_pattern: '_' + +"_" is a soft keyword within any pattern, but only within patterns. +It is an identifier, as usual, even within "match" subject +expressions, "guard"s, and "case" blocks. + +In simple terms, "_" will always succeed. + + +Value Patterns +-------------- + +A value pattern represents a named value in Python. Syntax: + + value_pattern: attr + attr: name_or_attr "." NAME + name_or_attr: attr | NAME + +The dotted name in the pattern is looked up using standard Python name +resolution rules. The pattern succeeds if the value found compares +equal to the subject value (using the "==" equality operator). + +In simple terms "NAME1.NAME2" will succeed only if "<subject> == +NAME1.NAME2" + +Note: + + If the same value occurs multiple times in the same match statement, + the interpreter may cache the first value found and reuse it rather + than repeat the same lookup. This cache is strictly tied to a given + execution of a given match statement. + + +Group Patterns +-------------- + +A group pattern allows users to add parentheses around patterns to +emphasize the intended grouping. Otherwise, it has no additional +syntax. Syntax: + + group_pattern: "(" pattern ")" + +In simple terms "(P)" has the same effect as "P". + + +Sequence Patterns +----------------- + +A sequence pattern contains several subpatterns to be matched against +sequence elements. The syntax is similar to the unpacking of a list or +tuple. + + sequence_pattern: "[" [maybe_sequence_pattern] "]" + | "(" [open_sequence_pattern] ")" + open_sequence_pattern: maybe_star_pattern "," [maybe_sequence_pattern] + maybe_sequence_pattern: ",".maybe_star_pattern+ ","? + maybe_star_pattern: star_pattern | pattern + star_pattern: "*" (capture_pattern | wildcard_pattern) + +There is no difference if parentheses or square brackets are used for +sequence patterns (i.e. "(...)" vs "[...]" ). + +Note: + + A single pattern enclosed in parentheses without a trailing comma + (e.g. "(3 | 4)") is a group pattern. While a single pattern enclosed + in square brackets (e.g. "[3 | 4]") is still a sequence pattern. + +At most one star subpattern may be in a sequence pattern. The star +subpattern may occur in any position. If no star subpattern is +present, the sequence pattern is a fixed-length sequence pattern; +otherwise it is a variable-length sequence pattern. + +The following is the logical flow for matching a sequence pattern +against a subject value: + +1. If the subject value is not a sequence [2], the sequence pattern + fails. + +2. If the subject value is an instance of "str", "bytes" or + "bytearray" the sequence pattern fails. + +3. The subsequent steps depend on whether the sequence pattern is + fixed or variable-length. + + If the sequence pattern is fixed-length: + + 1. If the length of the subject sequence is not equal to the number + of subpatterns, the sequence pattern fails + + 2. Subpatterns in the sequence pattern are matched to their + corresponding items in the subject sequence from left to right. + Matching stops as soon as a subpattern fails. If all + subpatterns succeed in matching their corresponding item, the + sequence pattern succeeds. + + Otherwise, if the sequence pattern is variable-length: + + 1. If the length of the subject sequence is less than the number of + non-star subpatterns, the sequence pattern fails. + + 2. The leading non-star subpatterns are matched to their + corresponding items as for fixed-length sequences. + + 3. If the previous step succeeds, the star subpattern matches a + list formed of the remaining subject items, excluding the + remaining items corresponding to non-star subpatterns following + the star subpattern. + + 4. Remaining non-star subpatterns are matched to their + corresponding subject items, as for a fixed-length sequence. + + Note: + + The length of the subject sequence is obtained via "len()" (i.e. + via the "__len__()" protocol). This length may be cached by the + interpreter in a similar manner as value patterns. + +In simple terms "[P1, P2, P3," … ", P<N>]" matches only if all the +following happens: + +* check "<subject>" is a sequence + +* "len(subject) == <N>" + +* "P1" matches "<subject>[0]" (note that this match can also bind + names) + +* "P2" matches "<subject>[1]" (note that this match can also bind + names) + +* … and so on for the corresponding pattern/element. + + +Mapping Patterns +---------------- + +A mapping pattern contains one or more key-value patterns. The syntax +is similar to the construction of a dictionary. Syntax: + + mapping_pattern: "{" [items_pattern] "}" + items_pattern: ",".key_value_pattern+ ","? + key_value_pattern: (literal_pattern | value_pattern) ":" pattern + | double_star_pattern + double_star_pattern: "**" capture_pattern + +At most one double star pattern may be in a mapping pattern. The +double star pattern must be the last subpattern in the mapping +pattern. + +Duplicate keys in mapping patterns are disallowed. Duplicate literal +keys will raise a "SyntaxError". Two keys that otherwise have the same +value will raise a "ValueError" at runtime. + +The following is the logical flow for matching a mapping pattern +against a subject value: + +1. If the subject value is not a mapping [3],the mapping pattern + fails. + +2. If every key given in the mapping pattern is present in the subject + mapping, and the pattern for each key matches the corresponding + item of the subject mapping, the mapping pattern succeeds. + +3. If duplicate keys are detected in the mapping pattern, the pattern + is considered invalid. A "SyntaxError" is raised for duplicate + literal values; or a "ValueError" for named keys of the same value. + +Note: + + Key-value pairs are matched using the two-argument form of the + mapping subject’s "get()" method. Matched key-value pairs must + already be present in the mapping, and not created on-the-fly via + "__missing__()" or "__getitem__()". + +In simple terms "{KEY1: P1, KEY2: P2, ... }" matches only if all the +following happens: + +* check "<subject>" is a mapping + +* "KEY1 in <subject>" + +* "P1" matches "<subject>[KEY1]" + +* … and so on for the corresponding KEY/pattern pair. + + +Class Patterns +-------------- + +A class pattern represents a class and its positional and keyword +arguments (if any). Syntax: + + class_pattern: name_or_attr "(" [pattern_arguments ","?] ")" + pattern_arguments: positional_patterns ["," keyword_patterns] + | keyword_patterns + positional_patterns: ",".pattern+ + keyword_patterns: ",".keyword_pattern+ + keyword_pattern: NAME "=" pattern + +The same keyword should not be repeated in class patterns. + +The following is the logical flow for matching a class pattern against +a subject value: + +1. If "name_or_attr" is not an instance of the builtin "type" , raise + "TypeError". + +2. If the subject value is not an instance of "name_or_attr" (tested + via "isinstance()"), the class pattern fails. + +3. If no pattern arguments are present, the pattern succeeds. + Otherwise, the subsequent steps depend on whether keyword or + positional argument patterns are present. + + For a number of built-in types (specified below), a single + positional subpattern is accepted which will match the entire + subject; for these types keyword patterns also work as for other + types. + + If only keyword patterns are present, they are processed as + follows, one by one: + + 1. The keyword is looked up as an attribute on the subject. + + * If this raises an exception other than "AttributeError", the + exception bubbles up. + + * If this raises "AttributeError", the class pattern has failed. + + * Else, the subpattern associated with the keyword pattern is + matched against the subject’s attribute value. If this fails, + the class pattern fails; if this succeeds, the match proceeds + to the next keyword. + + 2. If all keyword patterns succeed, the class pattern succeeds. + + If any positional patterns are present, they are converted to + keyword patterns using the "__match_args__" attribute on the class + "name_or_attr" before matching: + + 1. The equivalent of "getattr(cls, "__match_args__", ())" is + called. + + * If this raises an exception, the exception bubbles up. + + * If the returned value is not a tuple, the conversion fails and + "TypeError" is raised. + + * If there are more positional patterns than + "len(cls.__match_args__)", "TypeError" is raised. + + * Otherwise, positional pattern "i" is converted to a keyword + pattern using "__match_args__[i]" as the keyword. + "__match_args__[i]" must be a string; if not "TypeError" is + raised. + + * If there are duplicate keywords, "TypeError" is raised. + + See also: + + Customizing positional arguments in class pattern matching + + 2. Once all positional patterns have been converted to keyword + patterns, the match proceeds as if there were only keyword + patterns. + + For the following built-in types the handling of positional + subpatterns is different: + + * "bool" + + * "bytearray" + + * "bytes" + + * "dict" + + * "float" + + * "frozendict" + + * "frozenset" + + * "int" + + * "list" + + * "set" + + * "str" + + * "tuple" + + These classes accept a single positional argument, and the pattern + there is matched against the whole object rather than an attribute. + For example "int(0|1)" matches the value "0", but not the value + "0.0". + +In simple terms "CLS(P1, attr=P2)" matches only if the following +happens: + +* "isinstance(<subject>, CLS)" + +* convert "P1" to a keyword pattern using "CLS.__match_args__" + +* For each keyword argument "attr=P2": + + * "hasattr(<subject>, "attr")" + + * "P2" matches "<subject>.attr" + +* … and so on for the corresponding keyword argument/pattern pair. + +See also: + + * **PEP 634** – Structural Pattern Matching: Specification + + * **PEP 636** – Structural Pattern Matching: Tutorial ''', 'naming': r'''Naming and binding ****************** @@ -12106,12 +12706,12 @@ class is used in a class pattern with positional arguments, each handler, the outer handler will not handle the exception.) When an exception has been assigned using "as target", it is cleared -at the end of the "except" clause. This is as if +at the end of the "except" clause. This is as if: except E as N: foo -was translated to +was translated to: except E as N: try: @@ -12159,8 +12759,8 @@ class is used in a class pattern with positional arguments, each type for matching is mandatory in the case of "except*", so "except*:" is a syntax error. The type is interpreted as in the case of "except", but matching is performed on the exceptions contained in the group -that is being handled. An "TypeError" is raised if a matching type is -a subclass of "BaseExceptionGroup", because that would have ambiguous +that is being handled. A "TypeError" is raised if a matching type is a +subclass of "BaseExceptionGroup", because that would have ambiguous semantics. When an exception group is raised in the try block, each "except*" @@ -12175,7 +12775,7 @@ class is used in a class pattern with positional arguments, each After all "except*" clauses execute, the group of unhandled exceptions is merged with any exceptions that were raised or re-raised from -within "except*" clauses. This merged exception group propagates on.: +within "except*" clauses. This merged exception group propagates on: >>> try: ... raise ExceptionGroup("eg", @@ -14117,6 +14717,13 @@ class frozendict(iterable, /, **kwargs) signifying (respectively) the types of the frozendict’s keys and values. + classmethod fromkeys(iterable, value=None, /) + + Similar to "dict.fromkeys()", but call again the type + constructor with an initialized "frozendict" if the type is a + "frozendict" subclass or if the constructor returned a + "frozendict". + Added in version 3.15. ''', 'typesmethods': r'''Methods diff --git a/Misc/NEWS.d/3.15.0b4.rst b/Misc/NEWS.d/3.15.0b4.rst new file mode 100644 index 00000000000000..ebe9b3cc9e2941 --- /dev/null +++ b/Misc/NEWS.d/3.15.0b4.rst @@ -0,0 +1,1570 @@ +.. date: 2026-07-04-17-00-00 +.. gh-issue: 153030 +.. nonce: RovkP6 +.. release date: 2026-07-18 +.. section: Security + +Fixed quadratic complexity in incremental parsing of long unterminated +constructs (such as tags or comments) in :class:`html.parser.HTMLParser`, +which could be exploited for a denial of service. + +.. + +.. date: 2026-06-25-20-44-20 +.. gh-issue: 152216 +.. nonce: VxiK5y +.. section: Security + +Update bundled `libexpat <https://libexpat.github.io/>`_ to version 2.8.2. + +.. + +.. date: 2026-06-23-14-19-30 +.. gh-issue: 151987 +.. nonce: 8mNIMf +.. section: Security + +The :meth:`tarfile.TarFile.extract` method now applies the given filter when +it extracts a link target from the archive as a fallback. + +.. + +.. date: 2026-06-23-13-28-16 +.. gh-issue: 151981 +.. nonce: xBHEcU +.. section: Security + +In :mod:`tarfile`, seeking a stream now stops when end of the stream is +reached. + +.. + +.. date: 2026-06-10-13-08-19 +.. gh-issue: 151558 +.. nonce: mL74i2 +.. section: Security + +Fixed an vulnerability in the :mod:`tarfile` ``data`` and ``tar`` extraction +filters where crafted archives could create a symlink pointing outside the +destination directory. This was a bypass of :cve:`2025-4330`. + +.. + +.. date: 2026-05-30-00-00-00 +.. gh-issue: 150743 +.. nonce: httpdos +.. section: Security + +:mod:`http.client` now limits the number of chunked-response trailer lines +it will read to :attr:`~http.client.HTTPConnection.max_response_headers` +(100 by default), and the number of interim (1xx) responses it will skip to +100. A malicious or broken server could previously stream trailer lines or +``100 Continue`` responses forever, hanging the client even when a socket +timeout was in use. Reported by ``@YLChen-007`` via GHSA-w4q2-g22w-6fr4. + +.. + +.. date: 2026-01-16-11-58-19 +.. gh-issue: 143927 +.. nonce: aviFeG +.. section: Security + +Normalize all line endings (CR, CRLF, and LF) to LF+TAB when writing +multi-line configparser values. + +.. + +.. date: 2026-07-08-13-23-11 +.. gh-issue: 153298 +.. nonce: wvcXxN +.. section: Core and Builtins + +Fixes a data race in :class:`types.GenericAlias` ``__parameters__`` +initialization on free-threading builds. + +.. + +.. date: 2026-07-07-04-16-48 +.. gh-issue: 153205 +.. nonce: 5fE8QZ +.. section: Core and Builtins + +Fix a potential :exc:`SystemError` during vector calls when memory +allocation fails. A :exc:`MemoryError` is now raised instead. + +.. + +.. date: 2026-06-30-14-00-00 +.. gh-issue: 152682 +.. nonce: yId7e5 +.. section: Core and Builtins + +Fix NULL pointer dereference in :func:`compile` when a reserved name (e.g. +``__classdict__``) is used as a type parameter name and memory allocation +fails while formatting the error message. + +.. + +.. date: 2026-06-29-23-29-14 +.. gh-issue: 152635 +.. nonce: O21J0O +.. section: Core and Builtins + +Fix a crash caused when running out of memory creating a +:mod:`!_interpchannels` channel. Now a :exc:`MemoryError` is correctly +raised. + +.. + +.. date: 2026-06-28-14-39-05 +.. gh-issue: 152405 +.. nonce: -_3YRo +.. section: Core and Builtins + +Do not expose the internal mapping of :class:`types.MappingProxyType` when +performing rich-compare operations with non-stdlib types. Previously, it was +possible to mutate the internal mapping of a proxy there. Now we pass not +the original :class:`dict` instance, but its copy, when dealing with custom +types. + +.. + +.. date: 2026-06-28-14-31-03 +.. gh-issue: 152492 +.. nonce: _09Zee +.. section: Core and Builtins + +:type:`collections.OrderedDict` ``update`` method can now accept +:type:`frozendict` as an argument. + +.. + +.. date: 2026-06-27-10-05-12 +.. gh-issue: 152375 +.. nonce: L-ZBk6 +.. section: Core and Builtins + +Fix undefined behaviour when a :mod:`sys.monitoring` callback raised an +exception while the program was following a branch or loop. + +.. + +.. date: 2026-06-26-22-03-16 +.. gh-issue: 152235 +.. nonce: ZKWiWk +.. section: Core and Builtins + +Defer GC tracking of :meth:`set.intersection`, :meth:`set.difference`, +:meth:`set.symmetric_difference`, :meth:`set.union` and ``set.__sub__``. +Patch by Donghee Na. + +.. + +.. date: 2026-06-26-05-49-13 +.. gh-issue: 152235 +.. nonce: YU20T9 +.. section: Core and Builtins + +Defer GC tracking of a :class:`set` or :class:`frozenset` to the end of its +construction from iterable. Patch by Donghee Na. + +.. + +.. date: 2026-06-25-21-34-15 +.. gh-issue: 152228 +.. nonce: a6K14K +.. section: Core and Builtins + +Fix an assertion failure when python is built in a debug mode that happened +in :meth:`str.replace` under a limited memory situation. + +.. + +.. date: 2026-06-24-13-36-31 +.. gh-issue: 151722 +.. nonce: lWKfE1 +.. section: Core and Builtins + +:meth:`!frozendict.fromkeys` now only tracks the :class:`frozendict` in the +garbage collector once the dictionary is fully initialized. Patch by Donghee +Na and Victor Stinner. + +.. + +.. date: 2026-06-23-23-48-54 +.. gh-issue: 151763 +.. nonce: Eu8pYQ +.. section: Core and Builtins + +Fixes possible crash on :class:`types.CodeType` deallocation. + +.. + +.. date: 2026-06-23-19-50-22 +.. gh-issue: 152020 +.. nonce: DTKXjR +.. section: Core and Builtins + +On the free-threaded build, :func:`asyncio.all_tasks` no longer loses +eager-started tasks when called from a thread other than the one running the +event loop. + +.. + +.. date: 2026-06-23-12-03-55 +.. gh-issue: 151763 +.. nonce: K7QfWG +.. section: Core and Builtins + +Fix a potential crash in :func:`compile`, :func:`exec`, :func:`eval` and +:func:`ast.parse` when an allocation fails: the parser or compiler could +return without setting an exception. + +.. + +.. date: 2026-06-22-14-48-22 +.. gh-issue: 151912 +.. nonce: YcxfnU +.. section: Core and Builtins + +Fixed a crash in ``type()`` when selecting a metaclass whose ``tp_new`` slot +is ``NULL``. Such metaclasses are now rejected with ``TypeError`` instead of +causing a NULL pointer dereference. + +.. + +.. date: 2026-06-21-16-00-00 +.. gh-issue: 151773 +.. nonce: mN4kRt +.. section: Core and Builtins + +Fix a crash in :func:`contextvars.ContextVar.set` when memory allocation +fails. + +.. + +.. date: 2026-06-20-10-01-26 +.. gh-issue: 151672 +.. nonce: K-w7j0 +.. section: Core and Builtins + +Fix an inconsistency where calling ``__lazy_import__`` with a string +``fromlist`` would return a :class:`types.LazyImportType` that resolves to +the named member, rather than the module being imported. + +.. + +.. date: 2026-06-19-16-40-01 +.. gh-issue: 151619 +.. nonce: 35yyJW +.. section: Core and Builtins + +Fix an issue where using non-module global or builtin namespaces (such as +dictionaries passed to :func:`exec`) could cause cached global loads to +produce unresolved :ref:`lazy imports <lazy-imports>`. + +.. + +.. date: 2026-06-18-16-00-10 +.. gh-issue: 151126 +.. nonce: tBqn6I +.. section: Core and Builtins + +Fix a crash when sharing :class:`memoryview` objects between interpreters +fails due to running out of memory. It now raises a proper +:exc:`MemoryError`. + +.. + +.. date: 2026-06-18-00-00-00 +.. gh-issue: 151644 +.. nonce: 5cFffN +.. section: Core and Builtins + +Fix a data race in :func:`sys.setdlopenflags` and :func:`sys.getdlopenflags` +when called concurrently in the free-threaded build. The underlying +``_PyImport_GetDLOpenFlags`` and ``_PyImport_SetDLOpenFlags`` functions now +use atomic load/store operations. + +.. + +.. date: 2026-06-17-16-46-07 +.. gh-issue: 151126 +.. nonce: vhTL0T +.. section: Core and Builtins + +Avoid possible crash in ``_winapi.c`` where a device has no memory left. Now +it properly raises a :exc:`MemoryError`. Patch by Ivy Xu. + +.. + +.. date: 2026-06-06-20-15-08 +.. gh-issue: 151029 +.. nonce: A33CKK +.. section: Core and Builtins + +On Linux, fix :func:`sys.remote_exec` unable to find remote writable memory +when ``libpython`` replaced on disk. + +.. + +.. date: 2026-06-03-21-14-28 +.. gh-issue: 150459 +.. nonce: qpsCEl +.. section: Core and Builtins + +Fix :exc:`SyntaxError` error message for ``from x lazy import y``. Raise +:exc:`SyntaxWarning` on ``from . lazy import x`` (with whitespace between +the dots and a module named ``lazy``). + +.. + +.. date: 2026-06-03-16-27-00 +.. gh-issue: 150858 +.. nonce: j2dSkD +.. section: Core and Builtins + +Fix a data race while changing ``__qualname__`` of a type concurrently on +free-threaded builds. + +.. + +.. date: 2026-05-29-17-51-11 +.. gh-issue: 144774 +.. nonce: jPcixe +.. section: Core and Builtins + +Fix data race in :class:`BaseException` when an exception is copied while +being mutated. + +.. + +.. date: 2026-05-26-00-06-30 +.. gh-issue: 150411 +.. nonce: u-d-_5 +.. section: Core and Builtins + +Fix a data race in the free-threaded build when :func:`gc.get_count` reads +the young generation allocation count while another thread updates it. + +.. + +.. date: 2026-05-11-15-58-23 +.. gh-issue: 149689 +.. nonce: 9Ht49z +.. section: Core and Builtins + +Fix missing error propagation in parser action helpers when memory +allocation fails. Patch by Thomas Kowalski. + +.. + +.. date: 2026-04-29-15-10-59 +.. gh-issue: 149162 +.. nonce: BPPyrq +.. section: Core and Builtins + +Fix a potential deadlock in :c:func:`PyUnicode_InternFromString` and other +interning functions in the :term:`free-threaded build` when called from C++ +static local initializers. + +.. + +.. date: 2026-04-21-15-07-03 +.. gh-issue: 148825 +.. nonce: AbJzmZ +.. section: Core and Builtins + +Fix build error if specialization is disabled. + +.. + +.. date: 2026-07-14-19-45-21 +.. gh-issue: 153695 +.. nonce: UYdZJZ +.. section: Library + +Hashing a :class:`sqlite3.Row` that contains an unhashable value now raises +:exc:`TypeError` instead of :exc:`SystemError`. Patch by tonghuaroot. + +.. + +.. date: 2026-07-13-10-27-08 +.. gh-issue: 153658 +.. nonce: A6o4n5 +.. section: Library + +Fix :meth:`sqlite3.Connection.iterdump` raising +:exc:`sqlite3.OperationalError` when a table name contains a single quote. +Patch by tonghuaroot. + +.. + +.. date: 2026-07-12-00-00-00 +.. gh-issue: 85943 +.. nonce: 8f906e +.. section: Library + +Fix :mod:`struct` functions raising :exc:`BytesWarning` under the ``-bb`` +command line option when a :class:`str` format is used after an equal +:class:`bytes` format (or vice versa). The internal format cache no longer +mixes :class:`str` and :class:`bytes` keys. + +.. + +.. date: 2026-07-09-15-18-23 +.. gh-issue: 151292 +.. nonce: f4NQSW +.. section: Library + +Store the sample count in :mod:`profiling.sampling` binary format, as a +64-bit integer, widening from previously used 32-bit integer. This breaks +the existing recordings. Long or thread-heavy profiling sessions will no +longer fail because of :exc:`OverflowError`. Patch by Maurycy +Pawłowski-Wieroński. + +.. + +.. date: 2026-07-09-14-00-00 +.. gh-issue: 153417 +.. nonce: Bw7Rq2 +.. section: Library + +Error messages from :meth:`imaplib.IMAP4.select` and +:meth:`imaplib.IMAP4.uid` no longer raise :exc:`BytesWarning` under +:option:`!-bb` when the mailbox or command argument is :class:`bytes`. + +.. + +.. date: 2026-07-09-00-00-00 +.. gh-issue: 153406 +.. nonce: vyMmB6 +.. section: Library + +:func:`email.utils.parsedate_to_datetime` now raises :exc:`ValueError` +instead of :exc:`OverflowError` when the parsed year or timezone offset is +out of range, matching its documented behavior. + +.. + +.. date: 2026-07-08-21-15-00 +.. gh-issue: 153333 +.. nonce: Kp3mZq +.. section: Library + +The ``readprofile`` method of :class:`tkinter.Tk` now reads the user's +profile scripts using the encoding declared in the file, instead of the +locale encoding. + +.. + +.. date: 2026-07-08-01-47-15 +.. gh-issue: 153083 +.. nonce: XbKZCp +.. section: Library + +Defer GC tracking of an :class:`array.array` to the end of its construction. +Patch by Donghee Na. + +.. + +.. date: 2026-07-08-01-03-17 +.. gh-issue: 153292 +.. nonce: oHDt3l +.. section: Library + +Fix data race in repr of :class:`threading.RLock` in free-threading build. + +.. + +.. date: 2026-07-07-22-06-52 +.. gh-issue: 153293 +.. nonce: 0DvYdc +.. section: Library + +Fix the live sampling profiler TUI keeping stale aggregated opcode +statistics after a stats reset. + +.. + +.. date: 2026-07-07-17-50-54 +.. gh-issue: 143990 +.. nonce: FoNtCf +.. section: Library + +A :class:`tkinter.font.Font` created from a named font, including by +:meth:`~tkinter.font.Font.copy`, now copies its configured options rather +than the options resolved by Tcl's ``font actual``, preserving a size +specified in pixels (a negative size). + +.. + +.. date: 2026-07-07-13-31-52 +.. gh-issue: 148286 +.. nonce: -qu-em +.. section: Library + +Fix undefined behavior in +:attr:`compression.zstd.ZstdDecompressor.unused_data` when a complete frame +was decompressed in a single call. + +.. + +.. date: 2026-07-07-02-26-43 +.. gh-issue: 153210 +.. nonce: LUXIcm +.. section: Library + +Fix crash on :mod:`array` import under a memory pressure. + +.. + +.. date: 2026-07-06-12-00-00 +.. gh-issue: 153200 +.. nonce: isqrtLt +.. section: Library + +Fix :func:`math.isqrt` returning an incorrect result for arguments not less +than 2**64 that are instances of an :class:`int` subclass with an overridden +comparison operator. + +.. + +.. date: 2026-07-05-16-09-31 +.. gh-issue: 153068 +.. nonce: huY9Jh +.. section: Library + +Fix :meth:`!cProfile.Profile.enable` to no longer overwrite errors from +:mod:`sys.monitoring`. + +.. + +.. date: 2026-07-05-14-30-00 +.. gh-issue: 153062 +.. nonce: teeFT1 +.. section: Library + +Fix a crash when concurrently iterating an :func:`itertools.tee` iterator on +the free-threaded build. + +.. + +.. date: 2026-07-05-12-00-00 +.. gh-issue: 153056 +.. nonce: tMpLat +.. section: Library + +Fix :class:`string.Template` raising a spurious :exc:`ValueError` when the +*pattern* attribute is a compiled regular expression object, which the +documentation allows. On the free-threaded build this also occurred as a +data race on the first concurrent use. + +.. + +.. date: 2026-07-05-10-24-30 +.. gh-issue: 143921 +.. nonce: wQx3Tn +.. section: Library + +Narrow the control character check in :mod:`imaplib` commands: only NUL, CR +and LF are now rejected. Other control characters are valid in quoted +strings and can occur in mailbox names returned by the server, so they are +now accepted and sent quoted. + +.. + +.. date: 2026-07-04-20-28-51 +.. gh-issue: 153037 +.. nonce: XUSp_g +.. section: Library + +Fix :class:`~compression.zstd.ZstdFile` raising :exc:`AttributeError` +instead of :exc:`io.UnsupportedOperation` when iterating over a file that is +not open for reading. + +.. + +.. date: 2026-07-04-13-00-00 +.. gh-issue: 135661 +.. nonce: CIkADG +.. section: Library + +Fix :class:`html.parser.HTMLParser`: an abruptly closed empty comment +(``<!-->`` or ``<!--->``) no longer extends up to a later ``-->`` in the +same :meth:`~html.parser.HTMLParser.feed` call. + +.. + +.. date: 2026-07-04-11-14-06 +.. gh-issue: 152851 +.. nonce: diYvTf +.. section: Library + +Prevent a crash when allocation fails while copying a :func:`BLAKE-2s/2b +<hashlib.blake2b>` object. Patch by Bénédikt Tran. + +.. + +.. date: 2026-07-03-21-10-00 +.. gh-issue: 54930 +.. nonce: hq09Er +.. section: Library + +Error responses of :class:`http.server.BaseHTTPRequestHandler` to malformed +request lines now include a status line and headers instead of being sent in +the bare HTTP/0.9 style. Only a valid HTTP/0.9 request (a two-word ``GET`` +request line) now receives an HTTP/0.9 style response. + +.. + +.. date: 2026-07-03-18-30-00 +.. gh-issue: 119592 +.. nonce: mQr3Vx +.. section: Library + +Fix :class:`concurrent.futures.ProcessPoolExecutor` stranding submitted work +forever when a worker process exited upon reaching its *max_tasks_per_child* +limit after :meth:`~concurrent.futures.Executor.shutdown` was called with +``wait=False``: a replacement worker is now spawned and the remaining work +executed as documented. If the executor has instead been garbage collected +without ``shutdown()`` (:gh:`152967`), or a replacement worker cannot be +started, the remaining futures now fail with +:exc:`~concurrent.futures.process.BrokenProcessPool` instead of never +resolving. A worker exit racing ``shutdown(wait=False)`` can also no longer +crash the executor management thread. + +.. + +.. date: 2026-07-03-17-29-34 +.. gh-issue: 150579 +.. nonce: 0tLpQukIU +.. section: Library + +:mod:`concurrent.futures` now uses lazy imports for its executor submodules +instead of a module ``__getattr__`` hook. + +.. + +.. date: 2026-07-03-14-54-33 +.. gh-issue: 152951 +.. nonce: u8tPCI +.. section: Library + +:class:`collections.deque` prevent rare crash when calling ``extend`` under +high memory pressure conditions. + +.. + +.. date: 2026-07-02-22-19-53 +.. gh-issue: 150880 +.. nonce: vPZ7jK +.. section: Library + +Normalize non-extended Windows paths before appending the wildcard used by +``os.listdir()`` and ``os.scandir()``, making paths with trailing spaces +behave consistently with other filesystem APIs. + +.. + +.. date: 2026-07-02-19-21-15 +.. gh-issue: 152068 +.. nonce: ThsmJU +.. section: Library + +Fixes a bug when a line was split (particularly on macOS Terminal.app) in +the middle of a colorized keyword, causing the ANSI Color Reset sequence +(ESC0m) to not be properly printed, causing the output to be colored when it +shouldn't + +.. + +.. date: 2026-07-02-13-30-00 +.. gh-issue: 152849 +.. nonce: K9dRvP +.. section: Library + +Out-of-range float and integer timestamps now raise :exc:`OverflowError` +with the same message. Patch by tonghuaroot. + +.. + +.. date: 2026-07-02-12-00-00 +.. gh-issue: 152847 +.. nonce: PitKqc +.. section: Library + +Reject a POSIX TZ transition rule with non-digit characters in the +day-of-year field in the pure-Python :mod:`zoneinfo` parser. Patch by +tonghuaroot. + +.. + +.. date: 2026-07-01-12-00-00 +.. gh-issue: 152718 +.. nonce: pr0f1l +.. section: Library + +Fix unbounded memory allocation in the :mod:`profiling.sampling` binary +profile reader when a file declares more string or frame entries than it +contains. + +.. + +.. date: 2026-07-01-12-00-00 +.. gh-issue: 108280 +.. nonce: Nq8vTr +.. section: Library + +Connecting :mod:`imaplib` to a server that does not send a valid IMAP4 +greeting (for example a POP3 server answering on the IMAP port) now raises +an error reporting the server's response instead of ``imaplib.IMAP4.error: +None``. + +.. + +.. date: 2026-07-01-10-30-00 +.. gh-issue: 63121 +.. nonce: Rm4tZp +.. section: Library + +:mod:`imaplib` now refreshes the cached capability list after a successful +:meth:`~imaplib.IMAP4.login` or :meth:`~imaplib.IMAP4.authenticate`, using +the ``CAPABILITY`` response sent by the server or, if none was sent, by +querying it, so that capabilities that become available only after +authentication (such as ``ENABLE`` on Gmail) are recognized. Capabilities +advertised in the server greeting are now also used, avoiding a redundant +``CAPABILITY`` command. + +.. + +.. date: 2026-07-01-10-00-00 +.. gh-issue: 88574 +.. nonce: Kz3wQm +.. section: Library + +:mod:`imaplib` no longer fails when a server sends a spurious blank line +after the counted data of a literal, including after a literal that +terminates a response (such as a mailbox name returned by ``LIST``). Such +blank lines are now skipped without swallowing the following line. + +.. + +.. date: 2026-06-30-21-40-00 +.. gh-issue: 152502 +.. nonce: Kq3Vn7 +.. section: Library + +Detect the :mod:`curses` mouse interface (:func:`~curses.getmouse`, the +``BUTTON*`` constants, and others) with a configure capability probe or +library macros instead of gating it on ncurses-specific macros. It is now +also available with other curses implementations that provide it, such as +NetBSD curses and PDCurses (the latter underpins ``windows-curses``). + +.. + +.. date: 2026-06-30-13-00-00 +.. gh-issue: 151842 +.. nonce: OOM31g +.. section: Library + +Fix a crash in :func:`!_interpreters.capture_exception` when +:exc:`MemoryError` happens. Patch by Amrutha Modela. + +.. + +.. date: 2026-06-30-12-00-00 +.. gh-issue: 40038 +.. nonce: qK7mGv +.. section: Library + +:mod:`imaplib` now again quotes command arguments when necessary, for +example mailbox names containing a space. Such quoting was inadvertently +disabled when the module was ported to Python 3, and the arguments are now +quoted according to the :rfc:`3501` grammar. For backward compatibility, an +argument already enclosed in double quotes is left unchanged, so code that +quotes arguments itself keeps working. + +.. + +.. date: 2026-06-29-22-16-57 +.. gh-issue: 50966 +.. nonce: Tq5mLp +.. section: Library + +Fix unbounded recursion in :mod:`turtle` when a mouse event handler that +moves the turtle is reentered while the screen is being redrawn, for example +with ``screen.ondrag(turtle.goto)``. This could previously crash the +interpreter. + +.. + +.. date: 2026-06-29-09-45-00 +.. gh-issue: 152569 +.. nonce: Kf7Lq2 +.. section: Library + +Fix :func:`asyncio.wait` leaking waiting tasks via the await-graph when +racing a future that never resolves. The waiting task is now discarded from +every future's ``awaited_by`` set once :func:`~asyncio.wait` returns, even +for pending futures. + +.. + +.. date: 2026-06-29-01-08-53 +.. gh-issue: 110357 +.. nonce: QGWdZQ +.. section: Library + +Importing :mod:`hashlib` no longer logs an error to stderr when a normally +guaranteed hash algorithm is unavailable in the current runtime (for example +under an OpenSSL FIPS configuration or a build using +:option:`--without-builtin-hashlib-hashes <--with-builtin-hashlib-hashes>`). +Code that actually uses the missing algorithm still gets a clear +:exc:`ValueError`. + +.. + +.. date: 2026-06-28-12-45-09 +.. gh-issue: 152356 +.. nonce: Dr4w2Q +.. section: Library + +Fix a hang in ``profiling.sampling run --blocking`` on Windows when the +target process exits. The profiler now finalizes binary profiles instead of +continuing to sample the exited process. + +.. + +.. date: 2026-06-28-11-00-40 +.. gh-issue: 78335 +.. nonce: Kp3mWq +.. section: Library + +Update the docstrings of :mod:`tkinter` and :mod:`tkinter.ttk` widget +classes to list all supported widget options, including options added in Tk +9.0 and 9.1. ``tkinter.Menubutton`` and ``tkinter.Message`` previously had +no option list at all. + +.. + +.. date: 2026-06-27-17-19-09 +.. gh-issue: 151126 +.. nonce: huUyOM +.. section: Library + +Fix two crashes in :mod:`tkinter` and :mod:`socket` modules initialization +under a memory pressure. Sets missing :exc:`MemoryError`. + +.. + +.. date: 2026-06-27-12-30-00 +.. gh-issue: 133031 +.. nonce: Na8Bit +.. section: Library + +:class:`curses.textpad.Textbox` now enters and reads back the non-ASCII +characters of an 8-bit locale encoding, instead of mangling them with a +7-bit mask. + +.. + +.. date: 2026-06-26-23-56-40 +.. gh-issue: 71880 +.. nonce: 782D31 +.. section: Library + +:class:`curses.textpad.Textbox` now lets the lower-right cell of the window +be edited. Writing it with :meth:`~curses.window.addch` would move the +cursor past the end of the window, raising an error and scrolling a +scrollable window, so it is now written with :meth:`~curses.window.insch`, +which keeps the cursor in place. + +.. + +.. date: 2026-06-26-16-30-00 +.. gh-issue: 83274 +.. nonce: Kx9mQv +.. section: Library + +Deallocating a :mod:`tkinter` application from a thread other than the one +it was created in no longer crashes the interpreter. The underlying Tcl +interpreter is leaked instead, and a :exc:`RuntimeWarning` is reported. + +.. + +.. date: 2026-06-26-15-41-34 +.. gh-issue: 152305 +.. nonce: WnbbBc +.. section: Library + +Fix the pure-Python :meth:`datetime.time.strftime` implementation raising +:exc:`AttributeError` for the year directives. Patch by tonghuaroot. + +.. + +.. date: 2026-06-26-15-30-00 +.. gh-issue: 88758 +.. nonce: Qw7nLp +.. section: Library + +:meth:`!tkinter.Misc.focus_get`, :meth:`!focus_displayof`, +:meth:`!focus_lastfor` and :meth:`!winfo_containing` now return ``None`` +instead of raising :exc:`KeyError` when the widget was not created by +:mod:`tkinter` (for example a torn-off menu). + +.. + +.. date: 2026-06-26-15-00-00 +.. gh-issue: 38464 +.. nonce: yDPjKH +.. section: Library + +:meth:`!tkinter.Misc.nametowidget` now resolves the auto-generated names of +cloned menus (a menu used as a menubar or a cascade) back to the original +widget. + +.. + +.. date: 2026-06-26-13-39-11 +.. gh-issue: 152248 +.. nonce: N2Rmaf +.. section: Library + +Make the C and pure-Python :mod:`zoneinfo` parsers validate POSIX TZ +abbreviations consistently, rejecting unquoted abbreviations with non-letter +characters and empty quoted abbreviations. Patch by tonghuaroot. + +.. + +.. date: 2026-06-26-13-10-00 +.. gh-issue: 80937 +.. nonce: Hq3mNp +.. section: Library + +Fix a memory leak in :mod:`tkinter` when a Tcl command created with +``createcommand`` was not explicitly removed before the interpreter was +deleted. The command no longer keeps the interpreter alive through a +reference cycle. + +.. + +.. date: 2026-06-26-12-50-26 +.. gh-issue: 152246 +.. nonce: MfXMd1 +.. section: Library + +Fix the pure-Python :mod:`zoneinfo` parser accepting an invalid POSIX TZ +transition rule with a non-period separator. Patch by tonghuaroot. + +.. + +.. date: 2026-06-25-20-00-00 +.. gh-issue: 151496 +.. nonce: kMnT3x +.. section: Library + +Fixed ``profiling.sampling --gecko`` with ``--async-aware`` by flattening +async task stacks before generating Gecko samples. ``--binary`` now rejects +``--async-aware`` until the binary format supports async task data. + +.. + +.. date: 2026-06-25-14-32-43 +.. gh-issue: 139816 +.. nonce: Lq2vXa +.. section: Library + +Fix a hang in :mod:`tkinter` on interactive Python built without +:mod:`readline`. An exception raised in a callback no longer causes the +event loop to stop and wait for the user to press Enter; pending callbacks +now keep running until input is actually available on stdin. + +.. + +.. date: 2026-06-25-14-32-42 +.. gh-issue: 139145 +.. nonce: kT9rmP +.. section: Library + +Fix a busy loop in :mod:`tkinter` on interactive Python. When a Tcl command +running its own event loop (such as ``vwait`` or :meth:`!wait_variable`) was +active and input arrived on stdin, the event loop kept spinning at 100% CPU. +The stdin file handler is now removed as soon as input is available. Based +on a patch by Michiel de Hoon. + +.. + +.. date: 2026-06-25-12-00-00 +.. gh-issue: 152212 +.. nonce: Zk7Qm2 +.. section: Library + +Fix the pure-Python :mod:`zoneinfo` parser accepting a POSIX TZ string with +a ``std`` abbreviation but no offset. This is invalid per POSIX and now +raises :exc:`ValueError`, matching the C accelerator. Patch by tonghuaroot. + +.. + +.. date: 2026-06-25-10-07-54 +.. gh-issue: 152156 +.. nonce: gscPU9 +.. section: Library + +Fix a possible crash in :func:`concurrent.interpreters.create` under limited +memory conditions. + +.. + +.. date: 2026-06-25-07-08-17 +.. gh-issue: 152157 +.. nonce: dt5Ef0 +.. section: Library + +The C implementations of :meth:`~datetime.datetime.fromisoformat` and +:meth:`~datetime.time.fromisoformat` now reject a decimal separator that is +not followed by any fractional digit before a timezone designator. + +.. + +.. date: 2026-06-25-01-00-43 +.. gh-issue: 151763 +.. nonce: wWeHBe +.. section: Library + +Fix crash in :func:`!_interpqueues.create` whe :exc:`MemoryError` happens on +queue creation. + +.. + +.. date: 2026-06-24-23-28-42 +.. gh-issue: 151669 +.. nonce: tPUavQ +.. section: Library + +On Windows, when populating tar archives from filesystem content, to conform +to the tar format standard, backslashes in symlink targets are be replaced +by slashes. + +.. + +.. date: 2026-06-24-22-16-35 +.. gh-issue: 105895 +.. nonce: hRkuEw +.. section: Library + +Add :keyword:`match` and :keyword:`case` to the list of supported topics by +:func:`help`. + +.. + +.. date: 2026-06-24-16-40-15 +.. gh-issue: 151378 +.. nonce: iYWa_6 +.. section: Library + +Fix a bug in the binary collector in Tachyon that caused unbounded memory +growth while profiling a thread that stayed asleep. Patch by Maurycy +Pawłowski-Wieroński. + +.. + +.. date: 2026-06-24-12-00-00 +.. gh-issue: 152079 +.. nonce: f1tzus +.. section: Library + +Fix :meth:`datetime.datetime.fromisoformat` in the C implementation dropping +the sub-second part of a UTC offset whose whole-second part is zero, +matching the pure-Python implementation. + +.. + +.. date: 2026-06-24-12-00-00 +.. gh-issue: 152052 +.. nonce: yBssDE +.. section: Library + +The :mod:`json` C accelerator now correctly reports an unterminated string +for a ``\uXXXX`` escape at the end of the input. + +.. + +.. date: 2026-06-24-10-46-35 +.. gh-issue: 152060 +.. nonce: f2asrt +.. section: Library + +Fix :meth:`datetime.datetime.fromisoformat` raising :exc:`AssertionError` +instead of :exc:`ValueError` for some malformed strings in the pure-Python +implementation, matching the C implementation. + +.. + +.. date: 2026-06-23-17-14-04 +.. gh-issue: 127802 +.. nonce: nGSxo6 +.. section: Library + +The deprecated :class:`tkinter.Variable` methods :meth:`!trace_variable`, +:meth:`!trace`, :meth:`!trace_vdelete` and :meth:`!trace_vinfo` are now +scheduled for removal in Python 3.17. + +.. + +.. date: 2026-06-23-13-27-14 +.. gh-issue: 126219 +.. nonce: kOfv2g +.. section: Library + +Fixed a crash in :class:`tkinter.Tk` when *className* contains a non-BMP +character and tkinter is built against Tcl/Tk 8.x. Such a name is now +rejected with a :exc:`ValueError`. + +.. + +.. date: 2026-06-21-15-50-24 +.. gh-issue: 86165 +.. nonce: dyac1G +.. section: Library + +Fix :func:`imaplib.Time2Internaldate` to use the local timezone offset for +``time.struct_time`` values with ``tm_gmtoff`` set to ``None``, as returned +by ``datetime.datetime.timetuple()``. Contributed by Xiao Yuan. + +.. + +.. date: 2026-06-20-21-15-13 +.. gh-issue: 151814 +.. nonce: OIbgsO +.. section: Library + +Fix unbounded memory growth in :class:`io.TextIOWrapper` when repeatedly +writing an empty string. + +.. + +.. date: 2026-06-18-23-59-46 +.. gh-issue: 151596 +.. nonce: 5ma144 +.. section: Library + +Add missing ``size`` positional argument to the pure-Python implementation +of :meth:`io.TextIOBase.readline`. + +.. + +.. date: 2026-06-18-12-48-03 +.. gh-issue: 151640 +.. nonce: R4c3Fx +.. section: Library + +Fix a data race in :class:`io.BytesIO` in free-threaded builds when +whole-buffer reads or peeks, or :meth:`~io.BytesIO.getvalue`, share the +internal buffer with concurrent writes. + +.. + +.. date: 2026-06-17-22-31-57 +.. gh-issue: 151613 +.. nonce: n0nua1 +.. section: Library + +Fix another way the Tachyon profiler frame cache could produce impossible +mixed stack traces when ``_PyInterpreterFrame`` addresses are reused, by +validating cached frame anchors with a sequence counter. + +.. + +.. date: 2026-06-17-00-00-00 +.. gh-issue: 148660 +.. nonce: odcopy +.. section: Library + +Fix a crash in :meth:`!collections.OrderedDict.copy` when a key's ``__eq__`` +or a subclass method mutates the dict during the copy. Now raises +:exc:`RuntimeError` instead, as iteration does. + +.. + +.. date: 2026-06-15-15-32-36 +.. gh-issue: 151497 +.. nonce: 1cfmSV +.. section: Library + +Opening a :mod:`tarfile` archive no longer attempts to pre-allocate a huge +buffer when a crafted or truncated member claims an oversized extended +header (a GNU long name/link or a pax header). The extended header is now +read in bounded chunks, so its size field can no longer trigger memory +exhaustion. + +.. + +.. date: 2026-06-12-00-00-00 +.. gh-issue: 151416 +.. nonce: spawnUA +.. section: Library + +Fix a crash in :func:`os.spawnv` and :func:`os.spawnve` when an *argv* +item's :meth:`~os.PathLike.__fspath__` method mutates the *argv* list during +argument conversion. :func:`!os.spawnv` argument conversion errors other +than :exc:`TypeError`, such as the :exc:`ValueError` for an embedded null, +are no longer replaced with a generic :exc:`TypeError`. + +.. + +.. date: 2026-06-11-06-56-31 +.. gh-issue: 150994 +.. nonce: gd1wVw +.. section: Library + +Make type annotations in the private ``_colorize`` module resolvable. + +.. + +.. date: 2026-06-06-06-29-17 +.. gh-issue: 150994 +.. nonce: I2119M +.. section: Library + +Make the type annotations in the private ``_colorize`` module resolvable. + +.. + +.. date: 2026-06-03-19-35-32 +.. gh-issue: 150583 +.. nonce: dedI24 +.. section: Library + +Correctly set the default compression level in :mod:`compression.zstd` when +passing a digested dictionary during compression. + +.. + +.. date: 2026-05-31-14-39-25 +.. gh-issue: 150641 +.. nonce: LLIhd1 +.. section: Library + +Fix bug where :func:`typing.evaluate_forward_ref` with the ``STRING`` format +could leak internal names used by the annotation machinery. + +.. + +.. date: 2026-05-18-12-42-31 +.. gh-issue: 149816 +.. nonce: F98iME +.. section: Library + +Fix a potential use after free condition in :func:`pickle.dumps` in +free-threaded mode when serializing lists. + +.. + +.. date: 2026-03-26-00-00-00 +.. gh-issue: 47005 +.. nonce: xxc89c +.. section: Library + +Fix :meth:`!urllib.request.AbstractHTTPHandler.do_open` to give regular +headers set via :meth:`~urllib.request.Request.add_header` priority over +unredirected headers, consistent with +:meth:`~urllib.request.Request.get_header` and +:meth:`~urllib.request.Request.header_items`. + +.. + +.. date: 2026-02-11-16-47-27 +.. gh-issue: 140729 +.. nonce: 2uTPQp +.. section: Library + +Fix a pickling error in the ``cProfile`` module when profiling a script that +uses :class:`multiprocessing.Process` with the ``spawn`` and ``forkserver`` +start methods. + +.. + +.. date: 2025-11-02-05-28-56 +.. gh-issue: 115634 +.. nonce: JbcNnF +.. section: Library + +Fix a deadlock in :class:`concurrent.futures.ProcessPoolExecutor` when using +``max_tasks_per_child``, present since the feature was introduced in Python +3.11. The executor stopped scheduling queued tasks after a worker process +exited upon reaching its task limit. Based on a fix proposed by Tabrez +Mohammed. + +.. + +.. date: 2025-09-05-20-50-35 +.. gh-issue: 79638 +.. nonce: Y-JfaH +.. section: Library + +Disallow all access in :mod:`urllib.robotparser` if the ``robots.txt`` file +is unreachable due to server or network errors. + +.. + +.. date: 2023-06-12-21-31-02 +.. gh-issue: 105708 +.. nonce: 5fFwP8 +.. section: Library + +Accept an uppercase V prefix in IPvFuture addresses in +:func:`urllib.parse.urlsplit`. + +.. + +.. date: 2026-06-22-19-45-00 +.. gh-issue: 151626 +.. nonce: K9pZ2x +.. section: Tests + +Fix several tests in ``test.test_inspect``, ``test.test_import``, +``test.test_importlib``, ``test.test_py_compile`` and +``test.test_compileall`` that failed when the test suite was run with +:envvar:`PYTHONPYCACHEPREFIX` set. These tests now neutralize the pycache +prefix where they assume the default ``__pycache__`` bytecode layout. + +.. + +.. date: 2026-06-16-05-11-38 +.. gh-issue: 151096 +.. nonce: Kq3Lp9 +.. section: Tests + +Fix ``test_embed`` failing when CPython is configured with a split exec +prefix (``--exec-prefix`` differing from ``--prefix``). + +.. + +.. date: 2026-07-11-07-26-16 +.. gh-issue: 126877 +.. nonce: Zt7Kq2 +.. section: Build + +Fix the :program:`configure` check for Tcl/Tk which could wrongly succeed +with optimizing compilers when the libraries are missing. + +.. + +.. date: 2026-07-09-22-45-00 +.. gh-issue: 153438 +.. nonce: Qr7N2p +.. section: Build + +Update Windows build and installer tooling and documentation to use the +current download URL for ``nuget.exe``. + +.. + +.. date: 2026-07-02-16-25-13 +.. gh-issue: 152870 +.. nonce: oh9eD1 +.. section: Build + +Fix a compilation error in the :mod:`decimal` C extension (``_decimal``) +when it is built with ``EXTRA_FUNCTIONALITY``. ``Context.apply()`` called +the internal ``_apply`` helper using its pre-Argument-Clinic signature; the +call is now made through the generated ``_impl`` function. + +.. + +.. date: 2026-07-01-17-53-00 +.. gh-issue: 152769 +.. nonce: Kp7mQ2 +.. section: Build + +Enable the :ref:`perf profiler <perf_profiling>` trampoline on Alpine Linux +with the musl C library on ``x86_64`` and ``aarch64``. The trampoline is +architecture-specific and does not depend on the C library, so the same +assembly trampoline used for glibc is reused for musl. + +.. + +.. date: 2026-06-28-16-17-55 +.. gh-issue: 152502 +.. nonce: 6SNqMg +.. section: Build + +The :mod:`curses` module now detects ``set_escdelay()``, ``set_tabsize()`` +and the ``ESCDELAY`` and ``TABSIZE`` variables with :program:`configure` +capability probes instead of the ncurses-specific ``NCURSES_EXT_FUNCS`` +macro, so they are exposed when building against other curses +implementations such as NetBSD curses that provide them. + +.. + +.. date: 2026-04-21-16-07-11 +.. gh-issue: 140146 +.. nonce: TAcUHA +.. section: Windows + +Prevent :mod:`tkinter` from hanging on Windows if stdin is redirected to a +pipe in an interactive session. This is helpful for testing interactive +usage of tkinter from a script, for example as part of the cpython test +suite. + +.. + +.. date: 2026-07-17-23-35-36 +.. gh-issue: 124111 +.. nonce: dmM4lk +.. section: macOS + +Update macOS installer to use Tcl/Tk 9.0.4. + +.. + +.. date: 2026-07-17-23-20-27 +.. gh-issue: 152023 +.. nonce: QAAgdj +.. section: macOS + +Update macOS installer builds to SQLite 3.53.3. Enable median() and +percentile() functions. + +.. + +.. date: 2026-07-01-19-00-00 +.. gh-issue: 82183 +.. nonce: rNsTrt +.. section: IDLE + +When the shell is busy running code, using "Run... Customized" with "Restart +shell" unchecked now reports that the shell is executing instead of +restarting it anyway. + +.. + +.. date: 2026-07-01-18-00-00 +.. gh-issue: 83653 +.. nonce: cFgInt +.. section: IDLE + +Blanking an integer entry in IDLE's Settings dialog, such as "Auto squeeze +min lines", no longer saves an empty string as an invalid configuration +value. + +.. + +.. date: 2026-07-01-17-00-00 +.. gh-issue: 65339 +.. nonce: oUtTxt +.. section: IDLE + +Saving the IDLE Shell or an Output window now defaults to a ``.txt`` +extension and lists text files before Python files, since their content is +not Python source. + +.. + +.. date: 2026-07-01-16-00-00 +.. gh-issue: 80504 +.. nonce: gReP +.. section: IDLE + +The "In files:" field of IDLE's Find in Files dialog now always contains a +full directory path, even for an unsaved editor or the Shell. This shows in +the grep output which directory was searched. + +.. + +.. date: 2026-07-01-15-00-00 +.. gh-issue: 134300 +.. nonce: iDlPaT +.. section: IDLE + +Do not add the ``idlelib`` directory to the path of the IDLE user process. +User code run in IDLE can no longer import ``idlelib`` submodules as +top-level modules, such as ``import help``. + +.. + +.. date: 2026-07-01-14-00-00 +.. gh-issue: 89360 +.. nonce: mUlTiC +.. section: IDLE + +Fix a rare crash in the IDLE editor when the completion window is closed: +deleting a key binding for a sequence that is not bound to the virtual event +is now ignored instead of raising a ``ValueError``. + +.. + +.. date: 2026-07-01-12-00-00 +.. gh-issue: 71956 +.. nonce: rPlAlL +.. section: IDLE + +Fix Replace All in the IDLE editor's Replace dialog when the search +direction is "Up" and "Wrap around" is off: it now replaces all matches +above the current position instead of only the first one. + +.. + +.. date: 2026-07-01-00-15-58 +.. gh-issue: 152728 +.. nonce: yxIhMN +.. section: IDLE + +Move functions run.fix_scaling, editor.fixwordbreaks (as fix_word_breaks) +and pyshell.fix_x11_paste to idlelib.util. + +.. + +.. date: 2026-07-01-00-00-00 +.. gh-issue: 66331 +.. nonce: wMcLaS +.. section: IDLE + +Set the ``WM_CLASS`` window property of IDLE's windows to ``Idle`` on X11, +so that window managers group and label them correctly instead of using the +default ``Toplevel``. + +.. + +.. date: 2026-06-28-06-46-46 +.. gh-issue: 85320 +.. nonce: Hq2vKn +.. section: IDLE + +IDLE now reads and writes its configuration files and the breakpoints file +using UTF-8 instead of the locale encoding. This keeps non-ASCII data (such +as non-ASCII paths) from being corrupted and makes the files portable +between environments. + +.. + +.. date: 2026-07-09-17-33-29 +.. gh-issue: 152132 +.. nonce: Ma8MJZ +.. section: C API + +Fix :c:func:`Py_RunMain` to return an exit code, rather than calling +:c:func:`Py_Exit`, when running a script, a command, or the REPL. Patch by +Victor Stinner. + +.. + +.. date: 2026-07-09-16-46-30 +.. gh-issue: 145633 +.. nonce: jyNwAs +.. section: C API + +:c:func:`PyFloat_Pack8` and ``PyFloat_Unpack*`` functions are no longer +guaranteed to always succeed on CPython. + +.. + +.. date: 2026-07-08-00-38-32 +.. gh-issue: 153300 +.. nonce: lVoWyR +.. section: C API + +:c:func:`PyConfig_Set()` now also set global configuration variables. For +example, ``PyConfig_Set("inspect", value)`` now also sets +:c:var:`Py_InspectFlag`. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Build/2026-06-28-16-17-55.gh-issue-152502.6SNqMg.rst b/Misc/NEWS.d/next/Build/2026-06-28-16-17-55.gh-issue-152502.6SNqMg.rst deleted file mode 100644 index cc0fabed10f126..00000000000000 --- a/Misc/NEWS.d/next/Build/2026-06-28-16-17-55.gh-issue-152502.6SNqMg.rst +++ /dev/null @@ -1,5 +0,0 @@ -The :mod:`curses` module now detects ``set_escdelay()``, ``set_tabsize()`` and -the ``ESCDELAY`` and ``TABSIZE`` variables with :program:`configure` capability -probes instead of the ncurses-specific ``NCURSES_EXT_FUNCS`` macro, so they are -exposed when building against other curses implementations such as NetBSD curses -that provide them. diff --git a/Misc/NEWS.d/next/Build/2026-07-01-17-53-00.gh-issue-152769.Kp7mQ2.rst b/Misc/NEWS.d/next/Build/2026-07-01-17-53-00.gh-issue-152769.Kp7mQ2.rst deleted file mode 100644 index 04a6ef4f5e0a7f..00000000000000 --- a/Misc/NEWS.d/next/Build/2026-07-01-17-53-00.gh-issue-152769.Kp7mQ2.rst +++ /dev/null @@ -1,4 +0,0 @@ -Enable the :ref:`perf profiler <perf_profiling>` trampoline on Alpine Linux with the -musl C library on ``x86_64`` and ``aarch64``. The -trampoline is architecture-specific and does not depend on the C library, so -the same assembly trampoline used for glibc is reused for musl. diff --git a/Misc/NEWS.d/next/Build/2026-07-02-16-25-13.gh-issue-152870.oh9eD1.rst b/Misc/NEWS.d/next/Build/2026-07-02-16-25-13.gh-issue-152870.oh9eD1.rst deleted file mode 100644 index eaddd22a60fc09..00000000000000 --- a/Misc/NEWS.d/next/Build/2026-07-02-16-25-13.gh-issue-152870.oh9eD1.rst +++ /dev/null @@ -1,4 +0,0 @@ -Fix a compilation error in the :mod:`decimal` C extension (``_decimal``) when -it is built with ``EXTRA_FUNCTIONALITY``. ``Context.apply()`` called the -internal ``_apply`` helper using its pre-Argument-Clinic signature; the call is -now made through the generated ``_impl`` function. diff --git a/Misc/NEWS.d/next/Build/2026-07-09-22-45-00.gh-issue-153438.Qr7N2p.rst b/Misc/NEWS.d/next/Build/2026-07-09-22-45-00.gh-issue-153438.Qr7N2p.rst deleted file mode 100644 index edab8e6ba7b259..00000000000000 --- a/Misc/NEWS.d/next/Build/2026-07-09-22-45-00.gh-issue-153438.Qr7N2p.rst +++ /dev/null @@ -1,2 +0,0 @@ -Update Windows build and installer tooling and documentation to use the -current download URL for ``nuget.exe``. diff --git a/Misc/NEWS.d/next/Build/2026-07-11-07-26-16.gh-issue-126877.Zt7Kq2.rst b/Misc/NEWS.d/next/Build/2026-07-11-07-26-16.gh-issue-126877.Zt7Kq2.rst deleted file mode 100644 index 1d7d4fad886c56..00000000000000 --- a/Misc/NEWS.d/next/Build/2026-07-11-07-26-16.gh-issue-126877.Zt7Kq2.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix the :program:`configure` check for Tcl/Tk which could wrongly succeed -with optimizing compilers when the libraries are missing. diff --git a/Misc/NEWS.d/next/C_API/2026-07-08-00-38-32.gh-issue-153300.lVoWyR.rst b/Misc/NEWS.d/next/C_API/2026-07-08-00-38-32.gh-issue-153300.lVoWyR.rst deleted file mode 100644 index 3c19c0e15d2bc6..00000000000000 --- a/Misc/NEWS.d/next/C_API/2026-07-08-00-38-32.gh-issue-153300.lVoWyR.rst +++ /dev/null @@ -1,3 +0,0 @@ -:c:func:`PyConfig_Set()` now also set global configuration variables. For -example, ``PyConfig_Set("inspect", value)`` now also sets -:c:var:`Py_InspectFlag`. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/C_API/2026-07-09-16-46-30.gh-issue-145633.jyNwAs.rst b/Misc/NEWS.d/next/C_API/2026-07-09-16-46-30.gh-issue-145633.jyNwAs.rst deleted file mode 100644 index cdb68372b6ba7d..00000000000000 --- a/Misc/NEWS.d/next/C_API/2026-07-09-16-46-30.gh-issue-145633.jyNwAs.rst +++ /dev/null @@ -1,2 +0,0 @@ -:c:func:`PyFloat_Pack8` and ``PyFloat_Unpack*`` functions are no longer -guaranteed to always succeed on CPython. diff --git a/Misc/NEWS.d/next/C_API/2026-07-09-17-33-29.gh-issue-152132.Ma8MJZ.rst b/Misc/NEWS.d/next/C_API/2026-07-09-17-33-29.gh-issue-152132.Ma8MJZ.rst deleted file mode 100644 index 633c41e40bf269..00000000000000 --- a/Misc/NEWS.d/next/C_API/2026-07-09-17-33-29.gh-issue-152132.Ma8MJZ.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix :c:func:`Py_RunMain` to return an exit code, rather than calling -:c:func:`Py_Exit`, when running a script, a command, or the REPL. Patch by -Victor Stinner. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-04-21-15-07-03.gh-issue-148825.AbJzmZ.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-04-21-15-07-03.gh-issue-148825.AbJzmZ.rst deleted file mode 100644 index 5cf727b5d91fad..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2026-04-21-15-07-03.gh-issue-148825.AbJzmZ.rst +++ /dev/null @@ -1 +0,0 @@ -Fix build error if specialization is disabled. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-04-29-15-10-59.gh-issue-149162.BPPyrq.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-04-29-15-10-59.gh-issue-149162.BPPyrq.rst deleted file mode 100644 index b4c443ecee07ad..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2026-04-29-15-10-59.gh-issue-149162.BPPyrq.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix a potential deadlock in :c:func:`PyUnicode_InternFromString` and other -interning functions in the :term:`free-threaded build` when called from C++ -static local initializers. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-11-15-58-23.gh-issue-149689.9Ht49z.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-11-15-58-23.gh-issue-149689.9Ht49z.rst deleted file mode 100644 index aa672760730bd4..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-11-15-58-23.gh-issue-149689.9Ht49z.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix missing error propagation in parser action helpers when memory allocation -fails. Patch by Thomas Kowalski. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-26-00-06-30.gh-issue-150411.u-d-_5.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-26-00-06-30.gh-issue-150411.u-d-_5.rst deleted file mode 100644 index 5b19a4fff5ddc7..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-26-00-06-30.gh-issue-150411.u-d-_5.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix a data race in the free-threaded build when :func:`gc.get_count` reads -the young generation allocation count while another thread updates it. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-29-17-51-11.gh-issue-144774.jPcixe.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-29-17-51-11.gh-issue-144774.jPcixe.rst deleted file mode 100644 index 3dd117e7d3c350..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-29-17-51-11.gh-issue-144774.jPcixe.rst +++ /dev/null @@ -1 +0,0 @@ -Fix data race in :class:`BaseException` when an exception is copied while being mutated. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-03-16-27-00.gh-issue-150858.j2dSkD.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-03-16-27-00.gh-issue-150858.j2dSkD.rst deleted file mode 100644 index dcb932bf320629..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-03-16-27-00.gh-issue-150858.j2dSkD.rst +++ /dev/null @@ -1 +0,0 @@ -Fix a data race while changing ``__qualname__`` of a type concurrently on free-threaded builds. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-03-21-14-28.gh-issue-150459.qpsCEl.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-03-21-14-28.gh-issue-150459.qpsCEl.rst deleted file mode 100644 index a3e3e38ddcd1f4..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-03-21-14-28.gh-issue-150459.qpsCEl.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix :exc:`SyntaxError` error message for ``from x lazy import y``. -Raise :exc:`SyntaxWarning` on ``from . lazy import x`` -(with whitespace between the dots and a module named ``lazy``). diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-06-20-15-08.gh-issue-151029.A33CKK.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-06-20-15-08.gh-issue-151029.A33CKK.rst deleted file mode 100644 index cbfe5952627ad8..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-06-20-15-08.gh-issue-151029.A33CKK.rst +++ /dev/null @@ -1,2 +0,0 @@ -On Linux, fix :func:`sys.remote_exec` unable to find remote writable memory -when ``libpython`` replaced on disk. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-17-16-46-07.gh-issue-151126.vhTL0T.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-17-16-46-07.gh-issue-151126.vhTL0T.rst deleted file mode 100644 index 6f2d230b1dcfc0..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-17-16-46-07.gh-issue-151126.vhTL0T.rst +++ /dev/null @@ -1,2 +0,0 @@ -Avoid possible crash in ``_winapi.c`` where a device has no memory left. Now -it properly raises a :exc:`MemoryError`. Patch by Ivy Xu. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-18-00-00-00.gh-issue-151644.5cFffN.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-18-00-00-00.gh-issue-151644.5cFffN.rst deleted file mode 100644 index ff5058e14b42f1..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-18-00-00-00.gh-issue-151644.5cFffN.rst +++ /dev/null @@ -1,4 +0,0 @@ -Fix a data race in :func:`sys.setdlopenflags` and :func:`sys.getdlopenflags` -when called concurrently in the free-threaded build. The underlying -``_PyImport_GetDLOpenFlags`` and ``_PyImport_SetDLOpenFlags`` functions now -use atomic load/store operations. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-18-16-00-10.gh-issue-151126.tBqn6I.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-18-16-00-10.gh-issue-151126.tBqn6I.rst deleted file mode 100644 index d495df43ede932..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-18-16-00-10.gh-issue-151126.tBqn6I.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix a crash when sharing :class:`memoryview` objects between interpreters -fails due to running out of memory. It now raises a proper -:exc:`MemoryError`. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-19-16-40-01.gh-issue-151619.35yyJW.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-19-16-40-01.gh-issue-151619.35yyJW.rst deleted file mode 100644 index 28ba2038e876fa..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-19-16-40-01.gh-issue-151619.35yyJW.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix an issue where using non-module global or builtin namespaces (such as -dictionaries passed to :func:`exec`) could cause cached global loads to -produce unresolved :ref:`lazy imports <lazy-imports>`. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-20-10-01-26.gh-issue-151672.K-w7j0.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-20-10-01-26.gh-issue-151672.K-w7j0.rst deleted file mode 100644 index 4f4823df0b2101..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-20-10-01-26.gh-issue-151672.K-w7j0.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix an inconsistency where calling ``__lazy_import__`` with a string -``fromlist`` would return a :class:`types.LazyImportType` that resolves to -the named member, rather than the module being imported. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-21-16-00-00.gh-issue-151773.mN4kRt.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-21-16-00-00.gh-issue-151773.mN4kRt.rst deleted file mode 100644 index b4193c5e15ffef..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-21-16-00-00.gh-issue-151773.mN4kRt.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix a crash in :func:`contextvars.ContextVar.set` when memory allocation -fails. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-22-14-48-22.gh-issue-151912.YcxfnU.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-22-14-48-22.gh-issue-151912.YcxfnU.rst deleted file mode 100644 index 07b73949b438a3..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-22-14-48-22.gh-issue-151912.YcxfnU.rst +++ /dev/null @@ -1 +0,0 @@ -Fixed a crash in ``type()`` when selecting a metaclass whose ``tp_new`` slot is ``NULL``. Such metaclasses are now rejected with ``TypeError`` instead of causing a NULL pointer dereference. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-23-12-03-55.gh-issue-151763.K7QfWG.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-23-12-03-55.gh-issue-151763.K7QfWG.rst deleted file mode 100644 index 64d0146cb09101..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-23-12-03-55.gh-issue-151763.K7QfWG.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix a potential crash in :func:`compile`, :func:`exec`, :func:`eval` and -:func:`ast.parse` when an allocation fails: the parser or compiler could -return without setting an exception. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-23-19-50-22.gh-issue-152020.DTKXjR.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-23-19-50-22.gh-issue-152020.DTKXjR.rst deleted file mode 100644 index 93c716f7a6a1c8..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-23-19-50-22.gh-issue-152020.DTKXjR.rst +++ /dev/null @@ -1,3 +0,0 @@ -On the free-threaded build, :func:`asyncio.all_tasks` no longer loses -eager-started tasks when called from a thread other than the one running the -event loop. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-23-23-48-54.gh-issue-151763.Eu8pYQ.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-23-23-48-54.gh-issue-151763.Eu8pYQ.rst deleted file mode 100644 index d4746e992f8779..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-23-23-48-54.gh-issue-151763.Eu8pYQ.rst +++ /dev/null @@ -1 +0,0 @@ -Fixes possible crash on :class:`types.CodeType` deallocation. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-24-13-36-31.gh-issue-151722.lWKfE1.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-24-13-36-31.gh-issue-151722.lWKfE1.rst deleted file mode 100644 index db50b0058bdbdd..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-24-13-36-31.gh-issue-151722.lWKfE1.rst +++ /dev/null @@ -1,3 +0,0 @@ -:meth:`!frozendict.fromkeys` now only tracks the :class:`frozendict` in the -garbage collector once the dictionary is fully initialized. Patch by Donghee Na -and Victor Stinner. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-25-21-34-15.gh-issue-152228.a6K14K.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-25-21-34-15.gh-issue-152228.a6K14K.rst deleted file mode 100644 index 8af7ae0d173913..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-25-21-34-15.gh-issue-152228.a6K14K.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix an assertion failure when python is built in a debug mode -that happened in :meth:`str.replace` under a limited memory situation. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-26-05-49-13.gh-issue-152235.YU20T9.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-26-05-49-13.gh-issue-152235.YU20T9.rst deleted file mode 100644 index 8d386ad458dfff..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-26-05-49-13.gh-issue-152235.YU20T9.rst +++ /dev/null @@ -1,2 +0,0 @@ -Defer GC tracking of a :class:`set` or :class:`frozenset` to the end of its -construction from iterable. Patch by Donghee Na. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-26-22-03-16.gh-issue-152235.ZKWiWk.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-26-22-03-16.gh-issue-152235.ZKWiWk.rst deleted file mode 100644 index ff89a2445cb4fe..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-26-22-03-16.gh-issue-152235.ZKWiWk.rst +++ /dev/null @@ -1,3 +0,0 @@ -Defer GC tracking of :meth:`set.intersection`, :meth:`set.difference`, -:meth:`set.symmetric_difference`, :meth:`set.union` and ``set.__sub__``. -Patch by Donghee Na. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-27-10-05-12.gh-issue-152375.L-ZBk6.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-27-10-05-12.gh-issue-152375.L-ZBk6.rst deleted file mode 100644 index db6ae3060d8328..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-27-10-05-12.gh-issue-152375.L-ZBk6.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix undefined behaviour when a :mod:`sys.monitoring` callback raised an -exception while the program was following a branch or loop. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-28-14-31-03.gh-issue-152492._09Zee.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-28-14-31-03.gh-issue-152492._09Zee.rst deleted file mode 100644 index 16cb5a205c908a..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-28-14-31-03.gh-issue-152492._09Zee.rst +++ /dev/null @@ -1 +0,0 @@ -:type:`collections.OrderedDict` ``update`` method can now accept :type:`frozendict` as an argument. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-28-14-39-05.gh-issue-152405.-_3YRo.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-28-14-39-05.gh-issue-152405.-_3YRo.rst deleted file mode 100644 index d7c473ce171d4b..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-28-14-39-05.gh-issue-152405.-_3YRo.rst +++ /dev/null @@ -1,5 +0,0 @@ -Do not expose the internal mapping of :class:`types.MappingProxyType` -when performing rich-compare operations with non-stdlib types. -Previously, it was possible to mutate the internal mapping of a proxy there. -Now we pass not the original :class:`dict` instance, but its copy, -when dealing with custom types. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-29-23-29-14.gh-issue-152635.O21J0O.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-29-23-29-14.gh-issue-152635.O21J0O.rst deleted file mode 100644 index dadb25fc7c4477..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-29-23-29-14.gh-issue-152635.O21J0O.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix a crash caused when running out of memory creating a -:mod:`!_interpchannels` channel. Now a :exc:`MemoryError` is correctly raised. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-30-14-00-00.gh-issue-152682.yId7e5.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-30-14-00-00.gh-issue-152682.yId7e5.rst deleted file mode 100644 index aba0b594382bcf..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-30-14-00-00.gh-issue-152682.yId7e5.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix NULL pointer dereference in :func:`compile` when a reserved name (e.g. -``__classdict__``) is used as a type parameter name and memory allocation -fails while formatting the error message. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-07-07-04-16-48.gh-issue-153205.5fE8QZ.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-07-07-04-16-48.gh-issue-153205.5fE8QZ.rst deleted file mode 100644 index 9ccfbff7ee6977..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2026-07-07-04-16-48.gh-issue-153205.5fE8QZ.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix a potential :exc:`SystemError` during vector calls when memory allocation fails. -A :exc:`MemoryError` is now raised instead. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-07-08-13-23-11.gh-issue-153298.wvcXxN.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-07-08-13-23-11.gh-issue-153298.wvcXxN.rst deleted file mode 100644 index 38d548834d5e02..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2026-07-08-13-23-11.gh-issue-153298.wvcXxN.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fixes a data race in :class:`types.GenericAlias` ``__parameters__`` -initialization on free-threading builds. diff --git a/Misc/NEWS.d/next/IDLE/2026-06-28-06-46-46.gh-issue-85320.Hq2vKn.rst b/Misc/NEWS.d/next/IDLE/2026-06-28-06-46-46.gh-issue-85320.Hq2vKn.rst deleted file mode 100644 index ec34bf8ead9eb9..00000000000000 --- a/Misc/NEWS.d/next/IDLE/2026-06-28-06-46-46.gh-issue-85320.Hq2vKn.rst +++ /dev/null @@ -1,4 +0,0 @@ -IDLE now reads and writes its configuration files and the breakpoints file -using UTF-8 instead of the locale encoding. This keeps non-ASCII data (such -as non-ASCII paths) from being corrupted and makes the files portable between -environments. diff --git a/Misc/NEWS.d/next/IDLE/2026-07-01-00-00-00.gh-issue-66331.wMcLaS.rst b/Misc/NEWS.d/next/IDLE/2026-07-01-00-00-00.gh-issue-66331.wMcLaS.rst deleted file mode 100644 index e00e7c7d8fdc65..00000000000000 --- a/Misc/NEWS.d/next/IDLE/2026-07-01-00-00-00.gh-issue-66331.wMcLaS.rst +++ /dev/null @@ -1,3 +0,0 @@ -Set the ``WM_CLASS`` window property of IDLE's windows to ``Idle`` on X11, -so that window managers group and label them correctly instead of using the -default ``Toplevel``. diff --git a/Misc/NEWS.d/next/IDLE/2026-07-01-00-15-58.gh-issue-152728.yxIhMN.rst b/Misc/NEWS.d/next/IDLE/2026-07-01-00-15-58.gh-issue-152728.yxIhMN.rst deleted file mode 100644 index d73512a615c189..00000000000000 --- a/Misc/NEWS.d/next/IDLE/2026-07-01-00-15-58.gh-issue-152728.yxIhMN.rst +++ /dev/null @@ -1,2 +0,0 @@ -Move functions run.fix_scaling, editor.fixwordbreaks (as fix_word_breaks) -and pyshell.fix_x11_paste to idlelib.util. diff --git a/Misc/NEWS.d/next/IDLE/2026-07-01-12-00-00.gh-issue-71956.rPlAlL.rst b/Misc/NEWS.d/next/IDLE/2026-07-01-12-00-00.gh-issue-71956.rPlAlL.rst deleted file mode 100644 index 1a92ed4cd389cf..00000000000000 --- a/Misc/NEWS.d/next/IDLE/2026-07-01-12-00-00.gh-issue-71956.rPlAlL.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix Replace All in the IDLE editor's Replace dialog when the search -direction is "Up" and "Wrap around" is off: it now replaces all matches -above the current position instead of only the first one. diff --git a/Misc/NEWS.d/next/IDLE/2026-07-01-14-00-00.gh-issue-89360.mUlTiC.rst b/Misc/NEWS.d/next/IDLE/2026-07-01-14-00-00.gh-issue-89360.mUlTiC.rst deleted file mode 100644 index 9e3023f8228233..00000000000000 --- a/Misc/NEWS.d/next/IDLE/2026-07-01-14-00-00.gh-issue-89360.mUlTiC.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix a rare crash in the IDLE editor when the completion window is closed: -deleting a key binding for a sequence that is not bound to the virtual -event is now ignored instead of raising a ``ValueError``. diff --git a/Misc/NEWS.d/next/IDLE/2026-07-01-15-00-00.gh-issue-134300.iDlPaT.rst b/Misc/NEWS.d/next/IDLE/2026-07-01-15-00-00.gh-issue-134300.iDlPaT.rst deleted file mode 100644 index 791acbbed62aaf..00000000000000 --- a/Misc/NEWS.d/next/IDLE/2026-07-01-15-00-00.gh-issue-134300.iDlPaT.rst +++ /dev/null @@ -1,3 +0,0 @@ -Do not add the ``idlelib`` directory to the path of the IDLE user process. -User code run in IDLE can no longer import ``idlelib`` submodules as -top-level modules, such as ``import help``. diff --git a/Misc/NEWS.d/next/IDLE/2026-07-01-16-00-00.gh-issue-80504.gReP.rst b/Misc/NEWS.d/next/IDLE/2026-07-01-16-00-00.gh-issue-80504.gReP.rst deleted file mode 100644 index 93adb33202a41c..00000000000000 --- a/Misc/NEWS.d/next/IDLE/2026-07-01-16-00-00.gh-issue-80504.gReP.rst +++ /dev/null @@ -1,3 +0,0 @@ -The "In files:" field of IDLE's Find in Files dialog now always contains a -full directory path, even for an unsaved editor or the Shell. This shows -in the grep output which directory was searched. diff --git a/Misc/NEWS.d/next/IDLE/2026-07-01-17-00-00.gh-issue-65339.oUtTxt.rst b/Misc/NEWS.d/next/IDLE/2026-07-01-17-00-00.gh-issue-65339.oUtTxt.rst deleted file mode 100644 index a8b216e86dc8d7..00000000000000 --- a/Misc/NEWS.d/next/IDLE/2026-07-01-17-00-00.gh-issue-65339.oUtTxt.rst +++ /dev/null @@ -1,3 +0,0 @@ -Saving the IDLE Shell or an Output window now defaults to a ``.txt`` -extension and lists text files before Python files, since their content is -not Python source. diff --git a/Misc/NEWS.d/next/IDLE/2026-07-01-18-00-00.gh-issue-83653.cFgInt.rst b/Misc/NEWS.d/next/IDLE/2026-07-01-18-00-00.gh-issue-83653.cFgInt.rst deleted file mode 100644 index 5812b2dd977f6a..00000000000000 --- a/Misc/NEWS.d/next/IDLE/2026-07-01-18-00-00.gh-issue-83653.cFgInt.rst +++ /dev/null @@ -1,3 +0,0 @@ -Blanking an integer entry in IDLE's Settings dialog, such as "Auto squeeze -min lines", no longer saves an empty string as an invalid configuration -value. diff --git a/Misc/NEWS.d/next/IDLE/2026-07-01-19-00-00.gh-issue-82183.rNsTrt.rst b/Misc/NEWS.d/next/IDLE/2026-07-01-19-00-00.gh-issue-82183.rNsTrt.rst deleted file mode 100644 index 2af412f5200d0d..00000000000000 --- a/Misc/NEWS.d/next/IDLE/2026-07-01-19-00-00.gh-issue-82183.rNsTrt.rst +++ /dev/null @@ -1,3 +0,0 @@ -When the shell is busy running code, using "Run... Customized" with "Restart -shell" unchecked now reports that the shell is executing instead of -restarting it anyway. diff --git a/Misc/NEWS.d/next/Library/2023-06-12-21-31-02.gh-issue-105708.5fFwP8.rst b/Misc/NEWS.d/next/Library/2023-06-12-21-31-02.gh-issue-105708.5fFwP8.rst deleted file mode 100644 index 79289c1f0bd421..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-06-12-21-31-02.gh-issue-105708.5fFwP8.rst +++ /dev/null @@ -1 +0,0 @@ -Accept an uppercase V prefix in IPvFuture addresses in :func:`urllib.parse.urlsplit`. diff --git a/Misc/NEWS.d/next/Library/2025-09-05-20-50-35.gh-issue-79638.Y-JfaH.rst b/Misc/NEWS.d/next/Library/2025-09-05-20-50-35.gh-issue-79638.Y-JfaH.rst deleted file mode 100644 index bd9fff0bc2e31b..00000000000000 --- a/Misc/NEWS.d/next/Library/2025-09-05-20-50-35.gh-issue-79638.Y-JfaH.rst +++ /dev/null @@ -1,2 +0,0 @@ -Disallow all access in :mod:`urllib.robotparser` if the ``robots.txt`` file -is unreachable due to server or network errors. diff --git a/Misc/NEWS.d/next/Library/2025-11-02-05-28-56.gh-issue-115634.JbcNnF.rst b/Misc/NEWS.d/next/Library/2025-11-02-05-28-56.gh-issue-115634.JbcNnF.rst deleted file mode 100644 index f023ce999c60b7..00000000000000 --- a/Misc/NEWS.d/next/Library/2025-11-02-05-28-56.gh-issue-115634.JbcNnF.rst +++ /dev/null @@ -1,5 +0,0 @@ -Fix a deadlock in :class:`concurrent.futures.ProcessPoolExecutor` when -using ``max_tasks_per_child``, present since the feature was introduced in -Python 3.11. The executor stopped scheduling queued tasks after a worker -process exited upon reaching its task limit. Based on a fix proposed by -Tabrez Mohammed. diff --git a/Misc/NEWS.d/next/Library/2026-02-11-16-47-27.gh-issue-140729.2uTPQp.rst b/Misc/NEWS.d/next/Library/2026-02-11-16-47-27.gh-issue-140729.2uTPQp.rst deleted file mode 100644 index 49c9adc4679abb..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-02-11-16-47-27.gh-issue-140729.2uTPQp.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix a pickling error in the ``cProfile`` module when profiling a script that -uses :class:`multiprocessing.Process` with the ``spawn`` and ``forkserver`` -start methods. diff --git a/Misc/NEWS.d/next/Library/2026-03-26-00-00-00.gh-issue-47005.xxc89c.rst b/Misc/NEWS.d/next/Library/2026-03-26-00-00-00.gh-issue-47005.xxc89c.rst deleted file mode 100644 index 646367f0fa069d..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-03-26-00-00-00.gh-issue-47005.xxc89c.rst +++ /dev/null @@ -1,4 +0,0 @@ -Fix :meth:`!urllib.request.AbstractHTTPHandler.do_open` to give regular -headers set via :meth:`~urllib.request.Request.add_header` priority over -unredirected headers, consistent with :meth:`~urllib.request.Request.get_header` -and :meth:`~urllib.request.Request.header_items`. diff --git a/Misc/NEWS.d/next/Library/2026-05-18-12-42-31.gh-issue-149816.F98iME.rst b/Misc/NEWS.d/next/Library/2026-05-18-12-42-31.gh-issue-149816.F98iME.rst deleted file mode 100644 index 21e3ae0df57621..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-05-18-12-42-31.gh-issue-149816.F98iME.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix a potential use after free condition in :func:`pickle.dumps` in free-threaded -mode when serializing lists. diff --git a/Misc/NEWS.d/next/Library/2026-05-31-14-39-25.gh-issue-150641.LLIhd1.rst b/Misc/NEWS.d/next/Library/2026-05-31-14-39-25.gh-issue-150641.LLIhd1.rst deleted file mode 100644 index eba899c96fcd26..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-05-31-14-39-25.gh-issue-150641.LLIhd1.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix bug where :func:`typing.evaluate_forward_ref` with the ``STRING`` format -could leak internal names used by the annotation machinery. diff --git a/Misc/NEWS.d/next/Library/2026-06-03-19-35-32.gh-issue-150583.dedI24.rst b/Misc/NEWS.d/next/Library/2026-06-03-19-35-32.gh-issue-150583.dedI24.rst deleted file mode 100644 index edb551b3c3c8cb..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-06-03-19-35-32.gh-issue-150583.dedI24.rst +++ /dev/null @@ -1,2 +0,0 @@ -Correctly set the default compression level in :mod:`compression.zstd` when passing a digested -dictionary during compression. diff --git a/Misc/NEWS.d/next/Library/2026-06-06-06-29-17.gh-issue-150994.I2119M.rst b/Misc/NEWS.d/next/Library/2026-06-06-06-29-17.gh-issue-150994.I2119M.rst deleted file mode 100644 index c4a610c24806b0..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-06-06-06-29-17.gh-issue-150994.I2119M.rst +++ /dev/null @@ -1 +0,0 @@ -Make the type annotations in the private ``_colorize`` module resolvable. diff --git a/Misc/NEWS.d/next/Library/2026-06-11-06-56-31.gh-issue-150994.gd1wVw.rst b/Misc/NEWS.d/next/Library/2026-06-11-06-56-31.gh-issue-150994.gd1wVw.rst deleted file mode 100644 index 005a1d99b766dc..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-06-11-06-56-31.gh-issue-150994.gd1wVw.rst +++ /dev/null @@ -1 +0,0 @@ -Make type annotations in the private ``_colorize`` module resolvable. diff --git a/Misc/NEWS.d/next/Library/2026-06-12-00-00-00.gh-issue-151416.spawnUA.rst b/Misc/NEWS.d/next/Library/2026-06-12-00-00-00.gh-issue-151416.spawnUA.rst deleted file mode 100644 index fd034d9885a830..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-06-12-00-00-00.gh-issue-151416.spawnUA.rst +++ /dev/null @@ -1,5 +0,0 @@ -Fix a crash in :func:`os.spawnv` and :func:`os.spawnve` when an *argv* -item's :meth:`~os.PathLike.__fspath__` method mutates the *argv* list -during argument conversion. :func:`!os.spawnv` argument conversion errors -other than :exc:`TypeError`, such as the :exc:`ValueError` for an embedded -null, are no longer replaced with a generic :exc:`TypeError`. diff --git a/Misc/NEWS.d/next/Library/2026-06-15-15-32-36.gh-issue-151497.1cfmSV.rst b/Misc/NEWS.d/next/Library/2026-06-15-15-32-36.gh-issue-151497.1cfmSV.rst deleted file mode 100644 index a4c03c9d71d761..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-06-15-15-32-36.gh-issue-151497.1cfmSV.rst +++ /dev/null @@ -1,4 +0,0 @@ -Opening a :mod:`tarfile` archive no longer attempts to pre-allocate a huge -buffer when a crafted or truncated member claims an oversized extended header -(a GNU long name/link or a pax header). The extended header is now read in -bounded chunks, so its size field can no longer trigger memory exhaustion. diff --git a/Misc/NEWS.d/next/Library/2026-06-17-00-00-00.gh-issue-148660.odcopy.rst b/Misc/NEWS.d/next/Library/2026-06-17-00-00-00.gh-issue-148660.odcopy.rst deleted file mode 100644 index 30c2e366ca2ba0..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-06-17-00-00-00.gh-issue-148660.odcopy.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix a crash in :meth:`!collections.OrderedDict.copy` when a key's -``__eq__`` or a subclass method mutates the dict during the copy. Now -raises :exc:`RuntimeError` instead, as iteration does. diff --git a/Misc/NEWS.d/next/Library/2026-06-17-22-31-57.gh-issue-151613.n0nua1.rst b/Misc/NEWS.d/next/Library/2026-06-17-22-31-57.gh-issue-151613.n0nua1.rst deleted file mode 100644 index fbf3ce47ff2739..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-06-17-22-31-57.gh-issue-151613.n0nua1.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix another way the Tachyon profiler frame cache could produce impossible -mixed stack traces when ``_PyInterpreterFrame`` addresses are reused, by -validating cached frame anchors with a sequence counter. diff --git a/Misc/NEWS.d/next/Library/2026-06-18-12-48-03.gh-issue-151640.R4c3Fx.rst b/Misc/NEWS.d/next/Library/2026-06-18-12-48-03.gh-issue-151640.R4c3Fx.rst deleted file mode 100644 index ef61a7d27dd07d..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-06-18-12-48-03.gh-issue-151640.R4c3Fx.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix a data race in :class:`io.BytesIO` in free-threaded builds when -whole-buffer reads or peeks, or :meth:`~io.BytesIO.getvalue`, share the -internal buffer with concurrent writes. diff --git a/Misc/NEWS.d/next/Library/2026-06-18-23-59-46.gh-issue-151596.5ma144.rst b/Misc/NEWS.d/next/Library/2026-06-18-23-59-46.gh-issue-151596.5ma144.rst deleted file mode 100644 index 17ec1341142e93..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-06-18-23-59-46.gh-issue-151596.5ma144.rst +++ /dev/null @@ -1 +0,0 @@ -Add missing ``size`` positional argument to the pure-Python implementation of :meth:`io.TextIOBase.readline`. diff --git a/Misc/NEWS.d/next/Library/2026-06-20-21-15-13.gh-issue-151814.OIbgsO.rst b/Misc/NEWS.d/next/Library/2026-06-20-21-15-13.gh-issue-151814.OIbgsO.rst deleted file mode 100644 index 1365fb4d8edb1d..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-06-20-21-15-13.gh-issue-151814.OIbgsO.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix unbounded memory growth in :class:`io.TextIOWrapper` when repeatedly -writing an empty string. diff --git a/Misc/NEWS.d/next/Library/2026-06-21-15-50-24.gh-issue-86165.dyac1G.rst b/Misc/NEWS.d/next/Library/2026-06-21-15-50-24.gh-issue-86165.dyac1G.rst deleted file mode 100644 index 0b630e9ae34683..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-06-21-15-50-24.gh-issue-86165.dyac1G.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix :func:`imaplib.Time2Internaldate` to use the local timezone offset for -``time.struct_time`` values with ``tm_gmtoff`` set to ``None``, as returned by -``datetime.datetime.timetuple()``. Contributed by Xiao Yuan. diff --git a/Misc/NEWS.d/next/Library/2026-06-23-13-27-14.gh-issue-126219.kOfv2g.rst b/Misc/NEWS.d/next/Library/2026-06-23-13-27-14.gh-issue-126219.kOfv2g.rst deleted file mode 100644 index 8cc8c64c719471..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-06-23-13-27-14.gh-issue-126219.kOfv2g.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fixed a crash in :class:`tkinter.Tk` when *className* contains a non-BMP -character and tkinter is built against Tcl/Tk 8.x. Such a name is now -rejected with a :exc:`ValueError`. diff --git a/Misc/NEWS.d/next/Library/2026-06-23-17-14-04.gh-issue-127802.nGSxo6.rst b/Misc/NEWS.d/next/Library/2026-06-23-17-14-04.gh-issue-127802.nGSxo6.rst deleted file mode 100644 index 9484c9dbd23b2f..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-06-23-17-14-04.gh-issue-127802.nGSxo6.rst +++ /dev/null @@ -1,3 +0,0 @@ -The deprecated :class:`tkinter.Variable` methods :meth:`!trace_variable`, -:meth:`!trace`, :meth:`!trace_vdelete` and :meth:`!trace_vinfo` are now -scheduled for removal in Python 3.17. diff --git a/Misc/NEWS.d/next/Library/2026-06-24-10-46-35.gh-issue-152060.f2asrt.rst b/Misc/NEWS.d/next/Library/2026-06-24-10-46-35.gh-issue-152060.f2asrt.rst deleted file mode 100644 index 6088a6b80829bb..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-06-24-10-46-35.gh-issue-152060.f2asrt.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix :meth:`datetime.datetime.fromisoformat` raising :exc:`AssertionError` -instead of :exc:`ValueError` for some malformed strings in the pure-Python -implementation, matching the C implementation. diff --git a/Misc/NEWS.d/next/Library/2026-06-24-12-00-00.gh-issue-152052.yBssDE.rst b/Misc/NEWS.d/next/Library/2026-06-24-12-00-00.gh-issue-152052.yBssDE.rst deleted file mode 100644 index f9ffbbd342fc81..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-06-24-12-00-00.gh-issue-152052.yBssDE.rst +++ /dev/null @@ -1,2 +0,0 @@ -The :mod:`json` C accelerator now correctly reports an unterminated string for a -``\uXXXX`` escape at the end of the input. diff --git a/Misc/NEWS.d/next/Library/2026-06-24-12-00-00.gh-issue-152079.f1tzus.rst b/Misc/NEWS.d/next/Library/2026-06-24-12-00-00.gh-issue-152079.f1tzus.rst deleted file mode 100644 index 492d00724f6a46..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-06-24-12-00-00.gh-issue-152079.f1tzus.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix :meth:`datetime.datetime.fromisoformat` in the C implementation dropping -the sub-second part of a UTC offset whose whole-second part is zero, matching -the pure-Python implementation. diff --git a/Misc/NEWS.d/next/Library/2026-06-24-16-40-15.gh-issue-151378.iYWa_6.rst b/Misc/NEWS.d/next/Library/2026-06-24-16-40-15.gh-issue-151378.iYWa_6.rst deleted file mode 100644 index 0b3eb860ba8d32..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-06-24-16-40-15.gh-issue-151378.iYWa_6.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix a bug in the binary collector in Tachyon that caused unbounded memory -growth while profiling a thread that stayed asleep. Patch by Maurycy -Pawłowski-Wieroński. diff --git a/Misc/NEWS.d/next/Library/2026-06-24-22-16-35.gh-issue-105895.hRkuEw.rst b/Misc/NEWS.d/next/Library/2026-06-24-22-16-35.gh-issue-105895.hRkuEw.rst deleted file mode 100644 index c69e6fa7d14f4d..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-06-24-22-16-35.gh-issue-105895.hRkuEw.rst +++ /dev/null @@ -1,2 +0,0 @@ -Add :keyword:`match` and :keyword:`case` to the list of supported topics by -:func:`help`. diff --git a/Misc/NEWS.d/next/Library/2026-06-24-23-28-42.gh-issue-151669.tPUavQ.rst b/Misc/NEWS.d/next/Library/2026-06-24-23-28-42.gh-issue-151669.tPUavQ.rst deleted file mode 100644 index d8e4850ba94e14..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-06-24-23-28-42.gh-issue-151669.tPUavQ.rst +++ /dev/null @@ -1,3 +0,0 @@ -On Windows, when populating tar archives from filesystem content, to -conform to the tar format standard, backslashes in symlink targets are -be replaced by slashes. diff --git a/Misc/NEWS.d/next/Library/2026-06-25-01-00-43.gh-issue-151763.wWeHBe.rst b/Misc/NEWS.d/next/Library/2026-06-25-01-00-43.gh-issue-151763.wWeHBe.rst deleted file mode 100644 index 2f5e84027ad31b..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-06-25-01-00-43.gh-issue-151763.wWeHBe.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix crash in :func:`!_interpqueues.create` whe :exc:`MemoryError` -happens on queue creation. diff --git a/Misc/NEWS.d/next/Library/2026-06-25-07-08-17.gh-issue-152157.dt5Ef0.rst b/Misc/NEWS.d/next/Library/2026-06-25-07-08-17.gh-issue-152157.dt5Ef0.rst deleted file mode 100644 index 00e83b4af6be7a..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-06-25-07-08-17.gh-issue-152157.dt5Ef0.rst +++ /dev/null @@ -1,3 +0,0 @@ -The C implementations of :meth:`~datetime.datetime.fromisoformat` and :meth:`~datetime.time.fromisoformat` -now reject a decimal separator that is not followed by any -fractional digit before a timezone designator. diff --git a/Misc/NEWS.d/next/Library/2026-06-25-10-07-54.gh-issue-152156.gscPU9.rst b/Misc/NEWS.d/next/Library/2026-06-25-10-07-54.gh-issue-152156.gscPU9.rst deleted file mode 100644 index 30e561274dc50c..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-06-25-10-07-54.gh-issue-152156.gscPU9.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix a possible crash in :func:`concurrent.interpreters.create` under limited -memory conditions. diff --git a/Misc/NEWS.d/next/Library/2026-06-25-12-00-00.gh-issue-152212.Zk7Qm2.rst b/Misc/NEWS.d/next/Library/2026-06-25-12-00-00.gh-issue-152212.Zk7Qm2.rst deleted file mode 100644 index 2b1d272638b11a..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-06-25-12-00-00.gh-issue-152212.Zk7Qm2.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix the pure-Python :mod:`zoneinfo` parser accepting a POSIX TZ string with a -``std`` abbreviation but no offset. This is invalid per POSIX and now -raises :exc:`ValueError`, matching the C accelerator. Patch by tonghuaroot. diff --git a/Misc/NEWS.d/next/Library/2026-06-25-14-32-42.gh-issue-139145.kT9rmP.rst b/Misc/NEWS.d/next/Library/2026-06-25-14-32-42.gh-issue-139145.kT9rmP.rst deleted file mode 100644 index 3fa639c5f727ba..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-06-25-14-32-42.gh-issue-139145.kT9rmP.rst +++ /dev/null @@ -1,5 +0,0 @@ -Fix a busy loop in :mod:`tkinter` on interactive Python. When a Tcl command -running its own event loop (such as ``vwait`` or :meth:`!wait_variable`) was -active and input arrived on stdin, the event loop kept spinning at 100% CPU. -The stdin file handler is now removed as soon as input is available. Based on -a patch by Michiel de Hoon. diff --git a/Misc/NEWS.d/next/Library/2026-06-25-14-32-43.gh-issue-139816.Lq2vXa.rst b/Misc/NEWS.d/next/Library/2026-06-25-14-32-43.gh-issue-139816.Lq2vXa.rst deleted file mode 100644 index b180dee686caf8..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-06-25-14-32-43.gh-issue-139816.Lq2vXa.rst +++ /dev/null @@ -1,4 +0,0 @@ -Fix a hang in :mod:`tkinter` on interactive Python built without -:mod:`readline`. An exception raised in a callback no longer causes the -event loop to stop and wait for the user to press Enter; pending callbacks -now keep running until input is actually available on stdin. diff --git a/Misc/NEWS.d/next/Library/2026-06-25-20-00-00.gh-issue-151496.kMnT3x.rst b/Misc/NEWS.d/next/Library/2026-06-25-20-00-00.gh-issue-151496.kMnT3x.rst deleted file mode 100644 index 994e5dadcf2e8a..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-06-25-20-00-00.gh-issue-151496.kMnT3x.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fixed ``profiling.sampling --gecko`` with ``--async-aware`` by flattening -async task stacks before generating Gecko samples. ``--binary`` now rejects -``--async-aware`` until the binary format supports async task data. diff --git a/Misc/NEWS.d/next/Library/2026-06-26-12-50-26.gh-issue-152246.MfXMd1.rst b/Misc/NEWS.d/next/Library/2026-06-26-12-50-26.gh-issue-152246.MfXMd1.rst deleted file mode 100644 index 0858199a9fa279..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-06-26-12-50-26.gh-issue-152246.MfXMd1.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix the pure-Python :mod:`zoneinfo` parser accepting an invalid POSIX TZ -transition rule with a non-period separator. Patch by tonghuaroot. diff --git a/Misc/NEWS.d/next/Library/2026-06-26-13-10-00.gh-issue-80937.Hq3mNp.rst b/Misc/NEWS.d/next/Library/2026-06-26-13-10-00.gh-issue-80937.Hq3mNp.rst deleted file mode 100644 index 4ea0179c6586d4..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-06-26-13-10-00.gh-issue-80937.Hq3mNp.rst +++ /dev/null @@ -1,4 +0,0 @@ -Fix a memory leak in :mod:`tkinter` when a Tcl command created with -``createcommand`` was not explicitly removed before the interpreter was -deleted. The command no longer keeps the interpreter alive through a -reference cycle. diff --git a/Misc/NEWS.d/next/Library/2026-06-26-13-39-11.gh-issue-152248.N2Rmaf.rst b/Misc/NEWS.d/next/Library/2026-06-26-13-39-11.gh-issue-152248.N2Rmaf.rst deleted file mode 100644 index 8921ad17349e97..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-06-26-13-39-11.gh-issue-152248.N2Rmaf.rst +++ /dev/null @@ -1,3 +0,0 @@ -Make the C and pure-Python :mod:`zoneinfo` parsers validate POSIX TZ -abbreviations consistently, rejecting unquoted abbreviations with non-letter -characters and empty quoted abbreviations. Patch by tonghuaroot. diff --git a/Misc/NEWS.d/next/Library/2026-06-26-15-00-00.gh-issue-38464.yDPjKH.rst b/Misc/NEWS.d/next/Library/2026-06-26-15-00-00.gh-issue-38464.yDPjKH.rst deleted file mode 100644 index c1c272b97d4b0a..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-06-26-15-00-00.gh-issue-38464.yDPjKH.rst +++ /dev/null @@ -1,3 +0,0 @@ -:meth:`!tkinter.Misc.nametowidget` now resolves the auto-generated names of -cloned menus (a menu used as a menubar or a cascade) back to the original -widget. diff --git a/Misc/NEWS.d/next/Library/2026-06-26-15-30-00.gh-issue-88758.Qw7nLp.rst b/Misc/NEWS.d/next/Library/2026-06-26-15-30-00.gh-issue-88758.Qw7nLp.rst deleted file mode 100644 index 31d567194fb903..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-06-26-15-30-00.gh-issue-88758.Qw7nLp.rst +++ /dev/null @@ -1,4 +0,0 @@ -:meth:`!tkinter.Misc.focus_get`, :meth:`!focus_displayof`, -:meth:`!focus_lastfor` and :meth:`!winfo_containing` now return ``None`` -instead of raising :exc:`KeyError` when the widget was not created by -:mod:`tkinter` (for example a torn-off menu). diff --git a/Misc/NEWS.d/next/Library/2026-06-26-15-41-34.gh-issue-152305.WnbbBc.rst b/Misc/NEWS.d/next/Library/2026-06-26-15-41-34.gh-issue-152305.WnbbBc.rst deleted file mode 100644 index 4f27e2ed016d69..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-06-26-15-41-34.gh-issue-152305.WnbbBc.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix the pure-Python :meth:`datetime.time.strftime` implementation raising :exc:`AttributeError` for the -year directives. Patch by tonghuaroot. diff --git a/Misc/NEWS.d/next/Library/2026-06-26-16-30-00.gh-issue-83274.Kx9mQv.rst b/Misc/NEWS.d/next/Library/2026-06-26-16-30-00.gh-issue-83274.Kx9mQv.rst deleted file mode 100644 index 3b722d2176be92..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-06-26-16-30-00.gh-issue-83274.Kx9mQv.rst +++ /dev/null @@ -1,3 +0,0 @@ -Deallocating a :mod:`tkinter` application from a thread other than the one it -was created in no longer crashes the interpreter. The underlying Tcl -interpreter is leaked instead, and a :exc:`RuntimeWarning` is reported. diff --git a/Misc/NEWS.d/next/Library/2026-06-26-23-56-40.gh-issue-71880.782D31.rst b/Misc/NEWS.d/next/Library/2026-06-26-23-56-40.gh-issue-71880.782D31.rst deleted file mode 100644 index 5a12f428f2a8b6..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-06-26-23-56-40.gh-issue-71880.782D31.rst +++ /dev/null @@ -1,5 +0,0 @@ -:class:`curses.textpad.Textbox` now lets the lower-right cell of the window be -edited. Writing it with :meth:`~curses.window.addch` would move the cursor -past the end of the window, raising an error and scrolling a scrollable window, -so it is now written with :meth:`~curses.window.insch`, which keeps the cursor -in place. diff --git a/Misc/NEWS.d/next/Library/2026-06-27-12-30-00.gh-issue-133031.Na8Bit.rst b/Misc/NEWS.d/next/Library/2026-06-27-12-30-00.gh-issue-133031.Na8Bit.rst deleted file mode 100644 index 96e9efe20e42f0..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-06-27-12-30-00.gh-issue-133031.Na8Bit.rst +++ /dev/null @@ -1,3 +0,0 @@ -:class:`curses.textpad.Textbox` now enters and reads back the non-ASCII -characters of an 8-bit locale encoding, instead of mangling them with a 7-bit -mask. diff --git a/Misc/NEWS.d/next/Library/2026-06-27-17-19-09.gh-issue-151126.huUyOM.rst b/Misc/NEWS.d/next/Library/2026-06-27-17-19-09.gh-issue-151126.huUyOM.rst deleted file mode 100644 index 2e51fd45b59548..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-06-27-17-19-09.gh-issue-151126.huUyOM.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix two crashes in :mod:`tkinter` and :mod:`socket` modules initialization -under a memory pressure. Sets missing :exc:`MemoryError`. diff --git a/Misc/NEWS.d/next/Library/2026-06-28-11-00-40.gh-issue-78335.Kp3mWq.rst b/Misc/NEWS.d/next/Library/2026-06-28-11-00-40.gh-issue-78335.Kp3mWq.rst deleted file mode 100644 index 641889cfa9ef41..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-06-28-11-00-40.gh-issue-78335.Kp3mWq.rst +++ /dev/null @@ -1,4 +0,0 @@ -Update the docstrings of :mod:`tkinter` and :mod:`tkinter.ttk` widget classes -to list all supported widget options, including options added in Tk 9.0 and -9.1. ``tkinter.Menubutton`` and ``tkinter.Message`` previously had no option -list at all. diff --git a/Misc/NEWS.d/next/Library/2026-06-28-12-45-09.gh-issue-152356.Dr4w2Q.rst b/Misc/NEWS.d/next/Library/2026-06-28-12-45-09.gh-issue-152356.Dr4w2Q.rst deleted file mode 100644 index 6a4ceecbe9279e..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-06-28-12-45-09.gh-issue-152356.Dr4w2Q.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix a hang in ``profiling.sampling run --blocking`` on Windows when the -target process exits. The profiler now finalizes binary profiles instead of -continuing to sample the exited process. diff --git a/Misc/NEWS.d/next/Library/2026-06-29-01-08-53.gh-issue-110357.QGWdZQ.rst b/Misc/NEWS.d/next/Library/2026-06-29-01-08-53.gh-issue-110357.QGWdZQ.rst deleted file mode 100644 index 7c2384ea76fe53..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-06-29-01-08-53.gh-issue-110357.QGWdZQ.rst +++ /dev/null @@ -1,6 +0,0 @@ -Importing :mod:`hashlib` no longer logs an error to stderr when a normally -guaranteed hash algorithm is unavailable in the current runtime (for example -under an OpenSSL FIPS configuration or a build using -:option:`--without-builtin-hashlib-hashes <--with-builtin-hashlib-hashes>`). -Code that actually uses the missing algorithm still gets a clear -:exc:`ValueError`. diff --git a/Misc/NEWS.d/next/Library/2026-06-29-09-45-00.gh-issue-152569.Kf7Lq2.rst b/Misc/NEWS.d/next/Library/2026-06-29-09-45-00.gh-issue-152569.Kf7Lq2.rst deleted file mode 100644 index fb7e32a5260b39..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-06-29-09-45-00.gh-issue-152569.Kf7Lq2.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix :func:`asyncio.wait` leaking waiting tasks via the await-graph when racing a -future that never resolves. The waiting task is now discarded from every future's -``awaited_by`` set once :func:`~asyncio.wait` returns, even for pending futures. diff --git a/Misc/NEWS.d/next/Library/2026-06-29-22-16-57.gh-issue-50966.Tq5mLp.rst b/Misc/NEWS.d/next/Library/2026-06-29-22-16-57.gh-issue-50966.Tq5mLp.rst deleted file mode 100644 index 96a0938c02d226..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-06-29-22-16-57.gh-issue-50966.Tq5mLp.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix unbounded recursion in :mod:`turtle` when a mouse event handler that moves -the turtle is reentered while the screen is being redrawn, for example with -``screen.ondrag(turtle.goto)``. This could previously crash the interpreter. diff --git a/Misc/NEWS.d/next/Library/2026-06-30-12-00-00.gh-issue-40038.qK7mGv.rst b/Misc/NEWS.d/next/Library/2026-06-30-12-00-00.gh-issue-40038.qK7mGv.rst deleted file mode 100644 index 1f393d23266bce..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-06-30-12-00-00.gh-issue-40038.qK7mGv.rst +++ /dev/null @@ -1,6 +0,0 @@ -:mod:`imaplib` now again quotes command arguments when necessary, for -example mailbox names containing a space. Such quoting was inadvertently -disabled when the module was ported to Python 3, and the arguments are now -quoted according to the :rfc:`3501` grammar. For backward compatibility, -an argument already enclosed in double quotes is left unchanged, so code -that quotes arguments itself keeps working. diff --git a/Misc/NEWS.d/next/Library/2026-06-30-13-00-00.gh-issue-151842.OOM31g.rst b/Misc/NEWS.d/next/Library/2026-06-30-13-00-00.gh-issue-151842.OOM31g.rst deleted file mode 100644 index 8a2ecf3c40032f..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-06-30-13-00-00.gh-issue-151842.OOM31g.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix a crash in :func:`!_interpreters.capture_exception` when -:exc:`MemoryError` happens. Patch by Amrutha Modela. diff --git a/Misc/NEWS.d/next/Library/2026-06-30-21-40-00.gh-issue-152502.Kq3Vn7.rst b/Misc/NEWS.d/next/Library/2026-06-30-21-40-00.gh-issue-152502.Kq3Vn7.rst deleted file mode 100644 index 815bc47966c40c..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-06-30-21-40-00.gh-issue-152502.Kq3Vn7.rst +++ /dev/null @@ -1,5 +0,0 @@ -Detect the :mod:`curses` mouse interface (:func:`~curses.getmouse`, the -``BUTTON*`` constants, and others) with a configure capability probe or library -macros instead of gating it on ncurses-specific macros. It is now also -available with other curses implementations that provide it, such as NetBSD -curses and PDCurses (the latter underpins ``windows-curses``). diff --git a/Misc/NEWS.d/next/Library/2026-07-01-10-00-00.gh-issue-88574.Kz3wQm.rst b/Misc/NEWS.d/next/Library/2026-07-01-10-00-00.gh-issue-88574.Kz3wQm.rst deleted file mode 100644 index 371f4d08bccd2e..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-07-01-10-00-00.gh-issue-88574.Kz3wQm.rst +++ /dev/null @@ -1,4 +0,0 @@ -:mod:`imaplib` no longer fails when a server sends a spurious blank line -after the counted data of a literal, including after a literal that -terminates a response (such as a mailbox name returned by ``LIST``). -Such blank lines are now skipped without swallowing the following line. diff --git a/Misc/NEWS.d/next/Library/2026-07-01-10-30-00.gh-issue-63121.Rm4tZp.rst b/Misc/NEWS.d/next/Library/2026-07-01-10-30-00.gh-issue-63121.Rm4tZp.rst deleted file mode 100644 index a63b164ad7a627..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-07-01-10-30-00.gh-issue-63121.Rm4tZp.rst +++ /dev/null @@ -1,7 +0,0 @@ -:mod:`imaplib` now refreshes the cached capability list after a successful -:meth:`~imaplib.IMAP4.login` or :meth:`~imaplib.IMAP4.authenticate`, using -the ``CAPABILITY`` response sent by the server or, if none was sent, by -querying it, so that capabilities that become available only after -authentication (such as ``ENABLE`` on Gmail) are recognized. Capabilities -advertised in the server greeting are now also used, avoiding a redundant -``CAPABILITY`` command. diff --git a/Misc/NEWS.d/next/Library/2026-07-01-12-00-00.gh-issue-108280.Nq8vTr.rst b/Misc/NEWS.d/next/Library/2026-07-01-12-00-00.gh-issue-108280.Nq8vTr.rst deleted file mode 100644 index 487c9da67f1832..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-07-01-12-00-00.gh-issue-108280.Nq8vTr.rst +++ /dev/null @@ -1,4 +0,0 @@ -Connecting :mod:`imaplib` to a server that does not send a valid IMAP4 -greeting (for example a POP3 server answering on the IMAP port) now raises -an error reporting the server's response instead of -``imaplib.IMAP4.error: None``. diff --git a/Misc/NEWS.d/next/Library/2026-07-01-12-00-00.gh-issue-152718.pr0f1l.rst b/Misc/NEWS.d/next/Library/2026-07-01-12-00-00.gh-issue-152718.pr0f1l.rst deleted file mode 100644 index 63d9d7f878cb07..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-07-01-12-00-00.gh-issue-152718.pr0f1l.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix unbounded memory allocation in the :mod:`profiling.sampling` binary profile -reader when a file declares more string or frame entries than it contains. diff --git a/Misc/NEWS.d/next/Library/2026-07-02-12-00-00.gh-issue-152847.PitKqc.rst b/Misc/NEWS.d/next/Library/2026-07-02-12-00-00.gh-issue-152847.PitKqc.rst deleted file mode 100644 index 3f20d78a201e84..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-07-02-12-00-00.gh-issue-152847.PitKqc.rst +++ /dev/null @@ -1,3 +0,0 @@ -Reject a POSIX TZ transition rule with non-digit characters in the -day-of-year field in the pure-Python :mod:`zoneinfo` parser. Patch by -tonghuaroot. diff --git a/Misc/NEWS.d/next/Library/2026-07-02-13-30-00.gh-issue-152849.K9dRvP.rst b/Misc/NEWS.d/next/Library/2026-07-02-13-30-00.gh-issue-152849.K9dRvP.rst deleted file mode 100644 index 053a5dfea3f3ff..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-07-02-13-30-00.gh-issue-152849.K9dRvP.rst +++ /dev/null @@ -1,2 +0,0 @@ -Out-of-range float and integer timestamps now raise :exc:`OverflowError` -with the same message. Patch by tonghuaroot. diff --git a/Misc/NEWS.d/next/Library/2026-07-02-19-21-15.gh-issue-152068.ThsmJU.rst b/Misc/NEWS.d/next/Library/2026-07-02-19-21-15.gh-issue-152068.ThsmJU.rst deleted file mode 100644 index 9ec8413b4ac424..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-07-02-19-21-15.gh-issue-152068.ThsmJU.rst +++ /dev/null @@ -1 +0,0 @@ -Fixes a bug when a line was split (particularly on macOS Terminal.app) in the middle of a colorized keyword, causing the ANSI Color Reset sequence (ESC0m) to not be properly printed, causing the output to be colored when it shouldn't diff --git a/Misc/NEWS.d/next/Library/2026-07-02-22-19-53.gh-issue-150880.vPZ7jK.rst b/Misc/NEWS.d/next/Library/2026-07-02-22-19-53.gh-issue-150880.vPZ7jK.rst deleted file mode 100644 index a7bf210f8e1ca9..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-07-02-22-19-53.gh-issue-150880.vPZ7jK.rst +++ /dev/null @@ -1,3 +0,0 @@ -Normalize non-extended Windows paths before appending the wildcard used by -``os.listdir()`` and ``os.scandir()``, making paths with trailing spaces -behave consistently with other filesystem APIs. diff --git a/Misc/NEWS.d/next/Library/2026-07-03-14-54-33.gh-issue-152951.u8tPCI.rst b/Misc/NEWS.d/next/Library/2026-07-03-14-54-33.gh-issue-152951.u8tPCI.rst deleted file mode 100644 index c3d56c6d59c91b..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-07-03-14-54-33.gh-issue-152951.u8tPCI.rst +++ /dev/null @@ -1,2 +0,0 @@ -:class:`collections.deque` prevent rare crash when calling ``extend`` under -high memory pressure conditions. diff --git a/Misc/NEWS.d/next/Library/2026-07-03-17-29-34.gh-issue-150579.0tLpQukIU.rst b/Misc/NEWS.d/next/Library/2026-07-03-17-29-34.gh-issue-150579.0tLpQukIU.rst deleted file mode 100644 index 7aff384431edc7..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-07-03-17-29-34.gh-issue-150579.0tLpQukIU.rst +++ /dev/null @@ -1,2 +0,0 @@ -:mod:`concurrent.futures` now uses lazy imports for its executor submodules -instead of a module ``__getattr__`` hook. diff --git a/Misc/NEWS.d/next/Library/2026-07-03-18-30-00.gh-issue-119592.mQr3Vx.rst b/Misc/NEWS.d/next/Library/2026-07-03-18-30-00.gh-issue-119592.mQr3Vx.rst deleted file mode 100644 index f718c877c8ed22..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-07-03-18-30-00.gh-issue-119592.mQr3Vx.rst +++ /dev/null @@ -1,11 +0,0 @@ -Fix :class:`concurrent.futures.ProcessPoolExecutor` stranding submitted -work forever when a worker process exited upon reaching its -*max_tasks_per_child* limit after -:meth:`~concurrent.futures.Executor.shutdown` was called with -``wait=False``: a replacement worker is now spawned and the remaining work -executed as documented. If the executor has instead been garbage collected -without ``shutdown()`` (:gh:`152967`), or a replacement worker cannot be -started, the remaining futures now fail with -:exc:`~concurrent.futures.process.BrokenProcessPool` instead of never -resolving. A worker exit racing ``shutdown(wait=False)`` can also no -longer crash the executor management thread. diff --git a/Misc/NEWS.d/next/Library/2026-07-03-21-10-00.gh-issue-54930.hq09Er.rst b/Misc/NEWS.d/next/Library/2026-07-03-21-10-00.gh-issue-54930.hq09Er.rst deleted file mode 100644 index 1cfc0212c609a6..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-07-03-21-10-00.gh-issue-54930.hq09Er.rst +++ /dev/null @@ -1,5 +0,0 @@ -Error responses of :class:`http.server.BaseHTTPRequestHandler` to malformed -request lines now include a status line and headers instead of being sent in -the bare HTTP/0.9 style. -Only a valid HTTP/0.9 request (a two-word ``GET`` request line) now receives -an HTTP/0.9 style response. diff --git a/Misc/NEWS.d/next/Library/2026-07-04-11-14-06.gh-issue-152851.diYvTf.rst b/Misc/NEWS.d/next/Library/2026-07-04-11-14-06.gh-issue-152851.diYvTf.rst deleted file mode 100644 index aab033ebeed695..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-07-04-11-14-06.gh-issue-152851.diYvTf.rst +++ /dev/null @@ -1,2 +0,0 @@ -Prevent a crash when allocation fails while copying a :func:`BLAKE-2s/2b -<hashlib.blake2b>` object. Patch by Bénédikt Tran. diff --git a/Misc/NEWS.d/next/Library/2026-07-04-13-00-00.gh-issue-135661.CIkADG.rst b/Misc/NEWS.d/next/Library/2026-07-04-13-00-00.gh-issue-135661.CIkADG.rst deleted file mode 100644 index 26a912a6f3a194..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-07-04-13-00-00.gh-issue-135661.CIkADG.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix :class:`html.parser.HTMLParser`: an abruptly closed empty comment -(``<!-->`` or ``<!--->``) no longer extends up to a later ``-->`` in the same -:meth:`~html.parser.HTMLParser.feed` call. diff --git a/Misc/NEWS.d/next/Library/2026-07-04-20-28-51.gh-issue-153037.XUSp_g.rst b/Misc/NEWS.d/next/Library/2026-07-04-20-28-51.gh-issue-153037.XUSp_g.rst deleted file mode 100644 index cbfc62f7518470..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-07-04-20-28-51.gh-issue-153037.XUSp_g.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix :class:`~compression.zstd.ZstdFile` raising :exc:`AttributeError` -instead of :exc:`io.UnsupportedOperation` when iterating over a file that -is not open for reading. diff --git a/Misc/NEWS.d/next/Library/2026-07-05-10-24-30.gh-issue-143921.wQx3Tn.rst b/Misc/NEWS.d/next/Library/2026-07-05-10-24-30.gh-issue-143921.wQx3Tn.rst deleted file mode 100644 index 04e8bd6d6f9d6c..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-07-05-10-24-30.gh-issue-143921.wQx3Tn.rst +++ /dev/null @@ -1,4 +0,0 @@ -Narrow the control character check in :mod:`imaplib` commands: only NUL, CR -and LF are now rejected. Other control characters are valid in quoted -strings and can occur in mailbox names returned by the server, so they are -now accepted and sent quoted. diff --git a/Misc/NEWS.d/next/Library/2026-07-05-12-00-00.gh-issue-153056.tMpLat.rst b/Misc/NEWS.d/next/Library/2026-07-05-12-00-00.gh-issue-153056.tMpLat.rst deleted file mode 100644 index a2bc89f25a53c1..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-07-05-12-00-00.gh-issue-153056.tMpLat.rst +++ /dev/null @@ -1,4 +0,0 @@ -Fix :class:`string.Template` raising a spurious :exc:`ValueError` when the -*pattern* attribute is a compiled regular expression object, which the -documentation allows. On the free-threaded build this also occurred as a data -race on the first concurrent use. diff --git a/Misc/NEWS.d/next/Library/2026-07-05-14-30-00.gh-issue-153062.teeFT1.rst b/Misc/NEWS.d/next/Library/2026-07-05-14-30-00.gh-issue-153062.teeFT1.rst deleted file mode 100644 index ed1aaa15d37bd9..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-07-05-14-30-00.gh-issue-153062.teeFT1.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix a crash when concurrently iterating an :func:`itertools.tee` iterator on -the free-threaded build. diff --git a/Misc/NEWS.d/next/Library/2026-07-05-16-09-31.gh-issue-153068.huY9Jh.rst b/Misc/NEWS.d/next/Library/2026-07-05-16-09-31.gh-issue-153068.huY9Jh.rst deleted file mode 100644 index accf6e99cd6434..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-07-05-16-09-31.gh-issue-153068.huY9Jh.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix :meth:`!cProfile.Profile.enable` to no longer overwrite errors from -:mod:`sys.monitoring`. diff --git a/Misc/NEWS.d/next/Library/2026-07-06-12-00-00.gh-issue-153200.isqrtLt.rst b/Misc/NEWS.d/next/Library/2026-07-06-12-00-00.gh-issue-153200.isqrtLt.rst deleted file mode 100644 index a27ac73fe31a70..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-07-06-12-00-00.gh-issue-153200.isqrtLt.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix :func:`math.isqrt` returning an incorrect result for arguments not -less than 2**64 that are instances of an :class:`int` subclass with an -overridden comparison operator. diff --git a/Misc/NEWS.d/next/Library/2026-07-07-02-26-43.gh-issue-153210.LUXIcm.rst b/Misc/NEWS.d/next/Library/2026-07-07-02-26-43.gh-issue-153210.LUXIcm.rst deleted file mode 100644 index d5d4b7c1b8c0ed..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-07-07-02-26-43.gh-issue-153210.LUXIcm.rst +++ /dev/null @@ -1 +0,0 @@ -Fix crash on :mod:`array` import under a memory pressure. diff --git a/Misc/NEWS.d/next/Library/2026-07-07-13-31-52.gh-issue-148286.-qu-em.rst b/Misc/NEWS.d/next/Library/2026-07-07-13-31-52.gh-issue-148286.-qu-em.rst deleted file mode 100644 index 60cd49020c954a..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-07-07-13-31-52.gh-issue-148286.-qu-em.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix undefined behavior in -:attr:`compression.zstd.ZstdDecompressor.unused_data` when a complete frame -was decompressed in a single call. diff --git a/Misc/NEWS.d/next/Library/2026-07-07-17-50-54.gh-issue-143990.FoNtCf.rst b/Misc/NEWS.d/next/Library/2026-07-07-17-50-54.gh-issue-143990.FoNtCf.rst deleted file mode 100644 index a78dcccf482ab5..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-07-07-17-50-54.gh-issue-143990.FoNtCf.rst +++ /dev/null @@ -1,4 +0,0 @@ -A :class:`tkinter.font.Font` created from a named font, -including by :meth:`~tkinter.font.Font.copy`, -now copies its configured options rather than the options resolved by Tcl's ``font actual``, -preserving a size specified in pixels (a negative size). diff --git a/Misc/NEWS.d/next/Library/2026-07-07-22-06-52.gh-issue-153293.0DvYdc.rst b/Misc/NEWS.d/next/Library/2026-07-07-22-06-52.gh-issue-153293.0DvYdc.rst deleted file mode 100644 index ac358bb7fc0a50..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-07-07-22-06-52.gh-issue-153293.0DvYdc.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix the live sampling profiler TUI keeping stale aggregated opcode -statistics after a stats reset. diff --git a/Misc/NEWS.d/next/Library/2026-07-08-01-03-17.gh-issue-153292.oHDt3l.rst b/Misc/NEWS.d/next/Library/2026-07-08-01-03-17.gh-issue-153292.oHDt3l.rst deleted file mode 100644 index dc363e16007430..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-07-08-01-03-17.gh-issue-153292.oHDt3l.rst +++ /dev/null @@ -1 +0,0 @@ -Fix data race in repr of :class:`threading.RLock` in free-threading build. diff --git a/Misc/NEWS.d/next/Library/2026-07-08-01-47-15.gh-issue-153083.XbKZCp.rst b/Misc/NEWS.d/next/Library/2026-07-08-01-47-15.gh-issue-153083.XbKZCp.rst deleted file mode 100644 index b6d96851e17342..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-07-08-01-47-15.gh-issue-153083.XbKZCp.rst +++ /dev/null @@ -1,2 +0,0 @@ -Defer GC tracking of an :class:`array.array` to the end of its construction. -Patch by Donghee Na. diff --git a/Misc/NEWS.d/next/Library/2026-07-08-21-15-00.gh-issue-153333.Kp3mZq.rst b/Misc/NEWS.d/next/Library/2026-07-08-21-15-00.gh-issue-153333.Kp3mZq.rst deleted file mode 100644 index 6fcbd590d0d9d3..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-07-08-21-15-00.gh-issue-153333.Kp3mZq.rst +++ /dev/null @@ -1,3 +0,0 @@ -The ``readprofile`` method of :class:`tkinter.Tk` now reads the user's -profile scripts using the encoding declared in the file, instead of the -locale encoding. diff --git a/Misc/NEWS.d/next/Library/2026-07-09-00-00-00.gh-issue-153406.vyMmB6.rst b/Misc/NEWS.d/next/Library/2026-07-09-00-00-00.gh-issue-153406.vyMmB6.rst deleted file mode 100644 index c09575754e3380..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-07-09-00-00-00.gh-issue-153406.vyMmB6.rst +++ /dev/null @@ -1,3 +0,0 @@ -:func:`email.utils.parsedate_to_datetime` now raises :exc:`ValueError` -instead of :exc:`OverflowError` when the parsed year or timezone offset is -out of range, matching its documented behavior. diff --git a/Misc/NEWS.d/next/Library/2026-07-09-14-00-00.gh-issue-153417.Bw7Rq2.rst b/Misc/NEWS.d/next/Library/2026-07-09-14-00-00.gh-issue-153417.Bw7Rq2.rst deleted file mode 100644 index ebc36fa7c228d0..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-07-09-14-00-00.gh-issue-153417.Bw7Rq2.rst +++ /dev/null @@ -1,3 +0,0 @@ -Error messages from :meth:`imaplib.IMAP4.select` and :meth:`imaplib.IMAP4.uid` -no longer raise :exc:`BytesWarning` under :option:`!-bb` -when the mailbox or command argument is :class:`bytes`. diff --git a/Misc/NEWS.d/next/Library/2026-07-09-15-18-23.gh-issue-151292.f4NQSW.rst b/Misc/NEWS.d/next/Library/2026-07-09-15-18-23.gh-issue-151292.f4NQSW.rst deleted file mode 100644 index 4165893fc47457..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-07-09-15-18-23.gh-issue-151292.f4NQSW.rst +++ /dev/null @@ -1,5 +0,0 @@ -Store the sample count in :mod:`profiling.sampling` binary format, as a -64-bit integer, widening from previously used 32-bit integer. This breaks -the existing recordings. Long or thread-heavy profiling sessions will no -longer fail because of :exc:`OverflowError`. Patch by Maurycy -Pawłowski-Wieroński. diff --git a/Misc/NEWS.d/next/Library/2026-07-12-00-00-00.gh-issue-85943.8f906e.rst b/Misc/NEWS.d/next/Library/2026-07-12-00-00-00.gh-issue-85943.8f906e.rst deleted file mode 100644 index 0a93bf2e7b803e..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-07-12-00-00-00.gh-issue-85943.8f906e.rst +++ /dev/null @@ -1,4 +0,0 @@ -Fix :mod:`struct` functions raising :exc:`BytesWarning` under the ``-bb`` -command line option when a :class:`str` format is used after an equal -:class:`bytes` format (or vice versa). The internal format cache no longer -mixes :class:`str` and :class:`bytes` keys. diff --git a/Misc/NEWS.d/next/Library/2026-07-13-10-27-08.gh-issue-153658.A6o4n5.rst b/Misc/NEWS.d/next/Library/2026-07-13-10-27-08.gh-issue-153658.A6o4n5.rst deleted file mode 100644 index 06385bb7754b12..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-07-13-10-27-08.gh-issue-153658.A6o4n5.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix :meth:`sqlite3.Connection.iterdump` raising :exc:`sqlite3.OperationalError` -when a table name contains a single quote. Patch by tonghuaroot. diff --git a/Misc/NEWS.d/next/Library/2026-07-14-19-45-21.gh-issue-153695.UYdZJZ.rst b/Misc/NEWS.d/next/Library/2026-07-14-19-45-21.gh-issue-153695.UYdZJZ.rst deleted file mode 100644 index 43d7feebf97d6f..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-07-14-19-45-21.gh-issue-153695.UYdZJZ.rst +++ /dev/null @@ -1,2 +0,0 @@ -Hashing a :class:`sqlite3.Row` that contains an unhashable value now raises -:exc:`TypeError` instead of :exc:`SystemError`. Patch by tonghuaroot. diff --git a/Misc/NEWS.d/next/Security/2026-01-16-11-58-19.gh-issue-143927.aviFeG.rst b/Misc/NEWS.d/next/Security/2026-01-16-11-58-19.gh-issue-143927.aviFeG.rst deleted file mode 100644 index ca554997e5c396..00000000000000 --- a/Misc/NEWS.d/next/Security/2026-01-16-11-58-19.gh-issue-143927.aviFeG.rst +++ /dev/null @@ -1,2 +0,0 @@ -Normalize all line endings (CR, CRLF, and LF) to LF+TAB when writing -multi-line configparser values. diff --git a/Misc/NEWS.d/next/Security/2026-05-30-00-00-00.gh-issue-150743.httpdos.rst b/Misc/NEWS.d/next/Security/2026-05-30-00-00-00.gh-issue-150743.httpdos.rst deleted file mode 100644 index abc07d91c63fca..00000000000000 --- a/Misc/NEWS.d/next/Security/2026-05-30-00-00-00.gh-issue-150743.httpdos.rst +++ /dev/null @@ -1,7 +0,0 @@ -:mod:`http.client` now limits the number of chunked-response trailer lines -it will read to :attr:`~http.client.HTTPConnection.max_response_headers` -(100 by default), and the number of interim (1xx) responses it will skip -to 100. A malicious or broken server could previously stream trailer -lines or ``100 Continue`` responses forever, hanging the client even when -a socket timeout was in use. -Reported by ``@YLChen-007`` via GHSA-w4q2-g22w-6fr4. diff --git a/Misc/NEWS.d/next/Security/2026-06-10-13-08-19.gh-issue-151558.mL74i2.rst b/Misc/NEWS.d/next/Security/2026-06-10-13-08-19.gh-issue-151558.mL74i2.rst deleted file mode 100644 index 74459d5680e21a..00000000000000 --- a/Misc/NEWS.d/next/Security/2026-06-10-13-08-19.gh-issue-151558.mL74i2.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fixed an vulnerability in the :mod:`tarfile` ``data`` and ``tar`` extraction -filters where crafted archives could create a symlink pointing outside the -destination directory. This was a bypass of :cve:`2025-4330`. diff --git a/Misc/NEWS.d/next/Security/2026-06-23-13-28-16.gh-issue-151981.xBHEcU.rst b/Misc/NEWS.d/next/Security/2026-06-23-13-28-16.gh-issue-151981.xBHEcU.rst deleted file mode 100644 index 2123ab8e081b1d..00000000000000 --- a/Misc/NEWS.d/next/Security/2026-06-23-13-28-16.gh-issue-151981.xBHEcU.rst +++ /dev/null @@ -1,2 +0,0 @@ -In :mod:`tarfile`, seeking a stream now stops when end of the stream is -reached. diff --git a/Misc/NEWS.d/next/Security/2026-06-23-14-19-30.gh-issue-151987.8mNIMf.rst b/Misc/NEWS.d/next/Security/2026-06-23-14-19-30.gh-issue-151987.8mNIMf.rst deleted file mode 100644 index 9eea7b32c4d2b4..00000000000000 --- a/Misc/NEWS.d/next/Security/2026-06-23-14-19-30.gh-issue-151987.8mNIMf.rst +++ /dev/null @@ -1,2 +0,0 @@ -The :meth:`tarfile.TarFile.extract` method now applies the given filter when -it extracts a link target from the archive as a fallback. diff --git a/Misc/NEWS.d/next/Security/2026-06-25-20-44-20.gh-issue-152216.VxiK5y.rst b/Misc/NEWS.d/next/Security/2026-06-25-20-44-20.gh-issue-152216.VxiK5y.rst deleted file mode 100644 index 2769048e001d69..00000000000000 --- a/Misc/NEWS.d/next/Security/2026-06-25-20-44-20.gh-issue-152216.VxiK5y.rst +++ /dev/null @@ -1 +0,0 @@ -Update bundled `libexpat <https://libexpat.github.io/>`_ to version 2.8.2. diff --git a/Misc/NEWS.d/next/Security/2026-07-04-17-00-00.gh-issue-153030.RovkP6.rst b/Misc/NEWS.d/next/Security/2026-07-04-17-00-00.gh-issue-153030.RovkP6.rst deleted file mode 100644 index d1d60593f4ba7d..00000000000000 --- a/Misc/NEWS.d/next/Security/2026-07-04-17-00-00.gh-issue-153030.RovkP6.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fixed quadratic complexity in incremental parsing of long unterminated -constructs (such as tags or comments) in :class:`html.parser.HTMLParser`, -which could be exploited for a denial of service. diff --git a/Misc/NEWS.d/next/Tests/2026-06-16-05-11-38.gh-issue-151096.Kq3Lp9.rst b/Misc/NEWS.d/next/Tests/2026-06-16-05-11-38.gh-issue-151096.Kq3Lp9.rst deleted file mode 100644 index 3251c6fb094723..00000000000000 --- a/Misc/NEWS.d/next/Tests/2026-06-16-05-11-38.gh-issue-151096.Kq3Lp9.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix ``test_embed`` failing when CPython is configured with a split exec prefix -(``--exec-prefix`` differing from ``--prefix``). diff --git a/Misc/NEWS.d/next/Tests/2026-06-22-19-45-00.gh-issue-151626.K9pZ2x.rst b/Misc/NEWS.d/next/Tests/2026-06-22-19-45-00.gh-issue-151626.K9pZ2x.rst deleted file mode 100644 index 9858415018ae1b..00000000000000 --- a/Misc/NEWS.d/next/Tests/2026-06-22-19-45-00.gh-issue-151626.K9pZ2x.rst +++ /dev/null @@ -1,5 +0,0 @@ -Fix several tests in ``test.test_inspect``, ``test.test_import``, -``test.test_importlib``, ``test.test_py_compile`` and -``test.test_compileall`` that failed when the test suite was run with -:envvar:`PYTHONPYCACHEPREFIX` set. These tests now neutralize the pycache -prefix where they assume the default ``__pycache__`` bytecode layout. diff --git a/Misc/NEWS.d/next/Windows/2026-04-21-16-07-11.gh-issue-140146.TAcUHA.rst b/Misc/NEWS.d/next/Windows/2026-04-21-16-07-11.gh-issue-140146.TAcUHA.rst deleted file mode 100644 index 2d3e42c86fd521..00000000000000 --- a/Misc/NEWS.d/next/Windows/2026-04-21-16-07-11.gh-issue-140146.TAcUHA.rst +++ /dev/null @@ -1,3 +0,0 @@ -Prevent :mod:`tkinter` from hanging on Windows if stdin is redirected to a pipe in an -interactive session. This is helpful for testing interactive usage of -tkinter from a script, for example as part of the cpython test suite. diff --git a/Misc/NEWS.d/next/macOS/2026-07-17-23-20-27.gh-issue-152023.QAAgdj.rst b/Misc/NEWS.d/next/macOS/2026-07-17-23-20-27.gh-issue-152023.QAAgdj.rst deleted file mode 100644 index afabb3d5224970..00000000000000 --- a/Misc/NEWS.d/next/macOS/2026-07-17-23-20-27.gh-issue-152023.QAAgdj.rst +++ /dev/null @@ -1,2 +0,0 @@ -Update macOS installer builds to SQLite 3.53.3. Enable median() and -percentile() functions. diff --git a/Misc/NEWS.d/next/macOS/2026-07-17-23-35-36.gh-issue-124111.dmM4lk.rst b/Misc/NEWS.d/next/macOS/2026-07-17-23-35-36.gh-issue-124111.dmM4lk.rst deleted file mode 100644 index 48ab66407831a8..00000000000000 --- a/Misc/NEWS.d/next/macOS/2026-07-17-23-35-36.gh-issue-124111.dmM4lk.rst +++ /dev/null @@ -1 +0,0 @@ -Update macOS installer to use Tcl/Tk 9.0.4. diff --git a/README.rst b/README.rst index 56f6a71ffb24db..87c1bf2a5f7bac 100644 --- a/README.rst +++ b/README.rst @@ -1,4 +1,4 @@ -This is Python version 3.15.0 beta 3 +This is Python version 3.15.0 beta 4 ==================================== .. image:: https://github.com/python/cpython/actions/workflows/build.yml/badge.svg?branch=main&event=push From 841f1b9dbf9b0b492ad1aae67fbbf14d6d8f83c2 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 18 Jul 2026 11:43:37 +0200 Subject: [PATCH 699/818] [3.15] Add versionadded tag to wave module getformat functions (GH-153897) (#153898) Add versionadded tag to wave module getformat functions (GH-153897) (cherry picked from commit 7ce9eb1c097db4b611bda4c8e5d0ff3f28ed4698) Co-authored-by: Elias Dorneles <eliasdorneles@gmail.com> --- Doc/library/wave.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Doc/library/wave.rst b/Doc/library/wave.rst index d320975708c07c..c85e2d7a150a3e 100644 --- a/Doc/library/wave.rst +++ b/Doc/library/wave.rst @@ -125,6 +125,8 @@ Wave_read Objects This is one of :data:`WAVE_FORMAT_PCM`, :data:`WAVE_FORMAT_IEEE_FLOAT`, or :data:`WAVE_FORMAT_EXTENSIBLE`. + .. versionadded:: 3.15 + .. method:: getcomptype() @@ -284,6 +286,8 @@ Wave_write Objects Return the current frame format code. + .. versionadded:: 3.15 + .. method:: setparams(tuple) From 5825c270e08bb62bd2e8333635419bada1ce6bdb Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 18 Jul 2026 12:42:53 +0200 Subject: [PATCH 700/818] [3.15] gh-153899: Fix documented parameter names for `filecmp.cmpfiles` (GH-153900) (#153910) gh-153899: Fix documented parameter names for `filecmp.cmpfiles` (GH-153900) Update the `filecmp.cmpfiles()` docs to match its actual signature. (cherry picked from commit 26e7c4fe3f68668abbc96fc4ac57c2d5ef8048b5) Co-authored-by: Vyron Vasileiadis <hi@fedonman.com> --- Doc/library/filecmp.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/filecmp.rst b/Doc/library/filecmp.rst index f8365b44c5a502..4488322032c681 100644 --- a/Doc/library/filecmp.rst +++ b/Doc/library/filecmp.rst @@ -34,9 +34,9 @@ The :mod:`!filecmp` module defines the following functions: file changes. The entire cache may be cleared using :func:`clear_cache`. -.. function:: cmpfiles(dir1, dir2, common, shallow=True) +.. function:: cmpfiles(a, b, common, shallow=True) - Compare the files in the two directories *dir1* and *dir2* whose names are + Compare the files in the two directories *a* and *b* whose names are given by *common*. Returns three lists of file names: *match*, *mismatch*, From 9eeea8e571b4ab328bd40d002d325d99aea16179 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 18 Jul 2026 12:45:12 +0200 Subject: [PATCH 701/818] [3.15] Fix punctuation in `Doc/library/concurrent.interpreters.rst` (GH-153894) (#153915) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix punctuation in `Doc/library/concurrent.interpreters.rst` (GH-153894) (cherry picked from commit 6ebb22cb83d8ce05f7136166d1674d0a14a29459) Co-authored-by: Raúl Santos Quirós <130504291+raul-sq@users.noreply.github.com> --- Doc/library/concurrent.interpreters.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/concurrent.interpreters.rst b/Doc/library/concurrent.interpreters.rst index a7b115e5f6307d..24e9eaea5cad4b 100644 --- a/Doc/library/concurrent.interpreters.rst +++ b/Doc/library/concurrent.interpreters.rst @@ -21,7 +21,7 @@ thread) and calling a function in that execution context. For concurrency, interpreters themselves (and this module) don't provide much more than isolation, which on its own isn't useful. Actual concurrency is available separately through -:mod:`threads <threading>` See `below <interp-concurrency_>`_ +:mod:`threads <threading>` -- see `below <interp-concurrency_>`_. .. seealso:: From 6f74ce1ac429d88fbadb04705e3fbebb54da9161 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 18 Jul 2026 13:49:34 +0200 Subject: [PATCH 702/818] [3.15] gh-153808: Replace obsolete 'condition list' verbiage with 'expression list' in eval() docs (GH-153923) (cherry picked from commit c5e97ed6351766deff488ea6d95e4aa0853943ae) Co-authored-by: palakkhinvasara <109575264+palakkhinvasara@users.noreply.github.com> --- Doc/library/functions.rst | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst index f38440569d5169..f88253d7ad016b 100644 --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -611,9 +611,10 @@ are always available. They are listed here in alphabetical order. untrusted user-supplied input will lead to security vulnerabilities. The *source* argument is parsed and evaluated as a Python expression - (technically speaking, a condition list) using the *globals* and *locals* - mappings as global and local namespace. If the *globals* dictionary is - present and does not contain a value for the key ``__builtins__``, a + (technically speaking, an :ref:`expression list <exprlists>`) + using the *globals* and *locals* mappings as global and local namespace. + If the *globals* dictionary is present and does not contain a value for the + key ``__builtins__``, a reference to the dictionary of the built-in module :mod:`builtins` is inserted under that key before *source* is parsed. Overriding ``__builtins__`` can be used to restrict or change the available @@ -633,6 +634,9 @@ are always available. They are listed here in alphabetical order. >>> eval('x+1') 2 + >>> eval("1, 2") + (1, 2) + This function can also be used to execute arbitrary code objects (such as those created by :func:`compile`). In this case, pass a code object instead of a string. If the code object has been compiled with ``'exec'`` as the From e1453555e25114210abdcd9ff8bd1086945f8681 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 18 Jul 2026 14:14:40 +0200 Subject: [PATCH 703/818] [3.15] Fix duplicated words in "What's new in Python 3.15" documentation (GH-153922) (#153931) Fix duplicated words in "What's new in Python 3.15" documentation (GH-153922) (cherry picked from commit 2df69de5b36347d430aed0a959fa01e17b237331) Co-authored-by: Michael Newman <michael.b.newman@gmail.com> --- Doc/whatsnew/3.15.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst index ae75d14a3088ba..4d5f617867e5b8 100644 --- a/Doc/whatsnew/3.15.rst +++ b/Doc/whatsnew/3.15.rst @@ -1225,7 +1225,7 @@ importlib.metadata would return an empty ``PackageMetadata`` object as if the file was present but empty. Now, a ``MetadataNotFound`` exception is raised. See `importlib_metadata#493 <https://github.com/python/importlib_metadata/issues/493>`_ - for background and rationale and and :gh:`143387` for rationale on the + for background and rationale and :gh:`143387` for rationale on the compatibility concerns. (Contributed by Jason R. Coombs.) From 294e5637538063025c4f5af8fe74667b74f00cea Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 18 Jul 2026 14:19:35 +0200 Subject: [PATCH 704/818] [3.15] Fix duplicated words in the 'Coroutines and tasks' documentation (GH-153880) (#153886) Fix duplicated words in the 'Coroutines and tasks' documentation (GH-153880) (cherry picked from commit cffcee4d1bc9d49b5b45e2e792dd8aea7b6c65eb) Co-authored-by: Michael Newman <michael.newman@avalabs.org> --- Doc/library/asyncio-task.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/asyncio-task.rst b/Doc/library/asyncio-task.rst index d0cd241e42db26..86b8c5aa34d2fe 100644 --- a/Doc/library/asyncio-task.rst +++ b/Doc/library/asyncio-task.rst @@ -377,7 +377,7 @@ and reliable way to wait for all tasks in the group to finish. * call it from the task group body based on some condition or event * pass the task group instance to child tasks via :meth:`create_task`, allowing a child - task to conditionally cancel the entire entire group + task to conditionally cancel the entire group * pass the task group instance or bound :meth:`cancel` method to some other task *before* opening the task group, allowing remote cancellation From b009722988933331b479fd57c134db6ab7669cc8 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 18 Jul 2026 14:38:34 +0200 Subject: [PATCH 705/818] [3.15] gh-153926: Fix documented parameter name for `calendar.calendar` and `calendar.prcal` (GH-153927) (#153937) gh-153926: Fix documented parameter name for `calendar.calendar` and `calendar.prcal` (GH-153927) gh-153926: Fix documented parameter name for calendar.calendar and calendar.prcal calendar.calendar() and calendar.prcal() are bound methods of the module's TextCalendar instance, whose first parameter is named theyear, but the documentation named it year, so the documented keyword raised TypeError. Update the documentation to match the real signature, which also matches the sibling month() and prmonth() functions. (cherry picked from commit d12434b4661c6be7430002e66a54d920f7d4ca7f) Co-authored-by: Vyron Vasileiadis <hi@fedonman.com> --- Doc/library/calendar.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/calendar.rst b/Doc/library/calendar.rst index 60cd214b450101..b486425204946d 100644 --- a/Doc/library/calendar.rst +++ b/Doc/library/calendar.rst @@ -430,12 +430,12 @@ For simple text calendars this module provides the following functions. of the :class:`TextCalendar` class. -.. function:: prcal(year, w=0, l=0, c=6, m=3) +.. function:: prcal(theyear, w=0, l=0, c=6, m=3) Prints the calendar for an entire year as returned by :func:`calendar`. -.. function:: calendar(year, w=2, l=1, c=6, m=3) +.. function:: calendar(theyear, w=2, l=1, c=6, m=3) Returns a 3-column calendar for an entire year as a multi-line string using the :meth:`~TextCalendar.formatyear` of the :class:`TextCalendar` class. From 72b91633a6df0a89e32359bf6488ad820caefde3 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 18 Jul 2026 14:54:37 +0200 Subject: [PATCH 706/818] [3.15] gh-153934: Correct documented parameter in `calendar.weekheader` from `n` to `width` (GH-153942) (GH-153943) (cherry picked from commit 7486c7b3df7ff26ac23390947102f2604f55243a) Co-authored-by: Marta <marta.podziewska@gmail.com> --- Doc/library/calendar.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/calendar.rst b/Doc/library/calendar.rst index b486425204946d..fb0ffc73b48c40 100644 --- a/Doc/library/calendar.rst +++ b/Doc/library/calendar.rst @@ -400,9 +400,9 @@ For simple text calendars this module provides the following functions. *month* (``1``--``12``), *day* (``1``--``31``). -.. function:: weekheader(n) +.. function:: weekheader(width) - Return a header containing abbreviated weekday names. *n* specifies the width in + Return a header containing abbreviated weekday names. *width* specifies the width in characters for one weekday. From 9e955d5a74f572857ffd2c1d02bfe1d54712b5ad Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> Date: Sat, 18 Jul 2026 15:08:51 +0200 Subject: [PATCH 707/818] Post 3.15.0b4 --- Include/patchlevel.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Include/patchlevel.h b/Include/patchlevel.h index 425ce233955cfd..436b890d58881b 100644 --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -27,7 +27,7 @@ #define PY_RELEASE_SERIAL 4 /* Version as a string */ -#define PY_VERSION "3.15.0b4" +#define PY_VERSION "3.15.0b4+dev" /*--end constants--*/ From e09f49e390458dde60b8152dd5f941d411c5283d Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 18 Jul 2026 15:09:14 +0200 Subject: [PATCH 708/818] [3.15] Test `calendar.February` deprecation (GH-153893) (#153919) Test `calendar.February` deprecation (GH-153893) Calendar related tests now check if both deprecated constants surface the proper warnings. * extended `test_deprecation_warning` to check `constants.February` as well (cherry picked from commit 31c81e6ee3b1c874a807ea161182b83c6c607713) Co-authored-by: vjabuilds <77214151+vjabuilds@users.noreply.github.com> Co-authored-by: Tomas R. <tomas.roun8@gmail.com> --- Lib/test/test_calendar.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Lib/test/test_calendar.py b/Lib/test/test_calendar.py index 6ed27b4095bc1d..8646cfcad58cea 100644 --- a/Lib/test/test_calendar.py +++ b/Lib/test/test_calendar.py @@ -554,6 +554,11 @@ def test_deprecation_warning(self): "The 'January' attribute is deprecated, use 'JANUARY' instead" ): calendar.January + with self.assertWarnsRegex( + DeprecationWarning, + "The 'February' attribute is deprecated, use 'FEBRUARY' instead" + ): + calendar.February def test_isleap(self): # Make sure that the return is right for a few years, and From 1c6670a0b928d21799ee056a45f0566659a1107b Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 18 Jul 2026 15:33:24 +0200 Subject: [PATCH 709/818] [3.15] gh-122102: Fix/improve docs of descriptor-related tools in `inspect` (GH-153948) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (cherry picked from commit 87f8fc8e00704396a0c598c8843cdde373c0ea4c) Co-authored-by: Jan Kaliszewski <zuo@kaliszewski.net> Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com> --- Doc/library/inspect.rst | 39 +++++++++++++++++++++++++-------------- Lib/inspect.py | 25 +++++++++++++++---------- 2 files changed, 40 insertions(+), 24 deletions(-) diff --git a/Doc/library/inspect.rst b/Doc/library/inspect.rst index a0f7379b12a8a6..eddc98824d4810 100644 --- a/Doc/library/inspect.rst +++ b/Doc/library/inspect.rst @@ -635,8 +635,7 @@ attributes (see :ref:`import-mod-attrs` for module attributes): .. function:: ismethoddescriptor(object) Return ``True`` if the object is a method descriptor, but not if - :func:`ismethod`, :func:`isclass`, :func:`isfunction` or :func:`isbuiltin` - are true. + :func:`isclass`, :func:`ismethod` or :func:`isfunction` is true. This, for example, is true of ``int.__add__``. An object passing this test has a :meth:`~object.__get__` method, but not a :meth:`~object.__set__` @@ -644,10 +643,10 @@ attributes (see :ref:`import-mod-attrs` for module attributes): attributes varies. A :attr:`~definition.__name__` attribute is usually sensible, and :attr:`~definition.__doc__` often is. - Methods implemented via descriptors that also pass one of the other tests - return ``False`` from the :func:`ismethoddescriptor` test, simply because the - other tests promise more -- you can, e.g., count on having the - :attr:`~method.__func__` attribute (etc) when an object passes + Method descriptors that also pass any of the other tests (:func:`!isclass`, + :func:`!ismethod` or :func:`!isfunction`) make this function return ``False``, + simply because those other tests promise more -- you can, for example, count + on having the :attr:`~method.__func__` attribute when an object passes :func:`ismethod`. .. versionchanged:: 3.13 @@ -658,16 +657,28 @@ attributes (see :ref:`import-mod-attrs` for module attributes): .. function:: isdatadescriptor(object) - Return ``True`` if the object is a data descriptor. + Return ``True`` if the object is a data descriptor, but not if + :func:`isclass`, :func:`ismethod` or :func:`isfunction` is true. - Data descriptors have a :attr:`~object.__set__` or a :attr:`~object.__delete__` method. - Examples are properties (defined in Python), getsets, and members. The - latter two are defined in C and there are more specific tests available for - those types, which is robust across Python implementations. Typically, data - descriptors will also have :attr:`~definition.__name__` and :attr:`!__doc__` attributes - (properties, getsets, and members have both of these attributes), but this is - not guaranteed. + Data descriptors always have a :meth:`~object.__set__` method and/or + a :meth:`~object.__delete__` method. Optionally, they may also have a + :meth:`~object.__get__` method. + Examples of data descriptors are :func:`properties <property>`, getsets and + member descriptors. Note that for the latter two (defined only in C extension + modules), more specific tests are available: :func:`isgetsetdescriptor` and + :func:`ismemberdescriptor`, respectively. + + While data descriptors may also have :attr:`~definition.__name__` and + :attr:`!__doc__` attributes (as properties, getsets and member descriptors + do), this is not necessarily the case in general. + + .. versionchanged:: 3.8 + This function now reports objects with only a :meth:`~object.__set__` method + as being data descriptors (the presence of :meth:`~object.__get__` is no + longer required for that). Moreover, objects with :meth:`~object.__delete__`, + but not :meth:`~object.__set__`, are now properly recognized as data + descriptors as well, which was not the case previously. .. function:: isgetsetdescriptor(object) diff --git a/Lib/inspect.py b/Lib/inspect.py index 0dbd596db16023..92664f46d351ac 100644 --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -196,18 +196,18 @@ def ispackage(object): def ismethoddescriptor(object): """Return true if the object is a method descriptor. - But not if ismethod() or isclass() or isfunction() are true. + But not if ismethod(), isclass() or isfunction() is true. - This is new in Python 2.2, and, for example, is true of int.__add__. - An object passing this test has a __get__ attribute, but not a - __set__ attribute or a __delete__ attribute. Beyond that, the set - of attributes varies; __name__ is usually sensible, and __doc__ - often is. + An object passing this test (for example, int.__add__) has a __get__ + attribute, but not a __set__ attribute or a __delete__ attribute. + Beyond that, the set of attributes varies; __name__ is usually + sensible, and __doc__ often is. Methods implemented via descriptors that also pass one of the other - tests return false from the ismethoddescriptor() test, simply because - the other tests promise more -- you can, e.g., count on having the - __func__ attribute (etc) when an object passes ismethod().""" + tests (ismethod(), isclass(), isfunction()) make this function return + false, simply because those other tests promise more -- you can, for + example, count on having the __func__ attribute when an object passes + ismethod().""" if isclass(object) or ismethod(object) or isfunction(object): # mutual exclusion return False @@ -219,8 +219,13 @@ def ismethoddescriptor(object): def isdatadescriptor(object): """Return true if the object is a data descriptor. + But not if ismethod(), isclass() or isfunction() is true. + Data descriptors have a __set__ or a __delete__ attribute. Examples are - properties (defined in Python) and getsets and members (defined in C). + properties, getsets, and members. For the latter two (defined only in C + extension modules) more specific tests are available as well: + isgetsetdescriptor() and ismemberdescriptor(), respectively. + Typically, data descriptors will also have __name__ and __doc__ attributes (properties, getsets, and members have both of these attributes), but this is not guaranteed.""" From fd9197138f6a41af920e06b8c3b985407f6f7ddf Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 18 Jul 2026 15:35:29 +0200 Subject: [PATCH 710/818] [3.15] Docs: Fix typo in the pymanager command name (GH-153877) (GH-153960) (cherry picked from commit 32cfc88d6a5561c510a0d7bb954251e39b598dd5) Co-authored-by: Sam Katakouzinos <sam.katakouzinos@gmail.com> --- Doc/using/windows.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/using/windows.rst b/Doc/using/windows.rst index e48de587598e5f..5bec0c57b12214 100644 --- a/Doc/using/windows.rst +++ b/Doc/using/windows.rst @@ -128,7 +128,7 @@ difference between the two commands is when running without any arguments: help (``pymanager exec ...`` provides equivalent behaviour to ``py ...``). Each of these commands also has a windowed version that avoids creating a -console window. These are ``pyw``, ``pythonw`` and ``pymanagerw``. A ``python3`` +console window. These are ``pyw``, ``pythonw`` and ``pywmanager``. A ``python3`` command is also included that mimics the ``python`` command. It is intended to catch accidental uses of the typical POSIX command on Windows, but is not meant to be widely used or recommended. From b6a140b133d37ecc72688c80c0e51b5bf3789317 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 18 Jul 2026 16:08:50 +0200 Subject: [PATCH 711/818] [3.15] gh-71896: Add a docs warning about trailing newlines ignored by `difflib.HtmlDiff` (GH-153930) (GH-153965) (cherry picked from commit 755d97167f6f5d4361c790f8f18df76cae8f2ad2) Co-authored-by: Lenormand Julien <lenormand.julien0@gmail.com> --- Doc/library/difflib.rst | 5 +++++ Lib/difflib.py | 2 ++ Lib/test/test_difflib.py | 23 +++++++++++++++++++++++ 3 files changed, 30 insertions(+) diff --git a/Doc/library/difflib.rst b/Doc/library/difflib.rst index 8b812c173b5953..b828381e91e531 100644 --- a/Doc/library/difflib.rst +++ b/Doc/library/difflib.rst @@ -85,6 +85,11 @@ diffs. For comparing directories and files, see also, the :mod:`filecmp` module. with inter-line and intra-line change highlights. The table can be generated in either full or contextual difference mode. + .. warning:: + + The trailing newlines get stripped before the diff, so the result can be + incomplete. See :gh:`71896` for details. + The constructor for this class is: diff --git a/Lib/difflib.py b/Lib/difflib.py index ae8b284b4d3647..95ba8fd782c6c3 100644 --- a/Lib/difflib.py +++ b/Lib/difflib.py @@ -2016,6 +2016,8 @@ def make_table(self,fromlines,tolines,fromdesc='',todesc='',context=False, # change tabs to spaces before it gets more difficult after we insert # markup + # it also removes trailing newlines, causing some diffs to be missed + # see: gh-71896 fromlines,tolines = self._tab_newline_replace(fromlines,tolines) # create diffs iterator which generates side by side from/to data diff --git a/Lib/test/test_difflib.py b/Lib/test/test_difflib.py index 46c9b2c1d8c9fc..4f99b7c91c654e 100644 --- a/Lib/test/test_difflib.py +++ b/Lib/test/test_difflib.py @@ -284,6 +284,29 @@ def test_make_file_usascii_charset_with_nonascii_input(self): self.assertIn('charset="us-ascii"', output) self.assertIn('&#305;mpl&#305;c&#305;t', output) + def test_strip_trailing_newlines_before_diff(self): + # characterization test for the current buggy behavior + # see: gh-71896 + html_diff = difflib.HtmlDiff() + from_lines = [ + "Line 1: no newline after", + "Line 2: one newline after\n", + "Line 3: several newlines after\n\n\n\n\n", + ] + to_lines = [ + "Line 1: no newline after", + "Line 2: one newline after", # actually no \n + "Line 3: several newlines after", # actually no \n + ] + output = html_diff.make_table(from_lines, to_lines) + # we (currently) expect no line change, so all equal + self.assertNotIn('class="diff_add"', output) + self.assertNotIn('class="diff_chg"', output) + self.assertNotIn('class="diff_sub"', output) + self.assertEqual(output.count('>Line&nbsp;1:&nbsp;no&nbsp;newline&nbsp;after<'), 2) + self.assertEqual(output.count('>Line&nbsp;2:&nbsp;one&nbsp;newline&nbsp;after<'), 2) + self.assertEqual(output.count('>Line&nbsp;3:&nbsp;several&nbsp;newlines&nbsp;after<'), 2) + class TestDiffer(unittest.TestCase): def test_close_matches_aligned(self): # Of the 4 closely matching pairs, we want 1 to match with 3, From 57a8629974aae16fea75d83228dac9d1dac56fa4 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 18 Jul 2026 16:50:31 +0200 Subject: [PATCH 712/818] [3.15] gh-141004: Document remaining `PyCF_*` compiler flag macros (GH-153958) (GH-153984) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (cherry picked from commit 0a772f2967c77a2137c45d7db1fcde9b71afacde) Co-authored-by: Bartosz Sławecki <bartosz@ilikepython.com> --- Doc/c-api/veryhigh.rst | 114 +++++++++++++++++++++++ Tools/check-c-api-docs/ignored_c_api.txt | 8 -- 2 files changed, 114 insertions(+), 8 deletions(-) diff --git a/Doc/c-api/veryhigh.rst b/Doc/c-api/veryhigh.rst index 6256bf7a1454a9..bba5c7f8ecf775 100644 --- a/Doc/c-api/veryhigh.rst +++ b/Doc/c-api/veryhigh.rst @@ -343,11 +343,125 @@ the same library that the Python runtime is using. :py:mod:`!ast` Python module, which exports these constants under the same names. + .. rubric:: Low-level flags + + The following flags and masks serve narrow needs of the standard + library and interactive interpreters. Code outside the standard + library rarely has a reason to use them. They are considered + implementation details and may change at any time. + + .. c:macro:: PyCF_ALLOW_INCOMPLETE_INPUT + + This flag is a private interface between the compiler and the + :mod:`codeop` module. Do not use it; its behavior is unsupported + and may change without warning. + + With this flag set, when compilation fails because the source text + ends where more input is expected, for example in the middle of an + indented block or an unterminated string literal, the error raised + is the undocumented ``_IncompleteInputError``, a subclass of + :exc:`SyntaxError`. The :mod:`codeop` module sets this flag, + together with :c:macro:`PyCF_DONT_IMPLY_DEDENT`, to tell input + that is incomplete apart from input with a real syntax error, so + that interactive interpreters know when to prompt for another + line instead of reporting an error. + + .. versionadded:: 3.11 + + .. c:macro:: PyCF_DONT_IMPLY_DEDENT + + By default, when compiling with the :c:var:`Py_single_input` start + symbol, reaching the end of the source text implicitly closes any + open indented blocks. With this flag set, open blocks are only + closed if the last line of the source ends with a newline; otherwise, + compilation fails with a :exc:`SyntaxError`: + + .. code-block:: c + + PyCompilerFlags flags = { + .cf_flags = 0, + .cf_feature_version = PY_MINOR_VERSION, + }; + const char *source = "if a:\n pass"; + + /* The "if" block is closed implicitly; + this returns a code object: */ + Py_CompileStringFlags(source, "<input>", Py_single_input, &flags); + + /* With the flag, this fails with a SyntaxError, + because the last line does not end with a newline: */ + flags.cf_flags = PyCF_DONT_IMPLY_DEDENT; + Py_CompileStringFlags(source, "<input>", Py_single_input, &flags); + + The :mod:`codeop` module uses this flag to detect incomplete + interactive input. While the user is still typing inside an + indented block, the source does not yet end with a newline, so it + fails to compile and the user is prompted for another line. + + .. c:macro:: PyCF_IGNORE_COOKIE + + Read the source text as UTF-8, ignoring its :pep:`263` encoding + declaration ("coding cookie"), if any: + + .. code-block:: c + + PyCompilerFlags flags = { + .cf_flags = 0, + .cf_feature_version = PY_MINOR_VERSION, + }; + const char *source = "# coding: latin-1\ns = '\xe9'\n"; + + /* The coding cookie is honored: byte 0xE9 is decoded as + Latin-1, and this returns a code object that sets s to "é": */ + Py_CompileStringFlags(source, "<input>", Py_file_input, &flags); + + /* With the flag, the cookie is ignored and compilation fails + with a SyntaxError, because 0xE9 is not valid UTF-8: */ + flags.cf_flags = PyCF_IGNORE_COOKIE; + Py_CompileStringFlags(source, "<input>", Py_file_input, &flags); + + The :func:`compile`, :func:`eval` and :func:`exec` built-in functions + set this flag when the source is a :class:`str` object, because they + pass the text to the parser encoded as UTF-8. + + .. c:macro:: PyCF_SOURCE_IS_UTF8 + + Mark the source text as known to be UTF-8 encoded. + The :func:`compile`, :func:`eval` and :func:`exec` built-in functions + set this flag, but it currently has no effect. + The "``PyCF``" flags above can be combined with "``CO_FUTURE``" flags such as :c:macro:`CO_FUTURE_ANNOTATIONS` to enable features normally selectable using :ref:`future statements <future>`. See :ref:`c_codeobject_flags` for a complete list. + The following masks combine several flags: + + .. c:macro:: PyCF_MASK + + Bitmask of all ``CO_FUTURE`` flags (see :ref:`c_codeobject_flags`), + which select features normally enabled by + :ref:`future statements <future>`. + When code compiled with a ``PyCompilerFlags *flags`` argument + contains a ``from __future__ import`` statement, the flag for the + imported feature is added to *flags*, so that code executed later + in the same context inherits it. + + .. c:macro:: PyCF_MASK_OBSOLETE + + Do not use this mask in new code. It is kept only so that old + code passing its flags to :func:`compile` keeps working. + + Bitmask of flags for obsolete future features that no longer + have any effect. + + .. c:macro:: PyCF_COMPILE_MASK + + Bitmask of all ``PyCF`` flags that change how the source is + compiled, such as :c:macro:`PyCF_ONLY_AST`. + The :func:`compile` built-in function uses this mask to validate + its *flags* argument. + .. _start-symbols: diff --git a/Tools/check-c-api-docs/ignored_c_api.txt b/Tools/check-c-api-docs/ignored_c_api.txt index fa53b205c4ff6a..e04deffc64f510 100644 --- a/Tools/check-c-api-docs/ignored_c_api.txt +++ b/Tools/check-c-api-docs/ignored_c_api.txt @@ -29,14 +29,6 @@ PY_DWORD_MAX PY_BIG_ENDIAN # cpython/methodobject.h PyCFunction_GET_CLASS -# cpython/compile.h -PyCF_ALLOW_INCOMPLETE_INPUT -PyCF_COMPILE_MASK -PyCF_DONT_IMPLY_DEDENT -PyCF_IGNORE_COOKIE -PyCF_MASK -PyCF_MASK_OBSOLETE -PyCF_SOURCE_IS_UTF8 # cpython/descrobject.h PyDescr_NAME PyDescr_TYPE From f5c0906c9c006d8845f6f5833d2e8c70f70d00e0 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 18 Jul 2026 17:00:16 +0200 Subject: [PATCH 713/818] [3.15] gh-141004: Document unstable executable kind macros from `pyframe.h` (GH-143490) (GH-153988) (cherry picked from commit dc62ba84ab2b83d70dee111d3feec1a6f1c3f69d) Co-authored-by: Yashraj <yashrajpala8@gmail.com> Co-authored-by: Peter Bierma <zintensitydev@gmail.com> --- Doc/c-api/frame.rst | 59 ++++++++++++++++++++++++ Tools/check-c-api-docs/ignored_c_api.txt | 6 --- 2 files changed, 59 insertions(+), 6 deletions(-) diff --git a/Doc/c-api/frame.rst b/Doc/c-api/frame.rst index 4159ff6e5965fb..a04ef4e422949b 100644 --- a/Doc/c-api/frame.rst +++ b/Doc/c-api/frame.rst @@ -243,3 +243,62 @@ Unless using :pep:`523`, you will not need this. Return the currently executing line number, or -1 if there is no line number. .. versionadded:: 3.12 + + +.. c:var:: const PyTypeObject *PyUnstable_ExecutableKinds + + An array of executable kinds (executor types) for frames, used for internal + debugging and tracing. + + Tools like debuggers and profilers can use this to identify the type of execution + context associated with a frame (such as to filter out internal frames). + The entries are indexed by the following constants: + + .. list-table:: + :header-rows: 1 + :widths: auto + + * - Constant + - Description + * - .. c:macro:: PyUnstable_EXECUTABLE_KIND_SKIP + - The frame is internal (For example: inlined) and should be skipped by tools. + * - .. c:macro:: PyUnstable_EXECUTABLE_KIND_PY_FUNCTION + - The frame corresponds to a standard Python function. + * - .. c:macro:: PyUnstable_EXECUTABLE_KIND_BUILTIN_FUNCTION + - The frame corresponds to a function defined in native code. + * - .. c:macro:: PyUnstable_EXECUTABLE_KIND_METHOD_DESCRIPTOR + - The frame corresponds to a method on a class instance. + + However, Python's C API lacks a function to read the executable kind from + a frame. Instead, use this recipe: + + .. code-block:: c + + int + get_executable_kind(PyFrameObject *frame) + { + _PyInterpreterFrame *f = frame->f_frame; + PyObject *exec = PyStackRef_AsPyObjectBorrow(f->f_executable); + + if (PyCode_Check(exec)) { + return PyUnstable_EXECUTABLE_KIND_PY_FUNCTION; + } + if (PyMethod_Check(exec)) { + return PyUnstable_EXECUTABLE_KIND_BUILTIN_FUNCTION; + } + if (Py_IS_TYPE(exec, &PyMethodDescr_Type)) { + return PyUnstable_EXECUTABLE_KIND_METHOD_DESCRIPTOR; + } + + return PyUnstable_EXECUTABLE_KIND_SKIP; + } + + .. versionadded:: 3.13 + + +.. c:macro:: PyUnstable_EXECUTABLE_KINDS + + The number of entries in :c:data:`PyUnstable_ExecutableKinds`. + + .. versionadded:: 3.13 + diff --git a/Tools/check-c-api-docs/ignored_c_api.txt b/Tools/check-c-api-docs/ignored_c_api.txt index e04deffc64f510..aeae9e6553a3aa 100644 --- a/Tools/check-c-api-docs/ignored_c_api.txt +++ b/Tools/check-c-api-docs/ignored_c_api.txt @@ -35,12 +35,6 @@ PyDescr_TYPE PyWrapperFlag_KEYWORDS # cpython/fileobject.h Py_UniversalNewlineFgets -# cpython/pyframe.h -PyUnstable_EXECUTABLE_KINDS -PyUnstable_EXECUTABLE_KIND_BUILTIN_FUNCTION -PyUnstable_EXECUTABLE_KIND_METHOD_DESCRIPTOR -PyUnstable_EXECUTABLE_KIND_PY_FUNCTION -PyUnstable_EXECUTABLE_KIND_SKIP # cpython/pylifecycle.h Py_FrozenMain # pythonrun.h From 536d18b1a83fa1524705312be334db4d2e7c5249 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 18 Jul 2026 17:18:04 +0200 Subject: [PATCH 714/818] [3.15] gh-153908: Fix data race in `itertools.count.__repr__` (GH-153917) (GH-153951) (cherry picked from commit 5200f1192428becab0c31db98e7baa97f3c3c3e2) Co-authored-by: John <me@joh.ng> --- .../Library/2026-07-18-11-16-41.gh-issue-153908.82FiGk.rst | 1 + Modules/itertoolsmodule.c | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-07-18-11-16-41.gh-issue-153908.82FiGk.rst diff --git a/Misc/NEWS.d/next/Library/2026-07-18-11-16-41.gh-issue-153908.82FiGk.rst b/Misc/NEWS.d/next/Library/2026-07-18-11-16-41.gh-issue-153908.82FiGk.rst new file mode 100644 index 00000000000000..6ee943a5fb6672 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-18-11-16-41.gh-issue-153908.82FiGk.rst @@ -0,0 +1 @@ +Fix data race when calling :func:`repr` on :class:`itertools.count` under the :term:`free-threaded build`. diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c index 72bfab1abaf9ca..c0023c839ca7fe 100644 --- a/Modules/itertoolsmodule.c +++ b/Modules/itertoolsmodule.c @@ -3675,9 +3675,11 @@ static PyObject * count_repr(PyObject *op) { countobject *lz = countobject_CAST(op); - if (lz->long_cnt == NULL) + if (lz->long_cnt == NULL) { + Py_ssize_t cnt = FT_ATOMIC_LOAD_SSIZE_RELAXED(lz->cnt); return PyUnicode_FromFormat("%s(%zd)", - _PyType_Name(Py_TYPE(lz)), lz->cnt); + _PyType_Name(Py_TYPE(lz)), cnt); + } if (PyLong_Check(lz->long_step)) { long step = PyLong_AsLong(lz->long_step); From 13e7aedb59230f941419b5e64977e8f8b6db871f Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 18 Jul 2026 17:21:55 +0200 Subject: [PATCH 715/818] [3.15] gh-124111: Update Windows builds to Tcl/Tk 9.0.4 (GH-153990) (cherry picked from commit 46e950fc0df8ad300497d612c4c9de3e5a1e87f3) Co-authored-by: Zachary Ware <zach@python.org> --- ...026-07-18-11-56-53.gh-issue-124111.m4OBX8.rst | 1 + Misc/externals.spdx.json | 16 ++++++++-------- PCbuild/get_externals.bat | 6 +++--- PCbuild/readme.txt | 2 +- PCbuild/tcltk.props | 2 +- 5 files changed, 14 insertions(+), 13 deletions(-) create mode 100644 Misc/NEWS.d/next/Windows/2026-07-18-11-56-53.gh-issue-124111.m4OBX8.rst diff --git a/Misc/NEWS.d/next/Windows/2026-07-18-11-56-53.gh-issue-124111.m4OBX8.rst b/Misc/NEWS.d/next/Windows/2026-07-18-11-56-53.gh-issue-124111.m4OBX8.rst new file mode 100644 index 00000000000000..802afc6f7a6fc4 --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2026-07-18-11-56-53.gh-issue-124111.m4OBX8.rst @@ -0,0 +1 @@ +Updated Windows builds to use Tcl/Tk 9.0.4. diff --git a/Misc/externals.spdx.json b/Misc/externals.spdx.json index 523d20259adaaa..cdacaf6f586953 100644 --- a/Misc/externals.spdx.json +++ b/Misc/externals.spdx.json @@ -112,42 +112,42 @@ "checksums": [ { "algorithm": "SHA256", - "checksumValue": "7a1d1f3a2b8f4484a9c2a027a157963c18f85a81785e85fcb5d1e3df6b6a4fd4" + "checksumValue": "3ac2acd65ddaaac0b2b8df321b558419d21da20bf67ab39149b8248c85f0d214" } ], - "downloadLocation": "https://github.com/python/cpython-source-deps/archive/refs/tags/tcl-9.0.3.0.tar.gz", + "downloadLocation": "https://github.com/python/cpython-source-deps/archive/refs/tags/tcl-9.0.4.0.tar.gz", "externalRefs": [ { "referenceCategory": "SECURITY", - "referenceLocator": "cpe:2.3:a:tcl_tk:tcl_tk:9.0.3.0:*:*:*:*:*:*:*", + "referenceLocator": "cpe:2.3:a:tcl_tk:tcl_tk:9.0.4.0:*:*:*:*:*:*:*", "referenceType": "cpe23Type" } ], "licenseConcluded": "NOASSERTION", "name": "tcl", "primaryPackagePurpose": "SOURCE", - "versionInfo": "9.0.3.0" + "versionInfo": "9.0.4.0" }, { "SPDXID": "SPDXRef-PACKAGE-tk", "checksums": [ { "algorithm": "SHA256", - "checksumValue": "54fb59df12c489c6264f5b7d3d7444b150d1e3d6561fd59cdb11483440cec000" + "checksumValue": "66048966cfa88989333ff1632f454e10e9248516bb45efda7b4d2ae5a61642cb" } ], - "downloadLocation": "https://github.com/python/cpython-source-deps/archive/refs/tags/tk-9.0.3.1.tar.gz", + "downloadLocation": "https://github.com/python/cpython-source-deps/archive/refs/tags/tk-9.0.4.1.tar.gz", "externalRefs": [ { "referenceCategory": "SECURITY", - "referenceLocator": "cpe:2.3:a:tcl_tk:tcl_tk:9.0.3.1:*:*:*:*:*:*:*", + "referenceLocator": "cpe:2.3:a:tcl_tk:tcl_tk:9.0.4.1:*:*:*:*:*:*:*", "referenceType": "cpe23Type" } ], "licenseConcluded": "NOASSERTION", "name": "tk", "primaryPackagePurpose": "SOURCE", - "versionInfo": "9.0.3.1" + "versionInfo": "9.0.4.1" }, { "SPDXID": "SPDXRef-PACKAGE-xz", diff --git a/PCbuild/get_externals.bat b/PCbuild/get_externals.bat index 47399fe65d1e54..6bedd21299a73e 100644 --- a/PCbuild/get_externals.bat +++ b/PCbuild/get_externals.bat @@ -57,8 +57,8 @@ if NOT "%IncludeLibffiSrc%"=="false" set libraries=%libraries% libffi-3.4.4 if NOT "%IncludeSSLSrc%"=="false" set libraries=%libraries% openssl-3.5.7 set libraries=%libraries% mpdecimal-4.0.0 set libraries=%libraries% sqlite-3.53.2.0 -if NOT "%IncludeTkinterSrc%"=="false" set libraries=%libraries% tcl-9.0.3.0 -if NOT "%IncludeTkinterSrc%"=="false" set libraries=%libraries% tk-9.0.3.1 +if NOT "%IncludeTkinterSrc%"=="false" set libraries=%libraries% tcl-9.0.4.0 +if NOT "%IncludeTkinterSrc%"=="false" set libraries=%libraries% tk-9.0.4.1 set libraries=%libraries% xz-5.8.1.1 set libraries=%libraries% zlib-ng-2.2.4 set libraries=%libraries% zstd-1.5.7 @@ -80,7 +80,7 @@ echo.Fetching external binaries... set binaries= if NOT "%IncludeLibffi%"=="false" set binaries=%binaries% libffi-3.4.4 if NOT "%IncludeSSL%"=="false" set binaries=%binaries% openssl-bin-3.5.7 -if NOT "%IncludeTkinter%"=="false" set binaries=%binaries% tcltk-9.0.3.0 +if NOT "%IncludeTkinter%"=="false" set binaries=%binaries% tcltk-9.0.4.0 if NOT "%IncludeSSLSrc%"=="false" set binaries=%binaries% nasm-2.11.06 if NOT "%IncludeLLVM%"=="false" set binaries=%binaries% llvm-21.1.4.0 diff --git a/PCbuild/readme.txt b/PCbuild/readme.txt index 7c5eab2eb75a1d..7739264f56ccc2 100644 --- a/PCbuild/readme.txt +++ b/PCbuild/readme.txt @@ -247,7 +247,7 @@ _sqlite3 https://www.sqlite.org/ _tkinter - Wraps version 9.0.3 of the Tk windowing system, which is downloaded + Wraps version 9.0.4 of the Tk windowing system, which is downloaded from our binaries repository at https://github.com/python/cpython-bin-deps. diff --git a/PCbuild/tcltk.props b/PCbuild/tcltk.props index 28e8c0db4d1eaf..1d6b4f57f09f74 100644 --- a/PCbuild/tcltk.props +++ b/PCbuild/tcltk.props @@ -2,7 +2,7 @@ <Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Import Project="pyproject.props" Condition="$(__PyProject_Props_Imported) != 'true'" /> <PropertyGroup> - <TclVersion Condition="$(TclVersion) == ''">9.0.3.0</TclVersion> + <TclVersion Condition="$(TclVersion) == ''">9.0.4.0</TclVersion> <TkVersion Condition="$(TkVersion) == ''">$(TclVersion)</TkVersion> <TclMajorVersion>$([System.Version]::Parse($(TclVersion)).Major)</TclMajorVersion> <TclMinorVersion>$([System.Version]::Parse($(TclVersion)).Minor)</TclMinorVersion> From 0cb0723178c975eec1d5ca1ea6dc72d2eda13e16 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 18 Jul 2026 18:04:40 +0200 Subject: [PATCH 716/818] [3.15] gh-153236: Propagate lazy submodule import errors (GH-153237) (#153936) gh-153236: Propagate lazy submodule import errors (GH-153237) (cherry picked from commit 0a09dafb03dae17895d4a86af04985e373bbdceb) Co-authored-by: Pablo Galindo Salgado <Pablogsal@gmail.com> --- .../pycore_global_objects_fini_generated.h | 1 + Include/internal/pycore_global_strings.h | 1 + Include/internal/pycore_import.h | 9 +- .../internal/pycore_runtime_init_generated.h | 1 + .../internal/pycore_unicodeobject_generated.h | 4 + Lib/importlib/_bootstrap.py | 17 +- Lib/test/test_lazy_import/__init__.py | 148 ++++++++++-------- .../data/missing_dependency.py | 1 + .../data/self_named_module_not_found.py | 1 + ...-00.gh-issue-153236.lazy-import-errors.rst | 2 + Objects/moduleobject.c | 11 +- Python/import.c | 71 ++++++--- 12 files changed, 172 insertions(+), 95 deletions(-) create mode 100644 Lib/test/test_lazy_import/data/missing_dependency.py create mode 100644 Lib/test/test_lazy_import/data/self_named_module_not_found.py create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-07-06-16-30-00.gh-issue-153236.lazy-import-errors.rst diff --git a/Include/internal/pycore_global_objects_fini_generated.h b/Include/internal/pycore_global_objects_fini_generated.h index f8bab372f1e505..6c24cd9e8e89e4 100644 --- a/Include/internal/pycore_global_objects_fini_generated.h +++ b/Include/internal/pycore_global_objects_fini_generated.h @@ -1544,6 +1544,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_filters)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_finalizing)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_find_and_load)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_find_and_load_lazy_submodule)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_fix_up_module)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_flags_)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_get_sourcefile)); diff --git a/Include/internal/pycore_global_strings.h b/Include/internal/pycore_global_strings.h index 32dfb9677ecdfe..7df435c8353535 100644 --- a/Include/internal/pycore_global_strings.h +++ b/Include/internal/pycore_global_strings.h @@ -267,6 +267,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(_filters) STRUCT_FOR_ID(_finalizing) STRUCT_FOR_ID(_find_and_load) + STRUCT_FOR_ID(_find_and_load_lazy_submodule) STRUCT_FOR_ID(_fix_up_module) STRUCT_FOR_ID(_flags_) STRUCT_FOR_ID(_get_sourcefile) diff --git a/Include/internal/pycore_import.h b/Include/internal/pycore_import.h index a1078828afa572..669e328c266d00 100644 --- a/Include/internal/pycore_import.h +++ b/Include/internal/pycore_import.h @@ -39,8 +39,13 @@ extern PyObject * _PyImport_GetAbsName( // Symbol is exported for the JIT on Windows builds. PyAPI_FUNC(PyObject *) _PyImport_LoadLazyImportTstate( PyThreadState *tstate, PyObject *lazy_import); -extern PyObject * _PyImport_TryLoadLazySubmodule( - PyObject *mod_name, PyObject *attr_name); +typedef enum { + _Py_LAZY_SUBMODULE_ERROR = -1, + _Py_LAZY_SUBMODULE_NOT_FOUND = 0, + _Py_LAZY_SUBMODULE_LOADED = 1, +} _PyLazySubmoduleImportResult; +extern _PyLazySubmoduleImportResult _PyImport_TryLoadLazySubmodule( + PyObject *mod_name, PyObject *attr_name, PyObject **result); extern PyObject * _PyImport_LazyImportModuleLevelObject( PyThreadState *tstate, PyObject *name, PyObject *builtins, PyObject *globals, PyObject *locals, PyObject *fromlist, int level); diff --git a/Include/internal/pycore_runtime_init_generated.h b/Include/internal/pycore_runtime_init_generated.h index b5ec50968db222..0f49f78e21f863 100644 --- a/Include/internal/pycore_runtime_init_generated.h +++ b/Include/internal/pycore_runtime_init_generated.h @@ -1542,6 +1542,7 @@ extern "C" { INIT_ID(_filters), \ INIT_ID(_finalizing), \ INIT_ID(_find_and_load), \ + INIT_ID(_find_and_load_lazy_submodule), \ INIT_ID(_fix_up_module), \ INIT_ID(_flags_), \ INIT_ID(_get_sourcefile), \ diff --git a/Include/internal/pycore_unicodeobject_generated.h b/Include/internal/pycore_unicodeobject_generated.h index 00915c23f4b75c..fe7a4add65dc85 100644 --- a/Include/internal/pycore_unicodeobject_generated.h +++ b/Include/internal/pycore_unicodeobject_generated.h @@ -848,6 +848,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_ID(_find_and_load_lazy_submodule); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(_fix_up_module); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); diff --git a/Lib/importlib/_bootstrap.py b/Lib/importlib/_bootstrap.py index 06dc45d71d7ca4..75bc901e238293 100644 --- a/Lib/importlib/_bootstrap.py +++ b/Lib/importlib/_bootstrap.py @@ -1260,7 +1260,7 @@ def _sanity_check(name, package, level): _ERR_MSG_PREFIX = 'No module named ' -def _find_and_load_unlocked(name, import_): +def _find_and_load_unlocked(name, import_, *, lazy_submodule=False): path = None sys.audit( "import", @@ -1283,6 +1283,8 @@ def _find_and_load_unlocked(name, import_): try: path = parent_module.__path__ except AttributeError: + if lazy_submodule: + return None msg = f'{_ERR_MSG_PREFIX}{name!r}; {parent!r} is not a package' raise ModuleNotFoundError(msg, name=name) from None parent_spec = parent_module.__spec__ @@ -1295,6 +1297,8 @@ def _find_and_load_unlocked(name, import_): child = name.rpartition('.')[2] spec = _find_spec(name, path) if spec is None: + if lazy_submodule: + return None raise ModuleNotFoundError(f'{_ERR_MSG_PREFIX}{name!r}', name=name) else: if parent_spec: @@ -1326,7 +1330,7 @@ def _find_and_load_unlocked(name, import_): _NEEDS_LOADING = object() -def _find_and_load(name, import_): +def _find_and_load(name, import_, *, lazy_submodule=False): """Find and load the module.""" # Optimization: we avoid unneeded module locking if the module @@ -1343,7 +1347,8 @@ def _find_and_load(name, import_): with lock_manager: module = sys.modules.get(name, _NEEDS_LOADING) if module is _NEEDS_LOADING: - return _find_and_load_unlocked(name, import_) + return _find_and_load_unlocked( + name, import_, lazy_submodule=lazy_submodule) # Optimization: only call _bootstrap._lock_unlock_module() if # module.__spec__._initializing is True. @@ -1357,7 +1362,7 @@ def _find_and_load(name, import_): # to preserve normal semantics: the caller gets the exception from # the actual import failure rather than a synthetic error. if sys.modules.get(name) is not module: - return _find_and_load(name, import_) + return _find_and_load(name, import_, lazy_submodule=lazy_submodule) if module is None: message = f'import of {name} halted; None in sys.modules' @@ -1366,6 +1371,10 @@ def _find_and_load(name, import_): return module +def _find_and_load_lazy_submodule(name, import_): + return _find_and_load(name, import_, lazy_submodule=True) + + def _gcd_import(name, package=None, level=0): """Import and return the module based on its name, the package the call is being made from, and the level adjustment. diff --git a/Lib/test/test_lazy_import/__init__.py b/Lib/test/test_lazy_import/__init__.py index 417eab84c1088d..0a53d2559c91f0 100644 --- a/Lib/test/test_lazy_import/__init__.py +++ b/Lib/test/test_lazy_import/__init__.py @@ -684,52 +684,35 @@ def test_lazy_modules_tracks_lazy_imports(self): @support.requires_subprocess() class ErrorHandlingTests(LazyImportTestCase): - """Tests for error handling during lazy import reification. + """Tests for error handling during lazy import reification.""" - PEP 810: Errors during reification should show exception chaining with - both the lazy import definition location and the access location. - """ - - def test_import_error_shows_chained_traceback(self): + def test_missing_lazy_submodule_raises_attribute_error(self): """Accessing a nonexistent lazy submodule via parent attr raises AttributeError.""" code = textwrap.dedent(""" - import sys lazy import test.test_lazy_import.data.nonexistent_module try: - x = test.test_lazy_import.data.nonexistent_module - except AttributeError as e: - print("OK") + _ = test.test_lazy_import.data.nonexistent_module + except AttributeError: + pass + else: + raise AssertionError("AttributeError was not raised") """) - result = subprocess.run( - [sys.executable, "-c", code], - capture_output=True, - text=True - ) - self.assertEqual(result.returncode, 0, f"stdout: {result.stdout}, stderr: {result.stderr}") - self.assertIn("OK", result.stdout) + assert_python_ok("-c", code) - def test_attribute_error_on_from_import_shows_chained_traceback(self): + def test_missing_lazy_from_import_shows_chained_traceback(self): """Accessing missing attribute from lazy from-import should chain errors.""" - # Tests 'lazy from module import nonexistent' behavior code = textwrap.dedent(""" - import sys lazy from test.test_lazy_import.data.basic2 import nonexistent_name try: - x = nonexistent_name + _ = nonexistent_name except ImportError as e: - # PEP 810: Enhanced error reporting through exception chaining assert e.__cause__ is not None, "Expected chained exception" - print("OK") + else: + raise AssertionError("ImportError was not raised") """) - result = subprocess.run( - [sys.executable, "-c", code], - capture_output=True, - text=True - ) - self.assertEqual(result.returncode, 0, f"stdout: {result.stdout}, stderr: {result.stderr}") - self.assertIn("OK", result.stdout) + assert_python_ok("-c", code) def test_reification_retries_on_failure(self): """Failed reification should allow retry on subsequent access. @@ -739,53 +722,92 @@ def test_reification_retries_on_failure(self): """ code = textwrap.dedent(""" import sys - import types lazy import test.test_lazy_import.data.broken_module - # First access - should fail try: - x = test.test_lazy_import.data.broken_module - except AttributeError: - pass + _ = test.test_lazy_import.data.broken_module + except ValueError as exc: + assert str(exc) == "This module always fails to import", exc + else: + raise AssertionError("ValueError was not raised") + + assert "test.test_lazy_import.data.broken_module" not in sys.modules - # The lazy object should still be a lazy proxy (not reified) - g = globals() - lazy_obj = g['test'] - # The root 'test' binding should still allow retry - # Second access - should also fail (retry the import) try: - x = test.test_lazy_import.data.broken_module - except AttributeError: - print("OK - retry worked") + _ = test.test_lazy_import.data.broken_module + except ValueError as exc: + assert str(exc) == "This module always fails to import", exc + else: + raise AssertionError("ValueError was not raised") """) - result = subprocess.run( - [sys.executable, "-c", code], - capture_output=True, - text=True - ) - self.assertEqual(result.returncode, 0, f"stdout: {result.stdout}, stderr: {result.stderr}") - self.assertIn("OK", result.stdout) + assert_python_ok("-c", code) - def test_error_during_module_execution_propagates(self): - """Errors in module code during reification should propagate correctly.""" + def test_lazy_submodule_traceback_hides_importlib_frames(self): code = textwrap.dedent(""" - import sys + import traceback + lazy import test.test_lazy_import.data.broken_module try: _ = test.test_lazy_import.data.broken_module - print("FAIL - should have raised") - except AttributeError: - print("OK") + except ValueError as exc: + frames = traceback.extract_tb(exc.__traceback__) + assert [frame.name for frame in frames] == ["<module>", "<module>"], frames + assert frames[0].filename == "<string>", frames + assert frames[1].filename.endswith("broken_module.py"), frames + else: + raise AssertionError("ValueError was not raised") """) - result = subprocess.run( - [sys.executable, "-c", code], - capture_output=True, - text=True - ) - self.assertEqual(result.returncode, 0, f"stdout: {result.stdout}, stderr: {result.stderr}") - self.assertIn("OK", result.stdout) + assert_python_ok("-c", code) + + def test_module_not_found_during_module_execution_propagates(self): + code = textwrap.dedent(""" + lazy import test.test_lazy_import.data.missing_dependency + + try: + _ = test.test_lazy_import.data.missing_dependency + except ModuleNotFoundError as exc: + assert exc.name == "missing_dependency_for_lazy_import_test", exc.name + assert str(exc) == "No module named 'missing_dependency_for_lazy_import_test'", exc + else: + raise AssertionError("ModuleNotFoundError was not raised") + """) + assert_python_ok("-c", code) + + def test_self_named_module_not_found_during_module_execution_propagates(self): + code = textwrap.dedent(""" + lazy import test.test_lazy_import.data.self_named_module_not_found + + try: + _ = test.test_lazy_import.data.self_named_module_not_found + except ModuleNotFoundError as exc: + assert exc.name == "test.test_lazy_import.data.self_named_module_not_found", exc.name + assert str(exc) == "boom", exc + else: + raise AssertionError("ModuleNotFoundError was not raised") + """) + assert_python_ok("-c", code) + + def test_none_in_sys_modules_during_submodule_resolution_propagates(self): + code = textwrap.dedent(""" + import sys + + sys.modules["test.test_lazy_import.data.blocked_module"] = None + lazy import test.test_lazy_import.data.blocked_module + + try: + _ = test.test_lazy_import.data.blocked_module + except ModuleNotFoundError as exc: + assert exc.name == "test.test_lazy_import.data.blocked_module", exc.name + assert str(exc) == ( + "import of test.test_lazy_import.data.blocked_module " + "halted; None in sys.modules" + ), exc + else: + raise AssertionError("ModuleNotFoundError was not raised") + """) + assert_python_ok("-c", code) def test_circular_lazy_import_does_not_crash_for_gh_144727(self): with tempfile.TemporaryDirectory() as tmpdir: diff --git a/Lib/test/test_lazy_import/data/missing_dependency.py b/Lib/test/test_lazy_import/data/missing_dependency.py new file mode 100644 index 00000000000000..aa2f2d0f65f73f --- /dev/null +++ b/Lib/test/test_lazy_import/data/missing_dependency.py @@ -0,0 +1 @@ +import missing_dependency_for_lazy_import_test diff --git a/Lib/test/test_lazy_import/data/self_named_module_not_found.py b/Lib/test/test_lazy_import/data/self_named_module_not_found.py new file mode 100644 index 00000000000000..941230d5da211d --- /dev/null +++ b/Lib/test/test_lazy_import/data/self_named_module_not_found.py @@ -0,0 +1 @@ +raise ModuleNotFoundError("boom", name=__name__) diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-07-06-16-30-00.gh-issue-153236.lazy-import-errors.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-07-06-16-30-00.gh-issue-153236.lazy-import-errors.rst new file mode 100644 index 00000000000000..c5043af0a4f80b --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-07-06-16-30-00.gh-issue-153236.lazy-import-errors.rst @@ -0,0 +1,2 @@ +Propagate exceptions raised while importing lazy submodules instead of +reporting them as missing attributes. diff --git a/Objects/moduleobject.c b/Objects/moduleobject.c index f447403ef31b43..b8cd6025c20ba5 100644 --- a/Objects/moduleobject.c +++ b/Objects/moduleobject.c @@ -1299,8 +1299,6 @@ _PyModule_IsPossiblyShadowing(PyObject *origin) return result; } -// Check if `name` is a lazily pending submodule of module `m`. -// Returns a new reference on success, or NULL with no error set. static PyObject * try_load_lazy_submodule(PyModuleObject *m, PyObject *name) { @@ -1313,10 +1311,13 @@ try_load_lazy_submodule(PyModuleObject *m, PyObject *name) Py_DECREF(mod_name); return NULL; } - PyObject *result = _PyImport_TryLoadLazySubmodule(mod_name, name); + PyObject *result = NULL; + _PyLazySubmoduleImportResult status = + _PyImport_TryLoadLazySubmodule(mod_name, name, &result); Py_DECREF(mod_name); - if (result == NULL) { - PyErr_Clear(); + if (status != _Py_LAZY_SUBMODULE_LOADED) { + assert(status == _Py_LAZY_SUBMODULE_ERROR || + status == _Py_LAZY_SUBMODULE_NOT_FOUND); return NULL; } if (PyDict_SetItem(m->md_dict, name, result) < 0) { diff --git a/Python/import.c b/Python/import.c index a47b2383e99d5f..287f5f611f5534 100644 --- a/Python/import.c +++ b/Python/import.c @@ -4100,7 +4100,9 @@ _PyImport_LoadLazyImportTstate(PyThreadState *tstate, PyObject *lazy_import) } static PyObject * -import_find_and_load(PyThreadState *tstate, PyObject *abs_name) +import_find_and_load_with_name(PyThreadState *tstate, PyObject *abs_name, + PyObject *find_and_load, + PyObject *not_found) { PyObject *mod = NULL; PyInterpreterState *interp = tstate->interp; @@ -4127,12 +4129,14 @@ import_find_and_load(PyThreadState *tstate, PyObject *abs_name) if (PyDTrace_IMPORT_FIND_LOAD_START_ENABLED()) PyDTrace_IMPORT_FIND_LOAD_START(PyUnicode_AsUTF8(abs_name)); - mod = PyObject_CallMethodObjArgs(IMPORTLIB(interp), &_Py_ID(_find_and_load), + mod = PyObject_CallMethodObjArgs(IMPORTLIB(interp), find_and_load, abs_name, IMPORT_FUNC(interp), NULL); - if (PyDTrace_IMPORT_FIND_LOAD_DONE_ENABLED()) + if (PyDTrace_IMPORT_FIND_LOAD_DONE_ENABLED()) { + int found = mod != NULL && mod != not_found; PyDTrace_IMPORT_FIND_LOAD_DONE(PyUnicode_AsUTF8(abs_name), - mod != NULL); + found); + } if (import_time) { PyTime_t t2; @@ -4153,6 +4157,13 @@ import_find_and_load(PyThreadState *tstate, PyObject *abs_name) #undef accumulated } +static PyObject * +import_find_and_load(PyThreadState *tstate, PyObject *abs_name) +{ + return import_find_and_load_with_name( + tstate, abs_name, &_Py_ID(_find_and_load), NULL); +} + static PyObject * get_abs_name(PyThreadState *tstate, PyObject *name, PyObject *globals, int level) @@ -4436,52 +4447,70 @@ register_from_lazy_on_parent(PyThreadState *tstate, PyObject *abs_name, return res; } -PyObject * -_PyImport_TryLoadLazySubmodule(PyObject *mod_name, PyObject *attr_name) +_PyLazySubmoduleImportResult +_PyImport_TryLoadLazySubmodule(PyObject *mod_name, PyObject *attr_name, + PyObject **result) { - PyInterpreterState *interp = _PyInterpreterState_GET(); + assert(result != NULL); + *result = NULL; + + PyThreadState *tstate = _PyThreadState_GET(); + PyInterpreterState *interp = tstate->interp; PyObject *lazy_pending = LAZY_PENDING_SUBMODULES(interp); if (lazy_pending == NULL) { - return NULL; + return _Py_LAZY_SUBMODULE_NOT_FOUND; } PyObject *pending_set; int rc = PyDict_GetItemRef(lazy_pending, mod_name, &pending_set); - if (rc <= 0) { - return NULL; + if (rc < 0) { + return _Py_LAZY_SUBMODULE_ERROR; + } + if (rc == 0) { + return _Py_LAZY_SUBMODULE_NOT_FOUND; } int contains = PySet_Contains(pending_set, attr_name); - if (contains <= 0) { + if (contains < 0) { Py_DECREF(pending_set); - return NULL; + return _Py_LAZY_SUBMODULE_ERROR; + } + if (contains == 0) { + Py_DECREF(pending_set); + return _Py_LAZY_SUBMODULE_NOT_FOUND; } PyObject *full_name = PyUnicode_FromFormat("%U.%U", mod_name, attr_name); if (full_name == NULL) { Py_DECREF(pending_set); - return NULL; + return _Py_LAZY_SUBMODULE_ERROR; } - PyObject *mod = PyImport_ImportModuleLevelObject( - full_name, NULL, NULL, NULL, 0); + PyObject *mod = import_find_and_load_with_name( + tstate, full_name, &_Py_ID(_find_and_load_lazy_submodule), Py_None); if (mod == NULL) { Py_DECREF(pending_set); Py_DECREF(full_name); - return NULL; + remove_importlib_frames(tstate); + return _Py_LAZY_SUBMODULE_ERROR; + } + if (mod == Py_None) { + Py_DECREF(mod); + Py_DECREF(pending_set); + Py_DECREF(full_name); + return _Py_LAZY_SUBMODULE_NOT_FOUND; } - Py_DECREF(mod); if (PySet_Discard(pending_set, attr_name) < 0) { + Py_DECREF(mod); Py_DECREF(pending_set); Py_DECREF(full_name); - return NULL; + return _Py_LAZY_SUBMODULE_ERROR; } Py_DECREF(pending_set); - - PyObject *submod = PyImport_GetModule(full_name); Py_DECREF(full_name); - return submod; + *result = mod; + return _Py_LAZY_SUBMODULE_LOADED; } PyObject * From 0fb27f2c33a07d70936a6f4cb930811923297148 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 18 Jul 2026 18:47:09 +0200 Subject: [PATCH 717/818] [3.15] Fix parameter name of `read_mime_types()` in `mimetypes` docs (GH-153974) (#153979) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (cherry picked from commit c89b5effa11366e28cb4a290a302a534352b768f) Co-authored-by: Raúl Santos Quirós <130504291+raul-sq@users.noreply.github.com> --- Doc/library/mimetypes.rst | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Doc/library/mimetypes.rst b/Doc/library/mimetypes.rst index c2ccabe3cc5389..0d512a0b6b8acc 100644 --- a/Doc/library/mimetypes.rst +++ b/Doc/library/mimetypes.rst @@ -116,12 +116,13 @@ behavior of the module. Previously, Windows registry settings were ignored. -.. function:: read_mime_types(filename) +.. function:: read_mime_types(file) - Load the type map given in the file *filename*, if it exists. The type map is - returned as a dictionary mapping filename extensions, including the leading dot - (``'.'``), to strings of the form ``'type/subtype'``. If the file *filename* - does not exist or cannot be read, ``None`` is returned. + Load the type map given in the file named by *file*, if it exists. *file* + must be a string specifying the name of the file to read. The type map is + returned as a dictionary mapping file extensions, including the leading dot + (``'.'``), to strings of the form ``'type/subtype'``. If the file does not + exist or cannot be read, ``None`` is returned. .. function:: add_type(type, ext, strict=True) From e7966912569f8d2a28934856cffa791004fe40b2 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 18 Jul 2026 20:18:22 +0200 Subject: [PATCH 718/818] [3.15] gh-150663: Document that PyErr_SetRaisedException accepts null (GH-153046) (#154021) gh-150663: Document that PyErr_SetRaisedException accepts null (GH-153046) (cherry picked from commit a0c8329218402396478be92b691043453fc28c32) Co-authored-by: Andrii Hrimov <andrew.hrimov@gmail.com> --- Doc/c-api/exceptions.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Doc/c-api/exceptions.rst b/Doc/c-api/exceptions.rst index 312095ad85f8b6..d9074e6719673a 100644 --- a/Doc/c-api/exceptions.rst +++ b/Doc/c-api/exceptions.rst @@ -499,12 +499,12 @@ Querying the error indicator .. c:function:: void PyErr_SetRaisedException(PyObject *exc) Set *exc* as the exception currently being raised, - clearing the existing exception if one is set. + clearing the existing exception if one is set. If *exc* is ``NULL``, + just clear the existing exception. - .. warning:: + *exc* must be a valid exception or ``NULL``. - This call ":term:`steals <steal>`" a reference to *exc*, - which must be a valid exception. + This call ":term:`steals <steal>`" a reference to *exc*. .. versionadded:: 3.12 From 919f0a5b76982a9c0f9337c4489637d9b36639ea Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 18 Jul 2026 21:54:31 +0200 Subject: [PATCH 719/818] [3.15] Docs: point `uu` module users to the `"uu"` encoding (GH-153657) (#154026) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (cherry picked from commit a1d580430c81c298d267ec255d544d0fa1d197c4) Co-authored-by: Ondřej Hošek <ondra.hosek@gmail.com> Co-authored-by: Stan Ulbrych <stan@python.org> --- Doc/library/uu.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Doc/library/uu.rst b/Doc/library/uu.rst index 0636d180294d47..cf6ec0fcef386d 100644 --- a/Doc/library/uu.rst +++ b/Doc/library/uu.rst @@ -11,5 +11,9 @@ This module is no longer part of the Python standard library. It was :ref:`removed in Python 3.13 <whatsnew313-pep594>` after being deprecated in Python 3.11. The removal was decided in :pep:`594`. +Encoding and decoding in the uu format can instead be achieved using +:func:`codecs.encode` and :func:`codecs.decode`, specifying ``"uu"`` +as the encoding. + The last version of Python that provided the :mod:`!uu` module was `Python 3.12 <https://docs.python.org/3.12/library/uu.html>`_. From 13b29a98388505ecc72e30cd97b5c8b15b1ed751 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 19 Jul 2026 00:07:10 +0200 Subject: [PATCH 720/818] [3.15] Improve `getopt.getopt` and `getopt.gnu_getopt` test coverage (GH-153933) (GH-153972) (cherry picked from commit 0fa144bb78042fb91c703678bb378b4dbce3cb95) Co-authored-by: Florian Freitag <flohacksfriday@gmail.com> --- Lib/test/test_getopt.py | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/Lib/test/test_getopt.py b/Lib/test/test_getopt.py index 8d0d5084abbb59..8b6c3b8baa07c5 100644 --- a/Lib/test/test_getopt.py +++ b/Lib/test/test_getopt.py @@ -149,6 +149,18 @@ def test_getopt(self): ('-a', ''), ('--alpha', '')]) self.assertEqual(args, ['arg1', 'arg2']) + # Allow string for single long argument + opts, args = getopt.getopt(cmdline, 'a::', 'alpha=?') + self.assertEqual(opts, [('-a', '1'), ('--alpha', '2'), ('--alpha', ''), + ('-a', ''), ('--alpha', '')]) + self.assertEqual(args, ['arg1', 'arg2']) + + # Pass everything after -- as args + cmdline = ['-a1', '--alpha=2', '--', '-b', '--beta=5'] + opts, args = getopt.getopt(cmdline, 'a:b', ['alpha=', 'beta']) + self.assertEqual(opts, [('-a', '1'), ('--alpha', '2')]) + self.assertEqual(args, ['-b', '--beta=5']) + self.assertError(getopt.getopt, cmdline, 'a:b', ['alpha', 'beta']) def test_gnu_getopt(self): @@ -191,6 +203,25 @@ def test_gnu_getopt(self): self.assertEqual(args, ['arg1', '-b', '1', '--alpha', '--beta=2', '--beta', '3', 'arg2']) + # Allow string for single long argument + opts, args = getopt.gnu_getopt(cmdline, 'ab:', 'alpha') + self.assertEqual(opts, [('-a', '')]) + self.assertEqual(args, ['arg1', '-b', '1', '--alpha', '--beta=2', + '--beta', '3', 'arg2']) + + # Pass everything after -- as args + cmdline = ['-a1', '--alpha=2', '--', '-b', '--beta=5'] + opts, args = getopt.gnu_getopt(cmdline, 'a:b', ['alpha=', 'beta']) + self.assertEqual(opts, [('-a', '1'), ('--alpha', '2')]) + self.assertEqual(args, ['-b', '--beta=5']) + + # In order arguments + cmdline = ["gamma", "--alpha=3"] + opts, args = getopt.gnu_getopt(cmdline, '-', ["alpha="]) + self.assertEqual(opts, [(None, ['gamma']), ('--alpha', '3')]) + self.assertEqual(args, []) + + def test_issue4629(self): longopts, shortopts = getopt.getopt(['--help='], '', ['help=']) self.assertEqual(longopts, [('--help', '')]) From becc0f6180d689d655fd29b9b21a6ef4c59a0323 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 19 Jul 2026 10:16:03 +0200 Subject: [PATCH 721/818] [3.15] Add vfspath TypeError test (GH-153987) (#154010) Add vfspath TypeError test (GH-153987) typeerror with message test (cherry picked from commit 5763bfdd1b582ef30cf3e6dd88754991973c77ce) Co-authored-by: Ajob Kustra <ajobkustra.p@gmail.com> Co-authored-by: Tomas R. <tomas.roun8@gmail.com> --- Lib/test/test_pathlib/test_join_windows.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Lib/test/test_pathlib/test_join_windows.py b/Lib/test/test_pathlib/test_join_windows.py index f30c80605f7f91..5afefa61b585f3 100644 --- a/Lib/test/test_pathlib/test_join_windows.py +++ b/Lib/test/test_pathlib/test_join_windows.py @@ -87,6 +87,11 @@ def test_vfspath(self): p = self.cls(r'\\a\b\c\d') self.assertEqual(vfspath(p), '\\\\a\\b\\c\\d') + def test_invalid_vspath(self): + msg = "expected JoinablePath object, not NoneType" + with self.assertRaisesRegex(TypeError, msg): + vfspath(None) + def test_parts(self): P = self.cls p = P(r'c:a\b') From 61aa141fdac5f8ec216cfad3bca005552f38db5c Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 19 Jul 2026 10:29:23 +0200 Subject: [PATCH 722/818] [3.15] gh-153896: Deduplicate unhashable arguments in `typing.Literal` (GH-153914) (#153955) gh-153896: Deduplicate unhashable arguments in `typing.Literal` (GH-153914) (cherry picked from commit a53b5b126749133e50692fe0c3729f5580ee8500) Co-authored-by: Massimiliano Bruni <massimiliano.bruni@icloud.com> Co-authored-by: Tomas R. <tomas.roun8@gmail.com> --- Lib/test/test_typing.py | 10 ++++++++-- Lib/typing.py | 15 +++++++++------ ...2026-07-18-10-52-10.gh-issue-153896.87oevp.rst | 1 + 3 files changed, 18 insertions(+), 8 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-07-18-10-52-10.gh-issue-153896.87oevp.rst diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 0c57c83491042d..986b41b18a2acc 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -2796,8 +2796,14 @@ def test_args(self): self.assertEqual(Literal[1, 2, 3].__args__, (1, 2, 3)) self.assertEqual(Literal[1, 2, 3, 3].__args__, (1, 2, 3)) self.assertEqual(Literal[1, Literal[2], Literal[3, 4]].__args__, (1, 2, 3, 4)) - # Mutable arguments will not be deduplicated - self.assertEqual(Literal[[], []].__args__, ([], [])) + # Unhashable arguments will be deduplicated too + self.assertEqual(Literal[[], []].__args__, ([],)) + self.assertEqual(Literal[{"a": 1}, {"a": 1}].__args__, ({"a": 1},)) + self.assertEqual( + Literal[1, {'a': 'b'}, 2, {'a': 'b'}, 3].__args__, + (1, {'a': 'b'}, 2, 3), + ) + self.assertEqual(Literal[{1}, {1}, {2}, {2}].__args__, ({1}, {2})) def test_flatten(self): l1 = Literal[Literal[1], Literal[2], Literal[3]] diff --git a/Lib/typing.py b/Lib/typing.py index 8b17cbbae2f6ec..5b764419d8afaa 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -788,13 +788,16 @@ def open_helper(file: str, mode: MODE) -> str: # There is no '_type_check' call because arguments to Literal[...] are # values, not types. parameters = _flatten_literal_params(parameters) + value_and_type_parameters = list(_value_and_type_iter(parameters)) + deduplicated_parameters = tuple( + p + for p, _ in _deduplicate( + value_and_type_parameters, + unhashable_fallback=True, + ) + ) - try: - parameters = tuple(p for p, _ in _deduplicate(list(_value_and_type_iter(parameters)))) - except TypeError: # unhashable parameters - pass - - return _LiteralGenericAlias(self, parameters) + return _LiteralGenericAlias(self, deduplicated_parameters) @_SpecialForm diff --git a/Misc/NEWS.d/next/Library/2026-07-18-10-52-10.gh-issue-153896.87oevp.rst b/Misc/NEWS.d/next/Library/2026-07-18-10-52-10.gh-issue-153896.87oevp.rst new file mode 100644 index 00000000000000..217a3d3d272ed0 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-18-10-52-10.gh-issue-153896.87oevp.rst @@ -0,0 +1 @@ +Deduplicate unhashable args in :data:`typing.Literal`. From 9ba9c56aab8fa6ba9dcd3a13a8bec0def85cd0b9 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 19 Jul 2026 11:01:57 +0200 Subject: [PATCH 723/818] [3.15] Fix typo "interruptability" in Logging Cookbook documentation (GH-154027) (#154066) (cherry picked from commit 30541f202f81ab3d3da5a6ac10c07fb6f1e4dcb4) Co-authored-by: Michael Newman <michael.b.newman@gmail.com> --- Doc/howto/logging-cookbook.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/howto/logging-cookbook.rst b/Doc/howto/logging-cookbook.rst index 87025814aafb9a..2ff221cf258eda 100644 --- a/Doc/howto/logging-cookbook.rst +++ b/Doc/howto/logging-cookbook.rst @@ -1955,7 +1955,7 @@ Subclass ``QueueListener`` class NNGSocketListener(logging.handlers.QueueListener): def __init__(self, uri, /, *handlers, **kwargs): - # Have a timeout for interruptability, and open a + # Have a timeout for interruptibility, and open a # subscriber socket socket = pynng.Sub0(listen=uri, recv_timeout=500) # The b'' subscription matches all topics From b51ecd89c63ba5217b555e97953fb71933ce47d4 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 19 Jul 2026 11:09:28 +0200 Subject: [PATCH 724/818] [3.15] Add test coverage to check execution of GetoptError.__str__ (GH-153941) (#153997) Add test coverage to check execution of GetoptError.__str__ (GH-153941) * Increase test coverage of getopt to check execution of GetoptError.__str__ * Add test coverage to check execution of GetoptError.__str__ * Add test coverage to check execution of GetoptError.__str__ * Add test coverage to check execution of GetoptError.__str__ * Add test coverage to check execution of GetoptError.__str__ * Add test coverage to check execution of GetoptError.__str__ (cherry picked from commit 9adef68a7956744b804d09c8b8b06c8c171053e5) Co-authored-by: Manith Hettiarachchilage <manithhetti@gmail.com> --- Lib/test/test_getopt.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Lib/test/test_getopt.py b/Lib/test/test_getopt.py index 8b6c3b8baa07c5..fac2ca3db81d70 100644 --- a/Lib/test/test_getopt.py +++ b/Lib/test/test_getopt.py @@ -229,6 +229,10 @@ def test_issue4629(self): self.assertEqual(longopts, [('--help', 'x')]) self.assertRaises(getopt.GetoptError, getopt.getopt, ['--help='], '', ['help']) + def test_getopt_error_str(self): + error = getopt.GetoptError('option -a not recognized', 'a') + self.assertEqual(str(error), 'option -a not recognized') + def test_libref_examples(): """ Examples from the Library Reference: Doc/lib/libgetopt.tex From 003764f671893bb7d3233ffde3f140032ba3f79d Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 19 Jul 2026 11:10:16 +0200 Subject: [PATCH 725/818] [3.15] Test that `ValueError` is raised when `vfsopen` is passed an invalid mode (GH-154008) (#154064) Test that `ValueError` is raised when `vfsopen` is passed an invalid mode (GH-154008) * ValueError with message test * Remove white space * Apply suggestions from code review Change from double quotes to single quotes. --------- (cherry picked from commit 9f5af278960a2f73a2e070de5141701e72675cf6) Co-authored-by: Rayan <157278782+ravg998@users.noreply.github.com> Co-authored-by: Tomas R. <tomas.roun8@gmail.com> --- Lib/test/test_pathlib/test_read.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Lib/test/test_pathlib/test_read.py b/Lib/test/test_pathlib/test_read.py index 16fb555b2aee05..51eede9d9ebafb 100644 --- a/Lib/test/test_pathlib/test_read.py +++ b/Lib/test/test_pathlib/test_read.py @@ -329,6 +329,11 @@ def test_info_is_symlink(self): self.assertFalse((p / 'fileA\udfff').info.is_symlink()) self.assertFalse((p / 'fileA\x00').info.is_symlink()) + def test_invalid_mode(self): + p = self.root / 'fileA' + with self.assertRaisesRegex(ValueError, 'invalid mode'): + vfsopen(p, 'q') + class ZipPathReadTest(ReadTestBase, unittest.TestCase): ground = ZipPathGround(ReadableZipPath) From 3aa59f4d512e64887ff1366ab0706491535ed30c Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 19 Jul 2026 11:11:51 +0200 Subject: [PATCH 726/818] [3.15] fix typos in `abi3t-migration.rst` (GH-153918) (#154056) fix typos in `abi3t-migration.rst` (GH-153918) (cherry picked from commit 4b60b46f09e7148216d5e07c289a17c9ebbb6074) Co-authored-by: Jost Migenda <jost.migenda@kcl.ac.uk> Co-authored-by: Chris Eibl <138194463+chris-eibl@users.noreply.github.com> --- Doc/howto/abi3t-migration.rst | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Doc/howto/abi3t-migration.rst b/Doc/howto/abi3t-migration.rst index c542efbdea8dec..ec78a33ed25820 100644 --- a/Doc/howto/abi3t-migration.rst +++ b/Doc/howto/abi3t-migration.rst @@ -8,14 +8,14 @@ Migrating to Stable ABI for free threading (``abi3t``) Starting with the 3.15 release, CPython supports a variant of the Stable ABI that supports :term:`free-threaded <free threading>` Python: -Stable ABI for Free-Threaded Builds, or ``abi3t`` for short. +the Stable ABI for Free-Threaded Builds, or ``abi3t`` for short. This document describes how to adapt C API extensions to support free threading. Why do this =========== -The typical reason to use Stable ABI is to reduce the number of artifacts that -you need to build and distribute for each version of your library. +The typical reason to use the Stable ABI is to reduce the number of artifacts +that you need to build and distribute for each version of your library. Without the Stable ABI, you must build a separate shared library, and typically a *wheel* distribution, for each feature version of CPython you wish @@ -87,16 +87,16 @@ builds; even the 3.15+ ones that this table "attributes" to ``abi3t``.) Why *not* do this ----------------- -There are two main downsides to Stable ABI. +There are two main downsides to the Stable ABI. -First, you extension may become slower, since Stable ABI prioritizes +First, your extension may become slower, since the Stable ABI prioritizes compatibility over performance. The difference is usually not noticeable, and often can be mitigated by using the same source to build both a Stable ABI build and a few version-specific ones for "tier 1" CPython versions. Second, not all of the C API is available. -Extensions need to be ported to build for Stable ABI, which may be difficult +Extensions need to be ported to build for the Stable ABI, which may be difficult or, in rare cases, impossible. Specifically, ``abi3t`` requires APIs added in CPython 3.15. @@ -127,7 +127,7 @@ Prerequisites This guide assumes that you have an extension written directly in C (or C++), which you want to port to ``abi3t``. -If your extenstion uses a code generator (like Cython) or language binding +If your extension uses a code generator (like Cython) or language binding (like PyO3), it's best to wait until that tool has support for ``abi3t``. If you maintain such a tool, you might be able to adapt the instructions here for your tool. @@ -135,7 +135,7 @@ here for your tool. Non-free-threaded Stable ABI ---------------------------- -Your extension should support the Stable ABI (``abi3t``). +Your extension should support the non-free-threaded Stable ABI (``abi3``). If not, either port it first, or follow this guide but be prepared to fix issues it does not mention. @@ -183,7 +183,7 @@ following just after ``#include <Python.h>``:: #error "abi3t define is not set!" #endif -This should result in a different error than "``abt3t`` define is not set". +This should result in a different error than "``abi3t`` define is not set". .. note:: @@ -705,7 +705,7 @@ Testing Note that when you build an extension compatible with multiple versions of CPython, you should always *test* it with each version it supports (for example, 3.15, 3.16, and so on). -Stable ABI only guarantees *ABI* compatibility; there may also be behavior +The Stable ABI only guarantees *ABI* compatibility; there may also be behavior changes -- both intentional ones (covered by :pep:`387`) and bugs. Be sure to run tests on both free-threaded and non-free-threaded builds From 15335ae20f1f214a36148d31475a1de61614d4d6 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 19 Jul 2026 11:28:18 +0200 Subject: [PATCH 727/818] [3.15] gh-154001: Avoid division by zero in binomialvariate (GH-154004) (GH-154050) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (cherry picked from commit 1f1374009b681814642ca199136815b223fd90ae) Co-authored-by: Łukasz <lukaszlapinski7@gmail.com> --- Lib/random.py | 6 +++++- Lib/test/test_random.py | 8 ++++++++ .../2026-07-18-17-09-49.gh-issue-154001.3brrUv.rst | 2 ++ 3 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2026-07-18-17-09-49.gh-issue-154001.3brrUv.rst diff --git a/Lib/random.py b/Lib/random.py index 4541267bab866a..7db761034509d3 100644 --- a/Lib/random.py +++ b/Lib/random.py @@ -861,7 +861,11 @@ def binomialvariate(self, n=1, p=0.5): u = random() u -= 0.5 us = 0.5 - _fabs(u) - k = _floor((2.0 * a / us + b) * u + c) + try: + k = _floor((2.0 * a / us + b) * u + c) + except ZeroDivisionError: + # Reject case where random() returned 0.0 + continue if k < 0 or k > n: continue v = random() diff --git a/Lib/test/test_random.py b/Lib/test/test_random.py index dbd3b855f536a0..8d093ab1b7014a 100644 --- a/Lib/test/test_random.py +++ b/Lib/test/test_random.py @@ -1082,6 +1082,14 @@ def test_binomialvariate_log_zero(self): self.assertIsInstance(result, int) self.assertIn(result, range(11)) + def test_binomialvariate_btrs_random_zero(self): + for p, expected in ((0.25, 25), (0.75, 75)): + with self.subTest(p=p): + g = random.Random() + with unittest.mock.patch.object( + g, 'random', side_effect=(0.0, 0.5, 0.5)): + self.assertEqual(g.binomialvariate(100, p), expected) + def test_constant(self): g = random.Random() N = 100 diff --git a/Misc/NEWS.d/next/Library/2026-07-18-17-09-49.gh-issue-154001.3brrUv.rst b/Misc/NEWS.d/next/Library/2026-07-18-17-09-49.gh-issue-154001.3brrUv.rst new file mode 100644 index 00000000000000..ff019aa3618847 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-18-17-09-49.gh-issue-154001.3brrUv.rst @@ -0,0 +1,2 @@ +Fix :func:`random.binomialvariate` raising :exc:`ZeroDivisionError` +when :func:`random.random` returns zero. From 32cf04b159bd8990ff8a10eba929a22ad846e233 Mon Sep 17 00:00:00 2001 From: "Jonathan J. Helmus" <jjhelmus@gmail.com> Date: Sun, 19 Jul 2026 04:39:05 -0500 Subject: [PATCH 728/818] [3.15] gh-152769: fixup enabling of perf trampoline on musl (Alpine Linux) (#153995) Co-authored-by: Victor Stinner <vstinner@python.org> --- configure | 4 ++-- configure.ac | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/configure b/configure index 08a7c663ce0a9c..af350fbb132d78 100755 --- a/configure +++ b/configure @@ -14431,10 +14431,10 @@ case $PLATFORM_TRIPLET in #( perf_trampoline=yes ;; #( aarch64-linux-gnu) : perf_trampoline=yes ;; #( - x86_64-linux-gnu) : - perf_trampoline=yes ;; #( x86_64-linux-musl) : perf_trampoline=yes ;; #( + aarch64-linux-musl) : + perf_trampoline=yes ;; #( darwin) : case $MACOSX_DEPLOYMENT_TARGET in #( 10.[0-9]|10.1[0-1]) : diff --git a/configure.ac b/configure.ac index ead82d6da0b545..a8bd6b884a131c 100644 --- a/configure.ac +++ b/configure.ac @@ -3873,8 +3873,8 @@ AC_MSG_CHECKING([perf trampoline]) AS_CASE([$PLATFORM_TRIPLET], [x86_64-linux-gnu], [perf_trampoline=yes], [aarch64-linux-gnu], [perf_trampoline=yes], - [x86_64-linux-gnu], [perf_trampoline=yes], [x86_64-linux-musl], [perf_trampoline=yes], + [aarch64-linux-musl], [perf_trampoline=yes], [darwin], [AS_CASE([$MACOSX_DEPLOYMENT_TARGET], [[10.[0-9]|10.1[0-1]]], [perf_trampoline=no], [perf_trampoline=yes] From 5f2d0d222f9dc316d5952e8d64b36f03e720e4b0 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 19 Jul 2026 12:06:20 +0200 Subject: [PATCH 729/818] [3.15] Docs: add frozendict to data types theme (GH-154063) (#154079) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Docs: add frozendict to data types theme (GH-154063) (cherry picked from commit 426cf84e84ed85d94c9055affd19e6fd69cfc939) Co-authored-by: Rodrigo Girão Serrão <5621605+rodrigogiraoserrao@users.noreply.github.com> --- Doc/library/datatypes.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Doc/library/datatypes.rst b/Doc/library/datatypes.rst index ff51b2779e5fa3..4b4f3b1720accc 100644 --- a/Doc/library/datatypes.rst +++ b/Doc/library/datatypes.rst @@ -8,9 +8,10 @@ The modules described in this chapter provide a variety of specialized data types such as dates and times, fixed-type arrays, heap queues, double-ended queues, and enumerations. -Python also provides some built-in data types, in particular, -:class:`dict`, :class:`list`, :class:`set` and :class:`frozenset`, and -:class:`tuple`. The :class:`str` class is used to hold +Python also provides :ref:`some built-in data types <bltin-types>`, in particular, +:class:`list`, :class:`tuple`, :class:`dict`, :class:`frozendict`, +:class:`set`, and :class:`frozenset`. +The :class:`str` class is used to hold Unicode strings, and the :class:`bytes` and :class:`bytearray` classes are used to hold binary data. From 8177e470eb7a058d23e7d0dacf1b76136a88b186 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 19 Jul 2026 12:06:57 +0200 Subject: [PATCH 730/818] [3.15] gh-149319: Make `asyncio` REPL respect `-I` and `-E` options (GH-149405) (#154072) gh-149319: Make `asyncio` REPL respect `-I` and `-E` options (GH-149405) (cherry picked from commit 7f8fc07e850d7b27a220c815db8c8abd545286c3) Co-authored-by: Jonathan Dung <jonathandung@yahoo.com> --- Lib/asyncio/__main__.py | 4 ++-- .../Library/2026-05-06-23-13-40.gh-issue-149319.PLM93t.rst | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-05-06-23-13-40.gh-issue-149319.PLM93t.rst diff --git a/Lib/asyncio/__main__.py b/Lib/asyncio/__main__.py index 7f0565d0b8ddc7..708fdd595971e8 100644 --- a/Lib/asyncio/__main__.py +++ b/Lib/asyncio/__main__.py @@ -99,7 +99,7 @@ def run(self): console.write(banner) - if not sys.flags.isolated and (startup_path := os.getenv("PYTHONSTARTUP")): + if not sys.flags.ignore_environment and (startup_path := os.getenv("PYTHONSTARTUP")): sys.audit("cpython.run_startup", startup_path) try: import tokenize @@ -200,7 +200,7 @@ def interrupt(self) -> None: sys.audit("cpython.run_stdin") - if os.getenv('PYTHON_BASIC_REPL'): + if not sys.flags.ignore_environment and os.getenv('PYTHON_BASIC_REPL'): CAN_USE_PYREPL = False else: try: diff --git a/Misc/NEWS.d/next/Library/2026-05-06-23-13-40.gh-issue-149319.PLM93t.rst b/Misc/NEWS.d/next/Library/2026-05-06-23-13-40.gh-issue-149319.PLM93t.rst new file mode 100644 index 00000000000000..4018ec43f5a47d --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-05-06-23-13-40.gh-issue-149319.PLM93t.rst @@ -0,0 +1 @@ +The :mod:`asyncio` REPL now ignores :envvar:`PYTHONSTARTUP` and :envvar:`PYTHON_BASIC_REPL` when :option:`-E` or :option:`-I` is used. Patch by Jonathan Dung. From aa3b9722601764a9149d9cccb349453939817c5a Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 19 Jul 2026 12:17:49 +0200 Subject: [PATCH 731/818] [3.15] Improve colorsys coverage (GH-153982) (#154076) Improve colorsys coverage (GH-153982) * improve colorsys coverage * add subtest (cherry picked from commit 54b00c055210d738f5c3fb590ab85bde80b46ac6) Co-authored-by: MonadChains <monadchains@gmail.com> --- Lib/test/test_colorsys.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Lib/test/test_colorsys.py b/Lib/test/test_colorsys.py index 74d76294b0b4d4..9dfaef44a6a450 100644 --- a/Lib/test/test_colorsys.py +++ b/Lib/test/test_colorsys.py @@ -42,6 +42,10 @@ def test_hsv_values(self): self.assertTripleEqual(hsv, colorsys.rgb_to_hsv(*rgb)) self.assertTripleEqual(rgb, colorsys.hsv_to_rgb(*hsv)) + # test 360 phase shift in hue + h, s, v = hsv + self.assertTripleEqual(rgb, colorsys.hsv_to_rgb(h + 1.0, s, v)) + def test_hls_roundtrip(self): for r in frange(0.0, 1.0, 0.2): for g in frange(0.0, 1.0, 0.2): @@ -89,6 +93,18 @@ def test_yiq_roundtrip(self): colorsys.yiq_to_rgb(*colorsys.rgb_to_yiq(*rgb)) ) + def test_yiq_to_rgb_clamping(self): + values = [ + # rgb, yiq (invalid YIQ values clamped to RGB range) + ((1.0, 0.0, 1.0), (0.0, 0.5, 1.0)), + ((0.0, 1.0, 0.0), (0.25, -1.0, -1.0)), + ((0.0, 0.0, 1.0), (0.0, -1.0, 0.5)) + ] + + for (rgb, yiq) in values: + with self.subTest(rgb=rgb, yiq=yiq): + self.assertTripleEqual(rgb, colorsys.yiq_to_rgb(*yiq)) + def test_yiq_values(self): values = [ # rgb, yiq From bc8af591acee4da62c60d97924e546a7e2af0576 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 19 Jul 2026 13:16:32 +0200 Subject: [PATCH 732/818] [3.15] Document getopt and gnu_getopt longopts argument as string (GH-153976) (#154095) Document getopt and gnu_getopt longopts argument as string (GH-153976) Document getopt and gnu_getopt longopts as string (cherry picked from commit 16562f1ce31ba654c42eee644f253bb31cff9f9d) Co-authored-by: Florian Freitag <flohacksfriday@gmail.com> --- Doc/library/getopt.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Doc/library/getopt.rst b/Doc/library/getopt.rst index 5c63009e22d58c..9995f114d063e8 100644 --- a/Doc/library/getopt.rst +++ b/Doc/library/getopt.rst @@ -62,6 +62,8 @@ exception: option ``--fo`` will match as ``--foo``, but ``--f`` will not match uniquely, so :exc:`GetoptError` will be raised. + If *longopts* is a string it gets treated as a list of a single element. + The return value consists of two elements: the first is a list of ``(option, value)`` pairs; the second is the list of program arguments left after the option list was stripped (this is a trailing slice of *args*). Each From 9f7c44fc7bd3fcd041dd9d6daee7801131ad01a1 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 19 Jul 2026 14:28:27 +0200 Subject: [PATCH 733/818] [3.15] Add test for explicit `cls` argument bypassing default JSON decoder (GH-154094) (#154112) Add test for explicit `cls` argument bypassing default JSON decoder (GH-154094) * Add test for skipped `cls=None` case * Fix lint * Add new line between classes (cherry picked from commit 5380589615515fa9e2c48820073a3fd8e32a930d) Co-authored-by: Dominic H <dom@dominic.sk> --- Lib/test/test_json/test_decode.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Lib/test/test_json/test_decode.py b/Lib/test/test_json/test_decode.py index 1d51fb2de0e69e..6d05ef8f8eb091 100644 --- a/Lib/test/test_json/test_decode.py +++ b/Lib/test/test_json/test_decode.py @@ -1,4 +1,5 @@ import decimal +import unittest.mock from io import StringIO from collections import OrderedDict from test.test_json import PyTest, CTest @@ -155,6 +156,15 @@ def test_limit_int(self): with self.assertRaises(ValueError): self.loads('1' * (maxdigits + 1)) + def test_explicit_cls_skips_json_decoder_default(self): + class CustomDecoder: + pass + + with unittest.mock.patch.object( + CustomDecoder, 'decode', create=True) as mock_decode: + self.loads('{}', cls=CustomDecoder) + mock_decode.assert_called_once() + class TestPyDecode(TestDecode, PyTest): pass class TestCDecode(TestDecode, CTest): pass From 114aa8c402bd9289c8bd5b59137b14cf2f5dc64b Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 19 Jul 2026 14:30:29 +0200 Subject: [PATCH 734/818] [3.15] gh-154053: Fix compilation of the ssl module against LibreSSL (GH-154054) (GH-154075) LibreSSL does not provide SSL_CTX_set1_sigalgs_list() or SSL_CTX_set1_client_sigalgs_list(), added in gh-138252, so _ssl failed to compile against LibreSSL on 3.15+. Guard the set_server_sigalgs() and set_client_sigalgs() methods so they raise NotImplementedError on LibreSSL, and skip the corresponding tests. (cherry picked from commit 39b058f8ad29238edc8b65406bb1fb0bc3c0020d) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> --- Lib/test/test_ssl.py | 11 ++++++++++- ...07-19-00-00-00.gh-issue-154053.LibreSSLsigalgs.rst | 4 ++++ Modules/_ssl.c | 10 ++++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2026-07-19-00-00-00.gh-issue-154053.LibreSSLsigalgs.rst diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py index 90fe087ecb8511..d7ffe91bf31dc9 100644 --- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py @@ -49,12 +49,15 @@ PROTOCOLS = sorted(ssl._PROTOCOL_NAMES) HOST = socket_helper.HOST IS_AWS_LC = "AWS-LC" in ssl.OPENSSL_VERSION +IS_LIBRESSL = "LibreSSL" in ssl.OPENSSL_VERSION IS_OPENSSL_3_0_0 = ssl.OPENSSL_VERSION_INFO >= (3, 0, 0) CAN_GET_SELECTED_OPENSSL_GROUP = ssl.OPENSSL_VERSION_INFO >= (3, 2) CAN_IGNORE_UNKNOWN_OPENSSL_GROUPS = ssl.OPENSSL_VERSION_INFO >= (3, 3) CAN_GET_AVAILABLE_OPENSSL_GROUPS = ssl.OPENSSL_VERSION_INFO >= (3, 5) CAN_GET_AVAILABLE_OPENSSL_SIGALGS = ssl.OPENSSL_VERSION_INFO >= (3, 4) -CAN_SET_CLIENT_SIGALGS = not IS_AWS_LC +# LibreSSL does not provide SSL_CTX_set1_(client_)sigalgs_list(). +CAN_SET_CLIENT_SIGALGS = not IS_AWS_LC and not IS_LIBRESSL +CAN_SET_SERVER_SIGALGS = not IS_LIBRESSL CAN_IGNORE_UNKNOWN_OPENSSL_SIGALGS = ssl.OPENSSL_VERSION_INFO >= (3, 3) CAN_GET_SELECTED_OPENSSL_SIGALG = ssl.OPENSSL_VERSION_INFO >= (3, 5) PY_SSL_DEFAULT_CIPHERS = sysconfig.get_config_var('PY_SSL_DEFAULT_CIPHERS') @@ -1082,6 +1085,8 @@ def test_set_client_sigalgs(self): if CAN_IGNORE_UNKNOWN_OPENSSL_SIGALGS: self.assertIsNone(ctx.set_client_sigalgs('rsa_pss_rsae_sha256:?foo')) + @unittest.skipUnless(CAN_SET_SERVER_SIGALGS, + "SSL library doesn't support setting server sigalgs") def test_set_server_sigalgs(self): ctx = ssl.create_default_context() @@ -4593,6 +4598,8 @@ def test_client_sigalgs_mismatch(self): chatty=True, connectionchatty=True, sni_name=hostname) + @unittest.skipUnless(CAN_SET_SERVER_SIGALGS, + "SSL library doesn't support setting server sigalgs") def test_server_sigalgs(self): # server rsa_pss_rsae_sha384, client auto sigalg = "rsa_pss_rsae_sha384" @@ -4613,6 +4620,8 @@ def test_server_sigalgs(self): if CAN_GET_SELECTED_OPENSSL_SIGALG: self.assertEqual(stats['server_sigalg'], sigalg) + @unittest.skipUnless(CAN_SET_SERVER_SIGALGS, + "SSL library doesn't support setting server sigalgs") def test_server_sigalgs_mismatch(self): client_context, server_context, hostname = testing_context() client_context.set_server_sigalgs("rsa_pss_rsae_sha256") diff --git a/Misc/NEWS.d/next/Library/2026-07-19-00-00-00.gh-issue-154053.LibreSSLsigalgs.rst b/Misc/NEWS.d/next/Library/2026-07-19-00-00-00.gh-issue-154053.LibreSSLsigalgs.rst new file mode 100644 index 00000000000000..3d453eb7314345 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-19-00-00-00.gh-issue-154053.LibreSSLsigalgs.rst @@ -0,0 +1,4 @@ +Fix compilation of the :mod:`ssl` module against LibreSSL, which does not +provide ``SSL_CTX_set1_sigalgs_list()`` and ``SSL_CTX_set1_client_sigalgs_list()``. +The :meth:`!set_server_sigalgs` and :meth:`!set_client_sigalgs` methods of +:class:`ssl.SSLContext` now raise :exc:`NotImplementedError` on LibreSSL. diff --git a/Modules/_ssl.c b/Modules/_ssl.c index f451c0ce7364ab..af402f471a327d 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -3863,6 +3863,10 @@ _ssl__SSLContext_set_client_sigalgs_impl(PySSLContext *self, #ifdef OPENSSL_IS_AWSLC _setSSLError(get_state_ctx(self), "can't set client sigalgs on AWS-LC", 0, __FILE__, __LINE__); return NULL; +#elif defined(LIBRESSL_VERSION_NUMBER) + PyErr_SetString(PyExc_NotImplementedError, + "setting client sigalgs is not supported by LibreSSL"); + return NULL; #else if (!SSL_CTX_set1_client_sigalgs_list(self->ctx, sigalgslist)) { _setSSLError(get_state_ctx(self), "unrecognized signature algorithm", 0, __FILE__, __LINE__); @@ -3884,11 +3888,17 @@ _ssl__SSLContext_set_server_sigalgs_impl(PySSLContext *self, const char *sigalgslist) /*[clinic end generated code: output=31ecb1d310285644 input=653b752e4f8d801b]*/ { +#ifdef LIBRESSL_VERSION_NUMBER + PyErr_SetString(PyExc_NotImplementedError, + "setting server sigalgs is not supported by LibreSSL"); + return NULL; +#else if (!SSL_CTX_set1_sigalgs_list(self->ctx, sigalgslist)) { _setSSLError(get_state_ctx(self), "unrecognized signature algorithm", 0, __FILE__, __LINE__); return NULL; } Py_RETURN_NONE; +#endif } static int From 46d7aa9fbd2fafb099da6a61f3865620d4dc9125 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka <storchaka@gmail.com> Date: Sun, 19 Jul 2026 15:45:26 +0300 Subject: [PATCH 735/818] [3.15] gh-153864: Fix curses window.insch() for non-ASCII characters on a wide build (GH-153865) (GH-154117) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On a wide build, winsch() does not locale-decode a byte above 127, unlike waddch(), so insch() inserted '¤' (U+00A4) instead of '€' for byte 0xA4 under ISO-8859-15. Decode the byte with btowc() and insert it as a wide character, like addch(). (cherry picked from commit 223cbffca6df7e4c8c77b360a4e6ba0472255643) Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --- Lib/test/test_curses.py | 11 +++----- ...-07-17-20-56-32.gh-issue-153864.WmA9By.rst | 3 +++ Modules/_cursesmodule.c | 26 +++++++++++++++++++ 3 files changed, 33 insertions(+), 7 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-07-17-20-56-32.gh-issue-153864.WmA9By.rst diff --git a/Lib/test/test_curses.py b/Lib/test/test_curses.py index 737735fbcc0032..d5cd7483d77ff0 100644 --- a/Lib/test/test_curses.py +++ b/Lib/test/test_curses.py @@ -329,13 +329,10 @@ def test_output_character(self): stdscr.move(2, 0) stdscr.echochar(v) self.assertEqual(self._read_char(2, 0), c) - # insch() round-trips a byte only where its code point equals - # the byte value (Latin-1): on a wide build ncurses winsch - # stores a printable byte directly as a code point instead of - # decoding it through the locale. - if ord(c) < 0x100: - stdscr.insch(1, 0, v) - self.assertEqual(self._read_char(1, 0), c) + # insch() decodes the byte through the locale like addch(), so + # it round-trips the same character. + stdscr.insch(1, 0, v) + self.assertEqual(self._read_char(1, 0), c) # The same characters supplied as a str. Unlike the int path above, a # str is stored as a wide-character cell on a wide build, so every diff --git a/Misc/NEWS.d/next/Library/2026-07-17-20-56-32.gh-issue-153864.WmA9By.rst b/Misc/NEWS.d/next/Library/2026-07-17-20-56-32.gh-issue-153864.WmA9By.rst new file mode 100644 index 00000000000000..79857185d7d0c7 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-17-20-56-32.gh-issue-153864.WmA9By.rst @@ -0,0 +1,3 @@ +On a wide :mod:`curses` build, :meth:`curses.window.insch` now inserts a +non-ASCII byte as the character it encodes in the window's encoding, +consistently with :meth:`~curses.window.addch`, instead of its code point. diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index dd5af63fcc8a46..3a60749d440248 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -2064,6 +2064,32 @@ _curses_window_insch_impl(PyCursesWindowObject *self, int group_left_1, return NULL; const char *funcname; +#ifdef HAVE_NCURSESW + /* winsch() does not locale-decode a byte above 127 on a wide build, + unlike waddch(), so decode it here and insert it as a wide character. */ + chtype cch = ch_ & A_CHARTEXT; + if (cch > 127) { + wint_t wc = btowc((int)cch); + if (wc != WEOF) { + cchar_t wch; + wchar_t wstr[2] = { (wchar_t)wc, L'\0' }; + attr_t cattr = (attr_t)((ch_ | (attr_t)attr) & ~(chtype)A_CHARTEXT); + if (setcchar(&wch, wstr, cattr, PAIR_NUMBER(cattr), NULL) == ERR) { + curses_window_set_error(self, "setcchar", "insch"); + return NULL; + } + if (!group_left_1) { + rtn = wins_wch(self->win, &wch); + funcname = "wins_wch"; + } + else { + rtn = mvwins_wch(self->win, y, x, &wch); + funcname = "mvwins_wch"; + } + return curses_window_check_err(self, rtn, funcname, "insch"); + } + } +#endif if (!group_left_1) { rtn = winsch(self->win, ch_ | (attr_t)attr); funcname = "winsch"; From 7d1b64bd9a07deb4ce20e0f3d1b07b0507c51431 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka <storchaka@gmail.com> Date: Sun, 19 Jul 2026 15:46:08 +0300 Subject: [PATCH 736/818] [3.15] gh-153862: Fix curses window.inch() for non-ASCII characters on a wide build (GH-153863) (GH-154116) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On a wide build, winch() returns the low 8 bits of the character's code point with no locale conversion, so inch()/mvinch() disagreed with instr() for a non-ASCII character of an 8-bit locale ('€' under ISO-8859-15 gave 0xAC instead of 0xA4). Re-encode the cell to its locale byte via wctob(), as ncurses does for getbkgd(). (cherry picked from commit a83aaa91490d5885949eb0780a37b15963b6d0f3) Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --- Doc/library/curses.rst | 2 ++ Lib/test/test_curses.py | 10 +++--- ...-07-17-20-31-00.gh-issue-153862.X3kjoY.rst | 3 ++ Modules/_cursesmodule.c | 36 +++++++++++++++++++ 4 files changed, 45 insertions(+), 6 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-07-17-20-31-00.gh-issue-153862.X3kjoY.rst diff --git a/Doc/library/curses.rst b/Doc/library/curses.rst index f2115a236f2583..f46c89ec25a0c0 100644 --- a/Doc/library/curses.rst +++ b/Doc/library/curses.rst @@ -1079,6 +1079,8 @@ Window objects The bottom 8 bits are the character proper and the upper bits are the attributes; extract them with the :data:`A_CHARTEXT` and :data:`A_ATTRIBUTES` bit-masks, and the color pair with :func:`pair_number`. + The character byte is the locale-encoded byte of the cell's character, + consistent with :meth:`instr`. .. method:: window.insch(ch[, attr]) diff --git a/Lib/test/test_curses.py b/Lib/test/test_curses.py index d5cd7483d77ff0..8de61279a070f8 100644 --- a/Lib/test/test_curses.py +++ b/Lib/test/test_curses.py @@ -506,10 +506,9 @@ def test_read_from_window(self): self.assertRaises(ValueError, stdscr.instr, -2) self.assertRaises(ValueError, stdscr.instr, 0, 2, -2) # A non-ASCII character of an 8-bit locale reads back as its encoded - # byte (see _encodable for the set). instr() returns the locale bytes - # for any single-byte character; inch() packs the text into a chtype, so - # on a wide build it only round-trips a Latin-1 codepoint (byte == - # codepoint). + # byte (see _encodable for the set). Both instr() and inch() return the + # locale byte for any character that fits the locale's single-byte + # encoding. encoding = stdscr.encoding for ch in ('A', 'é', '¤', '€', 'є'): try: @@ -521,8 +520,7 @@ def test_read_from_window(self): with self.subTest(ch=ch): stdscr.addstr(2, 0, ch) self.assertEqual(stdscr.instr(2, 0, 1), b) - if ord(ch) < 0x100: - self.assertEqual(stdscr.inch(2, 0) & curses.A_CHARTEXT, b[0]) + self.assertEqual(stdscr.inch(2, 0) & curses.A_CHARTEXT, b[0]) def test_coordinate_errors(self): # Addressing a cell outside the window raises curses.error. diff --git a/Misc/NEWS.d/next/Library/2026-07-17-20-31-00.gh-issue-153862.X3kjoY.rst b/Misc/NEWS.d/next/Library/2026-07-17-20-31-00.gh-issue-153862.X3kjoY.rst new file mode 100644 index 00000000000000..aa646dc6c49174 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-17-20-31-00.gh-issue-153862.X3kjoY.rst @@ -0,0 +1,3 @@ +On a wide :mod:`curses` build, :meth:`curses.window.inch` now returns the +locale-encoded byte of a non-ASCII character, matching +:meth:`~curses.window.instr`, instead of the low byte of its code point. diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index 3a60749d440248..0440d412495e6f 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -2102,6 +2102,34 @@ _curses_window_insch_impl(PyCursesWindowObject *self, int group_left_1, return curses_window_check_err(self, rtn, funcname, "insch"); } +#ifdef HAVE_NCURSESW +/* winch() returns the low 8 bits of the character's code point with no locale + conversion, unlike instr(), so recover the locale byte from the wide cell + when the character maps to exactly one byte, keeping the attribute and color + bits in RTN. A character with no single-byte form is left to winch(). */ +static chtype +curses_cell_locale_byte(chtype rtn, const cchar_t *cell) +{ + wchar_t wstr[CCHARW_MAX + 1]; + attr_t attrs; + short pair; + /* getcchar() is not guaranteed to write the text of an empty cell. */ + wstr[0] = L'\0'; + if (getcchar(cell, wstr, &attrs, &pair, NULL) == ERR + || wstr[0] == L'\0' || wstr[1] != L'\0') + { + return rtn; + } + /* wctob() mirrors ncurses' own _nc_to_char(): the single-byte form, or EOF + when the character has none in this locale. */ + int byte = wctob(wstr[0]); + if (byte != EOF) { + rtn = (rtn & ~(chtype)A_CHARTEXT) | (unsigned char)byte; + } + return rtn; +} +#endif + /*[clinic input] _curses.window.inch @@ -2139,6 +2167,14 @@ _curses_window_inch_impl(PyCursesWindowObject *self, int group_right_1, curses_window_set_error(self, funcname, "inch"); return NULL; } +#ifdef HAVE_NCURSESW + cchar_t cell = {0}; + if ((group_right_1 ? mvwin_wch(self->win, y, x, &cell) + : win_wch(self->win, &cell)) != ERR) + { + rtn = curses_cell_locale_byte(rtn, &cell); + } +#endif return PyLong_FromUnsignedLong(rtn); } From fd6bd15c75955fee9cf2103d09de9e3c0f9fea5f Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 19 Jul 2026 17:01:00 +0200 Subject: [PATCH 737/818] [3.15] gh-153932: protect read of en_index during enumerate.reduce (GH-154118) (GH-154128) gh-153932: protect read of en_index during enumerate.reduce (GH-154118) (cherry picked from commit 1604043caf0a00fe4ea9f6e31e389c4cf8b8baab) Co-authored-by: L. Le <lelynn11@gmail.com> --- Lib/test/libregrtest/tsan.py | 1 + Lib/test/test_enumerate.py | 26 +++++++++++++++++++ ...-07-19-12-33-27.gh-issue-153932.lKw2bo.rst | 2 ++ Objects/enumobject.c | 9 ++++--- 4 files changed, 35 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-07-19-12-33-27.gh-issue-153932.lKw2bo.rst diff --git a/Lib/test/libregrtest/tsan.py b/Lib/test/libregrtest/tsan.py index bacfe5e21ba0b7..c7ec63763bc9d8 100644 --- a/Lib/test/libregrtest/tsan.py +++ b/Lib/test/libregrtest/tsan.py @@ -8,6 +8,7 @@ 'test_ctypes', 'test_concurrent_futures', 'test_enum', + 'test_enumerate', 'test_functools', 'test_httpservers', 'test_imaplib', diff --git a/Lib/test/test_enumerate.py b/Lib/test/test_enumerate.py index 5cb54cff9b76fd..c8b85fe8692178 100644 --- a/Lib/test/test_enumerate.py +++ b/Lib/test/test_enumerate.py @@ -3,8 +3,11 @@ import sys import pickle import gc +import threading + from test import support +from test.support import threading_helper class G: 'Sequence using __getitem__' @@ -292,5 +295,28 @@ def enum(self, iterable, start=sys.maxsize + 1): (sys.maxsize+3,'c')] +@threading_helper.requires_working_threading() +class TestThreadSafety(EnumerateStartTestCase): + def test_thread_safety_while_iterating(self): + # gh-153932: calling reduce while iterating should pass with TSAN + + en = enumerate(range(10_000)) + stop = threading.Event() + + def advance(): + for _ in en: + pass + stop.set() + + def read(): + while not stop.is_set(): + en.__reduce__() + + threads = [threading.Thread(target=advance), threading.Thread(target=read)] + + with threading_helper.start_threads(threads): + pass + + if __name__ == "__main__": unittest.main() diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-07-19-12-33-27.gh-issue-153932.lKw2bo.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-07-19-12-33-27.gh-issue-153932.lKw2bo.rst new file mode 100644 index 00000000000000..56b96307ed04cd --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-07-19-12-33-27.gh-issue-153932.lKw2bo.rst @@ -0,0 +1,2 @@ +Fix thread safety issue in the ``__reduce__`` method of +:py:class:`enumerate`. diff --git a/Objects/enumobject.c b/Objects/enumobject.c index fc53f1bfee8dde..68aa594c5540ce 100644 --- a/Objects/enumobject.c +++ b/Objects/enumobject.c @@ -277,10 +277,13 @@ enum_reduce(PyObject *op, PyObject *Py_UNUSED(ignored)) enumobject *en = _enumobject_CAST(op); PyObject *result; Py_BEGIN_CRITICAL_SECTION(en); - if (en->en_longindex != NULL) + if (en->en_longindex != NULL) { result = Py_BuildValue("O(OO)", Py_TYPE(en), en->en_sit, en->en_longindex); - else - result = Py_BuildValue("O(On)", Py_TYPE(en), en->en_sit, en->en_index); + } + else { + Py_ssize_t en_index = FT_ATOMIC_LOAD_SSIZE_RELAXED(en->en_index); + result = Py_BuildValue("O(On)", Py_TYPE(en), en->en_sit, en_index); + } Py_END_CRITICAL_SECTION(); return result; } From fbac0fba551d4ea2d61c87b82ec2d727d42cfda6 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 19 Jul 2026 17:03:25 +0200 Subject: [PATCH 738/818] [3.15] gh-152798: update sys.thread_info.lock documentation to match implementation (GH-153263) (#153276) gh-152798: update sys.thread_info.lock documentation to match implementation (GH-153263) (cherry picked from commit 48cc2579b65be508ca64b6cb64ce0f7922eab9ab) Co-authored-by: Wojusensei <wojusensei@outlook.com> --- Doc/library/sys.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst index b4f410a020f86e..212bd93d4a7cc1 100644 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -2265,8 +2265,9 @@ always available. Unless explicitly noted otherwise, all variables are read-only The name of the lock implementation: - * ``"semaphore"``: a lock uses a semaphore - * ``"mutex+cond"``: a lock uses a mutex and a condition variable + * ``"semaphore"``: a lock uses a semaphore (Python 3.14 and older) + * ``"mutex+cond"``: a lock uses a mutex and a condition variable (Python 3.14 and older) + * ``"pymutex"``: a lock uses the :c:type:`PyMutex` implementation (Python 3.15 and newer) * ``None`` if this information is unknown .. attribute:: thread_info.version From 618f4ec98c4306d0ee5f071df17a9828240b3f5e Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 19 Jul 2026 17:16:37 +0200 Subject: [PATCH 739/818] [3.15] improve json test coverage (GH-154123) (GH-154134) Add test that covers the except block on line 106 of decoder.py (cherry picked from commit ee1e48ebd8194cd5984714021c4df85dbb93c6df) Co-authored-by: David <slavicek.david29@gmail.com> --- Lib/test/test_json/test_decode.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Lib/test/test_json/test_decode.py b/Lib/test/test_json/test_decode.py index 6d05ef8f8eb091..33aeefa92f282a 100644 --- a/Lib/test/test_json/test_decode.py +++ b/Lib/test/test_json/test_decode.py @@ -149,6 +149,10 @@ def test_negative_index(self): d = self.json.JSONDecoder() self.assertRaises(ValueError, d.raw_decode, 'a'*42, -50000) + def test_unterminated_string(self): + d = self.json.JSONDecoder() + self.assertRaises(self.JSONDecodeError, d.raw_decode, '"\\') + def test_limit_int(self): maxdigits = 5000 with support.adjust_int_max_str_digits(maxdigits): From 52e73026282ecff5e58890cea356dff21ef8346a Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 19 Jul 2026 17:28:16 +0200 Subject: [PATCH 740/818] [3.15] gh-139806: Mention pickle error changes in What's New in 3.14 (GH-154020) (GH-154161) The gh-122311 changes made pickle.dump() and pickle.dumps() raise PicklingError for some failures that previously raised AttributeError, ImportError, ValueError or UnicodeEncodeError, depending on the implementation. Add an entry about this in the "Porting to Python 3.14" section. (cherry picked from commit eb447081ed8182f825fa01953ec87cff41f3d585) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> --- Doc/whatsnew/3.14.rst | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst index 0bb8858aea16fe..d3bc21e82eda40 100644 --- a/Doc/whatsnew/3.14.rst +++ b/Doc/whatsnew/3.14.rst @@ -3310,6 +3310,16 @@ Changes in the Python API This temporary change affects other threads. (Contributed by Serhiy Storchaka in :gh:`69998`.) +* :func:`pickle.dump` and :func:`pickle.dumps` now raise + :exc:`~pickle.PicklingError` for some failures that previously raised + :exc:`AttributeError`, :exc:`ImportError`, :exc:`ValueError`, + :exc:`UnicodeEncodeError` or :exc:`!PicklingError`, + depending on the implementation + (for example, pickling a local object, or an object whose module cannot be imported). + The original exception is chained to the :exc:`!PicklingError`. + Code that caught these exceptions should also catch :exc:`!PicklingError`. + (Contributed by Serhiy Storchaka in :gh:`122311`.) + * :class:`types.UnionType` is now an alias for :class:`typing.Union`, causing changes in some behaviors. See :ref:`above <whatsnew314-typing-union>` for more details. From 9bb83a1f2a999062ace4d684bce10d3b601abc21 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 19 Jul 2026 17:38:01 +0200 Subject: [PATCH 741/818] [3.15] gh-154144: Fix false positive from the stdbool.h guard in _testcapimodule.c (GH-154145) (GH-154157) (cherry picked from commit 8d11eb0c31efcfd1d504650a564d9a4b45cba721) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> --- .../Tests/2026-07-19-18-20-00.gh-issue-154144.tcbool.rst | 1 + Modules/_testcapimodule.c | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) create mode 100644 Misc/NEWS.d/next/Tests/2026-07-19-18-20-00.gh-issue-154144.tcbool.rst diff --git a/Misc/NEWS.d/next/Tests/2026-07-19-18-20-00.gh-issue-154144.tcbool.rst b/Misc/NEWS.d/next/Tests/2026-07-19-18-20-00.gh-issue-154144.tcbool.rst new file mode 100644 index 00000000000000..dc1ac8b4035153 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2026-07-19-18-20-00.gh-issue-154144.tcbool.rst @@ -0,0 +1 @@ +Fix building the :mod:`!_testcapi` module on NetBSD. diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 799390c2705328..fb18a866e62812 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -15,6 +15,10 @@ #include "frameobject.h" // PyFrame_New() #include "marshal.h" // PyMarshal_WriteLongToFile() +#ifdef bool +# error "The public headers should not include <stdbool.h>, see gh-90904" +#endif + #include <float.h> // FLT_MAX #include <signal.h> #include <stddef.h> // offsetof() @@ -26,10 +30,6 @@ # include <sys/sysctl.h> // sysctlbyname() #endif -#ifdef bool -# error "The public headers should not include <stdbool.h>, see gh-48924" -#endif - #include "_testcapi/util.h" From 9bb127132d0401027d579b4526a01ded96854ddf Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 19 Jul 2026 19:41:29 +0200 Subject: [PATCH 742/818] [3.15] Fix typos in `Py_tp_base` macro documentation (GH-154150) (#154180) (cherry picked from commit 53916ee48d2e78592898bea2e52bfeb4497e0bcd) Co-authored-by: Michael Newman <michael.b.newman@gmail.com> --- Doc/c-api/type.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/c-api/type.rst b/Doc/c-api/type.rst index 6b68c0d085589a..99a7ed8b1cb7b8 100644 --- a/Doc/c-api/type.rst +++ b/Doc/c-api/type.rst @@ -699,7 +699,7 @@ but need extra remarks for use as slots: .. soft-deprecated:: 3.15 - When not targetting older Python versions, pefer :c:macro:`!Py_tp_bases`. + When not targeting older Python versions, prefer :c:macro:`!Py_tp_bases`. The following slots do not correspond to public fields in the underlying structures: From b3ee1902bb57731e9c6d5458c96121bad18dcbdc Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 19 Jul 2026 20:59:49 +0200 Subject: [PATCH 743/818] [3.15] gh-151022: Fix remote debugging linetable reads (GH-151036) (#154187) --- Lib/test/test_external_inspection.py | 50 +++++++++++++++++++ ...-06-06-15-04-37.gh-issue-151022.1Aw8Tk.rst | 2 + Modules/_remote_debugging/code_objects.c | 11 ++-- 3 files changed, 57 insertions(+), 6 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-06-06-15-04-37.gh-issue-151022.1Aw8Tk.rst diff --git a/Lib/test/test_external_inspection.py b/Lib/test/test_external_inspection.py index 6b1529aa173f01..910fe96d5e7d81 100644 --- a/Lib/test/test_external_inspection.py +++ b/Lib/test/test_external_inspection.py @@ -438,6 +438,56 @@ def _extract_coroutine_stacks_lineno_only(self, stack_trace): # ============================================================================ +@requires_remote_subprocess_debugging() +class TestSelfStackTrace(RemoteInspectionTestBase): + @skip_if_not_supported + @unittest.skipIf( + sys.platform == "linux" and not PROCESS_VM_READV_SUPPORTED, + "Test only runs on Linux with process_vm_readv support", + ) + def test_self_trace_with_large_linetable(self): + script = textwrap.dedent("""\ + import os + import _remote_debugging + + assignments = "\\n".join( + f"value_{i} = {i}" for i in range(1000) + ) + expected_lineno = len(assignments.splitlines()) + 1 + source = ( + f"{assignments}\\n" + "stack_trace = " + "_remote_debugging.RemoteUnwinder(os.getpid()).get_stack_trace()\\n" + ) + code = compile(source, "large_linetable.py", "exec") + assert len(code.co_linetable) > 4096, len(code.co_linetable) + namespace = {"os": os, "_remote_debugging": _remote_debugging} + exec(code, namespace) + large_linetable_frames = [ + frame + for interpreter in namespace["stack_trace"] + for thread in interpreter.threads + for frame in thread.frame_info + if frame.filename == "large_linetable.py" + ] + assert len(large_linetable_frames) == 1, large_linetable_frames + assert large_linetable_frames[0].location.lineno == expected_lineno, ( + large_linetable_frames[0] + ) + """) + + result = subprocess.run( + [sys.executable, "-c", script], + capture_output=True, + text=True, + timeout=SHORT_TIMEOUT, + ) + self.assertEqual( + result.returncode, 0, + f"stdout: {result.stdout}\nstderr: {result.stderr}" + ) + + @requires_remote_subprocess_debugging() class TestGetStackTrace(RemoteInspectionTestBase): @skip_if_not_supported diff --git a/Misc/NEWS.d/next/Library/2026-06-06-15-04-37.gh-issue-151022.1Aw8Tk.rst b/Misc/NEWS.d/next/Library/2026-06-06-15-04-37.gh-issue-151022.1Aw8Tk.rst new file mode 100644 index 00000000000000..f16f024c582fb3 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-06-15-04-37.gh-issue-151022.1Aw8Tk.rst @@ -0,0 +1,2 @@ +Fix ``_remote_debugging`` stack traces for code objects with large line +tables. diff --git a/Modules/_remote_debugging/code_objects.c b/Modules/_remote_debugging/code_objects.c index ab889a130ee4e7..f83252524b96ff 100644 --- a/Modules/_remote_debugging/code_objects.c +++ b/Modules/_remote_debugging/code_objects.c @@ -7,6 +7,8 @@ #include "_remote_debugging.h" +#define MAX_LINETABLE_SIZE (64 * 1024) + /* ============================================================================ * TLBC CACHING FUNCTIONS (Py_GIL_DISABLED only) * ============================================================================ */ @@ -186,11 +188,7 @@ parse_linetable(const uintptr_t addrq, const char* linetable, Py_ssize_t linetab int computed_line = firstlineno; // Running accumulator, separate from output int val; // Temporary for varint results uint8_t byte; // Temporary for byte reads - const size_t MAX_LINETABLE_ENTRIES = 65536; - size_t entry_count = 0; - - while (ptr < end && *ptr != '\0' && entry_count < MAX_LINETABLE_ENTRIES) { - entry_count++; + while (ptr < end && *ptr != '\0') { uint8_t first_byte = *(ptr++); uint8_t code = (first_byte >> 3) & 15; size_t length = (first_byte & 7) + 1; @@ -387,7 +385,8 @@ parse_code_object(RemoteUnwinderObject *unwinder, } linetable = read_py_bytes(unwinder, - GET_MEMBER(uintptr_t, code_object, unwinder->debug_offsets.code_object.linetable), 4096); + GET_MEMBER(uintptr_t, code_object, unwinder->debug_offsets.code_object.linetable), + MAX_LINETABLE_SIZE); if (!linetable) { set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read linetable from code object"); goto error; From 2261368a01f9fdc86ae6034fc4c0d1b2d3486553 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 20 Jul 2026 06:54:52 +0200 Subject: [PATCH 744/818] [3.15] fix ResourceWarnings of test_kill_issue43884 in asyncio (GH-154178) (#154183) fix ResourceWarnings of test_kill_issue43884 in asyncio (GH-154178) (cherry picked from commit 6df4993bb646e7f1a30f37c3f65a5b4c9c033cb0) Co-authored-by: Kumar Aditya <kumaraditya@python.org> --- Lib/test/test_asyncio/test_subprocess.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_asyncio/test_subprocess.py b/Lib/test/test_asyncio/test_subprocess.py index c08eb7cf261568..11be3e2142bd15 100644 --- a/Lib/test/test_asyncio/test_subprocess.py +++ b/Lib/test/test_asyncio/test_subprocess.py @@ -250,7 +250,7 @@ def test_kill_issue43884(self): # kills the process and all its children. creationflags = CREATE_NEW_PROCESS_GROUP proc = self.loop.run_until_complete( - asyncio.create_subprocess_shell(blocking_shell_command, stdout=asyncio.subprocess.PIPE, + asyncio.create_subprocess_shell(blocking_shell_command, creationflags=creationflags) ) self.loop.run_until_complete(asyncio.sleep(1)) From a706e80ec32687e7b0dd18efafa4294f6014e364 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 20 Jul 2026 07:31:59 +0200 Subject: [PATCH 745/818] [3.15] gh-119710: fix asyncio Process.wait() to finish on process exit and not wait for closing of pipes (GH-151983) (#154170) * gh-119710: fix asyncio Process.wait() to finish on process exit and not wait for closing of pipes (GH-151983) (cherry picked from commit f2521324e6bdf331460abec7c2a88e2d3736b91c) Co-authored-by: Tobias Alex-Petersen <tobias.alex.petersen@gmail.com> Co-authored-by: Kumar Aditya <kumaraditya@python.org> --- Lib/asyncio/base_subprocess.py | 25 +++---- Lib/test/test_asyncio/test_subprocess.py | 71 +++++++++++-------- ...-06-11-10-00-00.gh-issue-119710.Qz7Kp2.rst | 4 ++ 3 files changed, 53 insertions(+), 47 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-06-11-10-00-00.gh-issue-119710.Qz7Kp2.rst diff --git a/Lib/asyncio/base_subprocess.py b/Lib/asyncio/base_subprocess.py index 224b1883808a41..3fa1ed1afd2a65 100644 --- a/Lib/asyncio/base_subprocess.py +++ b/Lib/asyncio/base_subprocess.py @@ -26,7 +26,6 @@ def __init__(self, loop, protocol, args, shell, self._pending_calls = collections.deque() self._pipes = {} self._finished = False - self._pipes_connected = False if stdin == subprocess.PIPE: self._pipes[0] = None @@ -214,7 +213,6 @@ async def _connect_pipes(self, waiter): else: if waiter is not None and not waiter.cancelled(): waiter.set_result(None) - self._pipes_connected = True def _call(self, cb, *data): if self._pending_calls is not None: @@ -235,6 +233,7 @@ def _process_exited(self, returncode): if self._loop.get_debug(): logger.info('%r exited with return code %r', self, returncode) self._returncode = returncode + if self._proc.returncode is None: # asyncio uses a child watcher: copy the status into the Popen # object. On Python 3.6, it is required to avoid a ResourceWarning. @@ -243,6 +242,13 @@ def _process_exited(self, returncode): self._try_finish() + # gh-119710: Wake up futures waiting for wait() as soon as the process + # exits. + for waiter in self._exit_waiters: + if not waiter.done(): + waiter.set_result(returncode) + self._exit_waiters = None + async def _wait(self): """Wait until the process exit and return the process return code. @@ -258,15 +264,7 @@ def _try_finish(self): assert not self._finished if self._returncode is None: return - if not self._pipes_connected: - # self._pipes_connected can be False if not all pipes were connected - # because either the process failed to start or the self._connect_pipes task - # got cancelled. In this broken state we consider all pipes disconnected and - # to avoid hanging forever in self._wait as otherwise _exit_waiters - # would never be woken up, we wake them up here. - for waiter in self._exit_waiters: - if not waiter.done(): - waiter.set_result(self._returncode) + if all(p is not None and p.disconnected for p in self._pipes.values()): self._finished = True @@ -276,11 +274,6 @@ def _call_connection_lost(self, exc): try: self._protocol.connection_lost(exc) finally: - # wake up futures waiting for wait() - for waiter in self._exit_waiters: - if not waiter.done(): - waiter.set_result(self._returncode) - self._exit_waiters = None self._loop = None self._proc = None self._protocol = None diff --git a/Lib/test/test_asyncio/test_subprocess.py b/Lib/test/test_asyncio/test_subprocess.py index 11be3e2142bd15..323f25d748aa7a 100644 --- a/Lib/test/test_asyncio/test_subprocess.py +++ b/Lib/test/test_asyncio/test_subprocess.py @@ -111,37 +111,6 @@ def test_subprocess_repr(self): ) transport.close() - def test_proc_exited_no_invalid_state_error_on_exit_waiters(self): - # gh-145541: when _connect_pipes hasn't completed (so - # _pipes_connected is False) and the process exits, _try_finish() - # sets the result on exit waiters. Then _call_connection_lost() must - # not call set_result() again on the same waiters. - self.loop.set_exception_handler( - lambda loop, context: self.fail( - f"unexpected exception: {context}") - ) - waiter = self.loop.create_future() - transport, protocol = self.create_transport(waiter) - - # Simulate a waiter registered via _wait() before the process exits. - exit_waiter = self.loop.create_future() - transport._exit_waiters.append(exit_waiter) - - # _connect_pipes hasn't completed, so _pipes_connected is False. - self.assertFalse(transport._pipes_connected) - - # Simulate process exit. _try_finish() will set the result on - # exit_waiter because _pipes_connected is False, and then schedule - # _call_connection_lost() because _pipes is empty (vacuously all - # disconnected). _call_connection_lost() must skip exit_waiter - # because it's already done. - transport._process_exited(6) - self.loop.run_until_complete(waiter) - - self.assertEqual(exit_waiter.result(), 6) - - transport.close() - class SubprocessMixin: @@ -435,6 +404,46 @@ async def len_message(message): self.assertEqual(output.rstrip(), b'3') self.assertEqual(exitcode, 0) + def test_wait_even_if_pipe_is_open(self): + # gh-119710: Process.wait() must return once the process exits even + # if its stdout pipe is inherited by a grandchild that keeps it open, + # so the pipe never reaches EOF. Otherwise wait() hangs forever + # despite the returncode being known. + + async def run(): + # The grandchild inherits the child's stdin and stdout pipes and + # keeps both open after the child is killed. It writes "ready" + # so we know it has started, and exits once its stdin hits EOF. + code = textwrap.dedent("""\ + import subprocess, sys + subprocess.run([sys.executable, "-c", + "import sys; sys.stdout.write('ready');" + " sys.stdout.flush(); sys.stdin.read()"]) + """) + + proc = await asyncio.create_subprocess_exec( + sys.executable, "-c", code, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + ) + try: + wait_proc = asyncio.create_task(proc.wait()) + # Wait until the grandchild holds the inherited pipes; this + # also lets the wait() task register its waiter. + await proc.stdout.readexactly(5) + proc.kill() + returncode = await asyncio.wait_for( + wait_proc, timeout=support.SHORT_TIMEOUT) + if sys.platform == 'win32': + self.assertIsInstance(returncode, int) + else: + self.assertEqual(-signal.SIGKILL, returncode) + finally: + proc.stdin.close() # let the grandchild exit + await proc.stdout.read() + + self.loop.run_until_complete(run()) + def test_empty_input(self): async def empty_input(): diff --git a/Misc/NEWS.d/next/Library/2026-06-11-10-00-00.gh-issue-119710.Qz7Kp2.rst b/Misc/NEWS.d/next/Library/2026-06-11-10-00-00.gh-issue-119710.Qz7Kp2.rst new file mode 100644 index 00000000000000..45f99d72ea29a2 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-11-10-00-00.gh-issue-119710.Qz7Kp2.rst @@ -0,0 +1,4 @@ +Fix :mod:`asyncio` subprocess :meth:`~asyncio.subprocess.Process.wait` +hanging when the process has exited but one of its pipes is kept open by an +inherited child process (so the pipe never reaches EOF). ``wait()`` now +returns as soon as the process exits, regardless of the pipes' state. From 404a81d2e8f823f40fdb486a58e2b07d69792f67 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 20 Jul 2026 08:24:07 +0200 Subject: [PATCH 746/818] [3.15] gh-154046: docs: fix dead link to codahale timing attacks article in secrets.rst (GH-154047) (#154213) gh-154046: docs: fix dead link to codahale timing attacks article in secrets.rst (GH-154047) (cherry picked from commit e8042329b6bb2472b16645c559e4223486b85965) Co-authored-by: Pranav Choudhary <pranav.nstblr@gmail.com> --- Doc/library/secrets.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/secrets.rst b/Doc/library/secrets.rst index 3b5b57fb1c2170..842e8c512def13 100644 --- a/Doc/library/secrets.rst +++ b/Doc/library/secrets.rst @@ -137,7 +137,7 @@ Other functions :term:`bytes-like objects <bytes-like object>` *a* and *b* are equal, otherwise ``False``, using a "constant-time compare" to reduce the risk of - `timing attacks <https://codahale.com/a-lesson-in-timing-attacks/>`_. + `timing attacks <https://web.archive.org/web/20250815071532/https://codahale.com/a-lesson-in-timing-attacks/>`__. See :func:`hmac.compare_digest` for additional details. From b7c3b5258ab49d4d3854036e4b39ba90b2c4d6f0 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 20 Jul 2026 08:35:14 +0200 Subject: [PATCH 747/818] [3.15] Fix grammatical typos in documentation (GH-154181) (#154190) Fix grammatical typos in documentation (GH-154181) (cherry picked from commit 40f7fbf4a53d2f2cb0414a22f891d6e7e288280c) Co-authored-by: ilya <110783299+bontail@users.noreply.github.com> --- Doc/library/ast.rst | 2 +- Doc/library/compression.zstd.rst | 4 ++-- Doc/library/sys.rst | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Doc/library/ast.rst b/Doc/library/ast.rst index 4809fdb42bf3d7..5bdfe7c182de3a 100644 --- a/Doc/library/ast.rst +++ b/Doc/library/ast.rst @@ -1366,7 +1366,7 @@ Control flow ``try`` blocks which are followed by ``except*`` clauses. The attributes are the same as for :class:`Try` but the :class:`ExceptHandler` nodes in ``handlers`` - are interpreted as ``except*`` blocks rather then ``except``. + are interpreted as ``except*`` blocks rather than ``except``. .. doctest:: diff --git a/Doc/library/compression.zstd.rst b/Doc/library/compression.zstd.rst index 6d99e36e1e5bb6..6618ccf7d559e7 100644 --- a/Doc/library/compression.zstd.rst +++ b/Doc/library/compression.zstd.rst @@ -503,7 +503,7 @@ Advanced parameter control The :meth:`~.bounds` method can be used on any attribute to get the valid values for that parameter. - Parameters are optional; any omitted parameter will have it's value selected + Parameters are optional; any omitted parameter will have its value selected automatically. Example getting the lower and upper bound of :attr:`~.compression_level`:: @@ -732,7 +732,7 @@ Advanced parameter control An :class:`~enum.IntEnum` containing the advanced decompression parameter keys that can be used when decompressing data. Parameters are optional; any - omitted parameter will have it's value selected automatically. + omitted parameter will have its value selected automatically. The :meth:`~.bounds` method can be used on any attribute to get the valid values for that parameter. diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst index 212bd93d4a7cc1..a22aac914cedfe 100644 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -2160,7 +2160,7 @@ always available. Unless explicitly noted otherwise, all variables are read-only returned by the :func:`open` function. Their parameters are chosen as follows: - * The encoding and error handling are is initialized from + * The encoding and error handling are initialized from :c:member:`PyConfig.stdio_encoding` and :c:member:`PyConfig.stdio_errors`. On Windows, UTF-8 is used for the console device. Non-character From 3dd4fdcebc35c966a527f9da15cc3525fb229bbd Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 20 Jul 2026 08:35:33 +0200 Subject: [PATCH 748/818] [3.15] gh-154211: Skip C-stack exhaustion tests when the C stack is huge (GH-154212) (GH-154216) (cherry picked from commit 863b31268c3160af1febcee4c79ff6ed380f328f) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> --- Lib/test/list_tests.py | 3 +- Lib/test/mapping_tests.py | 1 + Lib/test/support/__init__.py | 28 ++++++++++++++++++- Lib/test/test_ast/test_ast.py | 10 ++++--- Lib/test/test_call.py | 3 +- Lib/test/test_class.py | 1 + Lib/test/test_compile.py | 1 + Lib/test/test_copy.py | 5 ++++ Lib/test/test_ctypes/test_as_parameter.py | 4 ++- Lib/test/test_descr.py | 2 ++ Lib/test/test_dict.py | 1 + Lib/test/test_dictviews.py | 5 +++- Lib/test/test_exception_group.py | 6 +++- Lib/test/test_exceptions.py | 1 + Lib/test/test_functools.py | 2 +- Lib/test/test_isinstance.py | 6 ++-- Lib/test/test_json/test_recursion.py | 4 +-- Lib/test/test_pyexpat.py | 2 +- Lib/test/test_xml_etree.py | 2 +- ...-20-11-30-00.gh-issue-154211.hugestack.rst | 3 ++ 20 files changed, 73 insertions(+), 17 deletions(-) create mode 100644 Misc/NEWS.d/next/Tests/2026-07-20-11-30-00.gh-issue-154211.hugestack.rst diff --git a/Lib/test/list_tests.py b/Lib/test/list_tests.py index e76f79c274e744..ec2aa59f2cb872 100644 --- a/Lib/test/list_tests.py +++ b/Lib/test/list_tests.py @@ -6,7 +6,7 @@ from functools import cmp_to_key from test import seq_tests -from test.support import ALWAYS_EQ, NEVER_EQ +from test.support import ALWAYS_EQ, NEVER_EQ, skip_if_huge_c_stack from test.support import skip_emscripten_stack_overflow, skip_wasi_stack_overflow @@ -60,6 +60,7 @@ def test_repr(self): self.assertEqual(str(a2), "[0, 1, 2, [...], 3]") self.assertEqual(repr(a2), "[0, 1, 2, [...], 3]") + @skip_if_huge_c_stack(200_000) @skip_wasi_stack_overflow() @skip_emscripten_stack_overflow() def test_repr_deep(self): diff --git a/Lib/test/mapping_tests.py b/Lib/test/mapping_tests.py index 9624072e69adfc..ae2fb3f5f448e2 100644 --- a/Lib/test/mapping_tests.py +++ b/Lib/test/mapping_tests.py @@ -629,6 +629,7 @@ def __repr__(self): d = self._full_mapping({1: BadRepr()}) self.assertRaises(Exc, repr, d) + @support.skip_if_huge_c_stack() @support.skip_wasi_stack_overflow() @support.skip_emscripten_stack_overflow() @support.skip_if_sanitizer("requires deep stack", ub=True) diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index 65bf3e7feb837f..d7ca1e72813446 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -45,7 +45,7 @@ "check__all__", "skip_if_buggy_ucrt_strfptime", "check_disallow_instantiation", "check_sanitizer", "skip_if_sanitizer", "requires_limited_api", "requires_specialization", "thread_unsafe", - "skip_if_unlimited_stack_size", + "skip_if_unlimited_stack_size", "skip_if_huge_c_stack", # sys "MS_WINDOWS", "is_jython", "is_android", "is_emscripten", "is_wasi", "is_apple_mobile", "check_impl_detail", "unix_shell", "setswitchinterval", @@ -2827,6 +2827,32 @@ def exceeds_recursion_limit(): return 150_000 +def skip_if_huge_c_stack(depth=150_000): + """Skip decorator for tests which cannot overflow the C stack. + + Tests exhausting the C stack with *depth* recursive calls cannot + trigger the recursion protection if the C stack is too large (e.g. + with a large or unlimited RLIMIT_STACK), and either fail, or run + for a very long time, or crash, or consume all memory. + """ + try: + from _testinternalcapi import get_c_recursion_remaining + except ImportError: + # Fall back to checking for an unlimited stack size. + huge = False + if not (is_emscripten or is_wasi) and os.name != "nt": + import resource + soft, hard = resource.getrlimit(resource.RLIMIT_STACK) + huge = soft == hard and soft in (-1, 0xFFFF_FFFF_FFFF_FFFF) + else: + remaining = get_c_recursion_remaining() + # A negative value means integer overflow in the estimate + # (e.g. with an unlimited RLIMIT_STACK). + huge = remaining >= depth or remaining < 0 + return unittest.skipIf( + huge, f"the C stack is large enough for {depth} recursive calls") + + # Windows doesn't have os.uname() but it doesn't support s390x. is_s390x = hasattr(os, 'uname') and os.uname().machine == 's390x' skip_on_s390x = unittest.skipIf(is_s390x, 'skipped on s390x') diff --git a/Lib/test/test_ast/test_ast.py b/Lib/test/test_ast/test_ast.py index af8b334da03e70..66d5e92fd18472 100644 --- a/Lib/test/test_ast/test_ast.py +++ b/Lib/test/test_ast/test_ast.py @@ -26,7 +26,9 @@ from test import support from test.support import os_helper -from test.support import skip_emscripten_stack_overflow, skip_wasi_stack_overflow, skip_if_unlimited_stack_size +from test.support import (skip_emscripten_stack_overflow, + skip_wasi_stack_overflow, + skip_if_unlimited_stack_size, skip_if_huge_c_stack) from test.support.ast_helper import ASTTestMixin from test.support.import_helper import ensure_lazy_imports from test.test_ast.utils import to_tuple @@ -1017,7 +1019,7 @@ def next(self): enum._test_simple_enum(_Precedence, _ast_unparse._Precedence) @support.cpython_only - @skip_if_unlimited_stack_size + @support.skip_if_huge_c_stack(100_000 if sys.platform == "android" else 500_000) @skip_wasi_stack_overflow() @skip_emscripten_stack_overflow() def test_ast_recursion_limit(self): @@ -2026,7 +2028,7 @@ def test_level_as_none(self): exec(code, ns) self.assertIn('sleep', ns) - @skip_if_unlimited_stack_size + @skip_if_huge_c_stack() @skip_emscripten_stack_overflow() def test_recursion_direct(self): e = ast.UnaryOp(op=ast.Not(), lineno=0, col_offset=0, operand=ast.Constant(1)) @@ -2035,7 +2037,7 @@ def test_recursion_direct(self): with support.infinite_recursion(): compile(ast.Expression(e), "<test>", "eval") - @skip_if_unlimited_stack_size + @skip_if_huge_c_stack() @skip_emscripten_stack_overflow() def test_recursion_indirect(self): e = ast.UnaryOp(op=ast.Not(), lineno=0, col_offset=0, operand=ast.Constant(1)) diff --git a/Lib/test/test_call.py b/Lib/test/test_call.py index f42526aee19417..1e42356be21ddd 100644 --- a/Lib/test/test_call.py +++ b/Lib/test/test_call.py @@ -3,7 +3,7 @@ set_recursion_limit, skip_on_s390x, skip_emscripten_stack_overflow, skip_wasi_stack_overflow, skip_if_sanitizer, - import_helper) + skip_if_huge_c_stack, import_helper) try: import _testcapi except ImportError: @@ -1062,6 +1062,7 @@ def get_sp(): @unittest.skipIf(is_wasi and Py_DEBUG, "requires deep stack") @skip_if_sanitizer("requires deep stack", thread=True) @unittest.skipIf(_testcapi is None, "requires _testcapi") + @skip_if_huge_c_stack(90_000) @skip_emscripten_stack_overflow() @skip_wasi_stack_overflow() def test_super_deep(self): diff --git a/Lib/test/test_class.py b/Lib/test/test_class.py index e401941c6d6970..62d8806b75d9db 100644 --- a/Lib/test/test_class.py +++ b/Lib/test/test_class.py @@ -555,6 +555,7 @@ class Custom: self.assertFalse(hasattr(o, "__call__")) self.assertFalse(hasattr(c, "__call__")) + @support.skip_if_huge_c_stack() @support.skip_emscripten_stack_overflow() @support.skip_wasi_stack_overflow() def testSFBug532646(self): diff --git a/Lib/test/test_compile.py b/Lib/test/test_compile.py index 9edbca3c383b43..d279851e7b7f8e 100644 --- a/Lib/test/test_compile.py +++ b/Lib/test/test_compile.py @@ -724,6 +724,7 @@ def test_yet_more_evil_still_undecodable(self): @support.cpython_only @unittest.skipIf(support.is_wasi, "exhausts limited stack on WASI") + @support.skip_if_huge_c_stack(100_000 if sys.platform == "android" else 500_000) @support.skip_emscripten_stack_overflow() def test_compiler_recursion_limit(self): # Compiler frames are small diff --git a/Lib/test/test_copy.py b/Lib/test/test_copy.py index 98f56b5ae87f96..9455c9e00514ca 100644 --- a/Lib/test/test_copy.py +++ b/Lib/test/test_copy.py @@ -377,6 +377,7 @@ def test_deepcopy_list(self): self.assertIsNot(x, y) self.assertIsNot(x[0], y[0]) + @support.skip_if_huge_c_stack() @support.skip_emscripten_stack_overflow() @support.skip_wasi_stack_overflow() def test_deepcopy_reflexive_list(self): @@ -406,6 +407,7 @@ def test_deepcopy_tuple_of_immutables(self): y = copy.deepcopy(x) self.assertIs(x, y) + @support.skip_if_huge_c_stack() @support.skip_emscripten_stack_overflow() @support.skip_wasi_stack_overflow() def test_deepcopy_reflexive_tuple(self): @@ -449,6 +451,7 @@ def test_deepcopy_frozendict(self): self.assertIsNot(x[0], y[0]) self.assertIs(y[0]['foo'], y) + @support.skip_if_huge_c_stack() @support.skip_emscripten_stack_overflow() @support.skip_wasi_stack_overflow() def test_deepcopy_reflexive_dict(self): @@ -609,6 +612,7 @@ def __eq__(self, other): self.assertIsNot(y, x) self.assertIsNot(y.foo, x.foo) + @support.skip_if_huge_c_stack() def test_deepcopy_reflexive_inst(self): class C: pass @@ -671,6 +675,7 @@ def __eq__(self, other): self.assertEqual(y, x) self.assertIsNot(y.foo, x.foo) + @support.skip_if_huge_c_stack() def test_reconstruct_reflexive(self): class C(object): pass diff --git a/Lib/test/test_ctypes/test_as_parameter.py b/Lib/test/test_ctypes/test_as_parameter.py index c9d728e9ae2f9c..abbfb6efdcea55 100644 --- a/Lib/test/test_ctypes/test_as_parameter.py +++ b/Lib/test/test_ctypes/test_as_parameter.py @@ -5,7 +5,8 @@ c_short, c_int, c_long, c_longlong, c_byte, c_wchar, c_float, c_double, ArgumentError) -from test.support import import_helper, skip_if_sanitizer, skip_emscripten_stack_overflow +from test.support import (import_helper, skip_if_sanitizer, + skip_emscripten_stack_overflow, skip_if_huge_c_stack) _ctypes_test = import_helper.import_module("_ctypes_test") @@ -193,6 +194,7 @@ class S8I(Structure): (9*2, 8*3, 7*4, 6*5, 5*6, 4*7, 3*8, 2*9)) @skip_if_sanitizer('requires deep stack', thread=True) + @skip_if_huge_c_stack() @skip_emscripten_stack_overflow() def test_recursive_as_param(self): class A: diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py index ba504119d294fd..7ac22455541fe2 100644 --- a/Lib/test/test_descr.py +++ b/Lib/test/test_descr.py @@ -3774,6 +3774,7 @@ def f(a): return a encoding='latin1', errors='replace') self.assertEqual(ba, b'abc\xbd?') + @support.skip_if_huge_c_stack() @support.skip_wasi_stack_overflow() @support.skip_emscripten_stack_overflow() def test_recursive_call(self): @@ -5122,6 +5123,7 @@ class Thing: # CALL_METHOD_DESCRIPTOR_O deque.append(thing, thing) + @support.skip_if_huge_c_stack() @support.skip_emscripten_stack_overflow() @support.skip_wasi_stack_overflow() def test_repr_as_str(self): diff --git a/Lib/test/test_dict.py b/Lib/test/test_dict.py index 6d61c71e162f8b..dc31d403b837ad 100644 --- a/Lib/test/test_dict.py +++ b/Lib/test/test_dict.py @@ -678,6 +678,7 @@ def __repr__(self): d = {1: BadRepr()} self.assertRaises(Exc, repr, d) + @support.skip_if_huge_c_stack() @support.skip_wasi_stack_overflow() @support.skip_emscripten_stack_overflow() def test_repr_deep(self): diff --git a/Lib/test/test_dictviews.py b/Lib/test/test_dictviews.py index 691fc5dfb5e8ab..9816ae6c033ec7 100644 --- a/Lib/test/test_dictviews.py +++ b/Lib/test/test_dictviews.py @@ -2,7 +2,9 @@ import copy import pickle import unittest -from test.support import skip_emscripten_stack_overflow, skip_wasi_stack_overflow, exceeds_recursion_limit +from test.support import (skip_emscripten_stack_overflow, + skip_wasi_stack_overflow, skip_if_huge_c_stack, + exceeds_recursion_limit) class DictSetTest(unittest.TestCase): @@ -277,6 +279,7 @@ def test_recursive_repr(self): # Again. self.assertIsInstance(r, str) + @skip_if_huge_c_stack() @skip_wasi_stack_overflow() @skip_emscripten_stack_overflow() def test_deeply_nested_repr(self): diff --git a/Lib/test/test_exception_group.py b/Lib/test/test_exception_group.py index 35ffc9a0a4cf30..325b1c91fa5aee 100644 --- a/Lib/test/test_exception_group.py +++ b/Lib/test/test_exception_group.py @@ -1,7 +1,9 @@ import collections import types import unittest -from test.support import skip_emscripten_stack_overflow, skip_wasi_stack_overflow, exceeds_recursion_limit +from test.support import (skip_emscripten_stack_overflow, + skip_wasi_stack_overflow, skip_if_huge_c_stack, + exceeds_recursion_limit) class TestExceptionGroupTypeHierarchy(unittest.TestCase): def test_exception_group_types(self): @@ -547,6 +549,7 @@ def make_deep_eg(self): e = ExceptionGroup('eg', [e]) return e + @skip_if_huge_c_stack() @skip_emscripten_stack_overflow() @skip_wasi_stack_overflow() def test_deep_split(self): @@ -554,6 +557,7 @@ def test_deep_split(self): with self.assertRaises(RecursionError): e.split(TypeError) + @skip_if_huge_c_stack() @skip_emscripten_stack_overflow() @skip_wasi_stack_overflow() def test_deep_subgroup(self): diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py index cc7faef93e1af7..72c8b4dfa7d13f 100644 --- a/Lib/test/test_exceptions.py +++ b/Lib/test/test_exceptions.py @@ -1517,6 +1517,7 @@ def gen(): @cpython_only @unittest.skipIf(_testcapi is None, "requires _testcapi") @force_not_colorized + @support.skip_if_huge_c_stack() def test_recursion_normalizing_infinite_exception(self): # Issue #30697. Test that a RecursionError is raised when # maximum recursion depth has been exceeded when creating diff --git a/Lib/test/test_functools.py b/Lib/test/test_functools.py index a8ee7d119e4bc6..52501f12a2be69 100644 --- a/Lib/test/test_functools.py +++ b/Lib/test/test_functools.py @@ -438,7 +438,7 @@ def test_setstate_subclasses(self): self.assertIs(type(r[0]), tuple) @support.skip_if_sanitizer("thread sanitizer crashes in __tsan::FuncEntry", thread=True) - @support.skip_if_unlimited_stack_size + @support.skip_if_huge_c_stack() @support.skip_emscripten_stack_overflow() def test_recursive_pickle(self): with replaced_module('functools', self.module): diff --git a/Lib/test/test_isinstance.py b/Lib/test/test_isinstance.py index d97535ba46e677..16d879a3831bc6 100644 --- a/Lib/test/test_isinstance.py +++ b/Lib/test/test_isinstance.py @@ -263,6 +263,7 @@ def test_subclass_tuple(self): self.assertEqual(True, issubclass(int, (int, (float, int)))) self.assertEqual(True, issubclass(str, (str, (Child, str)))) + @support.skip_if_huge_c_stack() @support.skip_wasi_stack_overflow() @support.skip_emscripten_stack_overflow() def test_subclass_recursion_limit(self): @@ -270,6 +271,7 @@ def test_subclass_recursion_limit(self): # blown self.assertRaises(RecursionError, blowstack, issubclass, str, str) + @support.skip_if_huge_c_stack() @support.skip_wasi_stack_overflow() @support.skip_emscripten_stack_overflow() def test_isinstance_recursion_limit(self): @@ -317,7 +319,7 @@ def __bases__(self): self.assertRaises(RecursionError, issubclass, int, X()) self.assertRaises(RecursionError, isinstance, 1, X()) - @support.skip_if_unlimited_stack_size + @support.skip_if_huge_c_stack() @support.skip_emscripten_stack_overflow() @support.skip_wasi_stack_overflow() def test_infinite_recursion_via_bases_tuple(self): @@ -329,7 +331,7 @@ def __getattr__(self, attr): with self.assertRaises(RecursionError): issubclass(Failure(), int) - @support.skip_if_unlimited_stack_size + @support.skip_if_huge_c_stack() @support.skip_emscripten_stack_overflow() @support.skip_wasi_stack_overflow() def test_infinite_cycle_in_bases(self): diff --git a/Lib/test/test_json/test_recursion.py b/Lib/test/test_json/test_recursion.py index d732fc80cf1cf3..cbae9fbb4d624b 100644 --- a/Lib/test/test_json/test_recursion.py +++ b/Lib/test/test_json/test_recursion.py @@ -69,7 +69,7 @@ def default(self, o): @support.skip_if_pgo_task # fails during PGO training w/ some stack sizes - @support.skip_if_unlimited_stack_size + @support.skip_if_huge_c_stack(500_000) @support.skip_emscripten_stack_overflow() @support.skip_wasi_stack_overflow() def test_highly_nested_objects_decoding(self): @@ -102,7 +102,7 @@ def test_highly_nested_objects_encoding(self): with support.infinite_recursion(5000): self.dumps(d) - @support.skip_if_unlimited_stack_size + @support.skip_if_huge_c_stack() @support.skip_emscripten_stack_overflow() @support.skip_wasi_stack_overflow() def test_endless_recursion(self): diff --git a/Lib/test/test_pyexpat.py b/Lib/test/test_pyexpat.py index b69e093392def3..157db98c4d4a91 100644 --- a/Lib/test/test_pyexpat.py +++ b/Lib/test/test_pyexpat.py @@ -855,7 +855,7 @@ def test_trigger_leak(self): parser.ElementDeclHandler = lambda _1, _2: None self.assertRaises(TypeError, parser.Parse, data, True) - @support.skip_if_unlimited_stack_size + @support.skip_if_huge_c_stack(800_000) @support.skip_emscripten_stack_overflow() @support.skip_wasi_stack_overflow() def test_deeply_nested_content_model(self): diff --git a/Lib/test/test_xml_etree.py b/Lib/test/test_xml_etree.py index 27ea3c8c32fd8a..cb3fb4e3e82e07 100644 --- a/Lib/test/test_xml_etree.py +++ b/Lib/test/test_xml_etree.py @@ -3229,7 +3229,7 @@ def __deepcopy__(self, memo): self.assertEqual([c.tag for c in children[3:]], [a.tag, b.tag, a.tag, b.tag]) - @support.skip_if_unlimited_stack_size + @support.skip_if_huge_c_stack(500_000) @support.skip_emscripten_stack_overflow() @support.skip_wasi_stack_overflow() def test_deeply_nested_deepcopy(self): diff --git a/Misc/NEWS.d/next/Tests/2026-07-20-11-30-00.gh-issue-154211.hugestack.rst b/Misc/NEWS.d/next/Tests/2026-07-20-11-30-00.gh-issue-154211.hugestack.rst new file mode 100644 index 00000000000000..8030db869c7ba6 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2026-07-20-11-30-00.gh-issue-154211.hugestack.rst @@ -0,0 +1,3 @@ +Add ``test.support.skip_if_huge_c_stack()`` and use it to skip tests +that exhaust the C stack if the stack limit is very large +(e.g. on DragonFly BSD or with ``ulimit -s unlimited``). From 1df0ecd523b4c15cba26ed4df5ac22f2d209cfc7 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 20 Jul 2026 08:38:10 +0200 Subject: [PATCH 749/818] [3.15] urllib: Add tests for HTTP errors to complete coverage (GH-154102) (#154120) urllib: Add tests for HTTP errors to complete coverage (GH-154102) * add test for httperror props such as reason and fp, and stringified urlerror test * rm unnecessary 'reason' attr test, change url to filename and add reason and headers attr * separate file pointer test * prevent resource warning, close httperror exception * exc > err (cherry picked from commit b8ec956716c183430a93929e6415ceed74089af1) Co-authored-by: Ajob Kustra <ajob.edward.kustra@cern.ch> --- Lib/test/test_urllib.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/Lib/test/test_urllib.py b/Lib/test/test_urllib.py index 2dd739b77b8e4d..1e5f79998e7cab 100644 --- a/Lib/test/test_urllib.py +++ b/Lib/test/test_urllib.py @@ -467,6 +467,25 @@ def test_redirect_limit_independent(self): finally: self.unfakehttp() + def test_http_error_attribute_values(self): + hdrs = { + "Authorization": "Bearer foobar", + "Accept": "application/json" + } + err = urllib.error.HTTPError("http://something", 404, "foo", hdrs, None) + self.assertEqual(err.filename, "http://something") + self.assertEqual(err.code, 404) + self.assertEqual(err.msg, "foo") + self.assertEqual(err.reason, "foo") + self.assertEqual(err.hdrs, hdrs) + self.assertEqual(err.headers, hdrs) + err.close() + + def test_http_error_default_fp(self): + err = urllib.error.HTTPError("http://something", 404, "foo", {}, None) + self.assertIsInstance(err.fp, io.BytesIO) + err.close() + def test_empty_socket(self): # urlopen() raises OSError if the underlying socket does not send any # data. (#1680230) @@ -513,6 +532,11 @@ def test_ftp_nonexisting(self): self.assertFalse(e.exception.filename) self.assertTrue(e.exception.reason) + def test_url_error_stringified(self): + reason = 'sixseven' + err = urllib.error.URLError(reason) + self.assertEqual(str(err), f'<urlopen error {reason}>') + class urlopen_DataTests(unittest.TestCase): """Test urlopen() opening a data URL.""" From 346c7afa7fef25289d4d9c892b555f6cb6894cef Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 20 Jul 2026 09:27:58 +0200 Subject: [PATCH 750/818] [3.15] gh-127049: fix race condition in asyncio signalling an unrelated process with ThreadedChildWatcher (GH-153810) (#154220) gh-127049: fix race condition in asyncio signalling an unrelated process with ThreadedChildWatcher (GH-153810) (cherry picked from commit 2875d1dc913d2d7810465da4bc3899305da5abc7) Co-authored-by: Kumar Aditya <kumaraditya@python.org> --- Lib/asyncio/base_subprocess.py | 3 + Lib/asyncio/unix_events.py | 53 ++++++++++++--- Lib/test/test_asyncio/test_subprocess.py | 68 +++++++++++++++++++ ...-07-14-15-00-00.gh-issue-127049.pQw7Rk.rst | 5 ++ 4 files changed, 121 insertions(+), 8 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-07-14-15-00-00.gh-issue-127049.pQw7Rk.rst diff --git a/Lib/asyncio/base_subprocess.py b/Lib/asyncio/base_subprocess.py index 3fa1ed1afd2a65..98e72f212aa203 100644 --- a/Lib/asyncio/base_subprocess.py +++ b/Lib/asyncio/base_subprocess.py @@ -165,6 +165,9 @@ def kill(self): else: def send_signal(self, signal): self._check_proc() + if self._returncode is not None: + # The process already exited + return try: os.kill(self._proc.pid, signal) except ProcessLookupError: diff --git a/Lib/asyncio/unix_events.py b/Lib/asyncio/unix_events.py index f9d52617ed9f78..bb82ba5ae10f2e 100644 --- a/Lib/asyncio/unix_events.py +++ b/Lib/asyncio/unix_events.py @@ -218,7 +218,7 @@ async def _make_subprocess_transport(self, protocol, args, shell, return transp def _child_watcher_callback(self, pid, returncode, transp): - self.call_soon_threadsafe(transp._process_exited, returncode) + transp._process_exited(returncode) async def create_unix_connection( self, protocol_factory, path=None, *, @@ -928,6 +928,49 @@ def add_child_handler(self, pid, callback, *args): def _do_waitpid(self, loop, expected_pid, callback, args): assert expected_pid > 0 + if hasattr(os, 'waitid'): + # Wait for the child process using waitid() on platforms which support it. + # WNOWAIT is used to avoid reaping the child process, allowing the event loop to + # reap the child process with waitpid() later in event loop thread. + # This makes the reaping of the child and notification of the return code + # atomic with respect to the event loop thread. + try: + os.waitid(os.P_PID, expected_pid, os.WEXITED | os.WNOWAIT) + except ChildProcessError: + # The child process is already reaped + pass + if loop.is_closed(): + # loop is already closed, reap the zombie here so that it is not leaked. + pid, _ = self._reap(loop, expected_pid) + logger.warning("Loop %r that handles pid %r is closed", + loop, pid) + else: + try: + loop.call_soon_threadsafe( + self._reap_and_notify, loop, expected_pid, + callback, args) + except RuntimeError: + # The event loop was closed concurrently. + pid, _ = self._reap(loop, expected_pid) + logger.warning("Loop %r that handles pid %r is closed", + loop, pid) + else: + # Fallback for platforms that don't support waitid(): we have to + # reap the child here, which is racy with respect to send_signal() + pid, returncode = self._reap(loop, expected_pid) + if loop.is_closed(): + logger.warning("Loop %r that handles pid %r is closed", + loop, pid) + else: + loop.call_soon_threadsafe(callback, pid, returncode, *args) + + self._threads.pop(expected_pid) + + def _reap_and_notify(self, loop, expected_pid, callback, args): + pid, returncode = self._reap(loop, expected_pid) + callback(pid, returncode, *args) + + def _reap(self, loop, expected_pid): try: pid, status = os.waitpid(expected_pid, 0) except ChildProcessError: @@ -943,13 +986,7 @@ def _do_waitpid(self, loop, expected_pid, callback, args): if loop.get_debug(): logger.debug('process %s exited with returncode %s', expected_pid, returncode) - - if loop.is_closed(): - logger.warning("Loop %r that handles pid %r is closed", loop, pid) - else: - loop.call_soon_threadsafe(callback, pid, returncode, *args) - - self._threads.pop(expected_pid) + return pid, returncode def can_use_pidfd(): if not hasattr(os, 'pidfd_open'): diff --git a/Lib/test/test_asyncio/test_subprocess.py b/Lib/test/test_asyncio/test_subprocess.py index 323f25d748aa7a..4ab4315f1efe82 100644 --- a/Lib/test/test_asyncio/test_subprocess.py +++ b/Lib/test/test_asyncio/test_subprocess.py @@ -975,6 +975,45 @@ def test_watcher_implementation(self): else: self.assertIsInstance(watcher, unix_events._ThreadedChildWatcher) + @unittest.skipUnless(hasattr(os, 'waitid'), 'needs os.waitid()') + def test_send_signal_never_targets_reaped_pid(self): + # gh-127049: there must be no window between the child watcher + # reaping the child and asyncio publishing the exit in which + # send_signal() signals the freed (possibly recycled) PID. + reaped_pids = set() + stale_kills = [] + orig_waitpid = os.waitpid + orig_kill = os.kill + + def waitpid(pid, options): + res = orig_waitpid(pid, options) + if res[0] != 0: + reaped_pids.add(res[0]) + return res + + def kill(pid, sig): + if pid in reaped_pids: + stale_kills.append(pid) + return + orig_kill(pid, sig) + + async def run(): + with mock.patch('os.waitpid', waitpid), \ + mock.patch('os.kill', kill): + proc = await asyncio.create_subprocess_exec( + *PROGRAM_BLOCKED) + proc.kill() + deadline = self.loop.time() + support.SHORT_TIMEOUT + while proc.returncode is None: + if self.loop.time() > deadline: + self.fail('child exit was not published in time') + proc.kill() + await asyncio.sleep(0) + await proc.wait() + self.assertEqual(stale_kills, []) + + self.loop.run_until_complete(run()) + class SubprocessThreadedWatcherTests(SubprocessWatcherMixin, test_utils.TestCase): @@ -988,6 +1027,35 @@ def tearDown(self): unix_events.can_use_pidfd = self._original_can_use_pidfd return super().tearDown() + @unittest.skipUnless(hasattr(os, 'waitid'), 'needs os.waitid()') + def test_pid_not_reaped_before_exit_published(self): + # gh-127049: the watcher thread must wait for the child + # without reaping it: the PID must stay reserved until the + # event loop thread reaps it and publishes the exit as one + # atomic step. + async def run(): + proc = await asyncio.create_subprocess_exec( + *PROGRAM_BLOCKED) + thread = self.loop._watcher._threads.get(proc.pid) + self.assertIsNotNone(thread) + proc.kill() + # Wait for the watcher thread to observe the exit while + # the event loop cannot process the notification yet. + thread.join(support.SHORT_TIMEOUT) + self.assertFalse(thread.is_alive()) + # The exit has not been published yet... + self.assertIsNone(proc.returncode) + # ...so the child must still be an unreaped zombie and + # signalling its PID must still be safe. waitid() raises + # ChildProcessError if the PID was already reaped (and + # possibly recycled by the kernel). + os.waitid(os.P_PID, proc.pid, + os.WEXITED | os.WNOWAIT | os.WNOHANG) + proc.kill() + self.assertEqual(await proc.wait(), -signal.SIGKILL) + + self.loop.run_until_complete(run()) + @unittest.skipUnless( unix_events.can_use_pidfd(), "operating system does not support pidfds", diff --git a/Misc/NEWS.d/next/Library/2026-07-14-15-00-00.gh-issue-127049.pQw7Rk.rst b/Misc/NEWS.d/next/Library/2026-07-14-15-00-00.gh-issue-127049.pQw7Rk.rst new file mode 100644 index 00000000000000..d7557d8f562f7a --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-14-15-00-00.gh-issue-127049.pQw7Rk.rst @@ -0,0 +1,5 @@ +Fix a race condition in :mod:`asyncio` on Unix where +:meth:`asyncio.subprocess.Process.send_signal`, :meth:`~asyncio.subprocess.Process.terminate` +or :meth:`~asyncio.subprocess.Process.kill` could signal an unrelated process +that was recycled onto the PID of the already-reaped child when ThreadedChildWatcher is used. +Patch by Kumar Aditya. From 2e4a1fa41dab372af40aa886079b14d61db42c98 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 20 Jul 2026 10:15:34 +0200 Subject: [PATCH 751/818] [3.15] gh-154176: Fix locale.strxfrm() crash on DragonFly BSD (GH-154177) (GH-154217) Query the result size with a real one-element buffer instead of wcsxfrm(NULL, s, 0): DragonFly BSD's wcsxfrm() crashes when the destination is NULL or the size is 0. (cherry picked from commit f389b03f9f2768342bfd49987a257460d4aa4faf) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> --- .../Library/2026-07-19-21-30-00.gh-issue-154176.strxfrm.rst | 2 ++ Modules/_localemodule.c | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2026-07-19-21-30-00.gh-issue-154176.strxfrm.rst diff --git a/Misc/NEWS.d/next/Library/2026-07-19-21-30-00.gh-issue-154176.strxfrm.rst b/Misc/NEWS.d/next/Library/2026-07-19-21-30-00.gh-issue-154176.strxfrm.rst new file mode 100644 index 00000000000000..9ffa5828000113 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-19-21-30-00.gh-issue-154176.strxfrm.rst @@ -0,0 +1,2 @@ +Fix a crash in :func:`locale.strxfrm` on DragonFly BSD, +whose ``wcsxfrm()`` does not support the zero size. diff --git a/Modules/_localemodule.c b/Modules/_localemodule.c index 8f7d662b00b21b..35fbcd00045939 100644 --- a/Modules/_localemodule.c +++ b/Modules/_localemodule.c @@ -443,6 +443,7 @@ _locale_strxfrm_impl(PyObject *module, PyObject *str) { Py_ssize_t n1; wchar_t *s = NULL, *buf = NULL; + wchar_t dummy[1]; size_t n2; PyObject *result = NULL; @@ -456,7 +457,9 @@ _locale_strxfrm_impl(PyObject *module, PyObject *str) } errno = 0; - n2 = wcsxfrm(NULL, s, 0); + /* Query the size with a real one-element buffer: DragonFly BSD's + wcsxfrm() crashes when the destination is NULL or the size is 0. */ + n2 = wcsxfrm(dummy, s, 1); if (errno && errno != ERANGE) { PyErr_SetFromErrno(PyExc_OSError); goto exit; From 0dc3a04013383e0d8fb68ceba918f8d38b85ac3b Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 20 Jul 2026 11:35:36 +0200 Subject: [PATCH 752/818] [3.15] gh-154218: Fix test_posix_fallocate on file systems that do not support posix_fallocate() (GH-154219) (GH-154232) (cherry picked from commit 051b6e07f9e43980d99c563d67bea32144238461) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> --- Lib/test/test_os/test_posix.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_os/test_posix.py b/Lib/test/test_os/test_posix.py index a1ffd4fbe8cf2b..c0cbc3e4e2e7d1 100644 --- a/Lib/test/test_os/test_posix.py +++ b/Lib/test/test_os/test_posix.py @@ -415,8 +415,10 @@ def test_posix_fallocate(self): if inst.errno == errno.EINVAL and sys.platform.startswith( ('sunos', 'freebsd', 'openbsd', 'gnukfreebsd')): raise unittest.SkipTest("test may fail on ZFS filesystems") - elif inst.errno == errno.EOPNOTSUPP and sys.platform.startswith("netbsd"): - raise unittest.SkipTest("test may fail on FFS filesystems") + elif inst.errno == errno.EOPNOTSUPP: + # ZFS on FreeBSD, FFS on NetBSD, etc. + raise unittest.SkipTest( + "the file system does not support posix_fallocate()") else: raise finally: From b05ed78a8a97208c862b004ced8bfc824838e9d3 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 20 Jul 2026 11:36:17 +0200 Subject: [PATCH 753/818] [3.15] gh-154226: Fix test_posix_pty_functions on Solaris (GH-154230) (GH-154241) (cherry picked from commit 3d998611a48b45691894c687ac0ec52b54df52bf) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> --- Lib/test/test_os/test_os.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Lib/test/test_os/test_os.py b/Lib/test/test_os/test_os.py index 279c9ac804f6be..f2b9cf75d3bfa1 100644 --- a/Lib/test/test_os/test_os.py +++ b/Lib/test/test_os/test_os.py @@ -4715,6 +4715,13 @@ def test_posix_pty_functions(self): son_path = os.ptsname(mother_fd) son_fd = os.open(son_path, os.O_RDWR|os.O_NOCTTY) self.addCleanup(os.close, son_fd) + if sys.platform.startswith('sunos'): + # The slave is not a terminal until these STREAMS modules + # are pushed onto it. + import fcntl + I_PUSH = 0x5302 + fcntl.ioctl(son_fd, I_PUSH, b'ptem\0') + fcntl.ioctl(son_fd, I_PUSH, b'ldterm\0') self.assertEqual(os.ptsname(mother_fd), os.ttyname(son_fd)) @warnings_helper.ignore_fork_in_thread_deprecation_warnings() From 2aee2faff41046c351580f092e596a163489e000 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 20 Jul 2026 11:40:40 +0200 Subject: [PATCH 754/818] [3.15] gh-154225: Fix os.openpty() acquiring a controlling terminal on Solaris (GH-154229) (GH-154238) (cherry picked from commit a0caab9db6c2655d8429279892848d817343f99d) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> --- ...07-20-14-10-00.gh-issue-154225.openpty.rst | 2 ++ Modules/posixmodule.c | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2026-07-20-14-10-00.gh-issue-154225.openpty.rst diff --git a/Misc/NEWS.d/next/Library/2026-07-20-14-10-00.gh-issue-154225.openpty.rst b/Misc/NEWS.d/next/Library/2026-07-20-14-10-00.gh-issue-154225.openpty.rst new file mode 100644 index 00000000000000..f15022b6632006 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-20-14-10-00.gh-issue-154225.openpty.rst @@ -0,0 +1,2 @@ +Fix :func:`os.openpty` on Solaris and illumos: it no longer leaves the +pseudo-terminal as the controlling terminal of the calling process. diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 2a25be16e61dc2..b4009b8cb68694 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -9429,11 +9429,30 @@ os_openpty_impl(PyObject *module) goto posix_error; #if defined(HAVE_STROPTS_H) && !defined(HAVE_DEV_PTC) + // Pushing "ptem" makes the slave a terminal, which a session leader + // without a controlling terminal then acquires as one despite O_NOCTTY. + // Note whether we already had one, so a new one can be disowned below. + int had_ctty = 0; +#ifdef TIOCNOTTY + int tty_fd = open("/dev/tty", O_RDONLY | O_NOCTTY); + if (tty_fd >= 0) { + had_ctty = 1; + close(tty_fd); + } +#endif ioctl(slave_fd, I_PUSH, "ptem"); /* push ptem */ ioctl(slave_fd, I_PUSH, "ldterm"); /* push ldterm */ #ifndef __hpux ioctl(slave_fd, I_PUSH, "ttcompat"); /* push ttcompat */ #endif /* __hpux */ +#ifdef TIOCNOTTY + if (!had_ctty && getsid(0) == getpid()) { + // Disown it; TIOCNOTTY sends SIGHUP to the session leader. + PyOS_sighandler_t sig_saved = PyOS_setsig(SIGHUP, SIG_IGN); + ioctl(slave_fd, TIOCNOTTY); + PyOS_setsig(SIGHUP, sig_saved); + } +#endif #endif /* defined(HAVE_STROPTS_H) && !defined(HAVE_DEV_PTC) */ #endif /* HAVE_OPENPTY */ From 4aae1285d715db82db4e9fa0c36f1e5e6deac25d Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 20 Jul 2026 11:44:29 +0200 Subject: [PATCH 755/818] [3.15] gh-154227: Fix os.posix_openpt() on OpenBSD (GH-154228) (GH-154235) (cherry picked from commit d01b90cf33f8f77172eb9f445dbc2ed0055ffd3b) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> --- .../Library/2026-07-20-14-00-00.gh-issue-154227.openpt.rst | 2 ++ Modules/posixmodule.c | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2026-07-20-14-00-00.gh-issue-154227.openpt.rst diff --git a/Misc/NEWS.d/next/Library/2026-07-20-14-00-00.gh-issue-154227.openpt.rst b/Misc/NEWS.d/next/Library/2026-07-20-14-00-00.gh-issue-154227.openpt.rst new file mode 100644 index 00000000000000..e33d090d78c593 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-20-14-00-00.gh-issue-154227.openpt.rst @@ -0,0 +1,2 @@ +Fix :func:`os.posix_openpt` on OpenBSD, where it rejected the +:data:`~os.O_CLOEXEC` flag. diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index b4009b8cb68694..d4390370cc2f75 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -9186,7 +9186,9 @@ os_posix_openpt_impl(PyObject *module, int oflag) { int fd; -#if defined(O_CLOEXEC) + // OpenBSD posix_openpt() rejects any flag other than O_RDWR and + // O_NOCTTY; the fd is made non-inheritable below in any case. +#if defined(O_CLOEXEC) && !defined(__OpenBSD__) oflag |= O_CLOEXEC; #endif From 7d485fedf4c4a9894c1c49aa553ee8ab4736ef51 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 20 Jul 2026 12:15:06 +0200 Subject: [PATCH 756/818] [3.15] Fix typo in C API Type Object Structures documentation (GH-154249) (#154250) (cherry picked from commit 86e1fed859dab3de8f069208ef33cee24d816c79) Co-authored-by: Michael Newman <michael.b.newman@gmail.com> --- Doc/c-api/typeobj.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/c-api/typeobj.rst b/Doc/c-api/typeobj.rst index 16dcb880712d24..4000f8aa1d4c0c 100644 --- a/Doc/c-api/typeobj.rst +++ b/Doc/c-api/typeobj.rst @@ -3051,7 +3051,7 @@ Buffer Object Structures * Resource cleanup when the counter reaches zero must be done atomically, as the final release may race with concurrent releases from other - threads and dellocation must only happen once. + threads and deallocation must only happen once. The exporter MUST use the :c:member:`~Py_buffer.internal` field to keep track of buffer-specific resources. This field is guaranteed to remain From 6a4a1088f2fb4059585b9e718543e81f0c10d8cf Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 20 Jul 2026 12:56:31 +0200 Subject: [PATCH 757/818] [3.15] Fix two typos in two stdlib docstrings (GH-153479) (#154252) (cherry picked from commit e0293b0de4071ca591e36fd42ef04285b91ef546) Co-authored-by: Javad Koushyar <javadmokhtari@outlook.com> --- Lib/compression/zstd/_zstdfile.py | 2 +- Lib/concurrent/futures/_base.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/compression/zstd/_zstdfile.py b/Lib/compression/zstd/_zstdfile.py index c4477244e8327f..26d7c9006375fb 100644 --- a/Lib/compression/zstd/_zstdfile.py +++ b/Lib/compression/zstd/_zstdfile.py @@ -34,7 +34,7 @@ def __init__(self, file, /, mode='r', *, level=None, options=None, zstd_dict=None): """Open a Zstandard compressed file in binary mode. - *file* can be either an file-like object, or a file name to open. + *file* can be either a file-like object, or a file name to open. *mode* can be 'r' for reading (default), 'w' for (over)writing, 'x' for creating exclusively, or 'a' for appending. These can diff --git a/Lib/concurrent/futures/_base.py b/Lib/concurrent/futures/_base.py index 4e71331f9a0a59..43774066c5a9f0 100644 --- a/Lib/concurrent/futures/_base.py +++ b/Lib/concurrent/futures/_base.py @@ -703,5 +703,5 @@ def __exit__(self, exc_type, exc_val, exc_tb): class BrokenExecutor(RuntimeError): """ - Raised when a executor has become non-functional after a severe failure. + Raised when an executor has become non-functional after a severe failure. """ From 1ad838198a0ea8927bbd356afab32ee25fac9165 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 20 Jul 2026 16:44:07 +0200 Subject: [PATCH 758/818] [3.15] gh-154167: Fix test suite hang when SIGINT is ignored (GH-154168) (GH-154265) (cherry picked from commit 1047cbb9746f959f6787f2c393bd79cbae6100c5) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> --- Lib/test/libregrtest/setup.py | 8 ++++++++ .../Tests/2026-07-19-20-15-00.gh-issue-154167.sigint.rst | 3 +++ 2 files changed, 11 insertions(+) create mode 100644 Misc/NEWS.d/next/Tests/2026-07-19-20-15-00.gh-issue-154167.sigint.rst diff --git a/Lib/test/libregrtest/setup.py b/Lib/test/libregrtest/setup.py index b9b76a44e3b4e7..d62194acd9c29e 100644 --- a/Lib/test/libregrtest/setup.py +++ b/Lib/test/libregrtest/setup.py @@ -50,6 +50,14 @@ def setup_process() -> None: for signum in signals: faulthandler.register(signum, chain=True, file=stderr_fd) + # Restore the default SIGINT handler if there is no Python-level + # handler. Python inherits the SIG_IGN disposition when the test + # suite runs as a shell background job; then asyncio.Runner does not + # install its own handler and _thread.interrupt_main() is a no-op, + # which makes some tests in test_asyncio and test_threading hang. + if signal.getsignal(signal.SIGINT) in (signal.SIG_IGN, signal.SIG_DFL): + signal.signal(signal.SIGINT, signal.default_int_handler) + adjust_rlimit_nofile() support.record_original_stdout(sys.stdout) diff --git a/Misc/NEWS.d/next/Tests/2026-07-19-20-15-00.gh-issue-154167.sigint.rst b/Misc/NEWS.d/next/Tests/2026-07-19-20-15-00.gh-issue-154167.sigint.rst new file mode 100644 index 00000000000000..b2620f4a0bee54 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2026-07-19-20-15-00.gh-issue-154167.sigint.rst @@ -0,0 +1,3 @@ +The test runner (regrtest) now restores the default SIGINT handler if it +was inherited as ignored, so the test suite no longer hangs when run as +a shell background job. From 707802f8d022342284e78dfe1851d4cef8269dec Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 20 Jul 2026 16:51:38 +0200 Subject: [PATCH 759/818] [3.15] gh-154258: Fix mmap.resize() crash on NetBSD growing a shared anonymous mapping (GH-154259) (GH-154262) NetBSD mremap() returns a mapping whose grown region is not backed when growing a shared anonymous mapping, so accessing it crashes. Reject it with ValueError, as is already done on Linux. (cherry picked from commit 542b98293108a84fa5d904fb6dcf8bfb5080ec93) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> --- Lib/test/test_mmap.py | 7 ++++--- .../2026-07-20-18-30-00.gh-issue-154258.mmapresize.rst | 3 +++ Modules/mmapmodule.c | 7 +++++-- 3 files changed, 12 insertions(+), 5 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-07-20-18-30-00.gh-issue-154258.mmapresize.rst diff --git a/Lib/test/test_mmap.py b/Lib/test/test_mmap.py index 2e2ac147968dd4..5be9dfac2f5a76 100644 --- a/Lib/test/test_mmap.py +++ b/Lib/test/test_mmap.py @@ -907,9 +907,10 @@ def test_resize_up_anonymous_mapping(self): with mmap.mmap(-1, start_size) as m: m[:] = data - if sys.platform.startswith(('linux', 'android')): - # Can't expand a shared anonymous mapping on Linux. - # See https://bugzilla.kernel.org/show_bug.cgi?id=8691 + if sys.platform.startswith(('linux', 'android', 'netbsd')): + # Can't expand a shared anonymous mapping on Linux + # (see https://bugzilla.kernel.org/show_bug.cgi?id=8691) + # or NetBSD. with self.assertRaises(ValueError): m.resize(new_size) else: diff --git a/Misc/NEWS.d/next/Library/2026-07-20-18-30-00.gh-issue-154258.mmapresize.rst b/Misc/NEWS.d/next/Library/2026-07-20-18-30-00.gh-issue-154258.mmapresize.rst new file mode 100644 index 00000000000000..4c33336e0bbdca --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-20-18-30-00.gh-issue-154258.mmapresize.rst @@ -0,0 +1,3 @@ +Fix a crash in :meth:`mmap.mmap.resize` on NetBSD when growing a shared +anonymous mapping. :meth:`!resize` now raises :exc:`ValueError` in this +case, as it already did on Linux. diff --git a/Modules/mmapmodule.c b/Modules/mmapmodule.c index 6fb04ba7bd47c6..afe627d762cefe 100644 --- a/Modules/mmapmodule.c +++ b/Modules/mmapmodule.c @@ -977,10 +977,13 @@ mmap_mmap_resize_impl(mmap_object *self, Py_ssize_t new_size) #ifdef UNIX void *newmap; -#ifdef __linux__ +#if defined(__linux__) || defined(__NetBSD__) + // Linux mremap() refuses to grow a shared anonymous mapping, and + // NetBSD mremap() returns a mapping whose grown region is not backed, + // so accessing it crashes. Reject it here in both cases. if (self->fd == -1 && !(self->flags & MAP_PRIVATE) && new_size > self->size) { PyErr_Format(PyExc_ValueError, - "mmap: can't expand a shared anonymous mapping on Linux"); + "mmap: can't expand a shared anonymous mapping"); return NULL; } #endif From 84e0673706f3e4439dc1118c6f8a44009b5ca48a Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 20 Jul 2026 16:59:12 +0200 Subject: [PATCH 760/818] [3.15] gh-99968: FAQ: dev versions end in `+dev` (GH-153262) (#154268) gh-99968: FAQ: dev versions end in `+dev` (GH-153262) (cherry picked from commit 4cde5cfd5bc53e964ff8b594ff47fe88e64df789) Co-authored-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> Co-authored-by: Stan Ulbrych <stan@python.org> --- Doc/faq/general.rst | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Doc/faq/general.rst b/Doc/faq/general.rst index 698f2117ff5c64..ff38ba395fba22 100644 --- a/Doc/faq/general.rst +++ b/Doc/faq/general.rst @@ -152,10 +152,11 @@ Alpha, beta and release candidate versions have an additional suffix: In other words, all versions labeled *2.0aN* precede the versions labeled *2.0bN*, which precede versions labeled *2.0rcN*, and *those* precede 2.0. -You may also find version numbers with a "+" suffix, e.g. "2.2+". These are -unreleased versions, built directly from the CPython development repository. In -practice, after a final minor release is made, the version is incremented to the -next minor version, which becomes the "a0" version, e.g. "2.4a0". +You may also find version numbers with a "+dev" suffix, such as "3.15.0b3+dev". +These are unreleased versions, built directly from the CPython development +repository. After the first beta release is made, the version is +incremented to the next feature version, which becomes the "a0" version, +such as "3.16.0a0". See the `Developer's Guide <https://devguide.python.org/developer-workflow/development-cycle/>`__ From c6c1e9d7b42f3bbd0263a2f5bc18c8c318d1138e Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 20 Jul 2026 20:22:59 +0200 Subject: [PATCH 761/818] [3.15] gh-154260: Fix test_flush_parameters on DragonFly BSD (GH-154261) (GH-154269) DragonFly, like FreeBSD, rejects mmap.flush() with MS_ASYNC|MS_INVALIDATE (EINVAL). Use str.startswith() so the check also matches DragonFly, whose sys.platform carries a version suffix. (cherry picked from commit fc4d93dcf1a01f56fd8ffc35b6d3700c98ffa6c9) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> --- Lib/test/test_mmap.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_mmap.py b/Lib/test/test_mmap.py index 5be9dfac2f5a76..55c6ad04d44d82 100644 --- a/Lib/test/test_mmap.py +++ b/Lib/test/test_mmap.py @@ -1176,8 +1176,8 @@ def test_flush_parameters(self): if hasattr(mmap, 'MS_INVALIDATE'): m.flush(PAGESIZE * 2, flags=mmap.MS_INVALIDATE) if hasattr(mmap, 'MS_ASYNC') and hasattr(mmap, 'MS_INVALIDATE'): - if sys.platform == 'freebsd': - # FreeBSD doesn't support this combination + if sys.platform.startswith(('freebsd', 'dragonfly')): + # FreeBSD and DragonFly don't support this combination with self.assertRaises(OSError) as cm: m.flush(0, PAGESIZE, flags=mmap.MS_ASYNC | mmap.MS_INVALIDATE) self.assertEqual(cm.exception.errno, errno.EINVAL) From 1be67706eb07993a877b1d55df7ab1b542db3f6f Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 20 Jul 2026 20:25:13 +0200 Subject: [PATCH 762/818] [3.15] gh-125860: Skip separate-SCM_RIGHTS socket tests on NetBSD, OpenBSD and DragonFly (GH-154239) (GH-154245) (cherry picked from commit 9cfa08c80d588931ff4644c885f31598cf2b725f) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> --- Lib/test/test_socket.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py index ea315fd45e3a04..a47924de48c4e2 100644 --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -55,6 +55,10 @@ VSOCKPORT = 1234 AIX = platform.system() == "AIX" SOLARIS = sys.platform.startswith("sunos") +# NetBSD, OpenBSD and DragonFly deliver the file descriptors from only one +# SCM_RIGHTS control message when several are sent in a single sendmsg(). +BSD_COMBINES_SCM_RIGHTS = sys.platform.startswith( + ("netbsd", "openbsd", "dragonfly")) WSL = "microsoft-standard-WSL" in platform.release() try: @@ -4177,6 +4181,7 @@ def _testFDPassCMSG_LEN(self): @unittest.skipIf(is_apple, "skipping, see issue #12958") @unittest.skipIf(SOLARIS, "skipping, see gh-91214") @unittest.skipIf(AIX, "skipping, see issue #22397") + @unittest.skipIf(BSD_COMBINES_SCM_RIGHTS, "skipping, see gh-125860") @requireAttrs(socket, "CMSG_SPACE") def testFDPassSeparate(self): # Pass two FDs in two separate arrays. Arrays may be combined @@ -4189,6 +4194,7 @@ def testFDPassSeparate(self): @unittest.skipIf(is_apple, "skipping, see issue #12958") @unittest.skipIf(SOLARIS, "skipping, see gh-91214") @unittest.skipIf(AIX, "skipping, see issue #22397") + @unittest.skipIf(BSD_COMBINES_SCM_RIGHTS, "skipping, see gh-125860") def _testFDPassSeparate(self): fd0, fd1 = self.newFDs(2) self.assertEqual( @@ -4203,6 +4209,7 @@ def _testFDPassSeparate(self): @unittest.skipIf(is_apple, "skipping, see issue #12958") @unittest.skipIf(SOLARIS, "skipping, see gh-91214") @unittest.skipIf(AIX, "skipping, see issue #22397") + @unittest.skipIf(BSD_COMBINES_SCM_RIGHTS, "skipping, see gh-125860") @requireAttrs(socket, "CMSG_SPACE") def testFDPassSeparateMinSpace(self): # Pass two FDs in two separate arrays, receiving them into the @@ -4218,6 +4225,7 @@ def testFDPassSeparateMinSpace(self): @unittest.skipIf(is_apple, "skipping, see issue #12958") @unittest.skipIf(SOLARIS, "skipping, see gh-91214") @unittest.skipIf(AIX, "skipping, see issue #22397") + @unittest.skipIf(BSD_COMBINES_SCM_RIGHTS, "skipping, see gh-125860") def _testFDPassSeparateMinSpace(self): fd0, fd1 = self.newFDs(2) self.assertEqual( From 6747bcf2ac1237a78275cd2279f0336f243752f7 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 20 Jul 2026 21:12:40 +0200 Subject: [PATCH 763/818] [3.15] gh-154240: Skip cmsg truncation socket tests on OpenBSD and DragonFly (GH-154244) (GH-154286) (cherry picked from commit eca3b26067a48bf18e59648695ee1a7bc36534fc) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> --- Lib/test/test_socket.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py index a47924de48c4e2..d831ba7565cf5f 100644 --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -59,6 +59,9 @@ # SCM_RIGHTS control message when several are sent in a single sendmsg(). BSD_COMBINES_SCM_RIGHTS = sys.platform.startswith( ("netbsd", "openbsd", "dragonfly")) +# OpenBSD and DragonFly fail recvmsg() with EMSGSIZE, instead of setting +# MSG_CTRUNC, when the ancillary data buffer is too small for a cmsghdr. +CMSG_TRUNC_RAISES_EMSGSIZE = sys.platform.startswith(("openbsd", "dragonfly")) WSL = "microsoft-standard-WSL" in platform.release() try: @@ -4350,6 +4353,7 @@ def _testCmsgTrunc0(self): # (but still too small) buffer sizes. @skipForRefleakHuntinIf(sys.platform == "darwin", "#80931") + @unittest.skipIf(CMSG_TRUNC_RAISES_EMSGSIZE, "skipping, see gh-154240") def testCmsgTrunc1(self): self.checkTruncatedHeader(self.doRecvmsg(self.serv_sock, len(MSG), 1)) @@ -4358,6 +4362,7 @@ def _testCmsgTrunc1(self): self.createAndSendFDs(1) @skipForRefleakHuntinIf(sys.platform == "darwin", "#80931") + @unittest.skipIf(CMSG_TRUNC_RAISES_EMSGSIZE, "skipping, see gh-154240") def testCmsgTrunc2Int(self): # The cmsghdr structure has at least three members, two of # which are ints, so we still shouldn't see any ancillary @@ -4370,6 +4375,7 @@ def _testCmsgTrunc2Int(self): self.createAndSendFDs(1) @skipForRefleakHuntinIf(sys.platform == "darwin", "#80931") + @unittest.skipIf(CMSG_TRUNC_RAISES_EMSGSIZE, "skipping, see gh-154240") def testCmsgTruncLen0Minus1(self): self.checkTruncatedHeader(self.doRecvmsg(self.serv_sock, len(MSG), socket.CMSG_LEN(0) - 1)) @@ -4407,6 +4413,7 @@ def checkTruncatedArray(self, ancbuf, maxdata, mindata=0): self.checkFDs(fds) @skipForRefleakHuntinIf(sys.platform == "darwin", "#80931") + @unittest.skipIf(CMSG_TRUNC_RAISES_EMSGSIZE, "skipping, see gh-154240") def testCmsgTruncLen0(self): self.checkTruncatedArray(ancbuf=socket.CMSG_LEN(0), maxdata=0) @@ -4415,6 +4422,7 @@ def _testCmsgTruncLen0(self): self.createAndSendFDs(1) @skipForRefleakHuntinIf(sys.platform == "darwin", "#80931") + @unittest.skipIf(CMSG_TRUNC_RAISES_EMSGSIZE, "skipping, see gh-154240") def testCmsgTruncLen0Plus1(self): self.checkTruncatedArray(ancbuf=socket.CMSG_LEN(0) + 1, maxdata=1) @@ -4423,6 +4431,7 @@ def _testCmsgTruncLen0Plus1(self): self.createAndSendFDs(2) @skipForRefleakHuntinIf(sys.platform == "darwin", "#80931") + @unittest.skipIf(CMSG_TRUNC_RAISES_EMSGSIZE, "skipping, see gh-154240") def testCmsgTruncLen1(self): self.checkTruncatedArray(ancbuf=socket.CMSG_LEN(SIZEOF_INT), maxdata=SIZEOF_INT) @@ -4433,6 +4442,7 @@ def _testCmsgTruncLen1(self): @skipForRefleakHuntinIf(sys.platform == "darwin", "#80931") + @unittest.skipIf(CMSG_TRUNC_RAISES_EMSGSIZE, "skipping, see gh-154240") def testCmsgTruncLen2Minus1(self): self.checkTruncatedArray(ancbuf=socket.CMSG_LEN(2 * SIZEOF_INT) - 1, maxdata=(2 * SIZEOF_INT) - 1) @@ -4705,6 +4715,7 @@ def _testSingleCmsgTrunc0(self): # (but still too small) buffer sizes. @requireAttrs(socket, "IPV6_RECVHOPLIMIT", "IPV6_HOPLIMIT") + @unittest.skipIf(CMSG_TRUNC_RAISES_EMSGSIZE, "skipping, see gh-154240") def testSingleCmsgTrunc1(self): self.checkHopLimitTruncatedHeader(ancbufsize=1) @@ -4714,6 +4725,7 @@ def _testSingleCmsgTrunc1(self): self.sendToServer(MSG) @requireAttrs(socket, "IPV6_RECVHOPLIMIT", "IPV6_HOPLIMIT") + @unittest.skipIf(CMSG_TRUNC_RAISES_EMSGSIZE, "skipping, see gh-154240") def testSingleCmsgTrunc2Int(self): self.checkHopLimitTruncatedHeader(ancbufsize=2 * SIZEOF_INT) @@ -4723,6 +4735,7 @@ def _testSingleCmsgTrunc2Int(self): self.sendToServer(MSG) @requireAttrs(socket, "IPV6_RECVHOPLIMIT", "IPV6_HOPLIMIT") + @unittest.skipIf(CMSG_TRUNC_RAISES_EMSGSIZE, "skipping, see gh-154240") def testSingleCmsgTruncLen0Minus1(self): self.checkHopLimitTruncatedHeader(ancbufsize=socket.CMSG_LEN(0) - 1) @@ -4732,6 +4745,7 @@ def _testSingleCmsgTruncLen0Minus1(self): self.sendToServer(MSG) @requireAttrs(socket, "IPV6_RECVHOPLIMIT", "IPV6_HOPLIMIT") + @unittest.skipIf(CMSG_TRUNC_RAISES_EMSGSIZE, "skipping, see gh-154240") def testSingleCmsgTruncInData(self): # Test truncation of a control message inside its associated # data. The message may be returned with its data truncated, @@ -4804,6 +4818,7 @@ def _testSecondCmsgTrunc0(self): @requireAttrs(socket, "CMSG_SPACE", "IPV6_RECVHOPLIMIT", "IPV6_HOPLIMIT", "IPV6_RECVTCLASS", "IPV6_TCLASS") + @unittest.skipIf(CMSG_TRUNC_RAISES_EMSGSIZE, "skipping, see gh-154240") def testSecondCmsgTrunc1(self): self.checkTruncatedSecondHeader(socket.CMSG_SPACE(SIZEOF_INT) + 1) @@ -4814,6 +4829,7 @@ def _testSecondCmsgTrunc1(self): @requireAttrs(socket, "CMSG_SPACE", "IPV6_RECVHOPLIMIT", "IPV6_HOPLIMIT", "IPV6_RECVTCLASS", "IPV6_TCLASS") + @unittest.skipIf(CMSG_TRUNC_RAISES_EMSGSIZE, "skipping, see gh-154240") def testSecondCmsgTrunc2Int(self): self.checkTruncatedSecondHeader(socket.CMSG_SPACE(SIZEOF_INT) + 2 * SIZEOF_INT) @@ -4825,6 +4841,7 @@ def _testSecondCmsgTrunc2Int(self): @requireAttrs(socket, "CMSG_SPACE", "IPV6_RECVHOPLIMIT", "IPV6_HOPLIMIT", "IPV6_RECVTCLASS", "IPV6_TCLASS") + @unittest.skipIf(CMSG_TRUNC_RAISES_EMSGSIZE, "skipping, see gh-154240") def testSecondCmsgTruncLen0Minus1(self): self.checkTruncatedSecondHeader(socket.CMSG_SPACE(SIZEOF_INT) + socket.CMSG_LEN(0) - 1) @@ -4836,6 +4853,7 @@ def _testSecondCmsgTruncLen0Minus1(self): @requireAttrs(socket, "CMSG_SPACE", "IPV6_RECVHOPLIMIT", "IPV6_HOPLIMIT", "IPV6_RECVTCLASS", "IPV6_TCLASS") + @unittest.skipIf(CMSG_TRUNC_RAISES_EMSGSIZE, "skipping, see gh-154240") def testSecondCmsgTruncInData(self): # Test truncation of the second of two control messages inside # its associated data. From 9a52f94c5722056a735c10307a63d4f6f7e79050 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 20 Jul 2026 22:00:01 +0200 Subject: [PATCH 764/818] [3.15] gh-154289: Fix test_socket.testGetServBy on DragonFly (GH-154290) (GH-154294) DragonFly lists "echo 4/ddp" before "echo 7/tcp" in /etc/services, like FreeBSD, so avoid the "echo" service there too. (cherry picked from commit 96059f9446510f594c4148d53bd1a4e3532af697) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --- Lib/test/test_socket.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py index d831ba7565cf5f..fd2e0a14e33d52 100644 --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -1302,7 +1302,8 @@ def testGetServBy(self): # protocol, at least for modern Linuxes. if ( sys.platform.startswith( - ('linux', 'android', 'freebsd', 'netbsd', 'gnukfreebsd')) + ('linux', 'android', 'freebsd', 'dragonfly', 'netbsd', + 'gnukfreebsd')) or is_apple ): # avoid the 'echo' service on this platform, as there is an From 387f7cd81d285ca9ed9a95b2376a2290a3241f20 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 20 Jul 2026 22:20:57 +0200 Subject: [PATCH 765/818] [3.15] gh-154283: Make threading.get_native_id() unique across processes on DragonFly (GH-154287) (GH-154293) On DragonFly BSD lwp_gettid() is only unique within a process (the main thread is always LWP 1), so combine it with the process id, like Solaris. (cherry picked from commit 53597df11e2d9f01ade2529c147df24b49685878) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --- .../Library/2026-07-20-21-36-40.gh-issue-154283.Xip7xE.rst | 2 ++ Python/thread_pthread.h | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-07-20-21-36-40.gh-issue-154283.Xip7xE.rst diff --git a/Misc/NEWS.d/next/Library/2026-07-20-21-36-40.gh-issue-154283.Xip7xE.rst b/Misc/NEWS.d/next/Library/2026-07-20-21-36-40.gh-issue-154283.Xip7xE.rst new file mode 100644 index 00000000000000..a278d67e1824d5 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-20-21-36-40.gh-issue-154283.Xip7xE.rst @@ -0,0 +1,2 @@ +On DragonFly BSD, :func:`threading.get_native_id` now returns a value that is +unique across processes, matching the other platforms. diff --git a/Python/thread_pthread.h b/Python/thread_pthread.h index 8496f91db2eec2..de93178576e6ec 100644 --- a/Python/thread_pthread.h +++ b/Python/thread_pthread.h @@ -399,8 +399,8 @@ PyThread_get_thread_native_id(void) lwpid_t native_id; native_id = _lwp_self(); #elif defined(__DragonFly__) - lwpid_t native_id; - native_id = lwp_gettid(); + // lwp_gettid() is only unique within a process, so combine it with the pid. + unsigned long native_id = (unsigned long)getpid() << 32 | lwp_gettid(); #elif defined(__sun__) && SIZEOF_LONG >= 8 unsigned long native_id = (unsigned long)getpid() << 32 | thr_self(); #endif From 4294605c3da0d8a44412eb2ff1ad03530de13779 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 20 Jul 2026 22:26:18 +0200 Subject: [PATCH 766/818] [3.15] gh-154291: Fix socket.has_dualstack_ipv6() on DragonFly BSD (GH-154292) (GH-154299) On DragonFly BSD setsockopt(IPPROTO_IPV6, IPV6_V6ONLY, 0) succeeds without actually clearing the flag, so has_dualstack_ipv6() wrongly returned True. Verify with getsockopt() that IPV6_V6ONLY was cleared. (cherry picked from commit c7bbf040e721781be8f11a3b0716220835d4de2f) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --- Lib/socket.py | 4 +++- .../Library/2026-07-20-22-03-44.gh-issue-154291.Mi5HeQ.rst | 3 +++ 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2026-07-20-22-03-44.gh-issue-154291.Mi5HeQ.rst diff --git a/Lib/socket.py b/Lib/socket.py index 03c3fe88f15cfe..2a4f875f76b069 100644 --- a/Lib/socket.py +++ b/Lib/socket.py @@ -900,7 +900,9 @@ def has_dualstack_ipv6(): try: with socket(AF_INET6, SOCK_STREAM) as sock: sock.setsockopt(IPPROTO_IPV6, IPV6_V6ONLY, 0) - return True + # On some platforms (e.g. DragonFly BSD) setting IPV6_V6ONLY to 0 + # silently has no effect, so check that it was actually cleared. + return sock.getsockopt(IPPROTO_IPV6, IPV6_V6ONLY) == 0 except error: return False diff --git a/Misc/NEWS.d/next/Library/2026-07-20-22-03-44.gh-issue-154291.Mi5HeQ.rst b/Misc/NEWS.d/next/Library/2026-07-20-22-03-44.gh-issue-154291.Mi5HeQ.rst new file mode 100644 index 00000000000000..d962f8987ad491 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-20-22-03-44.gh-issue-154291.Mi5HeQ.rst @@ -0,0 +1,3 @@ +Fix :func:`socket.has_dualstack_ipv6` to return ``False`` on platforms such as +DragonFly BSD where setting ``IPV6_V6ONLY`` to 0 silently has no +effect. From d1494f022d2750514c273ab3733f7dd73e7e6fd9 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 21 Jul 2026 00:40:04 +0200 Subject: [PATCH 767/818] [3.15] gh-154275: Do not crash on deeply nested `__parameters__` in `GenericAlias` (GH-154277) (#154306) gh-154275: Do not crash on deeply nested `__parameters__` in `GenericAlias` (GH-154277) (cherry picked from commit 1034e07b7d55642c3a46252e6b0a631c2df588d2) Co-authored-by: sobolevn <mail@sobolevn.me> --- Lib/test/test_typing.py | 13 ++++++++ ...-07-20-20-16-08.gh-issue-154275.l961cA.rst | 2 ++ Objects/genericaliasobject.c | 30 +++++++++++-------- 3 files changed, 32 insertions(+), 13 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-07-20-20-16-08.gh-issue-154275.l961cA.rst diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 986b41b18a2acc..343159bf5dafa3 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -52,6 +52,8 @@ from test.support import ( captured_stderr, cpython_only, requires_docstrings, import_helper, run_code, subTests, EqualToForwardRef, + exceeds_recursion_limit, skip_if_huge_c_stack, skip_wasi_stack_overflow, + skip_emscripten_stack_overflow, ) from test.typinganndata import ( ann_module695, mod_generics_cache, _typed_dict_helper, @@ -5089,6 +5091,17 @@ class MM2(collections.abc.MutableMapping, MutableMapping[str, str]): pass self.assertEqual(MM2.__bases__, (collections.abc.MutableMapping, Generic)) + @cpython_only + @skip_if_huge_c_stack() + @skip_wasi_stack_overflow() + @skip_emscripten_stack_overflow() + def test_parameters_deep_recursion(self): + x = [0] + for _ in range(exceeds_recursion_limit()): + x = [x] + with self.assertRaisesRegex(RecursionError, "in __parameter__ calculation"): + list[x].__parameters__ + def test_orig_bases(self): T = TypeVar('T') class C(typing.Dict[str, T]): ... diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-07-20-20-16-08.gh-issue-154275.l961cA.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-07-20-20-16-08.gh-issue-154275.l961cA.rst new file mode 100644 index 00000000000000..998e91c77098e7 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-07-20-20-16-08.gh-issue-154275.l961cA.rst @@ -0,0 +1,2 @@ +Fix a crash when getting deeply nested ``__parameters__`` from a +:class:`types.GenericAlias` objects. diff --git a/Objects/genericaliasobject.c b/Objects/genericaliasobject.c index 4e85927def7ea7..5caf5c7086c87a 100644 --- a/Objects/genericaliasobject.c +++ b/Objects/genericaliasobject.c @@ -186,6 +186,10 @@ PyObject * _Py_make_parameters(PyObject *args) { assert(PyTuple_Check(args) || PyList_Check(args)); + if (Py_EnterRecursiveCall(" in __parameter__ calculation")) { + return NULL; + } + const bool is_args_list = PyList_Check(args); PyObject *tuple_args = NULL; if (is_args_list) { @@ -210,9 +214,7 @@ _Py_make_parameters(PyObject *args) } int rc = PyObject_HasAttrWithError(t, &_Py_ID(__typing_subst__)); if (rc < 0) { - Py_DECREF(parameters); - Py_XDECREF(tuple_args); - return NULL; + goto error; } if (rc) { iparam += tuple_add(parameters, iparam, t); @@ -221,18 +223,14 @@ _Py_make_parameters(PyObject *args) PyObject *subparams; if (PyObject_GetOptionalAttr(t, &_Py_ID(__parameters__), &subparams) < 0) { - Py_DECREF(parameters); - Py_XDECREF(tuple_args); - return NULL; + goto error; } if (!subparams && (PyTuple_Check(t) || PyList_Check(t))) { // Recursively call _Py_make_parameters for lists/tuples and // add the results to the current parameters. subparams = _Py_make_parameters(t); if (subparams == NULL) { - Py_DECREF(parameters); - Py_XDECREF(tuple_args); - return NULL; + goto error; } } if (subparams && PyTuple_Check(subparams)) { @@ -243,7 +241,7 @@ _Py_make_parameters(PyObject *args) if (_PyTuple_Resize(&parameters, len) < 0) { Py_DECREF(subparams); Py_XDECREF(tuple_args); - return NULL; + goto cleanup; } } for (Py_ssize_t j = 0; j < len2; j++) { @@ -256,13 +254,19 @@ _Py_make_parameters(PyObject *args) } if (iparam < len) { if (_PyTuple_Resize(&parameters, iparam) < 0) { - Py_XDECREF(parameters); - Py_XDECREF(tuple_args); - return NULL; + goto error; } } Py_XDECREF(tuple_args); + Py_LeaveRecursiveCall(); return parameters; + +error: + Py_XDECREF(parameters); + Py_XDECREF(tuple_args); +cleanup: + Py_LeaveRecursiveCall(); + return NULL; } /* If obj is a generic alias, substitute type variables params From 4eebb382ccb41959a39133f6ccc9f865edcbbeb5 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 21 Jul 2026 03:05:04 +0200 Subject: [PATCH 768/818] [3.15] gh-148665: Enable socket.shutdown function for emscripten (GH-148666) (#154319) Re-enable the autoconf check for socket.shutdown on Emscripten, as some Emscripten environments are able to provide this call. (cherry picked from commit 20b7e8e50b9a4a92989b36531429f9b51ee0a0bf) Co-authored-by: Gyeongjae Choi <gyeongjae@cloudflare.com> --- .../Library/2026-04-17-05-58-27.gh-issue-148665.AlUajE.rst | 1 + Platforms/emscripten/config.site-wasm32-emscripten | 3 --- 2 files changed, 1 insertion(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-04-17-05-58-27.gh-issue-148665.AlUajE.rst diff --git a/Misc/NEWS.d/next/Library/2026-04-17-05-58-27.gh-issue-148665.AlUajE.rst b/Misc/NEWS.d/next/Library/2026-04-17-05-58-27.gh-issue-148665.AlUajE.rst new file mode 100644 index 00000000000000..db7736f1ae6ef6 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-04-17-05-58-27.gh-issue-148665.AlUajE.rst @@ -0,0 +1 @@ +socket.shutdown function is now enabled for Emscripten builds. However, if the runtime does not implement the shutdown syscall, it will show "Function not implemented" error. diff --git a/Platforms/emscripten/config.site-wasm32-emscripten b/Platforms/emscripten/config.site-wasm32-emscripten index f69dbb8e779a42..3c9a1c2c2568b0 100644 --- a/Platforms/emscripten/config.site-wasm32-emscripten +++ b/Platforms/emscripten/config.site-wasm32-emscripten @@ -21,9 +21,6 @@ ac_cv_func_eventfd=no ac_cv_func_memfd_create=no ac_cv_func_prlimit=no -# unsupported syscall, https://github.com/emscripten-core/emscripten/issues/13393 -ac_cv_func_shutdown=no - # The rest is based on pyodide # https://github.com/pyodide/pyodide/blob/main/cpython/pyconfig.undefs.h From b7e0855344cce8bc1cb79be1afdf5382e8b5eb2e Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 21 Jul 2026 05:54:45 +0200 Subject: [PATCH 769/818] [3.15] gh-154307: Fix TemporaryDirectory cleanup on DragonFly BSD (GH-154309) (GH-154311) On DragonFly BSD, removing a file or directory with the UF_NOUNLINK flag fails with EISDIR (IsADirectoryError) instead of EPERM, so the cleanup did not reset the flags. Handle IsADirectoryError the same as PermissionError. (cherry picked from commit 1c1088b1da5a7484b7b04e90ccc47aa362e709eb) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --- Lib/tempfile.py | 3 ++- .../Library/2026-07-21-01-13-39.gh-issue-154307.UNFKL4.rst | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2026-07-21-01-13-39.gh-issue-154307.UNFKL4.rst diff --git a/Lib/tempfile.py b/Lib/tempfile.py index 6dac9ab3c41717..573451be61e681 100644 --- a/Lib/tempfile.py +++ b/Lib/tempfile.py @@ -915,7 +915,8 @@ def __init__(self, suffix=None, prefix=None, dir=None, @classmethod def _rmtree(cls, name, ignore_errors=False, repeated=False): def onexc(func, path, exc): - if isinstance(exc, PermissionError): + # On DragonFly BSD, UF_NOUNLINK removal fails with EISDIR, not EPERM. + if isinstance(exc, (PermissionError, IsADirectoryError)): if repeated and path == name: if ignore_errors: return diff --git a/Misc/NEWS.d/next/Library/2026-07-21-01-13-39.gh-issue-154307.UNFKL4.rst b/Misc/NEWS.d/next/Library/2026-07-21-01-13-39.gh-issue-154307.UNFKL4.rst new file mode 100644 index 00000000000000..fdba0c2940f005 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-21-01-13-39.gh-issue-154307.UNFKL4.rst @@ -0,0 +1,3 @@ +Fix :meth:`tempfile.TemporaryDirectory.cleanup` on DragonFly BSD, where removing +a file with the ``UF_NOUNLINK`` flag failed with ``EISDIR`` instead of +``EPERM``. From 8ba1b04b508d44900df63e6bb08031d0fb34fee2 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 21 Jul 2026 05:58:01 +0200 Subject: [PATCH 770/818] [3.15] gh-154303: Skip test_sqlite3 CLI completion tests on OpenBSD (GH-154304) (GH-154305) OpenBSD's readline does not honor "completion-query-items 0", so completing many candidates blocks on a "Display all N?" prompt that hangs the pseudo-terminal opened by run_pty(). Skip the whole Completion class on OpenBSD, like the existing libedit skip. (cherry picked from commit 63b564fc8728036f165805407f7d2b4e8bfd3ef0) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --- Lib/test/test_sqlite3/test_cli.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Lib/test/test_sqlite3/test_cli.py b/Lib/test/test_sqlite3/test_cli.py index 1fc0236780fa8b..5b3fd32cde653d 100644 --- a/Lib/test/test_sqlite3/test_cli.py +++ b/Lib/test/test_sqlite3/test_cli.py @@ -223,6 +223,9 @@ def setUpClass(cls): readline = import_module("readline") if readline.backend == "editline": raise unittest.SkipTest("libedit readline is not supported") + if sys.platform.startswith("openbsd"): + # OpenBSD's readline does not honor "completion-query-items 0". + raise unittest.SkipTest("OpenBSD readline hangs on completion") def write_input(self, input_, env=None): script = textwrap.dedent(""" From c0129a07efd95e6290fdf87651aa5a88f7d86a97 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 21 Jul 2026 07:57:38 +0200 Subject: [PATCH 771/818] [3.15] gh-103925: Fix csv.Sniffer for a quoted field ending a CRLF line (GH-103926) (GH-154322) "$" does not match before "\r" even in the MULTILINE mode, so such a field was not found and the delimiter was guessed from character frequencies instead, which could give a letter. (cherry picked from commit 70f7c6c0f2ddfd3b447946f1b926776b2a344703) Co-authored-by: Zhou Wei <lilaboc.cn@gmail.com> Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --- Lib/csv.py | 8 ++++---- Lib/test/test_csv.py | 6 ++++++ .../2023-04-27-14-50-03.gh-issue-103925.khC-El.rst | 3 +++ 3 files changed, 13 insertions(+), 4 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-04-27-14-50-03.gh-issue-103925.khC-El.rst diff --git a/Lib/csv.py b/Lib/csv.py index b2aaf5fd9fa91e..6cae34c705777d 100644 --- a/Lib/csv.py +++ b/Lib/csv.py @@ -281,10 +281,10 @@ def _guess_quote_and_delimiter(self, data, delimiters): import re matches = [] - for restr in (r'(?P<delim>[^\w\n"\'])(?P<space> ?)(?P<quote>["\']).*?(?P=quote)(?P=delim)', # ,".*?", - r'(?:^|\n)(?P<quote>["\']).*?(?P=quote)(?P<delim>[^\w\n"\'])(?P<space> ?)', # ".*?", - r'(?P<delim>[^\w\n"\'])(?P<space> ?)(?P<quote>["\']).*?(?P=quote)(?:$|\n)', # ,".*?" - r'(?:^|\n)(?P<quote>["\']).*?(?P=quote)(?:$|\n)'): # ".*?" (no delim, no space) + for restr in (r'(?P<delim>[^\w\n"\'])(?P<space> ?)(?P<quote>["\']).*?(?P=quote)(?P=delim)', # ,".*?", + r'(?:^|\n)(?P<quote>["\']).*?(?P=quote)(?P<delim>[^\w\n"\'])(?P<space> ?)', # ".*?", + r'(?P<delim>[^\w\n"\'])(?P<space> ?)(?P<quote>["\']).*?(?P=quote)(?:$|\r|\n)', # ,".*?" + r'(?:^|\n)(?P<quote>["\']).*?(?P=quote)(?:$|\r|\n)'): # ".*?" (no delim, no space) regexp = re.compile(restr, re.DOTALL | re.MULTILINE) matches = regexp.findall(data) if matches: diff --git a/Lib/test/test_csv.py b/Lib/test/test_csv.py index 7327c1bd5f5053..2ab529b51c207d 100644 --- a/Lib/test/test_csv.py +++ b/Lib/test/test_csv.py @@ -1415,6 +1415,9 @@ class TestSniffer(unittest.TestCase): sample18.append("v,twenty_one") # 'u' was not skipped sample18 = '\n'.join(sample18) + sample19 = ('time,title\r\n' + '2020-10-01,"Pocket - Save news, videos, stories and more"\r\n') + def test_issue43625(self): sniffer = csv.Sniffer() self.assertTrue(sniffer.has_header(self.sample12)) @@ -1494,6 +1497,9 @@ def test_delimiters(self): sniffer.sniff, self.sample15) self.assertRaisesRegex(csv.Error, "Could not determine delimiter", sniffer.sniff, self.sample16) + dialect = sniffer.sniff(self.sample19) + self.assertEqual(dialect.delimiter, ',') + self.assertEqual(dialect.quotechar, '"') def test_doublequote(self): sniffer = csv.Sniffer() diff --git a/Misc/NEWS.d/next/Library/2023-04-27-14-50-03.gh-issue-103925.khC-El.rst b/Misc/NEWS.d/next/Library/2023-04-27-14-50-03.gh-issue-103925.khC-El.rst new file mode 100644 index 00000000000000..858ce6e5bd98e7 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-04-27-14-50-03.gh-issue-103925.khC-El.rst @@ -0,0 +1,3 @@ +Fix :meth:`csv.Sniffer.sniff` for a sample with ``\r\n`` line endings in +which a quoted field ends a line: a letter could be detected as the +delimiter. From 91839e53a93a39e6fc7aa30343ded89a763a3fe6 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 21 Jul 2026 08:18:07 +0200 Subject: [PATCH 772/818] [3.15] gh-154279: Skip readline completion tests that fail on DragonFly and illumos (GH-154280) (GH-154282) They are already skipped on FreeBSD, where a backspace does not remove the auto-indentation. The same happens on DragonFly and illumos. (cherry picked from commit e81f19052ae1dad6bfaa240f3e56c2b34129a8fd) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --- Lib/test/test_pdb.py | 10 ++++++---- Lib/test/test_sqlite3/test_cli.py | 4 ++-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py index 410f1436ed4d20..771abb8f871bab 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -5167,8 +5167,9 @@ def f(): self.assertIn('I love Python', output) - @unittest.skipIf(sys.platform.startswith('freebsd'), - '\\x08 is not interpreted as backspace on FreeBSD') + @unittest.skipIf(sys.platform.startswith(('freebsd', 'dragonfly', 'sunos')), + '\\x08 does not remove the auto-indentation with ' + 'GNU readline on this platform') def test_multiline_auto_indent(self): script = textwrap.dedent(""" import pdb; pdb.Pdb().set_trace() @@ -5207,8 +5208,9 @@ def test_multiline_completion(self): self.assertIn('42', output) - @unittest.skipIf(sys.platform.startswith('freebsd'), - '\\x08 is not interpreted as backspace on FreeBSD') + @unittest.skipIf(sys.platform.startswith(('freebsd', 'dragonfly', 'sunos')), + '\\x08 does not remove the auto-indentation with ' + 'GNU readline on this platform') def test_multiline_indent_completion(self): script = textwrap.dedent(""" import pdb; pdb.Pdb().set_trace() diff --git a/Lib/test/test_sqlite3/test_cli.py b/Lib/test/test_sqlite3/test_cli.py index 5b3fd32cde653d..0d235d90f1101b 100644 --- a/Lib/test/test_sqlite3/test_cli.py +++ b/Lib/test/test_sqlite3/test_cli.py @@ -381,10 +381,10 @@ def test_complete_schemata(self): self.assertIn("main", candidates) self.assertIn("temp", candidates) - @unittest.skipIf(sys.platform.startswith("freebsd"), + @unittest.skipIf(sys.platform.startswith(("freebsd", "dragonfly", "sunos")), "Two actual tabs are inserted when there are no matching" " completions in the pseudo-terminal opened by run_pty()" - " on FreeBSD") + " on this platform") def test_complete_no_match(self): input_ = b"xyzzy\t\t\b\b\b\b\b\b\b.quit\n" # Set NO_COLOR to disable coloring for self.PS1. From 4f55c53a87412bef7579f00aafc705ab5c3c66c5 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 21 Jul 2026 08:42:10 +0200 Subject: [PATCH 773/818] [3.15] gh-154325: Skip test_add_file_after_2107() if the file system rejects the timestamp (GH-154328) (GH-154331) Some file systems (UFS and ZFS on illumos) reject timestamps that do not fit in 32 bits with EOVERFLOW instead of raising OverflowError. (cherry picked from commit 63a2709b700d5532b8925caca5bc8b9437e7a1f3) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --- Lib/test/test_zipfile/test_core.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Lib/test/test_zipfile/test_core.py b/Lib/test/test_zipfile/test_core.py index ffed328b171fda..85bc010fe00784 100644 --- a/Lib/test/test_zipfile/test_core.py +++ b/Lib/test/test_zipfile/test_core.py @@ -1,6 +1,7 @@ import _pyio import array import contextlib +import errno import importlib.util import io import itertools @@ -654,6 +655,12 @@ def test_add_file_after_2107(self): os.utime(TESTFN, (ts, ts)) except OverflowError: self.skipTest('Host fs cannot set timestamp to required value.') + except OSError as exc: + # Some file systems (e.g. UFS and ZFS on illumos) do not + # support timestamps that do not fit in 32 bits. + if exc.errno != errno.EOVERFLOW: + raise + self.skipTest('Host fs cannot set timestamp to required value.') mtime_ns = os.stat(TESTFN).st_mtime_ns if mtime_ns != (4386268800 * 10**9): From 0fd12095b3174bb3e622f07604fe0e9a57509863 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 21 Jul 2026 09:17:48 +0200 Subject: [PATCH 774/818] [3.15] gh-154326: Fix test_fsize_not_too_big() on Solaris (GH-154329) (GH-154334) Solaris silently converts resource limits that do not fit in a signed 64-bit integer to RLIM_INFINITY. (cherry picked from commit 202c4c88ed5cb68ba41c54ad91e99c5585debdb4) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --- Lib/test/test_resource.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Lib/test/test_resource.py b/Lib/test/test_resource.py index ba736b0806eb1b..9834b36043355b 100644 --- a/Lib/test/test_resource.py +++ b/Lib/test/test_resource.py @@ -99,6 +99,11 @@ def expected(cur): # silently converted the limit value to RLIM_INFINITY. if sys.maxsize < 2**32 <= cur <= resource.RLIM_INFINITY: return [(resource.RLIM_INFINITY, max), (cur, max)] + # Solaris silently converts limits that do not fit in a signed + # 64-bit integer to RLIM_INFINITY. + if cur >= 2**63-1: + return [(resource.RLIM_INFINITY, max), + (min(cur, resource.RLIM_INFINITY), max)] return [(min(cur, resource.RLIM_INFINITY), max)] resource.setrlimit(resource.RLIMIT_FSIZE, (2**31-5, max)) From 0f497458d76e03fdd408ba476f82c30699f67cc9 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 21 Jul 2026 09:48:31 +0200 Subject: [PATCH 775/818] [3.15] gh-154308: Clear file flags in os_helper.rmtree() (GH-154310) (GH-154314) On BSD systems a test may leave behind files or directories with flags such as UF_IMMUTABLE or UF_NOUNLINK set, which prevent the directory from being modified or removed. Clear the flags before removing, so cleaning up a temporary directory does not fail. (cherry picked from commit 1f649fecb645d70b9c48268839e4177d8fe4e1d1) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --- Lib/test/support/os_helper.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Lib/test/support/os_helper.py b/Lib/test/support/os_helper.py index 2c45fe2369ec36..daf6060940e97f 100644 --- a/Lib/test/support/os_helper.py +++ b/Lib/test/support/os_helper.py @@ -467,12 +467,23 @@ def _rmtree(path): def _rmtree_inner(path): from test.support import _force_run + # Clear file flags (e.g. UF_IMMUTABLE, UF_NOUNLINK on BSD). + if hasattr(os, 'chflags'): + try: + os.chflags(path, 0) + except OSError: + pass for name in _force_run(path, os.listdir, path): fullname = os.path.join(path, name) try: mode = os.lstat(fullname).st_mode except OSError: mode = 0 + if hasattr(os, 'lchflags'): + try: + os.lchflags(fullname, 0) + except OSError: + pass if stat.S_ISDIR(mode): _rmtree_inner(fullname) _force_run(path, os.rmdir, fullname) From b3e046cdb4e9ac869b77022579d47ddb848c4fda Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 21 Jul 2026 12:56:35 +0200 Subject: [PATCH 776/818] [3.15] gh-154275: Fix cleanup code in `_Py_make_parameters` (GH-154341) (#154342) gh-154275: Fix cleanup code in `_Py_make_parameters` (GH-154341) (cherry picked from commit 196e16d54f9f06f566c52e7bca3b5213a8a64223) Co-authored-by: sobolevn <mail@sobolevn.me> --- Objects/genericaliasobject.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Objects/genericaliasobject.c b/Objects/genericaliasobject.c index 5caf5c7086c87a..71d946a637df1c 100644 --- a/Objects/genericaliasobject.c +++ b/Objects/genericaliasobject.c @@ -195,15 +195,14 @@ _Py_make_parameters(PyObject *args) if (is_args_list) { args = tuple_args = PySequence_Tuple(args); if (args == NULL) { - return NULL; + goto cleanup; } } Py_ssize_t nargs = PyTuple_GET_SIZE(args); Py_ssize_t len = nargs; PyObject *parameters = PyTuple_New(len); if (parameters == NULL) { - Py_XDECREF(tuple_args); - return NULL; + goto error; } Py_ssize_t iparam = 0; for (Py_ssize_t iarg = 0; iarg < nargs; iarg++) { From 682610d700511439add24dcca62708b4c1644d3f Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 21 Jul 2026 14:47:37 +0200 Subject: [PATCH 777/818] [3.15] gh-153881: Atomically load `dk_nentries` in `_PyObject_IsInstanceDictEmpty` (GH-153882) (#154349) gh-153881: Atomically load `dk_nentries` in `_PyObject_IsInstanceDictEmpty` (GH-153882) (cherry picked from commit 7ebe773160327026ba5393b27e2e2860db4d08b2) Co-authored-by: Brij Kapadia <97006829+brijkapadia@users.noreply.github.com> --- Lib/test/test_free_threading/test_dict.py | 20 +++++++++++++++++++ ...-07-17-22-03-39.gh-issue-153881.oDa06s.rst | 2 ++ Objects/dictobject.c | 2 +- 3 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-07-17-22-03-39.gh-issue-153881.oDa06s.rst diff --git a/Lib/test/test_free_threading/test_dict.py b/Lib/test/test_free_threading/test_dict.py index ad23290a92ab34..4a812275143bc4 100644 --- a/Lib/test/test_free_threading/test_dict.py +++ b/Lib/test/test_free_threading/test_dict.py @@ -336,5 +336,25 @@ def reader(): with threading_helper.start_threads([t1, t2]): pass + def test_getstate_race_with_shared_keys(self): + box = [None] + enter = Barrier(2) + leave = Barrier(2) + + def reader(): + for _ in range(1000): + enter.wait() + box[0].__getstate__() + leave.wait() + + def writer(): + for i in range(1000): + box[0] = type(f"C{i}", (), {})() + enter.wait() + setattr(box[0], str(i), 1) + leave.wait() + + threading_helper.run_concurrently([reader, writer]) + if __name__ == "__main__": unittest.main() diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-07-17-22-03-39.gh-issue-153881.oDa06s.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-07-17-22-03-39.gh-issue-153881.oDa06s.rst new file mode 100644 index 00000000000000..8facf88367fda7 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-07-17-22-03-39.gh-issue-153881.oDa06s.rst @@ -0,0 +1,2 @@ +Fix potential data race when calling :meth:`~object.__getstate__` +under the :term:`free-threaded build`. diff --git a/Objects/dictobject.c b/Objects/dictobject.c index eebb896f5d785b..29b6361eea4feb 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -7654,7 +7654,7 @@ _PyObject_IsInstanceDictEmpty(PyObject *obj) PyDictValues *values = _PyObject_InlineValues(obj); if (FT_ATOMIC_LOAD_UINT8(values->valid)) { PyDictKeysObject *keys = CACHED_KEYS(tp); - for (Py_ssize_t i = 0; i < keys->dk_nentries; i++) { + for (Py_ssize_t i = 0; i < LOAD_KEYS_NENTRIES(keys); i++) { if (FT_ATOMIC_LOAD_PTR_RELAXED(values->values[i]) != NULL) { return 0; } From b8c7ff982144dc0057686c8a50e53446a7287db4 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 21 Jul 2026 16:30:04 +0200 Subject: [PATCH 778/818] [3.15] gh-154352: Fix killing a worker process in regrtest on OpenBSD (GH-154353) (GH-154360) os.getsid() is only allowed for a process in the same session on OpenBSD. Worker processes are started in their own session, so the failure means that the process group can be killed. (cherry picked from commit bfd774d61eeb384b74380deb1fc5b726decba75e) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --- Lib/test/libregrtest/run_workers.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Lib/test/libregrtest/run_workers.py b/Lib/test/libregrtest/run_workers.py index 424085a0050eb5..4458e160705bca 100644 --- a/Lib/test/libregrtest/run_workers.py +++ b/Lib/test/libregrtest/run_workers.py @@ -147,9 +147,12 @@ def _kill(self) -> None: use_killpg = USE_PROCESS_GROUP if use_killpg: - parent_sid = os.getsid(0) - sid = os.getsid(popen.pid) - use_killpg = (sid != parent_sid) + try: + use_killpg = (os.getsid(popen.pid) != os.getsid(0)) + except PermissionError: + # On OpenBSD getsid() is only allowed for a process in the + # same session, so the failure means that it is not. + use_killpg = True if use_killpg: what = f"{self} process group" From e265465d0519a38a89e52611110da806472f9432 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 21 Jul 2026 16:49:13 +0200 Subject: [PATCH 779/818] [3.15] gh-154345: Fix test_posix_pty_functions() killing the worker on Solaris (GH-154346) (GH-154354) Pushing the "ptem" STREAMS module makes a session leader without a controlling terminal acquire the slave as one, so closing the file descriptors sent SIGHUP to the session and killed the regrtest worker. Disown it after the pushes, as os.openpty() does. (cherry picked from commit f69f7fd526b6601a74ce0852c75466a183a86cea) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --- Lib/test/test_os/test_os.py | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_os/test_os.py b/Lib/test/test_os/test_os.py index f2b9cf75d3bfa1..6be86ac56a0d1f 100644 --- a/Lib/test/test_os/test_os.py +++ b/Lib/test/test_os/test_os.py @@ -4716,12 +4716,27 @@ def test_posix_pty_functions(self): son_fd = os.open(son_path, os.O_RDWR|os.O_NOCTTY) self.addCleanup(os.close, son_fd) if sys.platform.startswith('sunos'): - # The slave is not a terminal until these STREAMS modules - # are pushed onto it. import fcntl I_PUSH = 0x5302 + TIOCNOTTY = 0x7471 + # Pushing "ptem" makes the slave a terminal, which a session + # leader without a controlling terminal then acquires as one + # despite O_NOCTTY. Note whether we already had one. + try: + os.close(os.open('/dev/tty', os.O_RDONLY|os.O_NOCTTY)) + had_ctty = True + except OSError: + had_ctty = False fcntl.ioctl(son_fd, I_PUSH, b'ptem\0') fcntl.ioctl(son_fd, I_PUSH, b'ldterm\0') + if not had_ctty and os.getsid(0) == os.getpid(): + # Disown it, otherwise closing the file descriptors sends + # SIGHUP to the session. TIOCNOTTY sends it too. + old_handler = signal.signal(signal.SIGHUP, signal.SIG_IGN) + try: + fcntl.ioctl(son_fd, TIOCNOTTY) + finally: + signal.signal(signal.SIGHUP, old_handler) self.assertEqual(os.ptsname(mother_fd), os.ttyname(son_fd)) @warnings_helper.ignore_fork_in_thread_deprecation_warnings() From 098eb36257752ba4d2cac5764ffc4bff3624fe51 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 21 Jul 2026 18:44:29 +0200 Subject: [PATCH 780/818] [3.15] gh-154379: Fix test_epoll on Solaris (GH-154380) (GH-154382) A non-blocking connect() can be completed immediately, and unregistering a closed file descriptor succeeds on Solaris. (cherry picked from commit b6abee522f1dbbba36cc306aa99ac22d1df5c454) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --- Lib/test/test_epoll.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_epoll.py b/Lib/test/test_epoll.py index 5e6a4ab0166a86..51405ca7c9e57c 100644 --- a/Lib/test/test_epoll.py +++ b/Lib/test/test_epoll.py @@ -25,6 +25,7 @@ import os import select import socket +import sys import time import unittest from test import support @@ -52,12 +53,11 @@ def tearDown(self): def _connected_pair(self): client = socket.socket() client.setblocking(False) + # The connection is either established immediately or in progress. try: client.connect(('127.0.0.1', self.serverSocket.getsockname()[1])) except OSError as e: self.assertEqual(e.args[0], errno.EINPROGRESS) - else: - raise AssertionError("Connect should have raised EINPROGRESS") server, addr = self.serverSocket.accept() self.connections.extend((client, server)) @@ -218,6 +218,9 @@ def test_errors(self): self.assertRaises(ValueError, select.epoll().register, -1, select.EPOLLIN) + @unittest.skipIf(sys.platform.startswith('sunos'), + 'unregistering a closed file descriptor succeeds ' + 'on Solaris') def test_unregister_closed(self): server, client = self._connected_pair() fd = server.fileno() From fe66754f245d2ff3e80680429806b016992519dc Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 21 Jul 2026 22:02:34 +0200 Subject: [PATCH 781/818] [3.15] gh-154389: Do not use uuid_create() on OpenBSD (GH-154390) (GH-154391) Like NetBSD, OpenBSD generates version 4 UUIDs in uuid_create(), so it cannot be used for uuid.uuid1(). (cherry picked from commit c76fb912070389e0fbad3bf4eab066cd5da931b9) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --- .../Library/2026-07-21-20-34-05.gh-issue-154389.DlTiii.rst | 3 +++ configure | 5 +++-- configure.ac | 5 +++-- 3 files changed, 9 insertions(+), 4 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-07-21-20-34-05.gh-issue-154389.DlTiii.rst diff --git a/Misc/NEWS.d/next/Library/2026-07-21-20-34-05.gh-issue-154389.DlTiii.rst b/Misc/NEWS.d/next/Library/2026-07-21-20-34-05.gh-issue-154389.DlTiii.rst new file mode 100644 index 00000000000000..eb2e2edc2d720e --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-21-20-34-05.gh-issue-154389.DlTiii.rst @@ -0,0 +1,3 @@ +Fix :func:`uuid.uuid1` on OpenBSD: +it returned a version 4 UUID, +because ``uuid_create()`` generates random UUIDs on this platform. diff --git a/configure b/configure index af350fbb132d78..dd506e6899515b 100755 --- a/configure +++ b/configure @@ -15162,9 +15162,10 @@ then : fi -# gh-124228: While the libuuid library is available on NetBSD, it supports only UUID version 4. +# gh-124228: While the libuuid library is available on NetBSD and OpenBSD, +# it supports only UUID version 4. # This restriction inhibits the proper generation of time-based UUIDs. -if test "$ac_sys_system" = "NetBSD"; then +if test "$ac_sys_system" = "NetBSD" || test "$ac_sys_system" = "OpenBSD"; then have_uuid=missing printf "%s\n" "#define HAVE_UUID_H 0" >>confdefs.h diff --git a/configure.ac b/configure.ac index a8bd6b884a131c..73d0bb48ea8f4f 100644 --- a/configure.ac +++ b/configure.ac @@ -4003,9 +4003,10 @@ AS_VAR_IF([ac_cv_have_uuid_generate_time_safe], [yes], [ AC_DEFINE([HAVE_UUID_GENERATE_TIME_SAFE], [1]) ]) -# gh-124228: While the libuuid library is available on NetBSD, it supports only UUID version 4. +# gh-124228: While the libuuid library is available on NetBSD and OpenBSD, +# it supports only UUID version 4. # This restriction inhibits the proper generation of time-based UUIDs. -if test "$ac_sys_system" = "NetBSD"; then +if test "$ac_sys_system" = "NetBSD" || test "$ac_sys_system" = "OpenBSD"; then have_uuid=missing AC_DEFINE([HAVE_UUID_H], [0]) fi From a111ea1d7e090add94f204555ce2b122341dfea8 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 22 Jul 2026 03:49:48 +0200 Subject: [PATCH 782/818] [3.15] gh-153741: Harden IDLE GUI tests for newer Tk and display scaling (GH-153742) (#154404) gh-153741: Harden IDLE GUI tests for newer Tk and display scaling (GH-153742) In test_sidebar.test_mousewheel, only use the X11 <Button-4>/<Button-5> events when testing on x11 Tk before 8.7. Otherwise, use <Mousewheel> as on other systems. In test_configdialog, assert the 'disabled' state flag alone instead of the exact ttk state tuple (which transient pointer states break), and restore the tests' method masks with addCleanup(). (cherry picked from commit a2581ebc7a93ec573f64d3a5e29cbd9053de7a1f) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --- Lib/idlelib/idle_test/test_configdialog.py | 63 +++++++++++----------- Lib/idlelib/idle_test/test_sidebar.py | 10 ++-- 2 files changed, 38 insertions(+), 35 deletions(-) diff --git a/Lib/idlelib/idle_test/test_configdialog.py b/Lib/idlelib/idle_test/test_configdialog.py index c68fd304ea4235..696a3b2f8f1bc2 100644 --- a/Lib/idlelib/idle_test/test_configdialog.py +++ b/Lib/idlelib/idle_test/test_configdialog.py @@ -244,6 +244,7 @@ def test_font_set(self): def test_set_samples(self): d = self.page + self.addCleanup(setattr, d, 'set_samples', Func()) # Re-mask for other tests. del d.set_samples # Unmask method for test orig_samples = d.font_sample, d.highlight_sample d.font_sample, d.highlight_sample = {}, {} @@ -257,7 +258,6 @@ def test_set_samples(self): self.assertTrue(d.font_sample == d.highlight_sample == expected) d.font_sample, d.highlight_sample = orig_samples - d.set_samples = Func() # Re-mask for other tests. class HighPageTest(unittest.TestCase): @@ -307,7 +307,7 @@ def test_load_theme_cfg(self): # builtinlist sets variable builtin_name to the CurrentTheme default. eq(d.builtin_name.get(), 'IDLE Classic') eq(d.custom_name.get(), '- no custom themes -') - eq(d.custom_theme_on.state(), ('disabled',)) + self.assertIn('disabled', d.custom_theme_on.state()) eq(d.set_theme_type.called, 1) eq(d.paint_theme_sample.called, 1) eq(d.set_highlight_target.called, 1) @@ -495,6 +495,7 @@ def test_highlight_sample_b1_motion(self): def test_set_theme_type(self): eq = self.assertEqual d = self.page + self.addCleanup(setattr, d, 'set_theme_type', Func()) # Re-mask method. del d.set_theme_type # Builtin theme selected. @@ -502,16 +503,15 @@ def test_set_theme_type(self): d.set_theme_type() eq(d.builtinlist['state'], NORMAL) eq(d.customlist['state'], DISABLED) - eq(d.button_delete_custom.state(), ('disabled',)) + self.assertIn('disabled', d.button_delete_custom.state()) # Custom theme selected. d.theme_source.set(False) d.set_theme_type() eq(d.builtinlist['state'], DISABLED) - eq(d.custom_theme_on.state(), ('selected',)) + self.assertNotIn('disabled', d.custom_theme_on.state()) eq(d.customlist['state'], NORMAL) - eq(d.button_delete_custom.state(), ()) - d.set_theme_type = Func() + self.assertNotIn('disabled', d.button_delete_custom.state()) def test_get_color(self): eq = self.assertEqual @@ -637,24 +637,23 @@ def test_create_new_and_save_new(self): def test_set_highlight_target(self): eq = self.assertEqual d = self.page + self.addCleanup(setattr, d, 'set_highlight_target', Func()) # Re-mask method. del d.set_highlight_target # Target is cursor. d.highlight_target.set('Cursor') - eq(d.fg_on.state(), ('disabled', 'selected')) - eq(d.bg_on.state(), ('disabled',)) + self.assertIn('disabled', d.fg_on.state()) + self.assertIn('disabled', d.bg_on.state()) self.assertTrue(d.fg_bg_toggle) eq(d.set_color_sample.called, 1) # Target is not cursor. d.highlight_target.set('Comment') - eq(d.fg_on.state(), ('selected',)) - eq(d.bg_on.state(), ()) + self.assertNotIn('disabled', d.fg_on.state()) + self.assertNotIn('disabled', d.bg_on.state()) self.assertTrue(d.fg_bg_toggle) eq(d.set_color_sample.called, 2) - d.set_highlight_target = Func() - def test_set_color_sample_binding(self): d = self.page scs = d.set_color_sample @@ -667,6 +666,7 @@ def test_set_color_sample_binding(self): def test_set_color_sample(self): d = self.page + self.addCleanup(setattr, d, 'set_color_sample', Func()) # Re-mask method. del d.set_color_sample d.highlight_target.set('Selected Text') d.fg_bg_toggle.set(True) @@ -674,7 +674,6 @@ def test_set_color_sample(self): self.assertEqual( d.style.lookup(d.frame_color_set['style'], 'background'), d.highlight_sample.tag_cget('hilite', 'foreground')) - d.set_color_sample = Func() def test_paint_theme_sample(self): eq = self.assertEqual @@ -745,7 +744,7 @@ def test_delete_custom(self): eq(yesno.called, 2) self.assertNotIn(theme_name, highpage) eq(idleConf.GetSectionList('user', 'highlight'), [theme_name2]) - eq(d.custom_theme_on.state(), ()) + self.assertNotIn('disabled', d.custom_theme_on.state()) eq(d.custom_name.get(), theme_name2) eq(dialog.deactivate_current_config.called, 1) eq(dialog.activate_config_changes.called, 1) @@ -758,7 +757,7 @@ def test_delete_custom(self): eq(yesno.called, 3) self.assertNotIn(theme_name, highpage) eq(idleConf.GetSectionList('user', 'highlight'), []) - eq(d.custom_theme_on.state(), ('disabled',)) + self.assertIn('disabled', d.custom_theme_on.state()) eq(d.custom_name.get(), '- no custom themes -') eq(dialog.deactivate_current_config.called, 2) eq(dialog.activate_config_changes.called, 2) @@ -809,7 +808,7 @@ def test_load_key_cfg(self): # builtinlist sets variable builtin_name to the CurrentKeys default. eq(d.builtin_name.get(), 'IDLE Classic OSX') eq(d.custom_name.get(), '- no custom keys -') - eq(d.custom_keyset_on.state(), ('disabled',)) + self.assertIn('disabled', d.custom_keyset_on.state()) eq(d.set_keys_type.called, 1) eq(d.load_keys_list.called, 1) eq(d.load_keys_list.args, ('IDLE Classic OSX', )) @@ -930,6 +929,7 @@ def test_keybinding(self): def test_set_keys_type(self): eq = self.assertEqual d = self.page + self.addCleanup(setattr, d, 'set_keys_type', Func()) # Re-mask method. del d.set_keys_type # Builtin keyset selected. @@ -937,16 +937,15 @@ def test_set_keys_type(self): d.set_keys_type() eq(d.builtinlist['state'], NORMAL) eq(d.customlist['state'], DISABLED) - eq(d.button_delete_custom_keys.state(), ('disabled',)) + self.assertIn('disabled', d.button_delete_custom_keys.state()) # Custom keyset selected. d.keyset_source.set(False) d.set_keys_type() eq(d.builtinlist['state'], DISABLED) - eq(d.custom_keyset_on.state(), ('selected',)) + self.assertNotIn('disabled', d.custom_keyset_on.state()) eq(d.customlist['state'], NORMAL) - eq(d.button_delete_custom_keys.state(), ()) - d.set_keys_type = Func() + self.assertNotIn('disabled', d.button_delete_custom_keys.state()) def test_get_new_keys(self): eq = self.assertEqual @@ -1043,7 +1042,7 @@ def test_on_bindingslist_select(self): b.event_generate('<Button-1>', x=x, y=y) b.event_generate('<ButtonRelease-1>', x=x, y=y) self.assertEqual(b.get('anchor'), 'find') - self.assertEqual(d.button_new_keys.state(), ()) + self.assertNotIn('disabled', d.button_new_keys.state()) def test_create_new_key_set_and_save_new_key_set(self): eq = self.assertEqual @@ -1080,6 +1079,7 @@ def test_load_keys_list(self): eq = self.assertEqual d = self.page gks = idleConf.GetKeySet = Func() + self.addCleanup(setattr, d, 'load_keys_list', Func()) # Re-mask method. del d.load_keys_list b = d.bindingslist @@ -1115,7 +1115,6 @@ def test_load_keys_list(self): eq(b.get(0, 'end'), expected) eq(b.get('anchor'), 'spam - <Shift-Key-a>') eq(b.curselection(), (2, )) - d.load_keys_list = Func() del idleConf.GetKeySet @@ -1156,7 +1155,7 @@ def test_delete_custom_keys(self): eq(yesno.called, 2) self.assertNotIn(keyset_name, keyspage) eq(idleConf.GetSectionList('user', 'keys'), [keyset_name2]) - eq(d.custom_keyset_on.state(), ()) + self.assertNotIn('disabled', d.custom_keyset_on.state()) eq(d.custom_name.get(), keyset_name2) eq(dialog.deactivate_current_config.called, 1) eq(dialog.activate_config_changes.called, 1) @@ -1169,7 +1168,7 @@ def test_delete_custom_keys(self): eq(yesno.called, 3) self.assertNotIn(keyset_name, keyspage) eq(idleConf.GetSectionList('user', 'keys'), []) - eq(d.custom_keyset_on.state(), ('disabled',)) + self.assertIn('disabled', d.custom_keyset_on.state()) eq(d.custom_name.get(), '- no custom keys -') eq(dialog.deactivate_current_config.called, 2) eq(dialog.activate_config_changes.called, 2) @@ -1365,25 +1364,25 @@ def test_set_add_delete_state(self): # Call with 0 items, 1 unselected item, 1 selected item. eq = self.assertEqual fr = self.frame + self.addCleanup(setattr, fr, 'set_add_delete_state', Func()) # Re-mask method. del fr.set_add_delete_state # Unmask method. sad = fr.set_add_delete_state h = fr.helplist h.delete(0, 'end') sad() - eq(fr.button_helplist_edit.state(), ('disabled',)) - eq(fr.button_helplist_remove.state(), ('disabled',)) + self.assertIn('disabled', fr.button_helplist_edit.state()) + self.assertIn('disabled', fr.button_helplist_remove.state()) h.insert(0, 'source') sad() - eq(fr.button_helplist_edit.state(), ('disabled',)) - eq(fr.button_helplist_remove.state(), ('disabled',)) + self.assertIn('disabled', fr.button_helplist_edit.state()) + self.assertIn('disabled', fr.button_helplist_remove.state()) h.selection_set(0) sad() - eq(fr.button_helplist_edit.state(), ()) - eq(fr.button_helplist_remove.state(), ()) - fr.set_add_delete_state = Func() # Mask method. + self.assertNotIn('disabled', fr.button_helplist_edit.state()) + self.assertNotIn('disabled', fr.button_helplist_remove.state()) def test_helplist_item_add(self): # Call without and twice with HelpSource result. @@ -1461,6 +1460,7 @@ def test_helplist_item_remove(self): def test_update_help_changes(self): fr = self.frame + self.addCleanup(setattr, fr, 'update_help_changes', Func()) # Re-mask method. del fr.update_help_changes fr.user_helplist.clear() fr.user_helplist.append(('name1', 'file1')) @@ -1469,7 +1469,6 @@ def test_update_help_changes(self): fr.update_help_changes() self.assertEqual(mainpage['HelpFiles'], {'1': 'name1;file1', '2': 'name2;file2'}) - fr.update_help_changes = Func() class VarTraceTest(unittest.TestCase): diff --git a/Lib/idlelib/idle_test/test_sidebar.py b/Lib/idlelib/idle_test/test_sidebar.py index dc3431d8d8ef88..df84554c4f1a51 100644 --- a/Lib/idlelib/idle_test/test_sidebar.py +++ b/Lib/idlelib/idle_test/test_sidebar.py @@ -689,11 +689,15 @@ def test_mousewheel(self): last_lineno = get_end_linenumber(text) self.assertIsNotNone(text.dlineinfo(text.index(f'{last_lineno}.0'))) - # Delta for <MouseWheel>, whose meaning is platform-dependent. + # Simulate a mouse wheel notch. Tk 8.7 replaced the X11 + # <Button-4>/<Button-5> wheel events with <MouseWheel> (whose delta is + # platform-dependent); older Tk on X11 still uses the button events. + x11_buttons = (sidebar.canvas._windowingsystem == 'x11' + and tk.TkVersion < 8.7) delta = 1 if sidebar.canvas._windowingsystem == 'aqua' else 120 # Scroll up. - if sidebar.canvas._windowingsystem == 'x11': + if x11_buttons: sidebar.canvas.event_generate('<Button-4>', x=0, y=0) else: sidebar.canvas.event_generate('<MouseWheel>', x=0, y=0, delta=delta) @@ -701,7 +705,7 @@ def test_mousewheel(self): self.assertIsNone(text.dlineinfo(text.index(f'{last_lineno}.0'))) # Scroll back down. - if sidebar.canvas._windowingsystem == 'x11': + if x11_buttons: sidebar.canvas.event_generate('<Button-5>', x=0, y=0) else: sidebar.canvas.event_generate('<MouseWheel>', x=0, y=0, delta=-delta) From a5e2d7488d71d2889a3522cbc8983ce5612574fc Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 22 Jul 2026 06:38:09 +0200 Subject: [PATCH 783/818] [3.15] gh-154399: Fix venv activate.csh in a non-interactive shell (GH-154400) (GH-154408) activate.csh saved the prompt unconditionally, but the prompt variable only exists in interactive shells, and csh fails on an undefined variable. (cherry picked from commit 4448705d879ea41ea97114ef6c8215590913811a) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --- Lib/venv/scripts/posix/activate.csh | 8 +++++--- .../2026-07-21-21-36-59.gh-issue-154399.VSa6oH.rst | 3 +++ 2 files changed, 8 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-07-21-21-36-59.gh-issue-154399.VSa6oH.rst diff --git a/Lib/venv/scripts/posix/activate.csh b/Lib/venv/scripts/posix/activate.csh index 2a3fa835476ab9..7226034df0f394 100644 --- a/Lib/venv/scripts/posix/activate.csh +++ b/Lib/venv/scripts/posix/activate.csh @@ -16,10 +16,12 @@ setenv PATH "$VIRTUAL_ENV/"__VENV_BIN_NAME__":$PATH" setenv VIRTUAL_ENV_PROMPT __VENV_PROMPT__ -set _OLD_VIRTUAL_PROMPT="$prompt" +if ($?prompt) then + set _OLD_VIRTUAL_PROMPT="$prompt" -if (! "$?VIRTUAL_ENV_DISABLE_PROMPT") then - set prompt = "("__VENV_PROMPT__") $prompt:q" + if (! "$?VIRTUAL_ENV_DISABLE_PROMPT") then + set prompt = "("__VENV_PROMPT__") $prompt:q" + endif endif alias pydoc python -m pydoc diff --git a/Misc/NEWS.d/next/Library/2026-07-21-21-36-59.gh-issue-154399.VSa6oH.rst b/Misc/NEWS.d/next/Library/2026-07-21-21-36-59.gh-issue-154399.VSa6oH.rst new file mode 100644 index 00000000000000..598dd26694c73e --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-21-21-36-59.gh-issue-154399.VSa6oH.rst @@ -0,0 +1,3 @@ +Fix :mod:`venv` activation in a non-interactive csh: +``activate.csh`` no longer fails +when the ``prompt`` variable is not set. From 35560dc8e35df2c5d12287bd6f24a9b3531827ae Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka <storchaka@gmail.com> Date: Wed, 22 Jul 2026 08:43:33 +0300 Subject: [PATCH 784/818] [3.15] gh-154394: Skip test_tcsendbreak on OpenBSD (GH-154397) (GH-154411) tcsendbreak() is not supported for pseudo-terminals on OpenBSD. (cherry picked from commit f1730ddc474d9d103c4f85ecc4bb1e995a268ed9) Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --- Lib/test/test_termios.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_termios.py b/Lib/test/test_termios.py index ce8392a6ccdbd6..9fdf42c329521d 100644 --- a/Lib/test/test_termios.py +++ b/Lib/test/test_termios.py @@ -104,7 +104,7 @@ def test_tcsendbreak(self): try: termios.tcsendbreak(self.fd, 1) except termios.error as exc: - if exc.args[0] == errno.ENOTTY and sys.platform.startswith(('freebsd', "netbsd")): + if exc.args[0] == errno.ENOTTY and sys.platform.startswith(('freebsd', 'netbsd', 'openbsd')): self.skipTest('termios.tcsendbreak() is not supported ' 'with pseudo-terminals (?) on this platform') raise From 566d678323fdc7ced1365db0a8d4abc8ab562c6f Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka <storchaka@gmail.com> Date: Wed, 22 Jul 2026 08:57:42 +0300 Subject: [PATCH 785/818] [3.15] gh-154416: Fix hanging test_tcflow on DragonFly BSD (GH-154417) (GH-154423) TCIOFF and TCION transmit STOP and START characters, and closing the pseudo-terminal waits until they are read. Discard them. (cherry picked from commit b0c945a27e708419c6845234ef633ce3f7c4c41e) Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --- Lib/test/test_termios.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Lib/test/test_termios.py b/Lib/test/test_termios.py index 9fdf42c329521d..70972195264228 100644 --- a/Lib/test/test_termios.py +++ b/Lib/test/test_termios.py @@ -180,6 +180,9 @@ def test_tcflow(self): termios.tcflow(self.fd, termios.TCOON) termios.tcflow(self.fd, termios.TCIOFF) termios.tcflow(self.fd, termios.TCION) + # Discard the transmitted STOP and START characters, + # otherwise closing the pseudo-terminal can block. + termios.tcflush(self.fd, termios.TCOFLUSH) @support.skip_android_selinux('tcflow') def test_tcflow_errors(self): From 034408f41fcc482105dc67f030f2463199b44be9 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka <storchaka@gmail.com> Date: Wed, 22 Jul 2026 09:30:21 +0300 Subject: [PATCH 786/818] [3.15] gh-154414: Skip test_tcsendbreak on DragonFly BSD (GH-154415) (GH-154426) tcsendbreak() is not supported for pseudo-terminals on DragonFly BSD. (cherry picked from commit a84e780707d3baa3b9f73981d8b7e293eb10d076) Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --- Lib/test/test_termios.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_termios.py b/Lib/test/test_termios.py index 70972195264228..aa8927c1ba7ea2 100644 --- a/Lib/test/test_termios.py +++ b/Lib/test/test_termios.py @@ -104,7 +104,7 @@ def test_tcsendbreak(self): try: termios.tcsendbreak(self.fd, 1) except termios.error as exc: - if exc.args[0] == errno.ENOTTY and sys.platform.startswith(('freebsd', 'netbsd', 'openbsd')): + if exc.args[0] == errno.ENOTTY and sys.platform.startswith(('freebsd', 'netbsd', 'openbsd', 'dragonfly')): self.skipTest('termios.tcsendbreak() is not supported ' 'with pseudo-terminals (?) on this platform') raise From d4e3529e66cf5d43b663d5416ed99c4ffb5429ff Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 22 Jul 2026 09:32:39 +0200 Subject: [PATCH 787/818] [3.15] gh-154427: Check the access time in UtimeTests only if it is stored (GH-154428) (GH-154432) HAMMER2 on DragonFly BSD does not store the access time and os.stat() returns the modification time instead. Probe the file system, like it is already done for the timestamp resolution. (cherry picked from commit 6f8f97fe5246837b93e6c2f3525aa9f623ecd30b) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --- Lib/test/test_os/test_os.py | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/Lib/test/test_os/test_os.py b/Lib/test/test_os/test_os.py index 6be86ac56a0d1f..f9919e824b1abe 100644 --- a/Lib/test/test_os/test_os.py +++ b/Lib/test/test_os/test_os.py @@ -1058,11 +1058,18 @@ def support_subsecond(self, filename): or (st.st_mtime != st[8]) or (st.st_ctime != st[9])) + def support_atime(self, filename): + # Heuristic to check if the filesystem stores the access time. + # Use whole seconds, to not depend on the timestamp resolution. + os.utime(filename, (1, 2)) + return os.stat(filename).st_atime == 1 + def _test_utime(self, set_time, filename=None): if not filename: filename = self.fname support_subsecond = self.support_subsecond(filename) + support_atime = self.support_atime(filename) if support_subsecond: # Timestamp with a resolution of 1 microsecond (10^-6). # @@ -1089,18 +1096,22 @@ def _test_utime(self, set_time, filename=None): # digits worth of sub-second precision. # Some day it would be good to fix this upstream. delta=1e-5 - self.assertAlmostEqual(st.st_atime, atime_ns * 1e-9, delta=1e-5) + if support_atime: + self.assertAlmostEqual(st.st_atime, atime_ns * 1e-9, delta=1e-5) + self.assertAlmostEqual(st.st_atime_ns, atime_ns, delta=1e9 * 1e-5) self.assertAlmostEqual(st.st_mtime, mtime_ns * 1e-9, delta=1e-5) - self.assertAlmostEqual(st.st_atime_ns, atime_ns, delta=1e9 * 1e-5) self.assertAlmostEqual(st.st_mtime_ns, mtime_ns, delta=1e9 * 1e-5) else: if support_subsecond: - self.assertAlmostEqual(st.st_atime, atime_ns * 1e-9, delta=1e-6) + if support_atime: + self.assertAlmostEqual(st.st_atime, atime_ns * 1e-9, delta=1e-6) self.assertAlmostEqual(st.st_mtime, mtime_ns * 1e-9, delta=1e-6) else: - self.assertEqual(st.st_atime, atime_ns * 1e-9) + if support_atime: + self.assertEqual(st.st_atime, atime_ns * 1e-9) self.assertEqual(st.st_mtime, mtime_ns * 1e-9) - self.assertEqual(st.st_atime_ns, atime_ns) + if support_atime: + self.assertEqual(st.st_atime_ns, atime_ns) self.assertEqual(st.st_mtime_ns, mtime_ns) def test_utime(self): From 539bb545003b658e5539265eadd19eb1081c171d Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 22 Jul 2026 10:02:31 +0200 Subject: [PATCH 788/818] [3.15] Test `object_hook` and pickleability of some JSON components (GH-154155) (#154374) Test `object_hook` and pickleability of some JSON components (GH-154155) (cherry picked from commit d333e5aa59f6cc20198502f4ff50b14eabde9b8b) Co-authored-by: David <slavicek.david29@gmail.com> --- Lib/test/test_json/test_decode.py | 20 ++++++++++++++++++++ Lib/test/test_json/test_pickleable.py | 14 ++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 Lib/test/test_json/test_pickleable.py diff --git a/Lib/test/test_json/test_decode.py b/Lib/test/test_json/test_decode.py index 33aeefa92f282a..7bff16ddf2155e 100644 --- a/Lib/test/test_json/test_decode.py +++ b/Lib/test/test_json/test_decode.py @@ -48,6 +48,26 @@ def test_empty_objects(self): self.assertEqual(self.loads('[]'), []) self.assertEqual(self.loads('""'), "") + def test_object_hook(self): + s = '{"a":{"b":{}}}' + + expected_result = {"a":{"b":{"x":1}, "x":1}, "x":1} + expected_hook_arguments = [ + {}, {"b": {"x":1}}, {"a": {"b": {"x":1}, "x":1}} + ] + + hook_arguments = [] + + def hook(x): + hook_arguments.append(x) + return {**x, "x":1} + + result = self.loads(s, object_hook=hook) + + self.assertEqual(result, expected_result) + self.assertEqual(hook_arguments, expected_hook_arguments) + + def test_object_pairs_hook(self): s = '{"xkd":1, "kcw":2, "art":3, "hxm":4, "qrt":5, "pad":6, "hoy":7}' p = [("xkd", 1), ("kcw", 2), ("art", 3), ("hxm", 4), diff --git a/Lib/test/test_json/test_pickleable.py b/Lib/test/test_json/test_pickleable.py new file mode 100644 index 00000000000000..517cfcdd41a351 --- /dev/null +++ b/Lib/test/test_json/test_pickleable.py @@ -0,0 +1,14 @@ +import json +import pickle +import unittest + +class TestPickleable(unittest.TestCase): + def test_json_decode_error_is_pickleable(self): + e = json.JSONDecodeError(msg="abc", doc="def", pos=7) + + pickled = pickle.dumps(e) + unpickled = pickle.loads(pickled) + + self.assertEqual(unpickled.msg, e.msg) + self.assertEqual(unpickled.doc, e.doc) + self.assertEqual(unpickled.pos, e.pos) From f9ebe5e65b1a047bd343f8998c0d7ae85b66d3c0 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 22 Jul 2026 10:35:09 +0200 Subject: [PATCH 789/818] [3.15] gh-154007: Improve test coverage for the `shlex` module (GH-154009) (#154445) gh-154007: Improve test coverage for the `shlex` module (GH-154009) (cherry picked from commit 0eac28e3637d0ee15f4e8737b5d1a311623e46f9) Co-authored-by: Piotr Kaznowski <piotr@kazno.dev> --- Lib/test/test_shlex.py | 200 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 200 insertions(+) diff --git a/Lib/test/test_shlex.py b/Lib/test/test_shlex.py index 2a355abdeeb30f..a88dc286e4ee63 100644 --- a/Lib/test/test_shlex.py +++ b/Lib/test/test_shlex.py @@ -1,8 +1,11 @@ import io import itertools +import os import shlex import string +import tempfile import unittest +from unittest.mock import patch from test.support import cpython_only from test.support import import_helper @@ -368,6 +371,203 @@ def testPunctuationCharsReadOnly(self): with self.assertRaises(AttributeError): shlex_instance.punctuation_chars = False + def testLinenoAfterNewLine(self): + s = shlex.shlex("line 1\nline 2") + self.assertEqual(s.lineno, 1) # before consumption + list(s) + self.assertEqual(s.lineno, 2) + + def testLinenoAfterComment(self): + """Comment handler increments lineno even without a trailing newline.""" + s = shlex.shlex("line 1 # line 2") + list(s) + self.assertEqual(s.lineno, 2) + + def testPushToken(self): + s = shlex.shlex("b c") + s.push_token("a") + self.assertListEqual(list(s), ["a", "b", "c"]) + + def testPushTokenLifo(self): + s = shlex.shlex("") + s.push_token("first") + s.push_token("last") + self.assertListEqual(list(s), ["last", "first"]) + + def testPushTokenDebug(self): + s = shlex.shlex("") + s.debug = 1 + tok = "a" + with patch("builtins.print") as mock_print: + s.push_token(tok) + mock_print.assert_called_once_with(f"shlex: pushing token {tok!r}") + + def testPushSourceString(self): + s = shlex.shlex("world") + s.push_source("hello") + self.assertListEqual(list(s), ["hello", "world"]) + + def testPushSourceStream(self): + s = shlex.shlex("world") + s.push_source(io.StringIO("hello")) + self.assertListEqual(list(s), ["hello", "world"]) + + def testPushSourceStreamDebug(self): + s = shlex.shlex("") + stream = io.StringIO("hello") + s.debug = 1 + with patch("builtins.print") as mock_print: + s.push_source(stream) + mock_print.assert_called_once_with(f"shlex: pushing to stream {stream}") + + def testPushSourceNewfile(self): + """shlex.push_source sets infile to newfile; pop_source restores the original on exhaustion.""" + original_file = "original.sh" + new_file = "new.sh" + s = shlex.shlex("b", infile=original_file) + s.debug = 1 + with patch("builtins.print") as mock_print: + s.push_source("a", newfile=new_file) + mock_print.assert_called_once_with(f"shlex: pushing to file {new_file}") + self.assertEqual(s.infile, new_file) + s.debug = 0 + list(s) + self.assertEqual(s.infile, original_file) + + def testPopSourceDebug(self): + """pop_source emits debug output when debug is set.""" + s = shlex.shlex("b") + original_stream = s.instream + s.push_source("a") + s.debug = 1 + with patch("builtins.print") as mock_print: + list(s) # exhausts pushed source and triggers pop_source internally + mock_print.assert_any_call(f"shlex: popping to {original_stream}, line 1") + + def testErrorLeaderTracksPosition(self): + infile_label = "test.sh" + s = shlex.shlex("line 1\nline 2", infile=infile_label) + list(s) + result = s.error_leader() + self.assertEqual(result, f'"{infile_label}", line 2: ') + + def testErrorLeaderOverrides(self): + s = shlex.shlex("foo", infile="original.sh") + infile_label_override = "override.sh" + lineno_override = 42 + result = s.error_leader(infile=infile_label_override, lineno=lineno_override) + self.assertEqual(result, f'"{infile_label_override}", line {lineno_override}: ') + + def testNoClosingQuotation(self): + s = shlex.shlex('"foo') + with self.assertRaisesRegex(ValueError, "No closing quotation"): + list(s) + + def testNoEscapedCharacter(self): + s = shlex.shlex("\\", posix=True) + with self.assertRaisesRegex(ValueError, "No escaped character"): + list(s) + + def testSourcehookStripsQuotes(self): + with tempfile.NamedTemporaryFile(mode="w", suffix=".sh", delete_on_close=False) as f: + f.write("hello") + f.close() + s = shlex.shlex("") + newfile, stream = s.sourcehook(f'"{f.name}"') + stream.close() + self.assertEqual(newfile, f.name) + + def testSourcehookAbsolutePath(self): + with tempfile.NamedTemporaryFile(mode="w", delete_on_close=False) as f: + f.close() + s = shlex.shlex("", infile="/some/dir/main.sh") + newfile, stream = s.sourcehook(f.name) + stream.close() + self.assertEqual(newfile, f.name) + + def testSourcehookRelativePath(self): + with tempfile.TemporaryDirectory() as d: + fpath = os.path.join(d, "included.sh") + with open(fpath, "w"): + pass + s = shlex.shlex("", infile=os.path.join(d, "main.sh")) + newfile, stream = s.sourcehook("included.sh") + stream.close() + self.assertEqual(newfile, fpath) + + def testSourceInclusion(self): + """shlex.source sets a trigger keyword: when the lexer reads a token equal + to it, the next token is consumed as a filename and passed to + sourcehook, which returns a stream to push onto the input stack. + Tokens flow from that stream first, then resume from the original. + """ + s = shlex.shlex("trigger filename remaining") + s.source = "trigger" + s.sourcehook = lambda f: (f, io.StringIO("included")) + self.assertEqual(list(s), ["included", "remaining"]) + + def testGetTokenPopsPushbackDebug(self): + s = shlex.shlex("") + s.push_token("hello") + s.debug = 1 # set after push_token to isolate the pop-token branch + with patch("builtins.print") as mock_print: + tok = s.get_token() + self.assertEqual(tok, "hello") + mock_print.assert_called_once_with("shlex: popping token 'hello'") + + def testDebugWhitespaceInWhitespaceState(self): + s = shlex.shlex(" a") + s.debug = 2 + with patch("builtins.print") as mock_print: + list(s) + mock_print.assert_any_call("shlex: I see whitespace in whitespace state") + + def testDebugWhitespaceInWordState(self): + s = shlex.shlex("a b") + s.debug = 2 + with patch("builtins.print") as mock_print: + list(s) + mock_print.assert_any_call("shlex: I see whitespace in word state") + + def testDebugPunctuationInWordState(self): + s = shlex.shlex("a(") + s.debug = 2 + with patch("builtins.print") as mock_print: + list(s) + mock_print.assert_any_call("shlex: I see punctuation in word state") + + def testDebugRawToken(self): + s = shlex.shlex("hello") + s.debug = 2 + with patch("builtins.print") as mock_print: + list(s) + mock_print.assert_any_call("shlex: raw token='hello'") + + def testDebugEOFInQuote(self): + s = shlex.shlex('"oops', posix=True) + s.debug = 2 + with patch('builtins.print') as mock_print: + with self.assertRaises(ValueError): + list(s) + msgs = [call.args[0] for call in mock_print.call_args_list] + self.assertTrue(any("EOF in quotes" in m for m in msgs)) + + def testDebugEOFInEscape(self): + s = shlex.shlex("oops\\", posix=True) + s.debug = 2 + with patch("builtins.print") as mock_print: + with self.assertRaises(ValueError): + list(s) + msgs = [call.args[0] for call in mock_print.call_args_list] + self.assertTrue(any("EOF in escape" in m for m in msgs)) + + def testDebugStateTrace(self): + s = shlex.shlex("a") + s.debug = 3 + with patch("builtins.print") as mock_print: + list(s) + mock_print.assert_any_call("shlex: in state ' ' I see character: 'a'") + @cpython_only def test_lazy_imports(self): import_helper.ensure_lazy_imports('shlex', {'collections', 're', 'os'}) From 731d94d8cad0e8dbeac16c74b2672b1a349fee94 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 22 Jul 2026 10:48:25 +0200 Subject: [PATCH 790/818] [3.15] gh-154441: Skip the scheduler tests if the API requires privileges (GH-154442) (GH-154447) DragonFly BSD requires privileges to use the scheduler API, even for the calling process. (cherry picked from commit cbd15390e474e254ad2590c57de7e3bf657c0a09) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --- Lib/test/test_os/test_posix.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_os/test_posix.py b/Lib/test/test_os/test_posix.py index c0cbc3e4e2e7d1..38066a5426090a 100644 --- a/Lib/test/test_os/test_posix.py +++ b/Lib/test/test_os/test_posix.py @@ -46,7 +46,8 @@ def _supports_sched(): try: posix.sched_getscheduler(0) except OSError as e: - if e.errno == errno.ENOSYS: + # DragonFly BSD requires privileges to use the scheduler API. + if e.errno in (errno.ENOSYS, errno.EPERM): return False return True @@ -1451,6 +1452,7 @@ def test_bug_140634(self): del sched_priority, param # should not crash support.gc_collect() # just to be sure + @requires_sched @unittest.skipUnless(hasattr(posix, "sched_rr_get_interval"), "no function") def test_sched_rr_get_interval(self): try: From 074a365c5b377b920ac345b777f14d0150ad3244 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 22 Jul 2026 10:49:42 +0200 Subject: [PATCH 791/818] [3.15] gh-154366: Fix test_asyncio.test_sendfile timing out on DragonFly BSD (GH-154367) (GH-154371) A 4 KiB receive buffer makes DragonFly defer every window update to the delayed ACK timer, so each buffer worth of data costs 100 ms. Use a larger socket buffer there; it is still small enough to pause the protocol long before all data is sent. (cherry picked from commit a6e1b836ec5055cbc8be477ca0c2df0cc12b8cb5) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --- Lib/test/test_asyncio/test_sendfile.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_asyncio/test_sendfile.py b/Lib/test/test_asyncio/test_sendfile.py index 7afd7de3bb936e..bdc3aa604a158f 100644 --- a/Lib/test/test_asyncio/test_sendfile.py +++ b/Lib/test/test_asyncio/test_sendfile.py @@ -98,7 +98,12 @@ class SendfileBase: # 64 KiB page configuration. DATA = b"x" * (1024 * 17 * 64 + 1) # Reduce socket buffer size to test on relative small data sets. - BUF_SIZE = 4 * 1024 # 4 KiB + if sys.platform.startswith('dragonfly'): + # A smaller buffer makes every window update wait 100 ms for the + # delayed ACK timer. + BUF_SIZE = 32 * 1024 # 32 KiB + else: + BUF_SIZE = 4 * 1024 # 4 KiB def create_event_loop(self): raise NotImplementedError From 314e753c084ebcf6a1b311d64f5aff0547eef10a Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 22 Jul 2026 11:36:14 +0200 Subject: [PATCH 792/818] [3.15] gh-154437: Fix test_getcwd_long_path on DragonFly BSD (GH-154438) (GH-154454) DragonFly BSD raises EFAULT instead of ENAMETOOLONG when the path exceeds PATH_MAX. (cherry picked from commit 1bf86c134a5260876ad31fb32b832cbea24c21ad) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --- Lib/test/test_os/test_os.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_os/test_os.py b/Lib/test/test_os/test_os.py index f9919e824b1abe..c6d20447086ae4 100644 --- a/Lib/test/test_os/test_os.py +++ b/Lib/test/test_os/test_os.py @@ -156,7 +156,8 @@ def test_getcwd_long_path(self): # ("The filename or extension is too long") break except OSError as exc: - if exc.errno == errno.ENAMETOOLONG: + # DragonFly BSD raises EFAULT for a too long path. + if exc.errno in (errno.ENAMETOOLONG, errno.EFAULT): break else: raise From e8206b6ca51cc4e50431298357c55195c2a51e35 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 22 Jul 2026 11:49:29 +0200 Subject: [PATCH 793/818] [3.15] gh-154014: Initialize cold executor vm_data fields (GH-154142) (GH-154457) gh-154014: Initialize cold executor vm_data fields (GH-154142) (cherry picked from commit d1174a48ea8fda8bd0057f10e9776ec148276100) Co-authored-by: Bhuvansh <bhuvanshkataria@gmail.com> --- Lib/test/test_capi/test_opt.py | 10 ++++++++++ .../2026-07-19-16-18-25.gh-issue-154014.CJsjVL.rst | 2 ++ Python/optimizer.c | 7 ++++++- 3 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-07-19-16-18-25.gh-issue-154014.CJsjVL.rst diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py index 9f0427172b5048..b2439dfdeb7a22 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -5102,6 +5102,16 @@ def f(): f" {executor} at offset {idx} rather" f" than expected _EXIT_TRACE") + def test_jit_shutdown_after_cold_executor_creation(self): + script_helper.assert_python_ok("-c", textwrap.dedent(f""" + def f(): + for x in range({TIER2_THRESHOLD + 3}): + for y in range({TIER2_THRESHOLD + 3}): + z = x + y + + f() + """), PYTHON_JIT="1") + def test_enter_executor_valid_op_arg(self): script_helper.assert_python_ok("-c", textwrap.dedent(""" import sys diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-07-19-16-18-25.gh-issue-154014.CJsjVL.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-07-19-16-18-25.gh-issue-154014.CJsjVL.rst new file mode 100644 index 00000000000000..6bdcf83725168a --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-07-19-16-18-25.gh-issue-154014.CJsjVL.rst @@ -0,0 +1,2 @@ +Fix a JIT assertion during interpreter shutdown by initializing ``vm_data`` +fields for cold executors that bypass ``_Py_ExecutorInit()``. diff --git a/Python/optimizer.c b/Python/optimizer.c index db258fff22cdd1..a39d0494ddc5d5 100644 --- a/Python/optimizer.c +++ b/Python/optimizer.c @@ -1830,6 +1830,11 @@ make_cold_executor(uint16_t opcode) Py_FatalError("Cannot allocate core JIT code"); } ((_PyUOpInstruction *)cold->trace)->opcode = opcode; + // Cold executors bypass _Py_ExecutorInit(). + cold->vm_data.valid = true; + cold->vm_data.pending_deletion = 0; + cold->vm_data.code = NULL; + // This is initialized to false so we can prevent the executor // from being immediately detected as cold and invalidated. cold->vm_data.cold = false; @@ -1837,7 +1842,7 @@ make_cold_executor(uint16_t opcode) cold->jit_code = NULL; cold->jit_size = 0; if (_PyJIT_Compile(cold, cold->trace, 1)) { - Py_DECREF(cold); + _PyExecutor_Free(cold); Py_FatalError("Cannot allocate core JIT code"); } #endif From 5f3b228b6b209a3d88f10be250445404ec295283 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 22 Jul 2026 13:44:19 +0200 Subject: [PATCH 794/818] [3.15] gh-154272: Skip forkserver tests when the start method is unavailable (GH-154274) (GH-154468) (cherry picked from commit 13e3f8aa839d71285f3408241b0518da499eac39) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --- Lib/test/test_concurrent_futures/util.py | 2 ++ Lib/test/test_multiprocessing_forkserver/__init__.py | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/Lib/test/test_concurrent_futures/util.py b/Lib/test/test_concurrent_futures/util.py index 2a9e55152b82d5..1dad78f08e7af5 100644 --- a/Lib/test/test_concurrent_futures/util.py +++ b/Lib/test/test_concurrent_futures/util.py @@ -139,6 +139,8 @@ def get_context(self): self.skipTest("require unix system") if support.check_sanitizer(thread=True): self.skipTest("TSAN doesn't support threads after fork") + if "forkserver" not in multiprocessing.get_all_start_methods(): + self.skipTest("forkserver start method is not available") return super().get_context() def create_event(self): diff --git a/Lib/test/test_multiprocessing_forkserver/__init__.py b/Lib/test/test_multiprocessing_forkserver/__init__.py index 7b1b884ab297b5..162adf2071f732 100644 --- a/Lib/test/test_multiprocessing_forkserver/__init__.py +++ b/Lib/test/test_multiprocessing_forkserver/__init__.py @@ -1,3 +1,4 @@ +import multiprocessing import os.path import sys import unittest @@ -12,5 +13,10 @@ if not support.has_fork_support: raise unittest.SkipTest("requires working os.fork()") +# The forkserver start method requires passing file descriptors over a Unix +# socket, which is not available on every platform (e.g. Solaris/illumos). +if "forkserver" not in multiprocessing.get_all_start_methods(): + raise unittest.SkipTest("forkserver start method is not available") + def load_tests(*args): return support.load_package_tests(os.path.dirname(__file__), *args) From cd60bb7cd2ecb5ea5549794b2984a9bd60a77613 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 22 Jul 2026 14:16:11 +0200 Subject: [PATCH 795/818] [3.15] gh-153872: macOS: free-threading support is installed by default on Python 3.15 (GH-154103) (#154479) Co-authored-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> Co-authored-by: Petr Viktorin <encukou@gmail.com> --- Doc/using/mac.rst | 58 ++++++++++-------- Doc/using/mac_installer_01_introduction.png | Bin 190852 -> 157280 bytes Doc/using/mac_installer_02_readme.png | Bin 204902 -> 212896 bytes Doc/using/mac_installer_03_license.png | Bin 120419 -> 141311 bytes .../mac_installer_04_installation_type.png | Bin 125352 -> 120084 bytes Doc/using/mac_installer_05_custom_install.png | Bin 169369 -> 169504 bytes Doc/using/mac_installer_06_summary.png | Bin 157956 -> 155251 bytes Doc/using/mac_installer_07_applications.png | Bin 104859 -> 91254 bytes .../mac_installer_08_install_certificates.png | Bin 174152 -> 169299 bytes ...taller_09_custom_install_free_threaded.png | Bin 192812 -> 187689 bytes 10 files changed, 31 insertions(+), 27 deletions(-) diff --git a/Doc/using/mac.rst b/Doc/using/mac.rst index 6cf945de5b3f3b..a01dabbf2475aa 100644 --- a/Doc/using/mac.rst +++ b/Doc/using/mac.rst @@ -29,8 +29,8 @@ Installation steps For `current Python versions <https://www.python.org/downloads/>`_ (other than those in ``security`` status), the release team produces a **Python for macOS** installer package for each new release. -A list of available installers -is available `here <https://www.python.org/downloads/macos/>`_. +A list of available installers is provided on the +`macOS downloads page <https://www.python.org/downloads/macos/>`__. We recommend using the most recent supported Python version where possible. Current installers provide a `universal2 binary <https://en.wikipedia.org/wiki/Universal_binary>`_ build @@ -39,14 +39,14 @@ supported by a wide range of macOS versions, currently typically from at least **macOS 10.15 Catalina** on. The downloaded file is a standard macOS installer package file (``.pkg``). -File integrity information (checksum, size, sigstore signature, etc) for each file is included +File integrity information (such as checksum, size, and Sigstore signature) for each file is included on the release download page. Installer packages and their contents are signed and notarized with ``Python Software Foundation`` Apple Developer ID certificates to meet `macOS Gatekeeper requirements <https://support.apple.com/en-us/102445>`_. For a default installation, double-click on the downloaded installer package file. This should launch the standard macOS Installer app and display the first of several -installer windows steps. +installer steps. .. image:: mac_installer_01_introduction.png @@ -73,8 +73,8 @@ display. For most uses, the standard set of installation operations is appropria By pressing the **Customize** button, you can choose to omit or select certain package components of the installer. Click on each package name to see a description of what it installs. -To also install support for the optional free-threaded feature, -see :ref:`install-freethreaded-macos`. +For details of the optional free-threaded feature, which is installed +by default, see :ref:`install-freethreaded-macos`. .. image:: mac_installer_05_custom_install.png @@ -98,7 +98,7 @@ for its use. .. image:: mac_installer_08_install_certificates.png -If ``Successfully installed certifi`` and ``update complete`` appears +If ``Successfully installed certifi`` and ``update complete`` appear in the terminal window, the installation is complete. Close this terminal window and the installer window. @@ -171,7 +171,7 @@ be certain of what you are about to run. .. _alternative_bundles: -Alternative Distributions +Alternative distributions ========================= Besides the standard ``python.org`` for macOS installer, there are third-party @@ -199,7 +199,7 @@ other libraries, and are not maintained or supported by the core Python team. .. _mac-package-manager: -Installing Additional Python Packages +Installing additional Python packages ===================================== Refer to the `Python Packaging User Guide`_ for more information. @@ -211,7 +211,7 @@ Refer to the `Python Packaging User Guide`_ for more information. .. _gui-programming-on-the-mac: -GUI Programming +GUI programming =============== There are several options for building GUI applications on the Mac with Python. @@ -241,19 +241,22 @@ A number of alternative macOS GUI toolkits are available including: supports desktop operating systems. -Advanced Topics +Advanced topics =============== .. _install-freethreaded-macos: -Installing Free-threaded Binaries +Installing free-threaded binaries --------------------------------- .. versionadded:: 3.13 +.. versionchanged:: 3.15 + Free-threading support is now installed by default. + The ``python.org`` :ref:`Python for macOS <getting-and-installing-macpython>` -installer package can optionally install an additional build of -Python |version| that supports :pep:`703`, the free-threading feature +installer package installs, by default, an additional build of +Python |version| that supports :term:`free threading` (running with the :term:`global interpreter lock` disabled). Check the release page on ``python.org`` for possible updated information. @@ -262,14 +265,15 @@ there is some additional overhead in single-threaded workloads compared to the regular build. Additionally, third-party packages, in particular ones with an :term:`extension module`, may not be ready for use in a free-threaded build, and will re-enable the :term:`GIL`. -Therefore, the support for free-threading -is not installed by default. It is packaged as a separate install option, -available by clicking the **Customize** button on the **Installation Type** +As of Python 3.15, free-threading support is installed by default. +It is packaged as a separate install option, which can be deselected +by clicking the **Customize** button on the **Installation Type** step of the installer as described above. .. image:: mac_installer_09_custom_install_free_threaded.png -If the box next to the **Free-threaded Python** package name is checked, +If the box next to the **Free-threaded Python** package name is checked +(as it is by default), a separate :file:`PythonT.framework` will also be installed alongside the normal :file:`Python.framework` in :file:`/Library/Frameworks`. This configuration allows a free-threaded Python |version| build to co-exist @@ -284,7 +288,7 @@ Known cautions and limitations: the free-threaded interpreter, and |python_x_dot_y_t_literal_config|, a configuration utility which may be useful for package builders. Since :file:`/usr/local/bin` is typically included in your shell ``PATH``, - in most cases no changes to your ``PATH`` environment variables should + in most cases no changes to your ``PATH`` environment variable should be needed to use |python_x_dot_y_t_literal|. - For this release, the **Shell profile updater** package and the @@ -367,8 +371,8 @@ the macOS command line :command:`installer` utility lets you select non-default options, too. If you are not familiar with :command:`installer`, it can be somewhat cryptic (see :command:`man installer` for more information). As an example, the following shell snippet shows one way to do it, -using the |x_dot_y_b2_literal| release and selecting the free-threaded interpreter -option: +using the |x_dot_y_b2_literal| release and deselecting the free-threaded +interpreter option: .. parsed-literal:: @@ -378,7 +382,7 @@ option: curl -O \https://www.python.org/ftp/python/\ |version|\ .0/${RELEASE} # create installer choicechanges to customize the install: - # enable the PythonTFramework-\ |version|\ package + # disable the PythonTFramework-\ |version|\ package # while accepting the other defaults (install all other packages) cat > ./choicechanges.plist <<EOF <?xml version="1.0" encoding="UTF-8"?> @@ -387,7 +391,7 @@ option: <array> <dict> <key>attributeSetting</key> - <integer>1</integer> + <integer>0</integer> <key>choiceAttribute</key> <string>selected</string> <key>choiceIdentifier</key> @@ -400,7 +404,7 @@ option: sudo installer -pkg ./${RELEASE} -applyChoiceChangesXML ./choicechanges.plist -target / -You can then test that both installer builds are now available with something like: +After a default install, you can test that both builds are available with something like: .. parsed-literal:: @@ -425,7 +429,7 @@ You can then test that both installer builds are now available with something li .. _distributing-python-applications-on-the-mac: -Distributing Python Applications +Distributing Python applications -------------------------------- A range of tools exist for converting your Python code into a standalone @@ -442,7 +446,7 @@ distributable application: * `PyInstaller <https://pyinstaller.org/>`_: A cross-platform packaging tool that creates a single file or folder as a distributable artifact. -App Store Compliance +App Store compliance -------------------- Apps submitted for distribution through the macOS App Store must pass Apple's @@ -464,7 +468,7 @@ This patch is not normally required to use CPython on a Mac; nor is it required if you are distributing an app *outside* the macOS App Store. It is *only* required if you are using the macOS App Store as a distribution channel. -Other Resources +Other resources =============== The `python.org Help page <https://www.python.org/about/help/>`_ has links to many useful resources. diff --git a/Doc/using/mac_installer_01_introduction.png b/Doc/using/mac_installer_01_introduction.png index 1999f3a37590933a4ca77774d51bfc06e9322010..81e1f4e5ac5c32e6c33cb5ebb8e36bd07d780a83 100644 GIT binary patch literal 157280 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 b|IdcOB#D-qelGa(e^uvD7tXx3#NhuA{#;`4 literal 190852 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 diff --git a/Doc/using/mac_installer_02_readme.png b/Doc/using/mac_installer_02_readme.png index a36efaf7d50fd6a29762f6bcd1c311db36ba511b..7e4a9b15cf94f6acf37dec18a985a5adfa5bf99e 100644 GIT binary patch literal 212896 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 Tvf2&dU?1&g22U&1>>~aj9`2kU literal 204902 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 diff --git a/Doc/using/mac_installer_03_license.png b/Doc/using/mac_installer_03_license.png index 598c22a13d9e62e55d5b85b89d4e205a9830e9ad..153daa780efa9e996b63ce36c3e65d01260cad74 100644 GIT binary patch literal 141311 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%0D2**_5nnD99sHv0t+!0oWm2y+vE1q-g<mJ8@*$P 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 literal 120419 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 diff --git a/Doc/using/mac_installer_04_installation_type.png b/Doc/using/mac_installer_04_installation_type.png index 9498fd06240a4ed3821a31ca4f194a0fdcd647f2..1fc597c2427ab7663647f3daa3ed71242fe99911 100644 GIT binary patch literal 120084 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 P00000NkvXXu0mjf@02jX literal 125352 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 diff --git a/Doc/using/mac_installer_05_custom_install.png b/Doc/using/mac_installer_05_custom_install.png index 3a201d2f44655af4908048e3b9f92f2e267f1ddb..c70d93bbcee70a888a5c2a1b6d19506e024caa41 100644 GIT binary patch literal 169504 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%0DS6!Jse>a-~_k$?GduxM<BSb_|P7uy0litJ< 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 T6L7+u00000NkvXXu0mjf2iTc+ literal 169369 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 S<ZnN3V6d@1airidHR69@uTp&g diff --git a/Doc/using/mac_installer_06_summary.png b/Doc/using/mac_installer_06_summary.png index 1af6eee2c668cdbeb51fde0b84580ae38b83bbbd..f8a67052ef044795cc835c91d491c25d46790bf5 100644 GIT binary patch literal 155251 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%0D4Xi2* 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 literal 157956 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 diff --git a/Doc/using/mac_installer_07_applications.png b/Doc/using/mac_installer_07_applications.png index c8b3aa1099adfc95fc2cc12c336942ee6b9ebd9f..c39741f33ac807f9ca5cebed692b5f024d3295fc 100644 GIT binary patch literal 91254 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 WUB!W|3bFrv&&a@7zu<!1^Zx;yPPq#J literal 104859 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 R$rXSv7bjQ8R)?VUe*<&_d58c2 diff --git a/Doc/using/mac_installer_08_install_certificates.png b/Doc/using/mac_installer_08_install_certificates.png index c125eeb18aa0c140893a7e1825f059adbd2a759a..f476c7f37d245d6ed5379e42e99f6c048c96b43d 100644 GIT binary patch literal 169299 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%0DVl9^4;3@Q(s4UYyl!5=pj zg5YE%fa2J_Jc2ZS1^S&2r3#11XnEBh@YT&2ulv<JHQcF+jPl2C(QlVVK9Kk7qMCP| z*WFAk+JzB?*PG*;3Ce4h?k&4CUMKBEEAaMe*R*#G5e6q3f;SKVl1yT`WY+*W?yc{j zHEA_GT(F2--d^Jk83l$PW+9D8$B|wl2K0loUc(y>U9o;?n2?-~9CK+%t2yMf!a){~ z5Qip5YH{9tU6^F}`v8S(S|u5bOk^Ymb%c*r22rt-X*(2%TY^iio2n7CVhOSfkik%s z1uO9|G#rJu6iv~g0W}>ZKDZIAo{nl#X|NPpFj6wH;T5lV1<fO`I;VT<BGsPyXF-%v zpx+G7h^j<cz%R)T{M|T+eQ163zXDkA{=%*geSZsJox1HMG!v_R37hS{ZNvhwwj70y zW@2T;%2znCV_Dw4PYW|;?Za5P3o~UwSMy^Sv8K=}qNAAEcZHpIDXfhM69~F$@h%dR z8^Gcs%z|~|2fxmfH`^O$xy)7PX_)P4vxHVtd)0DU`pm7{c?qGGuxY#~E09oWI?pZ* z3!JB+_-QE3NV&{A<-E)*@*<O0#j*eeu=K&s(R34n-VsR)6knR0fB_?C^oZ;$zY%09 zWq?4y$~jgNkG!+XI0p`zY(9zz!Hkuwr0JIU3X(XGmz5}@NMT$G2{V17@qq3oOa&pz zo;;N@o~6=Vj_l={K3enJoXfRijm25AI3zrxWcXBpu^OC5mJ%b%(s{^Gf@SOI-B`DU zb>5QE(zCU7#EiV9p|qQ^-t?vsA4DsCD<h0jBoid7cPM+wWGR`Lj5pIuWp!DhI7kpt zWNC&ro0gkxDX;~Qbt%3`8IwU6pTgDAOvP~7Lsc^_#}f@PgziqcRjBhcnM)Nr%Iz*z zRa&(@d){SnWs&TlzZ*r)@<xo>Se^%=^8Wc>{^huLety@7zkk@rPT9SQu}%wPS#)%4 zO$cUzC{4!N=O|>#+FEBSnDw=7fYpTe4j2or8ebRYF`Q1!nt2Ravk+5L*4SxhIvHzh zAU(lY6APB330MwBHsZF*sK;ob(K~<Wn{BZ)0M^ocHCu;$<{})pYKg9vGuEfy3XZ#O z2ql=AvLco~LE*m^P;5$%n85Q0-I~U@y>r;FyyI$_SGaKJZP3|lZr;J+B@}e#fs9a& z^SBk=Ww!<`lxA=fq=-NISCa(Oyv|*rOF3A{Qv9;qK*P8zYMEwAlxzrde(~dSN=%cD z(#u?RO}Ui<F%w`Za|s9Syv#BaCc1#0aa*$L94bw5AIN)k(ayWhyX=OCxnml{iz>lX z$Cft46H(sc6GJGMFz7<L#$^a#%6ViN+>&I3X}Kfxyd@rK{(V~RBxU7_k!M*m(M!p@ z9K@)H9Utn~ayfP?w@Ql`OiCDikl&31=tE~N!h62&%h&tZ50CuR85^HEed9A{ZhZEv zjnAF4@%eK%zHr{=@ulD1`10>=eC78xzWVzcU;Vu!zV-(jU;o1+zWzr?eDjZw_~xH% zeCtn~kNDP)j`-G}9`T(Y9r5iS9r2x?9P!=F<5u7K@h!gh)0=$vCpY-cPp<u)pB!$X ztjP)v^J5!kjb+~*=$+h!5LHL?5@3ymM*D;?7a@SvLZc^s@Egs+YB`1(q7tHa{8}(9 zHQQ@*VYS*M!v37oEU2uS|M(C8@OQ%B{w-T5ODWQ}YA&69{^8WQk3j^4l^_55uRD;N zVe|iA{^izb`z(k@mB3}RiOu6Eh#zOkoFh>Fit#7w#X9ew|G5apnX}J2>s(&3v(N7A z*!nLZw$JBo-E;Ui?nW*1b}m`BW_gQ5tjJ3$^rGCeDtC3>WbW3y+=%_myL^y1tj>Gx z>gV0hyb=hLyayn&@S{KdQ;lWa77jw*bza2Ic_Ws23kO;*mG%G3E6koZ4)eTa-?7{Z zF8x8T=d$B}VR|?A#nd%R<IlO33;&nBs{n3eNupB>#}_C#W@hFqIKE;$W@cvi%>2U) z#(<gGmShN<nHj`dX@&P@dv`MN`fP=xcvP>tdV6M8G?8Drd%D?A{>y&%4EysA_Lp58 zf7`?UzL))DKl}GVj{h8D_Z(sO0>{|>SsV{!vj=iG9?WGA<*|qJIUYU99y!4tJINk9 z#U2MvvnLDK(?x7Y8QWdO4%V^bj@Rb4y(zza8*wa=m1R_ZzcM}Rj2toCBGrF~lpu<c ziVz_na<GnwBZRd^)l`FE?JoP&Q(0g`M6hJ9m0XBH4h!0k3ffNy$}vIkDn!%qLGu_* zPcOc!;gQktiOI>C*(nQ?(=(GZGxDV{8gh1GY8n!k0ADyeHvzkWiRo!Wq2*98Qy9fs zu8V0j3W*_r8;v`Y4oMS)MXeng9mUaSd~<^%qeBKrAK-Gt(uW}hhDOK8P806@wQBA7 z<P`l&x!!%H)~dB?ty*jU`^y*3xGr|PI{RE*ea=ge{XlE?0O0EEcXbasy9T(#We?XO zT|GmD*4|;Kb?N9fl-^+&0cZD6&Bgx0j;;euXYVa{d@H-^BfAUPvxOjAugh`0I=}tp zvNtQYos%sQD>T|g6VrmSx|^ZYC0Z!52kUaH95ciHpya{YS!#N)t}J#XH@&f+7F;up zo#d(*ADmU)UETcygR_fEzHr1Fj`(yP#d-tLcrca-CXy!NrXGSMMTR^ibTO3XOd!3r z_L*v}mQ00`Dean&DQnf*o4v2pTD4ZKRcm#0{xP7ZhiH29QEN&=`^9+NtLrOTcsZ!m z_l?|F+{B(f#rD;_F|Y0ARFxFc3=~2K%@UR0!KkP_sT4Gn!i7>XQo9F>Cx{7x#dEN% zB=@pUBgvfzmPM_|ePur<2%UJ9EZ6J@N#_^ft?lXSTSUk>8uLYC?ufn;jsVLV5WcZk zB0#?hP*@6SONNvnF2#^!k?m@2rmVf0TS!4cK><H9iy`f1U@2t&f`MazY<To2_*Nhm zKR+?^gRDyST=AQzuZ~sxT@=l-HP~6J9w`*5qmF2mLrL!DDZ(ujBE%`e{WV62u#$VQ zo-hbjG9f2j*;@+Q8wi3(2}$|sqB=g3>=0^2TnTT_6OAofZ~JCLK|w)5K|w(QlncZo zlt@56T+zawE_h>Z>&s1=C9<+irX>=y0NIJPMQ|*VmIsSMgn)yN5RwziN^-B}b+Gn= zV3mCK>1-+#YcIzjQ!9I9Q0}-aM+T8}g~Q>)<KzBV9B)!lt6L8R1qB5K1qC>_yn56d zjXhH7V9yp=9II8(ED9GIl8QK(G)ro*BRCe}9HY8hW}ygb_RPz;8@&h*)&L+_#wo(m zPd{;7vj`R*Yc{}<dk8|>Guh?RR%4^1eS?EwSBhHQMkpvKC@3f>Aan?h1?3mHRcvqd zYeA|+RZ>D807Z1yp|tmQs@)(Ld?zU-xl?udD;g0ZL|A2buqr^XJ_&-QAy{eFYPZ)B zC1q8IW;?Zl!~=yGP*Z0)7@~};OoYO+Cc(OdJrkjzprD|j!iC6x@19v;Pn~#WmSd|Z zMhYoqWtk9tb@J>fS?4T*mF2LK+$lcT09XXeN^;*>@~Ov<fif9c?J>E0C`p-GLD8g# z92OMavr&#=WNI4jxXg85DS+(zqY+<3^F_jtew|x3A;(gC_zwH<ul?ImP*6~g101${ zwziEuSNf*BHc%^KR|4e9vNwtbR`rLrnmr$Hw(4Lt0!DnW?s6sfJr!&x4-tkmO&lAv zw{2eYv>+b#zJVyxiegvuC^&1l<2C?(A4A#|xb|Pn@QS9%faMy$gD_4aXfj}dee=K_ z4quv_FS$5X);U|&IbGg0TY7P#Z+hOR!zHO>kJ@nOy13~4<8ny5wzVGG#&<jDQxbdy zy12ZJz=tot2I%q&lP4(L0ox`6pr8VU!C2feJi(qVcvY5TJEc)&JEbnsZ6pnL)h><} z0$Z#oAxUNx!E#z5!Uhm5YD8#-2&)hxq*H|8OrneP`n?5-SFK`KW?z~>U>a4g`ujI_ zUuj{$jlvDdlsjbtIxIAFmDDQi)?@Bi${kO+6I?=v1$K;H6}7_4_C{jCSW1hVfDQ}n zn}%lT^IrGA3NNzV-LKu>`?9@VuRq+o?Lg1>a?W=QjxPoLaA?`#*TX*jPK*fqV)0-y z6-XqnAz+PdJcDK#dNdP*-B)#P*Plq@Q}V|X#3`Wzc>8Nk7N?-yktn3FT>q;T_rYy} z8IMQ21`I(Dpi);Vh3}L<FQ4Freq*0HeJBKsZF8Mp!8#iZpi3bA32A=gSS#+Z;r$^M z?iTk!WFe$|<47qxSpO<wSCD|ru>|ru<ZAE8#M)v73gr-CGe99ic(AsBT><7P!g98w z<kL@Pfij8gD=;cZ(Evv-#~}Nzh*v?8+y9}j&A{lWcm4Es3}NHO6KI;V(AY3vaC$C3 z4-z^ouwyh`j>V_x?r36hWomw)eC}NCY+Dv2bXZ`=Xqva;|K!5DKbjcuOrIL5KHQmq z@O(BTbXZ`==%)CW7SYFMr+<F*{0nz<y>EBtTc5x5w%wiY*?DQp&hGc_yYOJ;;6CTX zUZ7>1!!fqkF}~k9v8QFkIXLCM!#F6oLg&zMNp(%F!#V3s%d0B?Ij?MN`oT|rQqj;r zo|23RN(zDkwgljnr}K<0XU-N?R&{iBW6Ai!Vnst^S#90m)U^GL;}U;RVTbDi{AR%) zAQlVzb-&sqZYwM&OG<zEv!At`Jxl*vgX|p}uWD*OT~>avf55HlIRynj`Q<O1=gwc} zvtv2<B{8}5p@0og?`p-iximO*V-rG%vElxU!4Q4*@;-z@4BI{-eYZ5d;5n}kcc4pi zxpw&l%=-gkdqdtmP*K8I?5{-)Y<I<L=oFx!S=1|<GT&{nLJ=+`Cl<5Vl|vL7<?%rP z9xMtG?yWEijh24u@uP4_Aw;;2?@G>R7sak1iCu}tnSH&zLlcu8azy<<N`&1U2+kLr zTKVqR!=HVB{FCn>K!*i(jIOM62l-Zdd^zNwyLe=|_@i18i<g^#4h!rU#heXqMUJaE zEwHC2`vY~KXAO+CFy`PAIxMhb6m#x+js>^G@YKY&_jRy;wzEGw*zX+dFKz7iF7_uU zxBRJ<{l>*De`)3VUunq2{@DJrBWLG4D`2$g`3Y<mK#OcR$3C>isAdK)@XL5KFP|~? zrLTT<cxD!tFp4Fn0<861|6}hipsYByy@5~M6#{V=+}+*XEd+OWk1G-*H?9zOH{5mb z1c~7`kQ)+`cV`Im{pJ+(o6NuoZ`~~8<E&n1^{LujU9!9Pzy5ny9Xi~jZ$H;|>CqE7 z3vY18|D7K?Ry_CP&Rydle|+%p5g&g&C6GyR?ii<w*q&`a|9jPU->=&69R@D0{2zoF zl754SXz94e9<v+r;?--ex#ns=znV2WR3rVhQoj9Z<HTp4>DIe<+m0PObm=nY?tA7h zTQ2<wH`*U=bmY57Cn~V|`yW=W->_+SQmFsVUw^Azuf95rzWZ(_(1dN);w6=;R4H1b zxWwlsO@ace*R1LMzH#HxT88!56^44GPh7ik6NvELw(ZBLVDWDh|GvjwPKI7`#F76$ z3IA<5j`$VR+hL5Fw{C3+CcX7m(35{?Qj}t>?;k(Dd+*-2wr@Y;_S;{7?|o1{OxlA6 zE?c{9{NodQ_3z)lbC;o`MuFPff7urYV@Xf{pl#W+_odh07&vTr>$Yus_UrfX6Hk~+ z1ehLnr~GW%^ig--bz7%S9lLeA{oZ?LEna*AV;xU^ZDCjsPZfss@wH*2(6F18^MJ7e z!1DcO#(#;1tD<<U1k#7SgaKepKeP$fOR=5Yp98RBs|Ybz<0tKpxd;Pyl^$LB4y;vr z?kWRomHzL+Z7%xL&YedESQ0%3`}S>}F!qn)x1`?IEVWD9)GoKBcD>EFb1Bm0k|9Yx zo@Wr;+5gLy=_7xCKOuES?$nv3QfHP4hjS^?<&q&uK8|M)a@w~4mqGLHOqiN*)6#N9 z5^EM)T00!hrAU`ch9vpp9AItwsmm+NZ~c7dpc%V+PuV?aTGGJjNrPr24Vkff*tFe4 zrzH)ZmNaxm(ui3}!)GK7o3VSywB2n!+u7swRX=Rm<nqi49o%gk3f@!cQyf$!{jEcy z*Ia-;&iAEV^=C*)kDt5;Ba$Wq2ndWwDC)I$-Yrn5P@CJ@1%M^%-^mBUC80`t4<jdU za6dy<$ept^(R+60!bO4Ji0bD2ml)#`YW0si^XkUZH)`69#d_++m((QG!4YIaV}o#< zj%EBf(GtI1TewJ(5~WJbTekeS)Kuw_JW28z8}-$WU-pf>^UhNe5*~m0Y5z5`^qX(0 zRIgU1TsgE~WH=*qwPf|0D%Gp!E0F)f3(mXx>Z`M6xj1L;T*XS3_~@&zBmOD6QHBwB zkV)VFs=>#!VawL)wQA+ak>iW$GyDv-0`ErOb=Trmt93Q``^JvTku%3_9XfvS#TS8E z!?E3d&%MjOJrs}-=cZ25D~!UU6uAS24n5<flm7MG^U6uz1e&QR>UTs1`(NHGF3bvd zQBHK<49|u1ScU&GvUD;GeRO#^&+s#PYK~bro!T73=n%-<cIn~a0*kx!>~+Dp=f3g& z`@j4X04o&!)`uVE%9H!jOS4z5TD57*mRDbM^_5p$F=XV(O-XygbG>lI${Mw6UwiGf z`3n}PRJH0YIdXVp?jJv4_iy{7(TTb`8iJ^N<&3=J&MU6G;>MeAs#>E)-u(Hmz3$r9 zx3$BMhG*^7ciuI@kXxy0l_Eup-jd^%eEIX^bfahC#Bm$|thbk}PI&nJ>tByCPyu6w z<M7hLum@@6G0e(W_}6H6F<7xHCp%^xX0XB%!l~hZa<~Wsz$!g%5-uvlU`4npat?-1 z=C~^#(8?!3D<2W=HfS(Ei0_!#_T1Bd6umLEd;5d!Tc+ODJpCa>x?D1U*HeNp{@6Be z>>tq8oN@=J6-=Fy&v7vJ?T{i}E*X;K<2YrL{^yUomplqZm0Vso_oB)<7FNiy;Lzb* zigdYTNbWtZ_0P+F!%sinHEZk0HGe*|?#~C;9UQy<;6v*Vj@=MDS$A;4hJz2TPdmm* zakAkcnc-{xykquO7rH#-OEU&*)^FLuHhYU9Bx0}Q-+$P#W8LO0KkV2UAdBxUdw-U) zVe2+B!P<SlZTpfn-ymbW%^9J9(MdYTb}+7xgg0hDPT_V6H{X@+Ue4eA;DeiPzPaVC zw+4WP`B=MYvumBR(~DNEa?=<}OOeh;wsF_)Xtqj|+5XLY_5^<fl4ITG&ESZiJdY}7 z-W;sgKLW7UZQ6WW$BsAOa`W?(Cc_yDcXySPt3$MC`MUL?XO7sh3{2$OfKG~+ELpZf z1!UMyyLP!sx=wRK5^7nyX;T1aK^{-QN<H?}Q)vKe%{LV)RVr4ZL<WFmI5sEkY2T@H z>2hTmwr5^`W!9p_=K5WF^Z<_v7A~y!U=AGxny463YSGG7#xC3_SU!WLnLqB_sj5aq zi;!*emoI1P3KuQ<`g`xu2h<2jW3+zDR=L{s?Z!=g1`Y(U5F6ib-%h|YXrwl5O%os- zj3~dM)-7DQ%6I6}$iC{UA9w6r`pviQ7$Ude61@S`cJJLspFjBU!v=TTztc(!xJONp zc}AIrr0)mar~+EIWX&2Xq3}35;6nYsc=c+!icO@D%8!Q6+6&}a=p`vpFS(=2P<|=; zfq-*$c54buX=z2k`i`x~CLFz!Wd+`j8tAA%^oIJAH#*^ga+RW_M7i#z9O=4|CivN@ zTX$;n`up$w_uwNmU(K7eXj!O8;i02O<6nQ;wR_TAZ&$8X?UGBfa`d|kWf*zK9d3$1 zotL;wzdiBXbF`7VE?l`XAU}@3=)nxds%->|0XUbtgs)jAy#3L~b?VoLx1M<RxuE=K zopoxSeEG&b{<tAF#p>3pcb<HCyZ7m9P);nWI6eTD9XhA1*^n^q?Hj@#3+XUcrjV@6 zdp9`J_HIbX^2T8X%k{6!h+?q9HtvV_!TQWL4dup70-pkd6@7rJ%+A5|Zoz=ABKm6Y z-n~glNdOl8K5|en6+iIjj#aCEtx_CW6``xl7)vf0lH^@=<f4)f?%1?+-v<e)vr8YG zRv>jMX!VyvigdYTNRoHe5xe`><b!jzE=!n_P;^<XT#G72=qf$Nk}j7FN%F2bz5&)9 zb9eMynml4z^62HsLsupbTai3sMe^|F$%B_CkM?tA@{kqDLzkze4_Tf(d_{7v#N<0> zZw~+~18x9Z?!5nj#?6}L%ALDj!$yNgj06a1$b^X#D^;sHaM&<bA-w%3KKpE)1`WFQ z?8Rz&Cyssev1YAWdArrDQ@8KHL6{_B!8bAa?RR(wDpanFO=;Vq10R7zw`1U01;l>6 zh7D`gtvm6VXP<oj1(v&ctJci98TmtxJW{f3X-MM5S6{1LzkbCkReJR4oA}MQUb~6{ z6k4@yEA&b$+>67mRJk(a9(_#R;204<bsIK(@wL|<e&SzlO}Nj10n9*VKiV-KnE@7` z$Tino^UO;xd)Kq>n$WIOr*}X3)C?X3F>&Xx02G3$%h0hyMvgMM|06Z^wRhhuSh!HV zMvXW|>o;!Px?MX)QQH?RUqPlp<0i$57uT_)?z$^rP}XR83}8Ka7+{sJRI%t^0Twe1 z^MO-<RH-s$o_gU$6_)aQYAT3u)zw$I{K1DG30R6<ym#zacB@d4BDL$)8-3T^0o^)Y znEYz-QYG(s=pn9K&FR^<uL06D!hSYt)~t5@dJ5FQ;bU$uR;q-ysAQQ6<u!*`vz9G+ z2|t}WO`V609$lt<xtHH~Qxgu~bX=omP0?w}88m#vf)y*J2MF@?i!bS0@-=JM;nw`< z%db>M$=r_h8#OYNE&&`rnKD&rAp)#L>(-^pmMvGIB2AkzcP`ZmMjEW-oT^r%CK?ZL zA3t&8MhcwC^oB8d`{R$>v};$sQl+ZZYjo_|?Tz<801*Q40uI0k4F`qQVZ`lsu=jz1 zd;hb~OO!4J^)ml1$K|Nr)VXs#0!>=9pr{R-G<o6G*C1m<aE!tMWUG?yz5SkhWECx5 zym9kp1BML)nD(Wq!7mR?7+<k!72da3-h8uW-MZCk*7P_`oijHIihA~yNsXH~mqji0 z6>MtU!Qy}F5m@uXk1D22&tpnzDrNp*`wnC(edZ|S3pUEQM%pzuF_G^1_utjueXpKq zR87X+niP$F^wGN?d`RaQ6lH?x-TU<MiU>D)e)8lFUAn?g&@Fk2)Nk-$bnLjt9_Jrl zuwuon?K?;TuMLF9;kikZFTeaUI^gkC+6jPld;qL@>wiob`__#}sIbk#s}aV6nj(Oe z31g-EFP((oSv<^O%}j@`zW!eZ>uEvmA6Z4X4}<kr=b%sK&8`A*6$M>ER{>f@0Bia3 z<-1}N(4z%V?|gD%O09CKoo|Juj&{f;Lz4W_W3m5d$J~2UK1)cQSv(L|nGfl5$&e%; zr>HSY#wN_kR&Z&JTLQYubV!#=h9vppp1~S5XM4A$$-|bV3|^MfZ$-+$Whq0Kr3_o1 zGH^x8faQ*~6UX4?DMMGJ3|f)WbxHD=nHd3Acqy|S-k5DWbOde~B<DWfgPclPvt;4P znzLl7HyvJqj4Y^#8F=JhPdW#TPz#;AcMn%BTf5d<l?Tl^{}d?JqD>pt#m`T^p5k@P zWU?*=3Kc9}wyYqYtFOL_fv;M#M$;B8H^cyz%H+tIleH^dwp`r?4NZ=jH%6{R>C!Nn zpU^|O3KdXCOcxK7lJB_pJ`GvBabw*E4NyBJOP4BEq9o|UDrd=Z5yZoErC0bsX&lS3 z_b34C>6c#iu7`&%$&wZ9(3XmoD}xu+YSd7lXJ39r-Q0A<9Y^k178g7MRn@Rb^XBb3 zcNX2H@F38jNfU7=<ttV^>-1BgTfkH#@31jr{uW>{Z>Y8G*|PzrcpzDxbh(cC%U4XF zzW}t=58~BE-kDZ0rk$bEX=j{vO7H#ya3RL-(I=nEdhx}2@5Y;M%#$}y?*RkYOFbXV zIhPRoiXBu=Fy7Bke$|-PfD{`w)&tNa?g2jsf_LlHi@=jFyhwSFE+g)^lV8d3p;dHR z?!0+?3m4O|cR%<bNsb<1ntBwA1#-c!jJKNx=+>lp3wi=UDoqETfBrf73l!+us~0rJ z3B|zASg??SsavVCW%B0BH)!~9FwxK`O7CUR0bXos@b0Id-EiZLa2PFZecNq-G@WHs z8`0K=39iK*ic4{dyGwD31rP34+#QM*w_=6j0YZ`D?oM%s;_hx=dhh-6i?za<%*>f{ z_TKNF^FFVcB{{HcE#c87%yB%aM=Nbe@crsC6PsRAor?IdNQ!A6G%AclQfJuKcj4NL zdcxs*Go+~KNe8IGua6WCqb|o*^?LPg0XyZhjXg7Cei0;Jt^RPsr8BF(|E8L1I~$G1 zJO}wS%^?5~oDg`jSB*?k=D6IQU>LD(Cjfxoo@f#l?^nefTUBs_5GX&_4&(;tk>|^b zI5E<cFnt1{$s-`S?henkyIQ4gWBlIVgc|HLUle~o_1TbUZlj8*s_J+Z6tQny#V%NC zwW?;3DkkgYxG9WFUiVp6%?T<i=m99vphd*Jciqv_33=L9%}?G!1XbSKD0YWBt>HD8 zAVH{O@zr$!mPIk%o@8tFT>wxb3`7!}6LIA3hoP(q3;Nu2o(mK+Ld5dg0r|r5x9Z~? zuF8TOH)?Zqc4+%uuV{<snTnEu2X_#i%WrUih=x9|yu&)vyUrxVi0xB;nU~w;Ty~OT zl@=y<Jqh5Ub)>;Z+98U{(wvSLZC~y0_A${e2;HCMgtnnI<(k$2UuU!b-0f*hG7^39 z^(UoJwHN3_HOT!4U#FmSz;0ndQupPw#nW^c(u?OdzwaFg0793;={|h#l9(`yJP5m= z#{vyv|5JQh>v_o4`uzr+?p68)uGT~*Gs7;$!bd{6C$Za^=?u6tA<H2avYQ<`yJAPZ zp@K+ptgdo&#F4R&ZEp{I<BRz4Q5D7GIXV@NBJ@qVBiaB^ml6@4_P~ijjDZO&7VDYc z<);l+g*3J?iO$sx3;#Pf%v|4b-O<|J^Rge@-0<4xa~{|G%Y<tme|YAu#f7j>adT~W z4cz85cQZd(qZ0&$$4e5{n0u~x=B0}ory4W@bR>WSADxH=Z;R%Q21+F)9}@(uUKcku zXtpqMNaH2c`7R%mSN~vEv_GjJM8uNdQ-H!1vUZH!rVwH&aEpqF(~l_lL6H395w;dQ zx*n}PS$>pR?M9(T6cIueP5DA-0ZM$LMLZeDPT%Y9f8Li4s5v0sK+ouL`aqF=C}v)2 z+DB9C-4(pxIhh~B-i);*Yu346lIN3TdJxf1Z3Bya`PZ&m9mfwn6*s;(*ZKV|!fwx3 z>zsI=d>sQ90db17kNJs|XMPB%lYB3+x3WMZ=hvn~n)Eq~kz9<T;aj_Rr*dx{x2G-K z+K!LEQ8h3czrNvKg#P`j+Ylk1T1tKNj$aTd#EMmq_W0mvv9_!0YFua;nFO{6o;!ur z_<dqwDKxT&>XF#3j8+-nNv%yzSfm?A2>$WF5FjwIKy03>H2H{`PfBb`2x~4VS6@b; zhxXSEpVG9kM(%Sy0VY~`#!sj6(zjIODpQ#nHE0@i!yh3BimVwV+t`uCRLa;$l-A0+ zo&19sM@njpN?`I5Sh8Oukib?ywXj>MXG2(zIdxacQ~j<+LtCEmV-sN<;hXz*Fos*9 zU`1#Ne_&V0nEvkvQN#{dL3EmZQjH2&zP(0^$L9xAwr`k^hwz<`H=V&+q`&Ef&mWbk zghfR9VJknX>w>fq<$j!nWlU}&dqRmEH>R;&IGgWb=D48S0Y91<*D!LRb_!Dar;6?~ z!GMwVWGK4cM~(aifDN_V8thV+8V<TVSpUMXK<mh)Z#pxPsTx*m&d#>M{4oDgW|!zo z`SkCf_lAp#Tv@?*NT8vA;S<V=>K|Q;Pa%P@6tUyj$;38ByXd^&Xgsni5{ETLC+feb z>q2x)zswg6neCnq!a#cedPQcHttWBGE#H#A_rLt)f;not@Fi-r4KuFoHR7lZzHNqI zBZDmYp4H}R#25*KH0|ZjaoPt?MW=v!DpImB17co!)K{;!D|T_}isvAlDFN_h2Xw{$ zqsXrHmD7~muv<PO<+t_fE>>srUAyaqD6aXBBFdDJtL-uU3dbc9soUM<IMPhquG-^L zg*Ep#xN>;QGNu+%Ahl)ekIx@_`u(F~rwXvPj}pc!W`B)U4&uNsV`I+5IQ>v$=Cem0 zJpKw36B(0f^+C!)QxxKpkH`r5@Zn(2<K&~K{Q^rg3JZ{NEZyo2fe`T(<#7tNMWs`` z8O^iXi#Fhi)nZrhSwE-<OQkc0y&VfcK%GY&=nrD~8K$u2cBTA?ipdZZp*o2QCrsBa zX9I1JFta&LSBWeazrpcqxMmlOo0DX6MnxoP+;^i*^f)27BFh^4UC8*gbWI@q`Z_Fl zvkmXbN!Gb@GjEKkX<~Z4Jux&iEUj`+uOuE$Y;#XKzH!^UyJRPT(PN40=r%;B3nS{e zNCEfAx8g?A=(^tM(uvCg>mg26swThm4qH&+zP5#w-hkw5@$={t@+5F@BgtMjxP(%? zM(b1aK4&X5^EaZ27F#mSKg;jpukE6NqEn(;_W9ZkmsDnNz8Qu0qbH0X{HfhLD51@; z9GoqfRuOn`3U6wV$`GT&KK!}+o+1>%e9QM-KjK@-{qxm$%hl`C?D~Gt!PmT_st%QT z?*wMea&-9b?><n)lI(4T@8#U-5K>vlbK26&mlhU^!L|vxAMt_))zsaHsTUacDo>Wx z4SS@O5IB@DMJ^eY2n3m6SmO0G>A*^nQ+1Z6)=NQgrljCe@%3f`WVEkp;e{>xxcKx= zSY7^@u#slma;S`BDD4EI1P^z^`cCAYEne9$K>c?Bu#Tmq9Cp9L8Cxs?egqA9e>4$` z<YrbUi2RkNdxN4*S&9YmsPJ-&fs+qrjv_NVG?Nc6yn@;dUpO>h>+^A~>)v=#R8$E1 z-~56$@}-|^k9ROJ=tEvGBUKj^T2TP77kb)%q8L8t<<ah;%)Qz`?~n*a`$N+9Hz@VV zXYSTfF-d}PWflv@t|_?=&JMvH0F;6OOP@1SR>DBy$wDo7M<=M``5Q|eTQ6ig!-KE0 zEW6p;_hGp#Yfci>wkh0zb?a80;<9`O?yEQRa0D!5`JJSU9}!Wof8Be2^+w<-*ah>g zc!lm~pHts<^Zb}dWVRaNjf5cx%u{@yea;b7<e1HG`4*SO8!il#=>PU%EQjwbHXMx$ z4ou*nXYA64pRWWoM8Mb{PafFzau5uniz)NKU+MoyexW7>`KaH(0-In+gaitXfSt`8 z1(D?WT*%N}9R*`M!lRPanEilXYnBX0GlMMrfbqv;dsKEp+SLEDyG_JufY+(#%L2p9 zeUh1OJpScErrGZ1Ze7mTXb{61@q=VPe>o2Smz`7{sI%>2Np=d1;l(i37j6QY9a#f) zMhXCoLc+dehPYYyc7+2xgsqVh15}oqr<cQHr_B?KaYPm5{$<qUuy_H_Z0bYA_)ug~ z$`ULcvL#Y@=4MzAg_OrME8mfM8)_LdgYT^(5UTg>tAz{p$nHz+<hhRP%EFHgp(C-+ zey8vQ7J86pD5>w|xTYl;``@iHx{0iir{(Yl1}viPaB><L+7ex3z;p}z2<)}i_m!}z zr`tcwxm&G9ac=su5fHu{ih)yb-YEXlKDeim;&+%dElew7kUL9vV@(hfrD3e$eso1u zb2Le5ltTH#SMDHpHX?G^L7e$2p7_ODivbYIUdL_o5&yabCoTj29ChL+Vp9k#nuU6~ zn~S=fFZ^|28Vey>)YjW9>r`#eJo<_5;=oZ{iaX(jM}E?uQR)!K1kW&MCAHLXN?4TE z=SNcbkgadBJoZbPI~V#S7AY1o_aDHZ{nd^Rh8nk~FVlo93DhDa66*zH!fNswVR;z| zTh7c&xG+br^Nu(o_yBOnJ?h>of>~SQf!GfK7&2wu_!%1jvWOxATXn!g-a#7%Mw`!D z)bQmAKym!oRPQm+Zs{$SC%))&Xp6_G!7uZnDVVf78@;)NfHKy@5|6KY)G7Z2ei1ol z+cziQcH3ORo68xS@V~wPqR>a>S8KNJmkyrnX{wQKYHtD^6ztRgm2q!xaGi%W+^iA) zAmldK%8hcOy34p}l4Dv<j4v*fr~zl=GW=HhFu+X0&n5<q1>(5A^xj9DiuX)G5hnfW zoQBk@%ChVoe^E=RTfzQjKiVG-7%C#+*<A&4@VIbDJ<oQ#OkydB#JW8A@8KLpt92X^ zbU1%6{<6@*gW%t0$j&+gK#)IhEc2JS94BW1k7dX%bDGLCkz$HJx$JwR$*@6&9*Y(L zPz@(V;ETIu&`#TgH^Z7XiqXo&x4|g_BoM$4MjJ@VzQzaxhN#Wc5eueCC4WPQz(7#1 zYEsz3yG-2-pRN_zn+P00%<%V05Nt=VSJ~$QWQb(K6H;Daum!eEd{HQ9W|&XEk5K!U z8!;n81bbdT_T{=nk7QvGiaGw5aGP{Ajwb9}#LfbyuB8Kg&MiS)OZW6bI4~4jcBJYa z00T@&=!;dud$0HvzZ`A~XM-Iq%;%CRNTk7tL<4&-sDlx-1vNMJx!p;R3MWMf+L6ub z>6b#x?r5!O*2%|A)d)PNTd>iwA#`JIHzLCA_*wN1d-5GZM4L>vBP`aal}3p=Yt&@W zO;Q?eL=G(f{5epN%3!wENo?leoYPF6M7j-Lq^0a#aONoW<<113Sr;tNN{thR9|7zP zY^R{dCd_JY7}eD^{taa|0F)U3f70zZ2iD)a9AVFEGcOxX=6+0G^BXZt0drA(ALRrN z|IpOf8;f~EhRMH84|y9zLg0$`>%Fzum@etGC1qq@3K`xRdJ%9KJJxpP&@(X)HTAs~ zyxZ?$u>R8L4|WtMZPaZ9s$T@&kn-V7?ch@>4j}q(VH{7Dd|Q*PiX;uMiFx%Kf<uP& zVLxCy+)nTnZo5*20ndJKpj+W1?rdJ@;3~}fW8in-4c?%O4XNpNA+l_%pY*)e5uie} zvqU#k9_fT`<k5!KNTnap=gtCO%-3#)8K|qe8N!Sn&Y_xRjoC#K-9^aCTXL(}pOGOg z#ig77)<?A7I^;#AZ}!IgoDUijr*s-6+ajo)!_5B#OBc$%MhjKCQ3b}<I?HTI&wojt z*jngHV58mIcmOkItbsr1J{pcjn~bQP>BMj55Kc<xJrRyjM5Q2yq^VNB_e3w8=jh^Q zH}noRl$tC<c*H{oQ%T%y(J=o`qr`OdmcnuiD|A;?o?iU9i-wN?+L>srJsAaBPB>?5 zxGlr|Qf>XBL{A;OddWnH{H^P+!}a@Tx5F8%&^{y75iH%E6#yt)+)%hH(<*y7ENqop z9QVxe2MD|KGe$sgCn#7u#Oc)g{0CO(Z23tg{e=M$0ObGCLLoQ=0UIVUhJ#x;i0Z?| zHwfqF2qG5jBQW_SRv)P58oLw6$?Z0?<c{KFSdosFD0q~7WGUS4LGXf&z%oMSi4m|r zS^pX+yUa>H`FZ*d2Et-B?Ig&09NLGV{Y&Wp9X*YnSs|hEtMBAyWyZR;HJUv`-%f)r zACSWTW)|v?JalorGn(m)=tg&YRP}TwCj%J<fH24fm_$0e`83P4$v;m~3%!%(1X4$G z7y&>RG;qw4ximq2C6<J2xuWj<bJ;G3L+G{n#0w;Ks9;30iKoz^P<pKititR4Z)&_i z0|B33Ivua@`B>Ni9^RHsP1$NZ+_=5-9&nYW+279zCP)SyMPb}+SgxxX?<{6`%y$c9 z5^yt!Bri5H3i@Jh4(C<nHqF41YIGpYitum&!sOS@bYs+s&#Hz@GF~m4p_${NN9fl4 z-AZ2^j9`B4OVvxdO^p&7DfcM7533#LXKg=!*vr8U>jI-qh*cZzsjNFJBPs>0N^HV) z{(^(W6w(qvhs@2{s8JNr&SL=)bPF^;#o@fs-rJ9^dTKzvJ2fGMrkYT&u(kRR<i8!L zD^ikw_;mezc!G6pNyn0fW$qa@h5bETc4udPuNd{ciTGjjQ8hjjp>S<$vOy-nvmQAM zYOUAM=YHfbJgg|+L(dJPS#kL><u4vWW+W$DftsPBlZ?r1Q-<9r(rkySu$Dq5-y?8g zcJ8CPU?KEl@Q^>xzS#X)(9P<a+AzSxbZ4VpGjc?r1X}_S6_u^K=j}S1VEY|N<ke)6 zC=@^Zw^fjK7Z*`qgH>@gZ1Z1=SSSdW7XwNpd|h{EF7dE;KWC&(``2dcUoSS<i?0_8 zgaP3z=NRpOUFQC$4w|nxki06b)Qg%7Ydzpr?CQF~<0$@rKf$GSYCj@QEIzBf?CJTX zC+(O5V*WPS`vRB4vMR>!@-|u2QBuTj{HtUA@A?z_tG~QymeRn(lbq`MF%*u9sVn0Y zHpUf$#~l3yE8Cn<0x?RJqqX+}K9)EndTXOehyIhqU~S@PZUwyf*ZUeX{(Vp;{_t>2 z25XITvuWxuXmL#73njz2*qg!Nkn#mCETr{X0+)TqbzCIohx_LWl~s-%3`G(u2K2N$ z_k2`vTC_o!shPS(@%-+zq<OdH-$-q2Ui*!bPnBP|<7}>{ZKdZCDKCwy)QwwQT(>O8 zQc=Pozxb0ha8>?xZJS}hjI0<|4c*-m)rNSDtkf{|3{%e%Il&Vx4{7eFVZBb6h3u9Y zRq(PaHAUn9vKSfv?4$RCxQR0SshimQYNze8ydo$H{lt_|7u@=A$@S%!4X;n_qV&>B zQZiP<xtR)inn}BrKLVzDSJ-YYrgF(_LyCy_4>U#wEprGW6QKruspX9u)1b3Eg55=f z85u{m;mOWuXcmP?NP7S56j?%(Rm!-B|3<s5ygoDB%y9@n3^r{J8IqQVL0Y2Y9tc<M zFKB@*b@5>gKKAFU!9BTAa#&+?+n^0YmCF&Fb9g|I<CLiqJw>bN$u_(Kerpj`_Ik7C zY#}X{?GI`hWpv8-FF|H4kL48`!sQ5_x1`+nNnqXBukJX`L;>-8Gw@RE;aXvprr&?t zkRx<XW_vFUy(e&o8Dz<#=`>TkuQ$U*WaK$H(ydh$dZ0ZL&R1%Lw?m#E4mZ2L%HQnC zUcZ`LIJf_UfhBx=fY}$l7CI%Ng)t?7_YHP1=lXW}ZIBnkQ9=Dg{>y_!dZrsR&g2#) z3b^j^>Q82G923Cz_Z>8G<fr9a$_dT4r4iY&^ReyaM@vKo_aGw8HoR?6!KC?wJRKhE ziKybnzRN+`t`eO5yf<ffNL``8>CrqmG9c9Dirr1D3QF1PmGNQ^+F8#m=>l?Q;3op1 zBrR`s6TI_)uU)7_%+IPSY3U^|XE>5jh3aOe#30OK017<@fQpO-ko6E^Q$-;n)Kwqz zne$GTf3xe=F@C{*k3dvp|Fj?K?_FDTvb<KNY}*WC+57x+1e)f(s+<~4E^D_ooSoEF zLOz!eD&}N~Em_Yr;r&msXPmgbvRhNQ@74zLps|$YUY$Dv+jA5Xp&h#+wV4YHNQCmk zkG^XWL#yKhL0{ExO};H-OVbXwxsI-P9=Wx@mq$fb_l{2l_x8qX15XdlZ*#}FlCzYR zNnUp_q3LTUMnW7$(Sjno8#)G*FN0Nj4|$4TFwaHCRsQjQ6Q7_#$y})A_7DRrBT0`w zE*cqX^-ZuIy^2JHzsY0I(POhVgkGo=hO}uW9f|C?(<_1Kw!f5mVESjfK-?aHABJxc zYWXVd>s|5lH<ueVY>ou1W55d+etuW>V(_Ft3M2f>MiQjuE=9oA0F7C?0{Lykkbqde zI4iMVvc_tZbm51nQn<lJ#A-bV^#QM;efzhd-oWGT%ajelr(okojFbAG<L^u!74T}k zJFxg<>5ij7Bb<fje~zlT7Ba*%{P?v{GM9_!1?AqDBPRwco6OeUj%%%->|y)yWM|?i z^VOYO@Q>z@V)-9VezO)zss3dM@oSVO`h}1y>}dP-CM7&6ETK0;2=n5mAa|CdF5Yu? z?etI_a9nx-(4l-pMM15$CS1cFB5WYS*A8!no7OtWQ5E$Eb@xQf_RA~K=PxHxY^aPh zI8a4xu)>A{JzIP^HU-u4Rj<!FvL;e3f752!6osUPXl%wsj+h)c_@h`vaL@-uIE_4N z2p+$E75}~8<ZQfM^(vA7s6((^xhN&!Z=JqeMrBU%T#g6R{u7-9XOec0Cm6EU?ZGfW zZEuPtnIb)TRd%5Ci0<*E%@>ENKYid@rwyzJ$uQkSBq22Q#MnB1C~YsgeRO?neIQsc zeG;uJTL^}Gn^8G+TYgmbu_Ke&Eo1sEdXs=p8p8can#ZjIWe&M#v0%8Hn#iXBiShi> z{ir}p?aL2BG(=7;OW?_^VROD%9NL$}VPc=HuRk>bgbhbCi+)ngW#q(#XGY~e7Pc(7 z?x2;_#4OC5NHT0^v<aB_9mj{Z!pX$<AOY&29U&@sTWrBrWjMkgfj*+6AQ7nHMIOD< zGsF!Yq$@@Aio-B&jPbV$T60XIc1BOmHaIL3K%0PEuhc@iZx0i5zt<LYm^^K_vdYNy zOFSIXmnz$w{x`oIRn@P7>WaB<JF8(cA4<WdWwpb_<7|7&|D9m5PdWm;u5aHQ^7DWf z3b5LyCRHJd75J)PL+YCN|3Ah-;~RT-oY>8awQ>==XZ^j8=g5Z^eWm49YCly~TTXY+ znCfIbrBAk^JSVM1X2Vt5Z{OM~qQB4#6x_V+6;14P&cCv9aYeSLdq-ww5@(rok7m1B zk*@Y|jg4-Eb0puTRlR6y95UvX^&U-opRH&ZrkR(qq%Y6kiHMv$?D73Ber;&L@IBr* zI2BW_YL7s(@0ONaDEm|MO3ViHoYlJ9|D857;kYma$J)@^gYt?+JI8_yJs?N1vEoHq zw!;)G&l-d~Aw_xD--x?y;^!snX7_@tDDBZ{L1M>ksi!kzbe;Nm_qQ+qeks%rM{4A~ zC=Pw>-8&L|Waf7EG56dY56U~+Mfy8W)UW7FwSYl{LW0i(G-EV|F1!m-cpt+kW{6u2 zd^YAT`S(udg#`QY9nkZ6-=tKwV#rQb0~-6|UcQ1tXXAkw(YhfOBe{S#2OB;w%sAr9 za7<)>@1{U9m^DeI>Wy)8KWDv3t_B(@1r9ZbU30l8|4(EjMk+QigC_&Gx8r(V`{R{p z4R`ZQmhmA7AzBV0#o`bwaf^@|n20txxV0v8wLhknO4Nf;s~3<Cj5JHJ3zEWbjjoWG z^NMe*5j0ri5{o!;3#oGL1s-(cT|;GMH8q@tAaAoym-Iq{sxWic!>Z-@=W{y-v8#*Z zyhp5femRt3^%&j;znwjx23&pFYM^i{CqIfk^0$BAyc`ez1!lf|TaGviGz`>&+`&mG zi*Jz8G0L$njULA#4+TXQ7v~!3T#aZspv~Qk8n3>L@Z?<0d5r1Li#Yk;71Xa@X?tQ{ z>3FgNr<<G|p!9cECx2VzvB~Y9iZNxM&yhspS3V`6EM9P7n<zPNO6*12^|;slAnx#5 z5xF1C{)u%yGtS{f&-)P*Hq#?>lz(gKhvm5N)0$9VUJVFiSaJ9z0>E}n0`Mj}P%i(O zwljSj`bAZYf7dQ2%awHdsHq8)Dp{6#Cm!En!;2I!p$}FIxw*wco>Qa+!jOm0)O1#% z9~LWLvV9<hO)Ch;-+t#&zxRUgi*t^db|R1GB!f<X2d)<W9H+*N!(yW2Xx{>1Mr_dN z!g)YN3`w=Oxj<;beWnZUrH%advssYA*x#Kxvln}hQKG4C2vA(XWpliro#o~Gi(O!9 zHkM{wJ>-jxt9pU}xkyfb{P<8=!%|neozHidUI7I)HU~@LbDH}465oMbLpxpvy*3*& zL{dPmT(G5eY{^EHKtNOysLLCv8l#nTWw!T;1&Q%4-d*Npq){pE<pnGJmTfTqg1!F^ zwrE%^x`U!j&<LhBC34TGd`M^M=hte`s=i2tZ8a7PN<U7#%;~nYX(EV65k2h!6ISb& z);lvuKFHxkZHfR3%r30wzdvb$1^((s*R4fcS!&)EqTXH*$UzGnG9RV_zW;#cX8ZPV z{pv;{m+c$I?4&b51;s_=tOXL}gvn(W!tb0lFe|()IGitJUf0yxkh#PsF`p!(Gj#WM z^*A?n_PMI(6O(LxI13&EtT^(rS1bNdW5go~<$1qihD=cK2e1i@VA*8MtSKmyJ7A>k zG9{mGoEAeipKf$Qij8sZA%tF=8xcG+iGO%u&W*xC>b3>eiEa17;Gn$gM;oN3J?UDk zX!%}hP6qK3`}=U_j+C3~tpSHo`^{kr%oHJ0^hCbba_BFjx?{&9-f51R_G<3D*B|($ zjR)IZbJ)~W`_mJXD6g;73kQs4f&*TqN12P4o@&5sBVqy?2mD0UM_YQ8(4%FCTf|qc zV<sw{ZRErPLmAvI*i3k+;gUbp@KQqXn~~3|vbBimwP0AtD+rL=!tiRs%oY=YBT_&p zzN#Rko{+<4#Z#h70ndp`;*=67+a-vH10MX_h1S;)su$&l;2{&jBPb{+EW9#f0D=F{ zEkX_N2PJ~S*My}Y9$ZL5GT=Kd95m<OA&Bx2$?`rwU0PtOmnD6ikYQMqDI@TEsMS0T z=3H<nl2nKV9U($>QtOGMo_bV^sl8Avd__%-x<S}~PL~l6p#-$53kbpYxysOykY)*D zMm7GWgGW+1yp+#@OfiBZxocgDj6(3JkU<NKqK0pB3J<v{nw0T6heuB16ygcRf=-PB z!zkATc(m6p=qI9IRtxgKd%@P#TwzM!rIn#>LI{IBf(3pPKrM;$NPlq+v5!aG?Fxb3 z3bL5@azAb46F}-+uw8;~$N*rz_UWU<FXnrsp{g*@r+xfI{OyV#lJvm;p0FGK=Af6e zm3IUvHNr?T)KI(5mlcTX$;ADEv>;xR2?%pfIL$pMDzJ|SKl0PY%LPpvJ76=B3BuUh z*m9Ygb3eT1>ij1I!i)oceSLj=^uc1G57dA@5YWM6#G+(YBMOCP`JO3brh*7xz>|vB z*4hzfv#`HVxZR-_I$0y#RSriR=i3-P3E_nYS>UrYA~R!$${>u4vnV9@g;x3XE!@WX z@o+;2G$LZugKhyC`cV8kd;v$0!S{jjl4V)?kYz=w5Uo~LS|C3Fyc4E995IL(p1Bit z7TYCB^Y6l^5*dM%zzOhEfjR`eYZy#XS6FTEpztTUJIoO3d<|bw)gEB&X76Qc>g8wf zzr%}j@bijZOlT_F$vNvhFpNe7%l1+a49m9Yz$Pu{*woM(OVQ&%?+7Gxg*a48g7Akr z#AwAHdCmvENvbQU&E<HXS*UeY*^kE-9Ukr276i(#uCA`CdN&ihSoh!IWJHAr@t3IP z?jKU1<Fil!=_DbPro{1D_330I!%<pJd%dt-I0$wWhGC<3LGelnzWda)U5|fzQYk;v z0v%z}a-MAeWUv}z5R-DxEicCqforWMiqR%!{`ZkBc_m)a6E5L4IJDxQd*^}|LL<`} zwhc^j)5HTKszc24$e4gp94K>hy)pWY(O9T+uW(55df2B`fgBd2snvrul*V0R3)9nZ z2uIfk(+86ES9=r2m+vNWga|z<ii-)hG=>VZva*(Txcv0D_=OWuQM4Jk5<!4vcC09i za1-4Jl3#3+nrdC;V3RQ45L5yKC{~y~40Vq1eN}!4-7zX^8koY35Hs2j`u8RNbEq2R z_GH;}cQo_btyr3tKCW=n&l1yIr>#P?sN%j_K9?v@tG34BHTXZ*$96Q)lsKg6>^eop zsLbv-{snvj-DbCKhZSNWW6D|v$7mRiO3)VeYq}P`iD9xD3v49;VUqYM4tb|{iI2~6 z0cFDAJShC)LMMXjIy^n4?}ENX>bAD<rZdp}(_y6%`>NCND!+MbA=uO)beZ1L2_n4S zX)B2Tz{$h&BE}`miNEsv*M4gNtqBW-KrJh-7dFf+(Xfr{ptKRW7L_0iHs7)U)CLit z1*%p*Q6ta2zWfq-7w>VcW$r{KbT^yN`G`bi?2SA(l+3Wayu2BbqLc9^VA$^W&>fCe z-F#TS?9@Td&bphb=DyJG?~4Wh4~^#Avb_$rk1&kY)7Lll-bsaG4VnAN2qwiFDLAAR z6&2;=2Ff%_js*a<fhYCz&KUW}O@22Dtim&m_z#m}3BvPNSbPF`f9FiwSRZ>?Q_vJU z*>RO@T51{^8pg*}t`8{oQ8@!b&Sl?@t;AZOP^nj_ouo;0ip|cz%uEVs?891;mx)G! zHJUUF4vVhJzO3mYJlghfRF~w@v22*qmLncmd6TJ|r3=Ty!s*+VrB%X;4u_>xejucx zqN1UJ0Di<@#2SVA5{e+YqNtGT3|icAOs$J_)6~|s)Opy$d!l92{k5HGmD`otSv&OQ zP2BPOAP*=&K|w(tL0IQh-A<T3Y|FFbiM-1D_IQzh{5v0}Q<!hgDZ=Eo@VNN6a4!k+ zuXSkC_ZwCF)9Tq@FDQfuxvkUi8fpLuAD#!b;&V1=u-6qt>hXVqGA{F9pop^0(r37u zxk9H+M5B%Xe~`VNLz3Ch_B~4P)r1%Ykk|9nz%NVflwy$Qt#YS2dR<>dOQoqqA^!eY zQ&V$e0F(YladH32`JW1ZTU%QNh@+2*%7ylz5~buB^O8cm1)ay<DfE$F$x@@Pfd)Bz z9G2&<EpW`_5(5(BQa`09Bhc8Z6xIj&G!iApbW?xF{3FH)KN8;_A|XcEmBg-?4r+tG z=fnSvLSL%oto`YH`L5&m#j~zh&Yj^^a4(29nQLKtV=zBxAY&tlYn*>C8*bdi`h0;v z5&(}%)Zf8Fi2~@xcI`s+^>ZB;AT2riWcS*ZC%S%Gt>|=sS8b%yGFxd?T|4fx#-O>P zbyL~qdE)Q1Oem{~qvhPzLBIdgEiwEfiARn-=^+$dsk8C6_;ws<DMJ6|{9@N}Yxl%w zW}G~al$VH$j>IRQ+zbWj(8jwO;A%H{+|TfgKlD32_d7inJHej9<%>L0JY&8hxmpZ- z{8^g!)Rgyxv3`!R{*bf&u>QInsBe{m$-Le@A@o&OaP4`M;&oF_<WRj&L>V{ox27wN zSBK14U&jOA8zN+S^)qh>I^Eqo@yU7;(&17uU(R#R{q}imKcMA}|M92lBkkqcMNaZ& z^B-AKhdKb5qzMjK-4p|VG>9Hka2|^l1J6WMQIod??lLAb?IWGDp}7Nq+L(EP>8qci zPE~*Cppt1XbeR<#?<l1+K?2G6;Rk8GPzK3Nn>-xY^TV-3r+N?HUa>lPkHi>V7fd|0 zPWV2I7{8miVV3dfgPH`TlnC!cGgmoFs3oedJ@4`b&RO}-bv)|4MGJ2*cU&@yv_bcy z5GFfu*?wxy{Shtx&!g7ZeO9YPCFk=?T31z;L73W}1-tK}ozWFZ-`B7I9A4Mu{Ceg5 zpinQ7dK$GqcT*iNzu#`55Jn#;?(`*NKsbVIaA;Wg1n0HL__1ghO#1{TmUdjfWL^K0 zr^$4k)TI5BHrIS8uk$NRBgM-Ug_h)-*q*ECo^QvUFLXoxEAh((#hXjV<FwezH2ZTm z`*ZBXJ$lo=i{~E+u}d1Ug6Y6>q(HTAgKXdCh_RPj50sq_|5OQ?lV8lfD|no9dYRLQ z(wZ9KT{S*q#j1GkFdIKu7~fhH!rP616)uZvxgzbjAa%4YeZJ01z(4JJ-p+ZC5Kw=H z9y~m2X+q0;n<8w<ZCLUQ^=axz!z3j3?<@;$zOrlIwUfVp{>Pkj^_(;Ktui(laG+=$ z{fXlrp>cN?KwSU%D#*dM7;VYBOaxlezrC!#`B&!1rIOf&p+J41ew%=k3*vZ}Xo1eN zH%@4sBucBUY3HgjHK)5^s*Gq1g1l2Xf>SH9xVi3}v;+Ww7%<H2Vmn}V#0l{ODkP-p zxf;G=jhLzHqah+lON=N8A^sQ>B3zyya^FjP`gb7kdEjY($*y`#hyH@CN4_}lMkmn1 z=It;0t0{jc&rw_(w<B)nFioaxYhr9?ICxsxQJu936427H01wi&V~q=hj^=9kj}hL? zu<uaPX=n)+uyzDZZ;1ToXj_wbn8J>QGF77aYLXb#BzW4VsnD+Vw#u`Oxx(_7*OC7E zqgCLo6`RpzQaW(sX)~AjCK1&~y6aKwCGS<0)t%zjgd##D<S+@Fv5<$YX&c9G69TSc zRAebDneZpQQ1$ttD^-B?N05g=-P?Ba?UMcN5*su|{1W+gPNDY!{90EcGN$a+#)s0G zB-x1l`%e9rbF$iDmR*&N0Gh(Wtv9NA+~nrJGYH(#3E24^`1CvPzL%lfwXfJ!_DP;N z)7AUIGholt;Qox{4Jn_j$DP@}{Gfe5rd>WAP){83&rNzojHR$IXm%zb;EFGh>op39 z&0bH$)hT&5=>BJsV-7lZ-C$vktf~Y5R;VgM3h0Dczch0aF<Szqth-IY08k&|5lb^p z)A_ZpoFj>m4k@_hz1xdE09=X;08dFsRaRTVfq}+ae$c7A4+`%14KuRG=;`<BLUHGk zlIo2yS!0e!%&1COk|1;1(tgxJpxlHAWQ`(eGQ;sCpVBmj<S)hlmR)~YU02RZtyaMF znG9uO9SrQVe4Jjw=f(?ufv!<hE43wZ+RU6ERGde5(v4L{L551Q(v<(1E3;PVj1c~e zS$EcpwuI_a2idR30O>)VwR2dYT2NmQ{kQAtJiAX)?~6_avsR8G1NI}Aeu`ajiCsY= zMPfPmTjj^qkL!be_@g4l!q_FM8{bpBe0!CfOfBKc!@I*P*!1wMdpLVpJ9~MoervX) zu4px;ijxah7)pof|L&#b3Da8@S8Q1))>-~Qh;NH;Wqe6zTtNF_GwW#5KyG*%<|R7D zt?2H|LH1tk+b%$8jx(Rk5Sn0M`fb3${cUq5>&$9$Oh|L6o028<pM-%fo{!cj0C24( zkVCs?x3|I<pv|ETlg3O0T{h*a-)B1FgW7h<<(RsKs{9_t06+;H1faDjbk5A4^PB4k zh<ydeAi=Pt@$uH1%kOH`a`jQj^RX>_CECb2^Rv<!!@8CV*F;MS1rTV-JEWnJm?Bim zYwwi%D&3{1Rq3Orp0uvdCZ-&bpLxku(dqMlS?Hd0D}Aez3R4<#9JNLSs!LEOMeua$ zS(#tZu+Sb-Mgf9MdEe2T)}=04WQOV8V)t7&pWVlwQA%~Yw?!>-H%eEvUJehU1-H7} znw`bM95u$yS#E@D)WS0t5EfEaCxY)kw8+?!z&nMVFk8g_)nc=z2%3Fjl0=4ooM9QF z!dy+nIh}A<PEZ@RLltQE0LsPyV*U}JWxuq`)JF=v1G!U3ZngHfH=vSsE?F1Gslb8^ z?|OAQUXqU1WJ9!AH|hB1wn{tt>HN|=Mr<S8^+Ngv$?FQJY1>gd%SrEghXfqNR6}lf zaadqtP#kHt#dT6aKf(j2qO0?v!il~~NG3vObjqN)pkTmr<@#ggLOm9F+v^P!LMTWQ zG_ndN*@=lei!Z}X{F4h)fmV`42z5~aq{aGFwdZ%?sq#%ZWu~g>(N(8V2p)HD<iLW} zA>8clm#gd2<N+sh6f%Q&=)?UKlLwzY$vO)NNda>J;+nsY(3maIppEy5Kt&{V_p;s7 zb_2oT8oW=!eE+5)cB3KFTtE1sA0w+w)=30ZXLS#FrV|}vh>6{G+7n`0uKp5<EEh`X zYJE;jbdr5ONf{9}@g14@b+9ePd0hTt4kjj%Ou}$PTouU=?+)DLsG_Fo?Vw%$K6i>6 zga!dxAfOUnlsuBliO7^<Goj=*Ici|%!a$!-L`VQV%u!_+kjK44-@5yI<ido@oLbNh z9+ew{S(6~{R}NmFC_e_|RbCIePON#jMW4sQGyknv>|W)LJ~XaF1oAi`LCAKgyY%2# zoW}P;S@eX-w;3AG|K%Wa^P{y+P;PaFh~Mgw5h1J8wE3n<sBd*v{RWM$W|i6pO*~se z{z~St6vQ!`Kv@Q%ihLRnr|O5P%Gkz|s68o0-oJtvEr`^*slkKB&wa+n{=A<ko@yva z&G16#Dgyd6>*uvwMCgD=v7#5aVw}Xf2I>^LYA%xae8)L4+m?hxTr!`oXG%ot^Bd0Q zwI4M^cQh!S=AV+sVU2HxN(oh1`DrCiKMKKqbu0N=%X^Gp{rVL6cJ@Ms$!hw#CwkX} z-s#KGAeT~EC4>qJf6o4>r(TJ3K+M(4|HFAuikYrut8u)ro}19OF+Ky812vt*;EtDu zg&Pw{_W7#){epQ+|2Z>p>idU5xuwI{k1BI_LI!-Di@5({sx=(2E^HJMQ~(Q}$FM?q zp|ey8hx&S|U?YMauKp~FhXH_Av_Q=;vN+igd`w`P)im`YK8vYEbof&|61cfT65AL7 zq$_NhDDJ?690vLj1AhW%hZ&>MhPvvt6<1Rvvs$v$u?r+v)+Zb%YVIgpg8Qhn6L`rG z_{(vc$ZM#NO2Rl%M%Rb<d>7$Ei%sxF2%600r#?e%>w<c+@;zkAiugypFu$baTT#u3 z?HzyEjON7SEL)kfhx1Yn!-_v&hS48QdZo~Ivt0g^78OV(3X#&xk6N$Hdsb0xv|7H9 zTCgISOCP0QAwgglWs9_deSeNhX8CZ~VZ~OPA(d>OP3E?6vE=ORnh8S1`?{3a!ErlJ zgV-uo@^m+&R-#;c@N`6z`P4D7)B#diHEo5d91(Y0II+xF=bUXQw*s1g2OIcLvx4mf zze;OLY2+FS<}5;Yb_T>=FDAUlT|;y+iUep_Ye5n3>z;3&-aNFP8l0XQ)cxd<1YK82 zKsL7GVhty<(kHj?#;xB&>SbJIGrZ|$a+AMzmOcq>ef8kq+UKtl3Jwi}Ccsk!Oh}!N z2Rb4b5x)(;oaDf0kK=R$)91$hoe$mz?VKSi<Y1fn%cDb{otb}pX<ZTzgCVE^s$d&= zA6hb7&;ji*fs<My&;;l!urc)A0Dz^e?IO;p?p_y-m3PjpLQmWDsMMlgTJ;;qkelaw zys!9ZQcrG=hG6d_!C8`2$%Zq9r*aB1g)?38yz^^Jb|~GizSt*syQ_>T)z@v+C2k>a zBuRG*SVjQ<JM2;>^XtEa9sH^}%-7Q-D83SLMi75hqq(1we3wjlc10K2BpcK%7r^zb z1u!ruQ&Ha@c>yoKufbk_zB2w@NEbM*0&Eqn`60*RlRqH?gn;-4_t21aR})~L=w3w> zZVm9;jM5h~&6Qz8@QW^Kk+2=j*I2l&^M?@JCdizH5kyFfbMZptnPKj$jDz~fq`q^J z#6%j3^lcXsVzO5hl5FC>pwVGzYk7VkL?Z8elnkRUo!-f1vnE)=I;^j!d`hvr)U&Fq zst%SVR`B1|_nUnha9P!pwpAjITEFvOkGz^?<lBoyKX-@53;o$2d=4^$1~)1i-v_X< zH$skh-P}L^3%H%lua)Tro_ln!$)MRH-+%LJ6mm(3Z<5W^J7paz;!7}pRstZP@q|&- zgPFT=dP~q*bAe{9RCVR>cJM&P{b=}#zsxWr=8?9Wj_M{s_(8Kffp1H>_fL_L72o~d z>E71K;?b=jJT$!?nj5CZ<B2yECr?;k$}b9O1<(GNM><P!p9<P*9+>||5TWh+xkIqg z$d%@d;=yWSMuoSqe){=F2d(M}WK#%T2w>(^b5cQughB4}2V(n&JQ&YpkwCff4lYht zubz-9rY^zgWY+^?Qt&hm%YJk;2h7pn)V>Y=<_>!YLc*hJw=m|uZG1u~OA!Fr3r!lP zFqh7jVwb==A@#m9b_Jp&WBpcqKhXkD9pjBFZP>(dvbk*etm8_=UJf{V|0SSLsvR0P zI|Z_?!vW)T0;B0KE20iP7xhMW2hh4yu8jzwO-JW%r5scIeOiEphfjxC`MFjFV~lk% z#(l`@y^&R2p!0X0@2eH<`wU3Xp|j^Y>@ymjl=g9<{x=j3yg)JcF&mV*iZvWAa5mkw zTnK*94yJiX6)faA=VoRDv-9z6{ITmY-8EvZMW6(k8CpEbLsTk|KS5qMPv4Q0Q<Jf- z9OeIbmHGD#Q&%%`soZbzPjW|@N?K)}?Zd8XTv>_K5oPoj0X))}ueODi2jgP@32Tmw zoj$&!ka*3oR+AT#5S%$uZU4AOAv6fdL8e*^pfx?eLfR)Dg8&8kM#1p10Ezz_)VVH5 zixjLLf?zmCg^UKRV7^xWI~$hYgk64ZYB>gzXg$zNg18rAI5<HIV+Mmjh9DkmlpH#; zR+F|WOQ4n6E<A|b1_i(pFMBlfV#qmDp6L5;6^EHiEpep!MdIH$ASd-N_3PEKz7Eo& zIE5NpU1WO(@z|0X<jIH7tU6`l<oH%J#=WyTyO`>mU)l?Vag+)ujAJtjn#~Y+wMHqV zjx9k9Oax&_pwM(hM^9Gje|rY4a?3;h7E6?7+c|bT&nRzb{`(0!;4CIRya@*6F#iWM z4XWS;?pX+*Wx~4NxQbx#6kfGcrjApj2|g5y=F1}e+}&-GT8`A(4zWHDMH<O%Q~NkO zx#U!k_=LZijPcIV4OaG4>|vO}0131T0L`v4s&V&^+RW@NHPv=4Apiq>5ka%cp|l?M zkXOef5P1o8EP!B%vy-~(?+u6|Xa}JkrxD-UK^3xzr$4OXdBxue?;8+I81b0mxd&e> zI!|2bI<MPGx?i{^AhA=-CW_6lgk9xKIi4f2YLTN^n+HnO*JK$B6*v2s%dQ9Uq##au zZ=?T|&2M#vEiC$O&d=+8**FQb>*|`KG#$TK91y`3=UjFJ)!_8MXM4@^e%u?_9DFEA z&eP<B7PA1L(}&LToF`)ZA06e$G+hOV;54jG1s2JmqhHg%RTLp?S4OnJS6E1u(625* zcP{BZM6~9Q;c<^$*q}I35>u#{0m=qtE)s|8$TXg#+azRgx|WPHJP;hh3+7Vkk#Qdt zwi=XVMU@}<Fw{$*oHL%EHga15v1~ubl@;*RX{FVOaD8dBiaWhHaIrL5iJh%!WZMw= ziloR!Ez`8A2gZJx%szABIjmu4JKo9}L}Tp%@C-*T$g0;!=vyj_ObxBh?*+c@UEK~H z;Ts$KE^Qsbu4%aJ##bQ3XGz0)b)gw`CN3P?P+Q<8oe>6X5*iFx;Hlm{XSlMDPbBAO zF0>nvkUW@=>4`+xa353)8#=Fsv|S-%#cHe|uGw&E2A@^=3L%w|GXUBBHqm6fwwWs! zgtHEsM;+2W=5BpNozu?BSsAu?4{2s+@Wzfb@ds46uHW=Bh`PK}PXOOd6*Sn}TB-DC zzW7b~AH~kqsZ?^WlM&mGw-Fu<7u*O>e{byw*tH5M{<Hx@!EC3eS}x>ntXh8LQumq7 zsqPab;O`+r63Ec?NmuBOhIO+dw1&DXI_GI)LgZBTTNuzPZpDO!;8ZgVnjHn|@nNKb zIKTWx!;9v4lsK}Z1KvzQ_$7&;Vw1(tcDOeN<l`zItSn!l%bJMbl4z__3$3%lTBqOD z#>Ctk)|te#FdN~ZWx&aK?7NS3I(Bq5Z56JHVu61d0z$Tiy{ZWDTMBMu*j(dw&s}|+ z<@Bt26K#S=a;G^He%eQ4zuowO0y+&gZls&ZXw3H#i<Xq*Kj9Lign&tx)#<kr{ryOZ zhtcCVlhe#bBhc5^`)1@Zq>)cfrmfL#<9m$ElQn{7`}!%}r{DY$b&Mb`mqR-KvpN@| zsN?kGT_(*L?GsU@oziU`?^Ef1)H(ms9kf(M@GOWq{Z?xTM&La;Y7aagb?y{$l|?FX zrM^NJ-Saa>%L`L`I3KQJm<?EPsnhZPC*8cAy`52Z`6#|L4WJ+W;qo{QB%_*348ZCv zC!X^itW<#mD{d8T#!`UGk>40$ViunlHNyDbP7*QZtb=%vhNA9K@j<gN(6Bi9$MkR7 z3{mgzXrh`Sc&edt-8W=BBzm=|7z_IJVsL4IBzmjY@>93pl{1M>e#BADO=5a#e}sFk z30)sgtL>?h*4my+ih*8y&f+TG{WmL?k%(@2T~zPp@xi})Jp?Va5z?(-+1#bLIEw`K z)C4s#Jn=$G6FG=F`zA?wTz20tY;TjlgNDsa%nWf!Zo4E0U~`ki+DTJ%<#JjKQ&;D> z6?>(h{&P6GZhO(aDi_ndAo6w+^kE%o(Yil{=UX!DKG<%le5uoRu(ikb&~mf?md#}F z+x^#XlY}&O7H*{<WoM5Y=!AUQIvy)JejyH8$3~%`Ul`^hC;4<uRAF(=-}Gd*S>>xK zyDZ*RK>w${^VP00A8Ox4cck!+)~I2soTRJN>1p5YxvcYX39aCx+QVjBW90yEfg^JS zRNVFh&U%!WxscdXTJZkfNVXE*BF5?v7_i4ONhM4E`UZ4F1QbIXHtf#!IQAV+(jJ$G zI$<rNq>cBgGxD`@N@E<XQA+L!ry3FDUJT@15%1Hda<f@14oH<h4(HtP{|PEKu$U{q zg^{gMq6wM3Cz)GFZ;@pBgk(?Ko+Z!6Q?F89&Vv2vlY}5^=+nKLvOg>+k>GdgT<V`D zQ?iq3WLFBUp6}nYip<nH8eLa@9){oW+ZH)j%bA^$IxtD%fEj|c6G5x2AeHB)H}x>! zEDiy*^_v3#x=(iwu98}j$H4;qxZy!<sql)W*|1;*NJz~tr9l6hR~QE(5CMqCseLEY z2T$V*<%6sMf^amxjfXoIR9MmwOiz9Fmj&h!St0s`reNEsVKoj;+J@k7x*<TpJ)Odj zQ{Q-v=O4V*C)(FF+Lt^<@rHVHCSF!1Zj9@a@g|g%^=a=Sg}15lZf)}D8%7zRC5~KF z!?^sgi+;Im+@N+RRsOI>?q$l%V0Nn9BxZ1)P_O)JjMd6R5pEp^kJ=O?_R3Vku*y-< z%fMuJSq_WeB~&iGa*azO(V9{;y2N32OyLPq^f?bAvH3IV)2ua^zowgv!wYiF$7D+y zG?g4+0x3)0sqLXmbE6)DkFe_ra`i-)%i~}*DR~t7sBJ5a8iV6x+|)l1!lwPMlTDDV z^`7*3zZu8GR_{SA|9TYoQVsPg_%bXP#jr?T#YI4HY$#65$fW@BF%G`NJVVy;UMxs$ z#YxdX57ivTf?WFm<jL)}KRn}M6n`w44rjQOmlM11!kn{6H~4~*!-5DctH=6-i^H$i z|A@+_;C$Kprz}vso=1`@6j<v-mdexq3X4BY_;qYAa0+#RvQ<w^BE&<*Js8K=G1%;| z{{9DrwmuNjHEp+W|1c5Qeyn8uFidi0Awlb|=JA1*3cps!)QYY!{<<C|2iAA--Ztg> zW;9<oAcDGA`3?4w?K2a3Vp@p^Qa8yHKFSaBrZb|$+{Mn?+#B$K@GfW7Y(f9lI#gyp zd)M~R^Zu42+ot=#ygeeeScoF&;FNex!JO-CD=bI!m!BI2f-B$Xj&K=oVITjcBu!p{ znOQir8^O{nsn-q5f>Y{an?a59tE)WPIRTUtFXKfL0|1i6DKIj1FMtq0bfd255H*0d zA9ruJ2n<>u3>pGxkq80AdQJXbWM2aFSHEZd;F66Vr@Q5%wX}a|?_f<8>4Ra<FPUVW zR8ehRKn7IE7ZbU1$L@F0_tS4Hp2i={w)-*^X1B`<KZS?$o3Prx(<edoGx@ZI6=U6C z>5;a!Ps+yJ?h19QQsXaPv*_CIB#EeA<^`%*l!|dG{a<Hb9MQB<wCT8Q7W#wdlyytN zQuTHMRkG0%avI2&k%9M-RhuOlbgLC4adTg0($glQt!}wn>F}_5REL3%s?Nn(I!4|* z$dKlO1bte2*T3@PUw_I57uL&#+WOXRK15^Ic@TbI>K|f`0W3GZOJJ*zh#u?aFmPTS zU3>9B1U{_i{_#ALB{e2k`snHLYtnSCX-1x^CtG<=TqVrXf};p;cuxvzuMr$fG@G5- zmCK+E#VNp+Wr%0BJTTQ%Om}D-OkuV}bweE|Z_V)YwGj_g!dv>l`Q8m|Uz6OjiKA6G zGGJo*=k;<A15+xAJ5bk6guWFz@&NcXjDK-y)}CCmvY`^7z;oYG6JkGL^+f?FRFc8G zqvn5IPe!@9taxqE1wkmC&1l{3nEv}x2d?ul6)UAtdg(lVP875Bf6$$J<~;F+9DA9} zRCw|4dba3iy~)O~C2>~+%SZl|d|QC();5n*EOly}N3>4UARbv-a5O~r6k6!HKxGwJ z;OpOFKxfE2G~iV@1&%X2@&r|q9dS(Dd_*;z?QT<noO3dAkT!k0LW_bmO1ES<wG9N( zPX{kbi@zRb_<(+jwatwwr(Rg5osOeH=JcP5@8o|T)f|2Uq{i9SYs-CCgn;lwzjsyU zD?c~JevyOj?Eehf4m3Zms(q4n9)fQ1C?YU4by#dG^o*u?S|7O$Y0G0`EZ+&s4kDt= zV|Gx^{b1KD^bKcV&ovH}ADI@Jim8+_L;n8=d#k7@-}jAo=<e<kky4P7?(QCX=n|AJ zX;7rQ)1ia`hAwI8mQLwTNkL%0{J#Hvu#ff$Fl(`3=6&jp>-s#yr)JRVcygG8llm~{ zVldrZ0iD(@d3JL%uC}&y(qIe7u`UzMO94%FZ|66<)R1@~<%V?Q=`08<`&V}_bc?$) z>`)4SgKiULZJw11!@!`?+UVm70;rs<&|-^P_YQ_IyP;y%El$<DgUqqg`}Rml!|<cV z!J@r=-c+`ArKQhNyWMDC?5ozAJf;Oo1k&IZ_c}N3x<p<{e_N5vcKYTVOH#c{wKvDJ z3STchLaJLzZ^MFc&~azG23dPT7~CY?!*qS+7px{}Hbr7X-i($LSfd1qU0272KO(`; z6lKaD4=)ipzGnSg?vf&)8)6qRdl7cjm088GCeah|*#OIKSCrGN{_o=#mJn+a_41nH zo7z2j49hsjvF`?3F10rn)G5DCTbCYV_^DusFvq^oFchGy7Ng+Zm*J;Q(5+)Z(4L0R z&L#zC2Sr6r2<SuuQGG0R%qnrvHukz&`YvTN6}B#c+$UW+92D@!@jGG$(R^knv<UL2 zK2#LUzn)ut3ru%rj)Wh+DOod44~{N+WbAl?^!RXjPV8%Bu?Yvi2orsY$uFs+>NL~O zsSMe<=}Z8wev|Vt{PbN^exOve{PI2HH7uMdBk}D%efcAKW?!~eOp0)C#Lo7c`<gdQ z3i-E8jc0~Y=H_FJ?m)NQ&P^b$T(gAB&md}{>1*BZn1J0N$`tZDa0OoclF`9VXemz$ zg(qkh*L+h6xR3FW*ZGvik%WN>PolxX(7`zC)D@9WUT1u?SKovj6Wy0+S~&Lb+UgV$ zCU&r{`lAltf&?ssJ}2ZWZoJzu)ef7uEZ#`)V(iZ1r|I1w$~_CC;q+9<B8FT&f}w0{ z*T`T>?GqF*g~ju{JMfk3gUGmNDmmM^U+^PweAS=*)6_4Dd!a!uwy&tp$O+|htL4W= z)lc!NM?ZSXz_b6|Etq4A>AvGad<`9r^2q;6(D;fI#StMj7t`kLebFJeo4Kf#jUf-A z@f%`@c^n1gVX^8VQ_;rCp3*^FU4#qudzMPD;GO$5l2R$f6n#xO1=6+A_^Q)^54Hc= z-aVBQA&l<H1Q=O3A#AaEE~B+$5rP6(M#|Z`_s~SIwP<4GWW85%=>7}|=lUNM(~y`m zgP}yQb99Et+cLmdq7zgP*QWJ~Y5q8yi8^FFxWTeyR%_)1f7?ikI#^B!8*^W+A}yZA zIaiRieBeJc;2FhKx?`;W7B=9GpR_yqen6PtXR`1pN%Msq-?y~)C6iXu_H%63Y9sDY z?^o=NU+dTUrZ`ql_Ua9~tDztF!z}_w`afawpyxNtoV!<Qio0h<^H<2paw63aBk(E3 zt~70yt{OC5=bH{{88Q`Cw%Rja#jrl8)Wp`*{E#UmRxsI9-&~%4Zucd@84SkPpfBH^ zxbrdUvv=0~#qInveSd<C$wU46^)&Ge5$nI$!Ltz$pB6knufc3A^-_cIxo`FLwJNP- z2j9{Y-JS?8V3E{ofB0!cDGi22FzEm2*f{iCn<x)yA?Wq(j4*tb#;IoCgq^%`QyV?w zY3zJ0JGf~ahG9!m5b!;o&&0+VTe%#9$0Zl7pJ6>(vDSNX=bH47Br8RI#L`C+^Wxpm zI3h=d!vrg5?;SSWN<ayI6oFnQAEi5GkB~|rgv3ET{2lBwf=@rPsvS~PN*dz7HGy)M z;$qQ|TrvEU2hf^)xc&Tr{01XRac0VgIwnj|RlA>Z4Jf;C5W>72nobl#bZt)_W0AFN zdkFX$&7+qCpA<gzj^zwZAj#t(R0I9ZBw><uk~c{3Z;aHRc(M6`a>zGswb-xu^5{^; z7rW^I;604ZZFS+DC#JNgX6mmI6uPH#I`w=DjSTq>XNiQC%342qX;cJNQDPwzs%0Ir zm*o;!4Ek%^Au>wAwc|Wz2Zz7B`L&go8})`p<aL8H3X=KPK2O^w8)k8H$`0j+)tK6D zi4(cLl!3zt`{0AJb2_T}K5@sEdaN74Cl#Z)Bzc9PFlG+^#atAy@aLxsiuZ2{MeoOq znNY@5%Ze5UExsO<=p38Ql(w1a7C)3%94rbo9hy=5vZhDT>_dKV>aZFF8#BHql(J(M zPf_*wh!Scru*&3tJdH_F%RBZf+3E!f5(B0ZyRqN$hRHY++l(5<T4&FqK?0*U7G|=c zpuzfibmDGtdv0@O`5&<(r+V#a(kdLp@5HfhD1RJdv@1`6tTfdQm`0~x-KyK;;1e=E z^>`epZ9?03@ZX#c#J>`P=4t7udpXFk+4#*;UP<d|@O1vFsIlx&39&A<z%ZEO#q>>8 zAhq<LOyWf#azNg0n!Q!!ACRtEx7tqdcKwoqL14*~KUE-VfDG+-S7&<lL#i*kBl&M6 zy5N2^{Tthx0ed#ttbWaH?k%V4s9z`uU@LnRaG6gWXn2ACtM`G}HXqeTvI?67V`LM` zGRW|2eN`TB)!s$(yzNMn=9?RzX8$ntx2X(*+Ro~@HQ_~mx~}$YK2zB&GiBDhE;<A@ zjrB6dt>petRoPoMw(g}d1-QemDTba1p9aC~TxrLgeh7+T+j(1n0BJ#5XZ2J7+&A*9 zWvT?d>YYatWW2shNG*iq0Rkd*pLr)ZiDyWH2#+4$ynZ0vr<tr2&Qbbfj=OAQ@4mB_ z7Wg;qL575i_(mosWJGmHyLE1vgTOyddsRW#?|bG-mhc5eyNc(4FLmwgSURWTz<JRp z>j3fBOsdma_0zfQ=q^}DPycw$qGKeoSHra{S|RMey1y0a^efnRGUm1m&JG}wzJj<m zrXDH4aZ4v*3Nv;FEVIf1F^AIIMPfJ#A-G7G+DEPm-(9h&{T8g#u3nx?8|kX{1Yi8^ zqF!X{l1LfX%qHQ6cXcDJEbk7GXL9z}<2{Zrfpka_HhAV}MpgmlnsT_~NmV#lc71>$ z5trLiFe@HkV`Dqo>}}lY+)Dk|?;2lXN1%UJzsYen5IHqqwk1V-3Vm~(aFvQMtoVg{ zL2j3L|1s_f?8T95v;SqMZVcN>q0LONviopo^~;4^U`cp^XNo21N=LZwvMqNkwdCld zHg{c$oWi(XNVshoBla0*qFkKsG!!0x97a|~T8cdE2;hKWQ}2e%ZsiUuxV0+?n;VbK zfAPgY`E;`2p23msJo{t5S~z5*o2A&6?|xrUjK}Z;m1t))IPKYxuR}zRaFA?>F3EZx z@2VR@YKNvQxi}c;aXKTyQArpuX4$Et&Yo;<S1hx$7l!vZx@x|p$1D$TAIaME%VxNY zbPHSfSd-)U8V@kKCLnTr9-L(;(uzJmi^zg}ON*(NkTc+|%8{=p9{l2xxp>oxoEbN5 z(njpDZ0gmfXr$<rquFRNgiYdsF@ChOeV#Mj7{aVtlHl<LgW1a>ZK$;OYD8L#-6CC4 zHL7!G+z86gfxOK2N&;E@%S@>bRSgYCQ@;1{x5~sn#@6qrwCb6DEW|39y#foWR<n}U zAMCx2)bvr)8=Kb=9#Jgv9GXq^R;7wnHOHy7x!<C7I$QaIRJh!p-h2YNem&C+!q^s4 z(>%3Aax9RXyjfEEoZB8@TxiC8qgBom`!*X^!&YCZIXLS2CtI_FvLNUu4k`8m9{Xh7 zd&{G<v-h{KO%dI05r>TPuO}CE->>|IRotfM#f~ozi0*Z>DwWvlXyy4PQuSS3`ol{c zD#8<56!c7A3q7=?W~Qy2+w9`p7_l8s$q!EId~nt$97#fG&1bvw`Wbw$ai`!FeRm## z*WUu=^Q-Dlkgt0Z4XT-xL+TU)Dun(^`HUi)BcgIA5UuECG%6TWI}9|F5P9ZbGC4!_ zh`5N^*<w}Kl_>KbUfF&;l=hn%gA@zqO;G{W1gJ%h@*&ocpWSVQ97xekS?T7f5bL_% z<y<}~HpAAmzpB~N`RM7apn02iUM#1BD>ZFeH`GiS@FL3=<y4L4$&QaPN)@v4HyFRV zDh|YPpUAKne$e9XzS67Id>>CcD|RTq%bxislYy)`uL;GgN_`^fKDbxxCU3f6u-pEu zx$;N|MWcpx<+B(6qSW?J)I&}@Z)*fSQNEufsdj=MJC7_WkX}5}iZy!@b8Ps*APs&L z%S~+w`gquoc_@k|Aa&6F6z&>^uN$Jv0)`@E^&!GZ`N8*S^K|1{1aNkh3V2rXAFkzU z1r9B8d;h=yAu`vzk~TN6oEzq0RbSKtnZn`WjJ}y_1yq{s_cvJ|+^Wg-x*@wfIU}zr z1QhV}$*N7=TGFreBYz8=0PhTCzd1WmKWed`QioP}SroIDXKT~ObRVmC^7v+1k3ZCz zh6X>_Ke^P2`;EtOP+uo)B3w)WDOp)0yj|{#c9{Iwa=&(1wcEIl<g*+j;l2nos|mN2 zJMjt4LIq(7B>^K;ioQ9RgUtTi|A|cSo6uzjYDOs#U0E;{taro9)#z6Y?uVIx0D|d_ zpY{Z;UYi*){4L}*n=$-BSC*hz8U%3nbB4#(#n$N>KVha5<`FLIEE{sQ`v~F)I^_M+ z@>e0`s$~jLGNgvpA;O#NZ?kSX@{r5LC~YuE&q)ply32rulf%|nWkzH?@}cn?k9ux# z1BV(i(R%Y!mP6k|zxKC_6I#Q~Bv;=oqSdl?1K=Y*PWMGl^+L<2hy4Mz@sJe)67%{n zu3wN)lAx=xGIaB@!0Rnsr<tTyec%~T1NAWrf?2%TO5pF8J1;wik_eo*721M;Ff%Gw zXmPTcwg*dnd$7%2t=tE3hc$}Q$=!81;&qJ@4IK6j3H4|r=^m+dRUW*zyxTr$v-Kzp zO}O71p%G&1{6iK*A`b2aKT#ho;5Gix1o~OJ7(jEg8l9mmka8I)%EdS@%TsZHut*@1 z`kH{iz@&*G4<dt_H53R>x$JE$O1=6@%-TONK3sStK^I6g_)vJ%sU`*uRWQZ6Pki7; z7Aj%HzfMM8t(_Z6qO<VdotQqtQ{3yXeZRMCWJNcy8Xm-BInT1Y-^?+;9x9vRlM^AG z?O!_ENG&k^(BI1mTD59CRIC@r^P2iNdW_d}H`+S3>=qv%dFBi{jAn<0F}(oBWEBl! zf(dDRTyfz&h)eK8Ag#i4;Wea!<uXzu%(@W5G-cBj#x)66$zFg(n}(tEY1@Zmdj!s6 zmehjWZ6_2&rm8gATZLcVOmHjp3~H(SJ8q#)mCCycAbm8!XU=^;P_fv15e-rwCuqM` zmyb@k)B1oPAY!@yKp#~?aQk%|Au7w&RBDHhRgC8^v-m!)5FSPShFd98&(uqnk+r)} z5!K??fLQ!ck;b;C5xV>EAkIs$F8atd%724tVy=(WEPfa>9<;4F1^FJ8nxnSmUN$x= zI+NHmO>FzInmeZln@;UZjaO8ebyy4GgUK{PFI87+C<k>9;D&z8SQIbmQoY)>2zOq; ziuG*2{G}|PN9=*Pk^QdUu;VtWV?gj2j5Ss?$2}|{6hz6Cc;Dvd$I<4Vm#Kr5Gso85 ziUez<Mu0Wm53_bRb+@!4N9Fi21KnV5SKCkzM>T@SL4wY^9vUXE67=6sk0$a^VbHJ) z50EQCVo<?!8X@(&im5ZKiTjg6e5)4T;GKd>U*o!W{ykJgwxg_1->^}vHnjTf8J;3P zg$uZ^w0JWe8!#p1kTd<+xUZhF+t_L~*f=>g&Q4p02<>P6=6PVI%>Qh%TTiszGT`CP zeel#mGwV-~&Em~SK3Z$tosvvBz2Kq)TM|Zdqv>W4y=n`TJ9LY^=aDw5XIP5V=!p^e zQBvCp-FzVzMagG2yae1ThNs?jg<F-t`b%LUFyQ@9a^f_&uMgcS>auLg_2XQ?@f^R3 zxk&Fv%3ZO>okt_(lSvBlS3PMTPR1WO`$0a33-;~KpQO#%OU^X39h9$M%dNw4sHV?9 zbi5_&EeO0=`4aZyz3OI3Kpch>Ur}hSgcif}SnN5V*hcfT?NjSS;>qpP2bzBdUR<93 z$g~YA(`^~o)6Sze@C<Xw`!~8QuI`s>KBzPLMHRh+mGo$rlfGIeanNST*%I{URxlR) z9}Puw5~NqPNA1V1csVkVpxywxel&D)9$1p~T`fD;<v<4)4NH}+8w8W{&D9O#niT`~ zhTEPIL|lo{cEX)*8)w{4OHmK@ECYCod>S(cXMgSKd^S`J(BHVM)|p*o&P9Wi-EnEF z-LAC*_kW6d#g~3KA-W;^kp5MsZj?!?^)A|Ucb?w8+w4fC3L|+K;ZE^5@o%d-a_0jp z^FmTRB~&%Pu}4?LP0qSve^Mm5Z(9;%&y9KCe88TS`}RGODHYgvCAvcMl%*~K;@NZQ z<sI{5_O_sw=Ld?U0%Gr)!!i9kE$%yuRh3sH)wMDMzy&+sx9hm(q=gI?)gmrYyUQ)l zPoTs>wMs`yA0kM3dc@pvzSiY#%mJrH;4c>c#0gzt?y6|L3+c)m3Jt@TO(L4SDt0lb zufj!bPg`VV5AlPs2*=xlOGtUEiaAX`RC*vv)gXR6EGj#tYp3O_f3W>58r0oldlT4k zp~4h<YVgK8Kf5E4j=2iy(%&x@dbdKYv*k##?u19q40hSUrRh>gfy^Y`bDj!qI@aYb zo6Mjd)`Sgxg-(KChk*Qmh^?e6w*VNGx~o#guu2=I8&t*@3M^82x?z^oyady-<@Bx2 zI{M8Tv;<1}J63kV#8=ns{KuAb_h5!j<5%X*GN*|#S%Klq2yOkWK{^HyNteZ5-mSXD zgWL!mDLDmXwv8WII(@Mk32y-?p+dpH644E`xpeJW)8qSF+h-v>OY-e;85Wo#A_rs? za=dqi%!$yk<-9@EJH8u33l%9_o~Jo8V~ii+!#pjE#mCp`Nt2SmH;9Q!HEEhRXN`Me zadg#`r4^f%xr+eh@0De3it-s;QRZd6I{@4qg&EV(6E(!%onkDOe`|P;^zkJ`7zf5) z6~~zJVN)aua-3!E$mI>4r^MiSBKB$v^g#ZTFph8Y63Z&*>gafj4Y!!u!F=l8-9$eJ zcg|LD-x;v)W^1xkEjhQUI^>;G<RLI8-N*9%;*fbc?%l_ekI>@~J!v0IJWD2i*7iDW zVeUkYSMFZ$eC3YP`w~g~3`vszjqhZXXA^Ki*&nqS9g%$`a7YXJSl++EJPwUSk5@N% zl?heYq6k*kR#e)-8+_*@C2|@>*&UJCecqGw;9-&4+WF1Ac8>Z<vp`2qF_qBeZOui! z8cVs0k%@)<rsgqYwwAo6O~g6!VajEXzR8e7o9own(=wK!u^t2}JPhvF?>};W#u>5~ zyA(9nLYkS<q4Z6c99qc^@_%XcL=rSG#q#@{=63;T7V)USn)W<G{`RNviP5!%e3A8t ztCT`QZmcTj-9!)F<HyNhc%(-cu_}l(d8Bi#0MEblJiOnNvGm{#5mZC!A4^a8Ej)%x zy^OWtv8FfzJ#1H0>zq59O7r0&_eMlI)X;Nl-AB~0(P{IAgOH^`oMrT~Su|6K^l*|z zR@xCVOv#hd#6V}_qs`s7c+fW-PlNEHNCCba#hOpypQI4WzP_^3<%el8lybgaB1hpm zJYnjh+*CRi&*ro$L|RncrBt$S8Bvpq_t%Up#IEb?S1mJ*I67!@*$RjCQmUF_4OcwL zs}q<$6o)ZI^V}>#CjXE?_zcxnc(K`}$fINqqmd8mppz~3@uc$57hwG#|7@Ho3E4{c z!Im6Sdu7k(G`eN)fWLX@Ooe%ayjUGa48deCcc+TIHbyMNDhK(3hE2ac=AKS&u|RaS z;oN--$xEHf6#Hs3R-<nyn<ZgkwLu=3*VEV*9s;c%b4yN*%~}YIk^RNtG|@@KM%nve zjY)>r?W7Gq?ClKR8~%{NVIrqP`e1+j^4;7kgwIr04InJ*)hEEk!5rew^i#p;=(Jz6 z;%jNxuK}UqZcA4)Y`hH|qEd?fA5~DQdB-+?3R!=g<GIA1a80{dh6{YP^sGt*i-e4B zH7qvY#i?99qd6;?z6p}jYj&8TL{FszXV6-efrYgdrIWl4vx7;p{#`lks;aq?UC5NG zmR^Ib9F%cfijfJu-cM$sNG`Lx`?Q-QTd!s_4MmQxIZ1YOR=I0-VOxMn94d+XaH;-O zCv0Akaad=I?Yu)76P#hr@hPMWGvU-JX1a)3eQlCEVnWPHM2XH+1$*tPk&;W@9;1Re zTnXCwR!N}T!{aVykr;K!-eHb%>Xy<A{bB^4sHfMsWaA~~aq3_B!*wgS?vO*R=!`b` zOawja4;5o#%Ji%`!Cc*TJ=7OE>vkr*ie)y;XoC2Vb(Ib(cqhWdnh`dsa9Q#wa@5=U z0~wMu#2^&y6L63Zj<m&NT^xn3!`G8=*=oIQhYB6a1(BVHu$wWKi^9xs<7$(jugSe^ z%ven<_IldIp(7p{gIALlqKhm_ZS5B+>kF#gBC(jx`KdpH!=H@9=#qak-Mdi*MXUBm zYO`?oqr|_Hu`Ve3+$NxmcDo8_SYN(kcqtrgslW-cXvwQ?#_JrK3hS@$pLgSsR$CAI zNhZLj8v<d_!xkrj9`mS|(V*Y%KF{LFYWB*pQNj5O0|6X)e(+p2zw6DMb{LNQJ8#!G zidp)u7Ty3j2sW3eOVI9&o<j7jbjFx1WaMa3D$Pb^l!4-;3K2s_W95uQD>S5oLEqg2 z(^>|C)87TXTNJ`E|7r0ZCS)4#v5V`2LgkZj!f_EHe60xia#+^*jnS(0E+0+w)n`3t zxuA2vRP^$zm!0TM^LWaDS~dHZe=)yraj0U)dVPJflU4UH2CR|H8_Hlcv)Bm}@pM*? zZ*$CBm-8HXDJ673AfGxwMdL``!!Zm$RNHPh{G!q@Gdzz=Yoe@OWN)L{|BBtEcD0|y z-<<QyT;a##v7;wWz^(MXl|oN=dZhcO5WmTio+nQ1(wS}X<|b%XZGrZ-6Yb!J<{cum z3Ej7rP=d$)(^moaIRCPg5AuPMtNRu?ny%HIOP0YdDYUw5^ih2^qs7g&Mr`cRNd8g2 z(ei!d*+#kRyU0uz2cK)i0Mm~-RXdb?Som8Ac-}#R3_;`0t8Y^e9~^a#igcqolN|!v zQX(z=%sdzj0_VxjW&n<0fE@Qqj@HFNEXCZ_7$Rhp2T5#vT43CxE7=luIaFa3wApk5 z3Yx*1Vm;r=?f)k1INAomRw@x#w;7pm*8TIjp7uNA7VoeKI4DbH?7{+DeWdplR*XE( z3)4!hG0<%{kYvmRy7DoO=XlPdhx?}&M6-kg8|j6)9tCTV@Ba6|o6|>=9W<~Ttvt7@ zuGbOqz4*JAS<KKSl&^l67xsXHVE_E}Yr(VWHOrW{CFE8C#jR5Fv#-D<F!H8Z5-U-z zQJ#aEk}f^OB>iM8A1@n)!3SP>f<H53f0`EjxMSs@WSsUOJ!Ci{I04Wvjj(p}pkbhi zgTLO0wAeRA%K(|)-0b9@i6%iGo*sgpB|$e>mta<2`UUXq8zRTlQ1@i1c_%%+pV($e z*~1CX>fbT17E;0A7C(sOcohtiV%T|47?fYg#AG9tjz{?J@Z>3qBoSYhHwOjrZfH+% zk|E04BG6Y}Dn_Q!G%)Csm`g90YvO1}BpB|1V3ibBDFzn<b<yQqdb59sF?<+^Wb~kA zBES&-3aEzw$+oQd0xp~A3_}YzY$SSzum1DkP6}$prgYEueR(QY!OCMKL$i@uD4jbI z)jYaQm*d(}6>z2RZ+juCsxkL`xnG($#5M@<Mc<5&C_jhnlGdfG0;P0wy)1oUdrU0l z952IwZv=1WB9~_=GEjV3jAhOXLI#UCrv@vN)EX-CZolT0)^e?@VQ^*_ZtU#o1@iZ| zZ>Jh1_fMhB`3TLu%3A}+<YoP;KIe<AA*9xTk|xGNEfW0|NHLfQ3<gTk!L9Ut7&ouF zhQe&hxv<KgZC!Se?SLccVnhPZI-XWwt{$Sd9kTf;mehE6zYC<?daUvms|I`cfp#hN zd!9STb?285*%wJL9_XxyGp|ksj^3IY-IcUr45<7R>?oQ2Bh~$G09zwyW^ysZ9JfML zy=)V8CK9y43pKV2q>;C9K>EyPVOAyY20f03R=@8b#m?6%-WwUbWiXa6pa`;_w&llH zBn{HAIgr(Avtr?kE+bN;c#$h0ES2?vj3dg!Ypxb&76WxJ8AY|)R6~T=#iW&k&BJR% zDrag(vHm8GO8(}TDpJtZk_#^-(~aCP0-TU-7rXC(wOavxfOhyxpuMpKeWfk>Yw8Uk z8ODLH(hA_D<+TX%g9FKefbw(_P%ao0z3aMrR!m$IPYn45n}p|t6$j7UMPxYf8rR;E zjn#_xnbY?EEbPG^_pzd7*-Cy7A{|X&ZXV`>SvJ{_f;8Tq242bsx<~g9LcBn!47PEv zZ)k$Hg`mu!s9R2lH{|Th3_STV+Kc47glGH)OsVbpiEP(sHDl9L$$Y13G3esLZJ)=J zf5#shTb@r?C^9?^_9dO>Vx>FJ_$xY%#^$Ru$TS>rA5B=3lvJqGXD0VoYi2NW4EKe| zOnBhX8;0}K<ZA@!(v-H`8}$A-=vQFI+QL2QiZ=;nqYnRpakleSeW)dUXrxY7NR`s? z!K31*#nI^wBlLwMzK7?Tm<4tG5NYg4t<eB}D5x_*ErO5WFx6j&L6el-0WnmLHkxwQ zZKq|z7|MvMZElL*iMWQSfm@ou>xcQCSTsOl&LF&lLa+YsE8)>{Lx(R!rAN%aBnw5M z+PLfNL(rEbo5)W~xt1Y1MQgHU**CixT^n-+yyG5F50ex!6LP?RiRWkJY+K<UPIu2C z$W{un)bYkn%4IC4cV@WeYRk$$it=S_qB$PTsqrYxdSTR%Ly4eup<jk!b@_-5hY_@e z&e(dh<n$J1TB-KF%v;{q`xz)f)Y82!@l~(>dM@_3>8g~MN#uPoyVtPi$OwKAiu+4z zpked4`x66S{U4F09*A_Z#s}8GUFfw#*Yjg)6CExT;BOS9+x$JV5^yN-9xy@-{<2}n z)lfS=UCZ)z$Z2@69xmMH_D>?j%2hQV*8$bK!^}z4!%AP*xJZ15NW_ouF5mHea2Q6) zW@9VH^-&cdsCVJL%hq51(-=r44wf#>rfgORl?T8P;ec;u|9<m596N|3dnPD;G?gg^ zOu9j;kJfzOT-+~|f{=M$uJ{u(rS$;xj@5{W1|o<S&n{kiy;vu^M_6cWf+s)Zu0wDj zOSon{ha6Y$@dbzbovcJkoFQv1p1U1LXVXz8qjgkc<=in<FO?v)?JfOYPmZDkOw)Rf zS*bHWhIU?&htypU|J5kbIb7c@=_HhIQ6TU_04*0$9V=?HAy7ce-|7KgJ~c^zu($w1 z>*veqZ51I>&_^w8EGe_MX;Y7gG5l%5M4gcE)(V!nq65#^5z@{wd5`94Big{!Y-*ca zne3_;)s1Dx%9pt<>Z(4Tc@u>?5|_zrGTRczwy5;Zb-<l8ecX7i#4W}(c%~u{1$_O} z0Lx?akuMV=HT6Xyb=o-JMLf|o;jkTZ3l;Nk;-Mqu5uJ-fi4AKp3SmS!0PbR5B>aH6 z+qvwPFofEbHtL^Cq4Fl+^^TB7Rd_1Jhg91U<3@46tl5+5-z#QSnQb5J^s974W9#9* zuT3<L$c@miDu_}srCNk$C)zPjRzJkRw~YypB%MT&szPolWp#tnR6Sg+cpPj_6f#(5 zPK5TTF%vUs8oreH5xv~gO!N^|QY;IJr}x$=vNEhcej`uqXh$ayyEYl!?_T%x^TX?Z zaj&B6IH$gQu*tV#M+UJBXGg~Qc3vh7ZMb1+2v&GA6Se*=%L?<?341%5=+skNqEGLy z6YLUQ8l>a62R5vSj5t%6sF&p^_POx3+Wrbn(fCA9!Vsj(bkkyw-nsGJT!TPL<LiyF zIH2+X<{L1jNeb{75ri#6nddKt!-f#xj|88-C-~`xRd->w)DQ#8ZJvT`M(P#b5kM&; z%%dtTMetVHs;-~+ew=oTw=oNxf&9v0aT2w6XEm%m>yW8rN{E|Pmq~_jX~Ym|`qwwZ zbP&h>KuE+d8tvM3C#}89Y5VE5^V%=IKYZf;p-IR@!*oz3$i`f-q8u)3OB2*3DE{_I z{NkVE%7<Yzz*#;{z3Nqo_8biJg>SEQn$}V!(hBc|m~-*)R9)S;gmMYrW;W^@8_(;A z6R)H=)a4Y1o+iDah|Y6Y;YPH6YtcQ#^iaeqb^sMq@+>wq$q>Yyv#0j@@xjueJ5itP z>n#`3J8a0VV<8cjc~Rk2TEt4An7iBM2{~%04aZZnpe?bLMu}Ll0-vj7p@WUR@@#aE zX+sQT_7RSE&n3>6Up6zq>a%_Ou)G*;T7Abc=OXH6!Y3)r_e-q#>-KvcO!y^=VkZJ$ znb~I>2fT?C`?f7AGjsk~hL^u1LWHasRb*f0t=9dE4_w0+z8@g}S2y8VEl`C2_}9!B zT(CAjz>I@v;CpbC&c9!+7sEe}y`FSsyi0@{!J38IzuNCYL%W*ScC6LCTB|8Ol?v8? z87;l5-yWER7uwezTtph3flL@^hvh2UqR*Gj1&W3Eh9n>2t-6_zDn2Dr`ftex6hcj3 z^72uBAy;E!TwK=@+(5$@OaiSqRxphOWS}AujEra*sg!Zjf{$#%&J%9jZ9vO>lp~^; z#=BQ`?>ouGzR_B$V7>dI{AkNT)m)t*?o7Qc4W;TOj<cBx?@m7fE-Vfn20mhDf2WF~ z>TgZ%I8x$1DW~Z(BLkX&p2+=k?~g0}36b(1T}`%iLDvbSJ*cnkEV-n6k@ZFv_if#3 z(%Z;3OPz9^hjJ_tX5(lT;bn|4I-neg6mJoVV$z#*|GG0W3zd+g1Ih?X01CEqs~8Xy zTnG+7(D^_ynNjU|)g?8di!i&G<cG&krSFX*hTcRwnEt)#*ZqoBkYvLSh?QR{O-JSf z(pJKPb{a7PvU1nG3^70Q$7*|CtY~7_;DV{ZbW{5)1Y91A2eje$Wyu;>OjaidSNV;; zq}M)2Kl#F2;yTUxmF2ZRjo*BVJ2}1Ou*H92_hm@-q*{)Gwnh&n3i&$mB?f6>Q3Wx_ zMUBwn(IRxMgs+uO&R52^=mmiKRZwh!n%sJk$I!Ah>gy;Qo?3EMYz5Y3yG`j1yyw5E zFv<5?w#SGu8YN7Q?jNa52+kN*(G}8(%Tn=h^z^G&dE0215xq`;u<1FH9~()KaSaZb z+j(2w{z0+f!PqveF5Ox&L<t?PXK*x1nMYv|>4ZIdHZ|-^N=0<bk~StOI`e}mc<+z+ zFHu($`x3ciVjsG4G$zl}lble;WZwQBUp@iTy!Z)}mu5z8ulgmH7D_VfNAYHm<W52; zrcqcRgvvF#k={+a^AA>8MY?Xa%9}3zR98@#Dx%hun3MU%x(LtKu0`eH<3uBNS@a>T zX;!mZE#1iKMR%3gEKcss*c}?>qC;6Mg9xscHGCus+TtodYL$&>x^O!>Tq|YxH1IT1 zNpV&Dy;+X$9hM%slXDABQhPyJ*sA_HKa4QMENtUi*-8ibMRPOwB_*_5b+pp9UrBL+ zCPlYF=%WElUN$LGzWA+C_jg#5zk^f3(Zgn6LY6rX8A6RskOX6f%}(RC!h0m;bkZ?; zK1hn{Yf_6NLrW@;BYSLrhl5ILT(5ny3+zX3#<x``p}m6#A#ZL9t`n-?Yw)H;JYZ|} z?ggN}u?`2e+>3V(0tV-;6h=z$0AWH7@+fwI`=KAQ9Tz!4H>kr5es0x8g$oPLp5|br z)H;TGyd+(>R|k9;2e3GoCvrAhe%Gq3&j!!!^jxuiA%9EBe#W4^B(HIC+ZKW2&9$(c zFKq<t7vAx!?InluzpKs>PU!rJKE)p#FR-lo#A)g(ru4oa@A+KH4|Zya9dUN&T7PV7 zPG{P=+`a$8Kem1|H;vNsqO$cy{Q^`;Wpr!hs3R`DQgR}F_OnY>AaFjW3tf_U|7U-9 zxA@hgzt_7toY*}D#F2Hsmv&OC=cs~WhH2}7GlJ@P8L#?k<m3F1tAvB&(-8{^wAP1) zx}9|uESAm;Yo_C$;pi@rTSCG)Ens|Kn%(Euo|SMP%W|VAd)s%jqfh`6D#`1eEDa62 z3iaSrKk)(%Bpn2BeU}vQ(DusYP9|o^kDA$}%IIpJ3>o-7!@d_@KI7w^SV?2&{7@ZY zUGoI)?fwaxT_$M}9SJ+;7+OIr2Nf5Y5_5)aimAfq4=Jx6RW6#2N8M;D>r+JEbuDl! zI(^wKmIhKZ^SYXcX6ZwD%cv`h%0K@UORa@Dpno4jruyz3GoxD8T0|Xr+dq28;F|t> z8G0g{a=+*c2*#iEXzW+aqMDswTRl}hcl;me`)!6BYzA_c$x>E2<}Y%3iQCdq$&wuG zm7IE44<+bFw~=0dI*iU7_{7~IUVEvt(1vQiWIi6h^ojO(A8I}+e__>*=2z9HIj%j| z@PQ)gtnoWwqY9~}jQZ$4B|*%G>X!=w8jw=3ca&G@S)YAf(=ah+uWT&{`UX~5yAfdu zKscCRzA(_1yDUBc84se_<6j%a3MDNnLKdtPN<d$vH@(!Hz?*-;nK?GlmFJP>p((I3 zNY-TR6|A>zd~=InU|c9tE1$o7kLGkSBIICv3BOVO)|D+WASF96;Qx`=*W>}xW|;^y zxZ29A(SLhUnzXII`S-aRU{wowyOuEim}2c_S6@NY<aUk2(UaPi&}ZsgOaOj;MpYVt z6l1pQqAAlXp9zh|_;U=u(C)ulmz8G}&Llb8u6!J5_O$)$EgPUhbG-pvo7cqa1bv8k z|5gaqPfpu`>L{S8-77XnPtjIC0aE>eHbU4S@P%W~LF`#yQVqBmaY3*49^t0B?^Wd) z4h%2-U3gazyl=XTk>vWDKO{Yy!$VogAPdFdFinD&I%D3E_??Ww2dq*X?15LIvKAiv zI%8(jczX2YBn9FVu&!M7R{M7zJQ}jPXeM3Y8@nyBC5Uba2}yxvr7pp0zaW(MomyC- zCs(5r);d2O#T%=|D0Q{mL*U;4{!<J+-LNW33!r;Gk<h`QqvizUm0y;DPsdY@eu#$E zQWhCs$qhPOC~-zC0pw9zV#@G{DtvdqCaDCxQhQ$S{tebNW|?hfv=WvIH7yx`$tt7T zKZ;RThCBQHV%uOxaXTaL>bfaUA#d%A>Ozr3#Yz+3Fga>EIt(|r%U@XXzW7+V^!!#9 z?f6~koZyugWWqNlR4@=MqUv847y!x`hM+jf%92w76K4Z0D#6c!;PJSS5r&M_;s6IE zym2Myj$2|a_V3>4R4i<`n}7N_bErsnmGlrtHe<jwN8{$;Msepp_UhEp30VDPWfEjp z*Dt?q#9|>uagT$gl3T}Ze+r69aHZAGMd=+s{3RY7^XCmr$+~#BmE4JQ5m6T__5_ht zcvQJ{DIMz_e~>0@wimw?e~olI;n&BLt10easgT{ID}xts7J3olOVjUhKlQ)qf(l0! z!1+KS(u^l}0tJ`}?17@P>5%b>S*Z{YtF3^G-#?xnP{5^xuwK?~A<Bw``@gybugB1? z0&^;IAaXeNf4c6iHuPi2eqJ@UCGnBl{}cSoWM1fzvm|<QL?wA4R)iuxFFCfzfXVU- zQ3;WeWsl3|$`0>s1ZC;Fy3l)?!3=F4*hW*v$!abOpW(-qfd3hC0pIE%Dm&0;1PElH zeV_%&Q-U7HHEZuaqa9Yl3{Im(cwV-^#MTSBnr*TN!NZ2Q<KhT8rnP}BPxsj$d!LD{ zEJ&gydyBY}>3LaEG=HLjYj_}65R1qzQfQ$_q%Q4I7Hc4E#H0|!>aW{T=h0XJQtD=^ zji(e|cO)M7Uya;!Xh=YA8!S4FGW%z7C-%Ce{*0V|ST$U~fkJ2xD)>_p${nHYaso;% z)`rtA%;07UIAK+>b5`R-baGc4p2}oS`QD*>egA$SFS1G0E&GIkjx$Ukf>(JW@S<Uw zSFN?4Hp2rsus=PC>;psSouW`0kvSb{{}I$yhu<v5f4bDX1urjJNwkVJCHk_pW!Yyp z$9;QIa#(xUC5N))`t#ShI+c&QLW_aDw5>BB_oOe@>-Kyhvl3cHA5H$}*|vj<F7pB_ zFlHH$c7$o900!JX#^nTvCczyI34_3i00KDhoznAUwf!taiPIMu`LUsEk=u2gpnEdu z{%=i}gZKBnUKwH6;Fh|m`7;1ep?g`*HvKKC`qd6mG1tGGm;6ccSViDas%~i<2fa8a zXTopsvZ99u<CN0A40~NP)gDO%=`$LtQlBwwTmeBJ2BMPf3q*;~#g}`DyhLN)IkU;8 ztpQ0>*DMVpJddk0laZt$9N~L%As>n7X2$rZ9hOhsEWGX_-6H#xllOEtP5sUIhxB(f zY`w3Z??y7alnv5ky3l^w4v_ZsVXKT4{&5f$zlSoJFeNjgD^<cgKq+wU7(Ih8WJ-Fc zF?H<zdMnwY1UuXeNBSk3+v{%2MS0-bkr(2Z(&9R=1U$M3F)(A9kzI&fy0fHGP{jF` z3+yc7t38Q~smnzGI1>-{QulU?tjT{nl3@-b01Ue-?qh`E00|zGmop_IAiVsjACdwY zM=)D$+A0RLqm^Te&n8h_TXlkyQoyTyP}~)XXd)}?z3K#Lp^mJuWohvh(<<MYsGzT} z>YTHPtYb(-_ZWxU-M4=C|F=o^VSx(Au4&}tfE`(0wLOS7LB8X#wVj=g(0)3)n6{B2 zk>&+jGa`PZ$!6B#VLk=qYAMW9NFG!U)N8)VSvgM0x@5r5CPF1jEMof*6{or0F@;bg zvQ=Tk@%0_zR3;)KkUOiWqO6+F=FCA@2{tHCR`0(8vQrsnQhvS&(n739$9Q}0AG4|n zpevj+m^@_$n2cAAt((gtF9uBX=_VvSh}BcGetilQ!b9)_VObD55mHoT4x_;pkNt1w z#w}EpeTVATUhus8(PHR5Kw`Rb4VpT{3S3uxGSUtP+ngzXGE)D8%uL$7hihDh^0~?b z^=4G8naRCe(6G|1b^6GT8C}AI&|uPhC8;KZcFn}j<VD`oKY8)H$t@vACfeW^gWr6$ z@l}ItQg4VMeArQcTAh<EN?qD~XR?=vg$ooZ(xVg(TFkTTl8xtnnlg}B;=Wdnzi|3} z?Nl3_KzM*S`Z|a7st}}COMhQr%*3KBZ+FH^%q4o0fF7Nwy0-f27N6N>iFCt-hFG^6 zA0e^I82y(4$*MH%AN&LyO!&YDOhsjThh>GJG7*d;N^TO+LpNDFyvhW)GNtTDlOARv z-x>pYqZzPb7WQ$H)fLUb=!X<DI%{-6`@t)GSYFCYO1=dDF_qVjaqzozkHhjfUV8++ z-@$nUm4*#`bHI5nM@1u%1=TEY1;GX<_vnZrnh#yzD<C<;0eYPP%ww%;O77%pD}YQB z4756@2OfYk2*7*+hxq{rL+|E6&w5~_k%66^;&X}Xvd>S5Z1ExTpcHz%v6bcvwS4HH z(oWzy`g9W#+!yUHYn3R1-gy!pRg{LX4rG?>k61Kwd{S0jaHjJ={7)R6QaJyRC1hmL zef11C_c6-QInUx%7n_M&nIn>TtxuSMSey?DhW_nW?)UJ#7GY2nN0~X!bZmaP_3R%K z;pQoeD5}$dEB}qYFH<tZPc2pVE$xb+zuCJY^1^6N@(jw`O0Surk=SI#9u-oAtlvHG z#b2;VE{cA1LW2;18|GDOLFFFH`%I#KaUiVtm9)d_lIH^%I*JMu@5muBawh=V=}t1R zan&Tm!~P#|t&lt+a86Vpv*#}7F#gz>UU>o5B$yrE`xN=Ht}9cWAoF3|63+6CX?MpE z^~-hO8d?Bk1j`DRibDda{ywB0_fMx)RC&+ZxAGi!e@uAwJeC4tpz-z7KlRseVpf8% z$!K)TfhC)PTW-1wZZVjWn)WzfByP11)6KUSH^~G@*TRgat}HrAgN`nWl>Pupf^Kk5 z-pD4V-CDX-wjPms%Yt6pc^}n2^;DvaUUc>%C9El80aBGN2Ux8AXT0}Z{eyTHM?CE) zjeYV*GGi&|IejWybt5!aMv~-4rDRLv<jVhHKscM7fw)8{2%vQ6>4ZH8h`j?3sDT*Q z#_~|9?daTP0KtGm>IJox+UA{iV+KGEP&!y35a%%fQB^InqYeQrbrjqpJ!3YG6i2?A zT$}39Z1#4p{kq;`&H1m+8YJZ3$S?2xqO`ZXda90GW*DXuh>k(b{%4HCY@B%6Iw^F) zk)G*5ZSe2ThesQmInwut4caAY3E@pAnM##JnqLYvTv^<|2C0%(ecEQ1N6~XkzFHc` zET_kymv#gf&d6$tLprD@2z~)nGP+wPfJ9iMA=Nk6CFk*ZFsc}~^7U3#i|>6mmxD}+ z-l$<>40o&2_e{2E`gHtZ8YQ8*XX#lf4*R+9($Z?NyuzF@Qj<?|USWEG9R40x7aFlj z`xf&Xgh}`8L~R+lGd=d#Ciyw%Ujy6^YTvSiGU98Hz54r!IOvhgSh?fql3>-5E(R2J z=^|dal=t6GPX*&4geh0HbIP6k1GJvx7_%QExdPy^FMu`Zu}_5n%Vzx4*qT;7{)d*t z{JBkL>VLmo;v9=yUf}vlX$Kr8oV(l)880nxt!a1|)?SaOU+!uvO=^F-@92=i3VJD^ ztVFdxz(jkFu91JUp!z1&{Lrk3k4cfiOjAiH!z^e9$&8PSO%n9C(3Ns$$>;K!Ejg$_ zcDc8#{xGdRgY)oBF4df}`aB@T`K{0bDjI7hN{T^BiYCDhKAlB!j1$`pV2ipdSZ1ka z3T#>bO!a4vq{>_NBoF{i%4k?pWxszL2jXMlmCU0jdHSw*5wR0%3};lKYX|T@@6X$> zj5<7GvK*&S&o9|Y6t!l88^Q$f-o5SV_h0V+dkQz#rW!ZR&%B{{30SkaDY5+f5wF)< zkXk+d7b#zC(Tans7`w{oU_hu`iVn!1Z+<=-URFXx@2Nm~(aRtF#)d!qUFwLT<JiOG z3=#b;{{X392dnp^Dr1lcV>unC1uJ;77q(x`Crbx9C%!-4|D2pJg{i8_`0Gv3S)C_8 zZH&u%E4DZ2DMt>k1BulaJO02weOp*jaR`UI#mHgkvGxjkMM^bkIF{E}rX@U8JJ?zk zi}(glYm;CS!%6XX{7D!vf8CBT7S2~_mN9+LY2sdFU}VgTqeo5imHD=5?+5Q?QoHDW z<jg1I62$#LmqJWlsl;t#L;lx6uY}S-s4>OxCgE*Uv-sSx`g8InmlgRjLiSxQ;|~DM z^P55daO_DCp93t8Ny0u=Y0>73$+gg?U~$XP-pRdT=Sb)zHz~v7SJ@__qvmRKBsdJ1 zLAx}NgmA8q)wYf=RS1CY-8kEfUgyd<-kSaG9UHX5GT`!8TDyDnh1-Uz@0e(_nfHGY zGevV=Ll@vE{o6If+KuX0d?WlP)MFSOh&dR#a-ob?Tc*#`^Zza1J;(Y$-o$cKioUBM z2*ieDpj3|>r^qP32rB{2ZRr=U99F8XM_s=8r>_5fz`J$-QCm5AFe&)$ySM1SJ$y6f z2+Q>qtGB%@ESo20x8Y``!xPQ(hp4|VCJ{K{wiMURW<vRKJHjlBwf{X8mYb!fZp!H8 z-zRSfIoPBE>wydt$U8u!SYEEM-@-&}w!o0H0jHX&Ovttc%lt)b)@Pb$$_<dZ{dH<} zdxN#GXJwd(=<N9SLh}C}G{AfdO}JkJ46|iW&A^G7LdH*<er|>F&`BWa<>xe)+NM^7 z-*&ZZ4uuUF09t1l4as^e9RQh$l^g$XL9<3t8d5H5+C*N;C*<YS8n6Jxnaef%U%t60 z0tg|yz@gB|CVTJxqAiV0)^0y|m&KM^gvXZMwB?%_JiRRl#<dCn^n18`&WmWIw^afF z@(<9rRA;)$J^MX7egE!S=uJqa+kf+d$_d0C03Rc7R*#iKfYD&+Il)(Fz+tDtF_o)l zWC1+@@Wm7bKBfeS%ufM&-H>*pgwA>BjE3L@pi1z30fuIM_WuVtwl}N!n9TQEo+V<2 zbcbW?guCDQEEOwAtwm1p3w=^3_m?^T_wEFMupO9-q-<Yqhkg^YvE(iv+7W+p;OO=; zlMC^f1sys&Q@&>H{Nt}iphdt>y3Wy+xy&n}f59q64)p&iATxCfjv<w2*sR-Ej5#;q z(ga%i|152hF#6bxH5;n_W>&3l4r#wU-Ze~xwyU+6xDGO3wFJ=F<n#c#ie7^`k2#b6 zC6xYLXkL`r)0J6Oc?GA`aJbU{MvbbIGE~%zr^&wQ5fHl{tP?Ywr*zzPF;)vvvF*M& zKpWl+8#+hJ<eR^+7r+5_(F9>}D3EdIF@tOAU_zAPVLNx=0l=sfxbWv6K&@VRYGLZ= zPjU%I1hAHAn>If_W3sS>FRO^yIChk%`z=m2q2w8Td}6w3TT>@2j354|5c4iF42z7B zk?asCM|DW~P208j*u^Y1{L4MeIlXT`-So*$8zX>d;s}#BDZ*cW`folwZ}ue5>nBEb zUPCYxXI8V6+7-}Uj{O9x<*?5~=b|Qn!oOC11z9cOISx5Fy6swYnbN=jvM)ur4N1Y> z3$|?QEH{VpCghF{_V$q0i#to$k=19cbJNk<YjT{%pDTiIR^2@9)-_DE+~m#^aAK)B z_A(JR5V~0^1R8pB`O2iL^p4jkP25KL#P4gxTVr}+UI+Z|-Kn2|0HFpjvOSeJzz?XZ zU0{*sJe(A1WpWbp_i%trLkBwqY(juw_p5A#=Q8gl@j6hhZ%gV}LwV!9Fl;(2j3LNa zzlO?v3m_0|F|hvtxaORg8sh<GRmp_|=qDM=7rZE7|1z#mF#!i90S9h*_sc&^_w^a) z(Rt+gUh2Rjw_a+$NQ4i+=`ilh-W5Id`9r9UG8@gqB4Bp;jqH3r`IbdB#!eM1^rS13 zDfO02(_UgjXog@o;|u3x@z)#Dcy<g2r**SjfG#WccToLh-i51phGViPQJlK{1KHA- zZr(}ACn-<n98t#?H*yqrKx+tIB6juNVosv-*@*w$Zt6&<juvB6x`waR>y6BRg9gwG z6Q1SFM*k%BTmOHH8&Z1?xYr^`Fd6si>#5fy<OwE<Tu}mXtGOX!zX&qM>Ob|nJ;Go% zK`HY15+J=(iC`^!IK>~LorQYfKAPBg&rt=wl^Z&c@2I0G5k;0GGI5_Kk!WTiec}P5 zHY)kRJ#~Vg0YzWLm^i?IT;KIuy~yo&JnZ<~X54Y=f9i;_`=};|ALr05w>ZIqpLHKa zIjG>Zh5Jo`S&Uc^jCI%#XqFN))sX)*fl^SEIdZZde{Iq#iWi^?1bJ}(x7>G%*E9D4 znHZ2{wOs?k9;RpyN|P(%b%1MDBoAVbl^bkAeBNMIDS>?#s3%4fa>(d$-*+vFlbW+9 zdAofGxXAJ=LFO0T6&%O7cCg#>YQM+{W&((=jLeAX#ZQ1RET-c^xFhK>?{7vP0f*q6 zgYRaHz}uIHSzPh3-R>{Qob3Se+6y!rO7{;^%3DwGsU(-FAk=AWI{P-Do7XX@$cbu+ zJV8OTEJP!UGFVKt!w#E91Dde><9g9?mk{-<62AC*&>`ag1@%e77yzu9&y`M%pfAbq z0n!T`sE1z9pt1mY*@2jQRp9dJlX-}Vi<dmK3oI)8ZV56oAiC#J*9GWJC?JwAYX9=f zkgzJtyrmVSRnT$;0hne)HVn+pKhi+Xzn1KH`r@3d<F;4P2hB~P><?$q_j%^zgLoa1 zSl;|q^`}eqk{5LzAIAaIH>P;KqUtSyWKQ0gS|tK0U(wvw%p577>q<zl^T}QUv2fn< z5@kXAg;B?q5y;q7S;#*Ofj`J&{l5a6XCznd^6xsTsCZ;{5LS!tF+~ti#cCylA^YLp z{^?^D06f6%9<!*2nM+kdevxpt?#*Rh{5tS3lyUhtYE;hEa~b5v-AvW%ri5Dn39VNq zEl3J6=$$0<pCp?hkjM|p1E3q$>OI>X^3`3g^A&a+A<Tx&H|;lV0K7U7+nnn<1pQ)A z;8Tyl&x1YM(X-!Im0qkEIE&cwiJFiv#&SWrZm+)nX6j`8d!fw@AX+i23KCZKp|UZB zdX5dNf-t#F{l%mM_>FB)k(|FT!+)O&2z21jxHdsqFw@Pmy2lawdZhc|3M1uWZ1@$y z;r}<Yx7ZTvW0ZN$?14j&w7^v@N9f8R@5(@MJ<jx|WzL|?^7Sa;4?~friar&SZVDbr z6JZ?UyXP5qSk)mmN8+VeuuG))nV4e^d%WYIyq&FAo9ypfZ#G}hAFV<F_a$-UKYPff zbfS<%;^Tl2r}U-En^x27Zjjs&0Up`&2#~Me3S_7&8rMWoqOjQes9()}I{WxU8KYjn zj)q~o7Eb>G192mZ?i%a=f_?#<7vM$&a1wM<{8i_-yU^+bpvp|C6UGIsn@+QmnB_yj z2zGc3Na!?~ZY<x!<%0N>;jr^44Z+!cOmS+G!ZVA9%}l3zbjf$dAOqufujTg$L0xrw z#aYe(DgW-}joDS1zQKK0JM3~Iy5vOoYUlsq>#d`zirej9x{+?_PU$W|HYL)qL1NRb zbW4MDNOyN_1eEUXF6r)&lKw5;bMClt#<~A67{-v{T6?YUGoLv>GctXCvsbc)^4t&E zyU)TKshK0xn)f?g@#B9m`D+iYYfiD}TrnOPiIxgr`26v^jPVVVY4idc5fZV>)bY1G z0a6V@l?aN_?N^HJ3E7<4x38q~>z#MLjooe!B`Ad*A4bxrkiY50o;S8v;q0R>G+w5+ z-=%X`{(bX`bNQr~DX;POIYA@C#LAbP$jQrku`_BBQRcti+5jQ(I<ObUhWGVNJc)JR ze0>TGMdSZEaak-l9jjjl?CQ3YaCNtMh>Q&QUH&C=*Cdk79{xsGeDk=!A28@w2hv$q zx6BovBZqc8;f^N}#A36pcpg<^R6Q|bJL-)!QTQRk!F}!#T}2k5Q#8_sAmjfS{g3It zADeS68X5T~Z{J6i;H7IHIsMSN{ef+;Ah$U}=>QYVFtrFYU&aOP2jRF&<&2QSx=)vk zjJk~grla?C`sy|(l{dT)LDm@GA!9<wAqP<*T>8}vET8qX=4m0#lMXP*Mu7|uz746c zH^Nq+$NksP=Lak%RDezoV8p{eSX|SuvA=Z#78-y#4Yy(e;vk@q$A{omg#akj0M$q$ zn<f(5MhkcY^Od9A#>k*#9?v6umtf~jr5q*tE~A*C&QwD{+dyNgAkrZTLulV98}Kk= z`82q}r~7+^u<R}`_dhBI`+^f4I9c!8=g8$d;2g<`Td{#}^avrB|8MJ@o2ZO?s>Le6 zR(y@-lz#;vilcErGKW(ONM9lYm!_KWHuFD&X0*SGShavrux|8i-YsJp*vyC5V%vB; zvJdNFRyaTNWB+EHIjkn2Sx|0CY^Gad%Fgu~h^CS5os%XOi9|#<#QwK_JR0xy2x$d4 zqdrhqyH`SiEp!!6`4j+v1M-2pu=xfI)Og$HkCTDV@Y?eUi3FIyaD}#`NgFulRxfNl z()hjnqkN&Yah|(RyAap>&q(<CMI%U>t?L4RLmwUpeBnUI?>b49aqc71Lx5NqNz>n( zxOAkoex!)}$>bG$*?hpUUxycA&$!?O9Bm*qo)n^uYwecOie-TuL7;{ITFLM@O4z;L zp7U69sep_6=Hr>$Hu6yt2}DS0Al^$O=ps<_|8MxwZ-6=K;WM0KwnMAu@8xe1Xj(T9 zd18!uU|acGoHJWjYxlyhe0mXxXflaAH_*z`1)Nc}$=ImMzL3HIn7<K#zS&?U#|GT; zic-J`qapJ@Mi?P-79#%v1w02C2QK*)-TWtsun1rE7g!8VgYlR-trr{N91LJP>gjIH zXm}iv&7Y&Pl&wF`_esoF<8-_mnex=i>Wq@uMjfXQ$%fOBa)r0W+@ALkE1)SI;VA0t zny9XK(((<iXL=H6t|OpK0I*F5GpQYDr?3GKbT}zNaeEcRTzEZ=tmZHnHwCyXVo5V? z2{USWUcT#nb}vS6ti^4{4r)c|JI@2P`pxjMjggqZT3t3ti&Wrv^I6=!W1EdV*yvs5 zow>E+PF&=T=A!f5U^weMW_wb$4SZl4Ri9`Vbm(IIdFWBvY*pNOa7(!)%8)j(F!_ac z=Xo7?SfcllzK!Zr>K5Uk{|;R40Oi{7iEMR1uJS1Lfp+i$a@GGFrbsn|`p(1Tpi2lp zp0dvFvcA6DeBB$5$5PIXXiOiP*7?vbXqQan>3^?z;m?Mk@oV+9Y(XshVAQM<-BQhx zqJ){<R(I{{l#ZL%qWIC*deuCkAX*W6d#f#YTF^N0h0W1wG1h!?%k)#J93{DSzUkpp z1Eb7q2|!EiIN7!ZK!XoWdh2<?%4&~&X1VOiN8|<nta@ks^yA$fP?2+@Em@nM{d|yJ z6>+hbvFql03zXKZoPAL{;)Xm^{`05&H!}V>0vw7n0&DKEKEL})NQ^UD-LQ#PX_`FM zQU@PXo&B_!eNq|$`m<cCY%xaJPVP04v)ihLY$aU7Q27=h)$Ts}OjW;`FC|Y<{c`Hv zR(xOaE?EX|V7Mh&B=hrT+88Yk!{b-Zu%{z#QmhJO+tmc}F)K7=<@aAWLSBqW*hzm~ z(0$w;rNPl{2jr%g17+WPpv;7(^LS;Mu^vc4o#@E+m~6uFU$<@ir^=)6K+mkUN87ts zJM`<#kK~q~8KVnQi8_21r~GAuNMI@VuT$7$TU>|~@pUAH1v^Z~f`i&$l7W>HrU^Zv z5dge=)fe4_W!!g4KU0<c>$EO;YqRlx4X}lj72Wg*<_LNefW{eMGd3-@wAMYH#p<SI zIh+prh-i3@$Z;bNB|4H_f_4(h4muevuLg_i?XP4<$l4r+=S{~bIw2KBZFe)5Gs%N( zEL`8{{fXZ^$m;M*UUI*wwx~aQ96O5?(56u7myDh8U3I3G`enoO(2$U}yu!wzC&0jP z!5s;Abm@JRHa?5Bfas9+&d*=y2`9$AXYbqU9^x9+s-YOS>1&%y^E#(%w(;@WWG|Y- z?Mt!meX;0b)4Git<*tz5<-Ao^t@2zp<uf;gG%Iy&rtBZd_{+bTmj<E3^{&YHj?JQT zRA|@v<2mzw54Wxwyhexg#_v2<b^pJ_wG7Co(fa+>KZ_%F)`4=F2my}{Y6IM~8%5x~ zEwaJpNEEonl)g1i+DLh=N=Y9YiY`LQJn!WAQ=Lx0Xj&=M#o_zVhGoM4J=f1LclFVD z-<n}2!kgTYzhJ5?&<kWDg4@QKrC5O9$)E?vrz5?t^({+gl)B|%*-lq#-0ME+qc^*H z%C^nvmg{$)Fy}htA%+Rao$<gWDiJv5y0QRWsGrKu#@1`#NSYAA`wfw041Ua&N8C!4 z>1iRG-I@PB_&0yMioTWq@;DztFkp6(gu=s6&!FOO*dMuXy>lv_Qa(z(@-3t_SqU!# z%7}j@Xa8eRCZLy)xpsNfP*<LC8JO4S^$$zlAD;)EhIPoxmIuIDqynTlFp9)^yYgy2 z&deKmcAmDweJUVv2%aFmDK?_FdQ0lB8rX13k?>(?nVhf*m^NP3--b7k);^DKBpC4x z(k*r4DYhVmAL$wEz=9}7Jo*pop9kRh2Mp`!`e-Z^vJ_PwedDx5KBRs}eDJr2O5_D+ zoLNb18og8bqyuBJjQk^oZ%ETWq1g})L6WKXcNf=0ISIS>JSTEc_J|IQDJl<(WQB(_ zy??GZZIzIeCZ}z3NX(N^$NxzGHci|g<Y^QaF<Dt;G;AM7dO&-CtY(8opKXIr^Fk~` zZsQldk*I=BeDHVn*A|;;8aHHAN(13ZYq73F`LRd2<zMf+F>v?y?@I4?ydyX8<m+hx z@VmYl$sj4KE9j(W)vhn*c|V2}dNhOoz^v?{aKl3$=1vtuh|4B&3HT7QH8~^TYUW;5 z;hna&fzwu)x-P}QLLEI*;DgKcdbn_ymOMv*#7SP`Q?GA-JqL^ti7G+>!XHoz_$Tvd zuKsu3rFV`I4vJyU#&NqOO>BbyHWe1{?CiB1>Pa?4Pn%hJ^f^(nnRBushb16eF2u?d zHzD@kd<KQ-5kSgm`XxSykd!t&EPh|4XuJfrW1MRKRlJK&q5xv;S}ycx?2EaDf--FJ ziYk(HYa(B6v;5N)Kt=u|Qy{)o7TNZfwO#G8XQ+zE-;LBg&ieQjeW?$oxJTXIjt({q zl_t{B_mp6dM=x083gNa%#sBlY>iVGxH1txyD0bi^aqILtajS~NE_-hf`54Vvq2Dlm zn_@&w+h&bW8g2oxDC7ml3mPeJpp=f7CF}31+Eij*;*srT;!M;vclJwSzAN6&MQjK| zVLwA}pi|gI)+7GmLz0jAWwG4(L#<`hX$p}|2w$I#fzPQ^cKRD`;_?|PcCuhX{wJ#@ zs>#?`S*q%5NB?co=qHi3Es?3S0S!)&sq(_aKuW#Ej+pbkaAwmSpJ^&W%vMu<2JzUr zd4T!-*NB~68d`wEYoY3ebk^j=b^dAsZ|3~%t}~o+54To-2y99u^MAx{kpRKf6xBvK zl^ebe>+b=cYB~6q*<Hezio0b$`Q&-^QKZ(GSt~ef3g~oWB;~La&Y{dqOEp2k*X=*j zySa6-Qu91eirjvXhJ3B{2H^FSE*qY2t*p`CPla8}{r-FeQ~gmK;h&?O9a^|T_2R#$ zZRKav#Zs^}K5SQ-E+ihJKZ9Fw4-meA!)hN5!s{_q1?LCgFkqOfZRau9`5g<10ye$x z=ZXEUkJSZI)khfeDcRgy0U@)&ssy1NbZQ=3hN6rHVU~20;1}M!a6yKbF|(1;vmHEW zf(wtMv+!5_n@96GiNk7JIFWt^y8ikJK!YwbH<0jfPnw37Ri|o4^D$28En?|Bf>D`3 zxsq!8dN8MwWb680ttG2TZc_bnB;$Ro0Z!)A^sbvgy6W8IHLN3&fW6v%SKXAREOo#A zq!#leR=*NIE#tdb-VzjNwM7_yrr69<K5I25L?r7Nbq;Sp^|IcgIF;bHHz%VG?QB^S zpZ)7cZcgzz|Gr@;`^wzKdv1X2Yl}m+@p=i>%Ign_WH6j@R9&~7>9%U66E4LmKs^lU zIsR*v*0fZKu9Aq>lS&{Q!$$XN$C)h;d55E3|4_obGxbUDTsawZ@PTaxDQ3VQLPgRE zyMi%r>Ja1g7S$LAb3GBs(0(P2H*GzA!^joR-l&Ri$$`YIrcQn69&HYb>T7Zt2AroJ z*rC?eBEe`^4hnQ0wUv`-e$myR8h?2lKZA#&l_v6JhRR$I<WpRi(7kp*u{Zbswe}Fy zNq@SpjqhvC4B*X?G=Ny*b`Gvoo@7tzmak$>+hBPubOTDkA%Df?c~-n1%Q~f3`bf78 z8QYZLy&J1GiC_>b1psi3@2}mx3MHNz7BS<=vE|(UX;cxh953PrNZkOL7itp-eDhwN zlMvVh$;hDC$<*y&Rs-E365z;XK%u0FTE>gO2JVf0=B{AI+jvCqmmehFXSY6Ig9z>Y z(zmik#w*f>q|Zz!%}+V~<W&OLkIhrY8un@Ip1|;Iflgy3C~6TTO=(?k_2XRT6sKd4 zIM^W{rYcHCFa+V){z_EOGRRw67^iH)%$5?52klsi>-9uYXxkvZ(J0fw{aC?TIYFZq z!#8zSYo$7irsOo@S*1Fpf~S46Uh6NXFw4PY?y?6+rvA#YZP2^tG(ZafIKf;n8){aQ zKKlUX1dmz8hbF6iBCrZ1Lf#MFy^eNk0Ui`>NdqH6mTXXC&TX0!c<^hPR-ti7aG{40 zYtFhJt|W6w<EmBc(0u#z_4DWNbXkABu3opGSRMn?p%%Pwwn|7krsfA`Nq-W!K*`d1 z6{qx}2zjumpqPb0@||&WF@cTBE$%LOz|gQZ#}V=`lanc+)LSNo3?LrT=2tH?;aUn< zR1F(QrSDrdvcj{C^_;{@+{GvI2hYcdt1>sOd>6mU^^Xj>%ur2CdDBy(ee&X+zMAnc zAY<UQO-pIzqqvoV5Guq6;o&y@Te*rFx`+&vi238B2_Fn_;f>*C|NCH<ViZk}Fa6Mv zT?uKQ{nupjeeq37z*PFu(AzI?zdfe4H1AHb;}(4={am^+1z@6U8#JQXi{qLtn=%pd zZw)`oUbltRn=ar=Y@jN0-uF36ehwp!lruaEUV>bc`;CB%1qU4CfD#};%1#gY{V%Y} zHELNF73e4E1m|OFaVGZzd;eU=5|o$Sr?YBILZBeSAso9YEkG=rmB6SkJ*wz{jf~a{ zfQ24)9h2+)F-SLxv)inGKCHg~8d<1g#fx7Z|EYJE_H+>zj6miDD$U`)7*MA9#ymgL zD?Fe0^VfzGsExg&><g=MevU&K7fku?_#LXRigyKUQk%_m6kP8ijg?|pLkAH$V+9l* z`tj;g6(DicXINHDVn9D0&5gAI!t$?=ekk!cV0D`y-ctUr7kUfoK3$C7aD*q?Nd^br zuTg>9c$0^c=50{W@gm5ku~8GRG?{rp0l*(2X(qDHFhNQC#K<ob1VXikSN%l@+E_j& zd3z=D2Oy~;%3z*Se~oZwkP=aw#s8D}D#3?@7{n&vt3h?<h%r|jNH!Misc=FgNYQ0A ziiky^DQvL1>>X2)uPi*Cd9#jRF!XL94?Fw_KO#_9cBhyVXcofqxkqA~_qd)&oX?X& z#lz>d$<7F6i(JGALxeTPmM>iuR%`aNCJr3^krN#vxPjv!)(^=PXt#-(Z%KRO{gIqm zj36Dx%h?mIo8UIcQS^NE(|d7@U(l0Ct))m^j2d4M*o@LI@kyE<{7oao7ij$x?rN@I zYBHI~m~fthVbw)PcCn)nwhC&+ylbnT>sdt%U}7;j8VHdCiYE9LA$K-xUE1Ttz+!KD zzYL(ppaZB35x-snE0{SQ)Va@Fz+w<cOHU4vlfVPZBNw(V;CZ4yE^M>#XLc%&L}vR- zRvCMXUF+dOJ=l?$mQl%7LkHCyi1E1n4Rh%DoVXYHcUsL2@IC03*}%plQsCMRJ?Rh_ z@o=xRdUJFr%yHqsKxv?`<hBS-l>aW%%phXz|5%C-^(@~1>`L7&JDr?Nl*Fgm9wltk zAX``}kLI06sf5)k4YuX5se-cj4i$SV%;3>$k|pDnXWrG(haDIEP@Dm!3^uKH$q`Dp zorHlyb*)8>=e*;|4d}NtTC~>4S>0U!%vR(0x%dx~{2f?ma(^c$Lv{Q&tRRoK+9eY{ z5P@@BO_S4z-7df>JZb3|{pYveg4cMTJ&u%w3djf^vsD+7YB1AblNyb8o3Jch;bDop zJd_N15zQ<?JRLtj{v71dIH=e{D3FbDyDvdp@0LQ-kXoW_p>p=0LW8E^B&9rrx>^CM zUIuVmi{F??@WVvd%gh(3&(tsvG__{*w&e|(*Sz3speE_GN)6dk)i@&$Ka*6_gFQ5c zi+|lPO$XPK2$2|;7XeU_S;kY3kV*TF$C`F$jK!xkV%(K$rS4qv6|sfy-xj{dVc(AR z%BC~k0vlLK4IsQXtsZo-Z6E>W>iFAVxWA4Zfqf*FOaPh0T19|7ZA4?v5y(b^$Raq2 z0a0!d$)<lmOcq5}`IONnP)4pubh4N@K189AnUG9Q%0usub-{-5>Zc{jqm1w&c&KnK zKE#Yg+bv#P2Tm+F{IezeyoLuO?WGmBBTw_^j$VvE^8E=$8h_4#DvAY6B1ja;dq;+5 zbB$MomEPu4c#o4U+WC;eIjn%aYlqszx1Z3Gex&m9oFuM5cl>V(?Dqg{l0Uy~ar^}G z&KQG;VUZ@L5#*ua$F~F_U;yc*73#L)7nS*^HW7bt&4aXQVvxA>xwVKg*0SJ9@qJZ0 z`WGe#S`uv`Ct+WyaqYO&x0-r0E4?FL3R;lg`f&8y=~S6yId}bt{Ht!I{0hEg&BY(f zd90ea6qYd8d{JX~-X`X>($MU1Ju>s_E*AFOds5n+*yRe?a94hBwxnJ$13?bjYL^H~ zKY(NgCSBK}WmSo4n#xVOB!M87j_A4RnO%ln#P?~KD;2~nK;(-nnDR*=nmjw7_<DO` zohWyn_LD2us#52;%y_CSUL6l4yWzP+ISBtgQqKaNdv#7QNvCf*90zD&BD_`?AaOW9 zCd#cIdsTF;#^>Z>EJEVq_&<VTud>utU<uozrm??SPmKl5vF|*Sq@LWug4Ix(i)i>D zej6nrb~F0rMbs_(v>Mf7bYSr?Hpn+Y-V>Po_&m)>J4&zsW^Cc%z>;9o_76o2HM<{< zu2{R1MU*Y>%D@KcA>GvkIGZ8@ifOeNV0L@u@xlONZmY=pFj?|4zA})C&>^b;%4rUd znE}#TjMFp(>3dZkjVOQ(nY~UpE|yK-OsV;9E8J`tlM{Sc5bk<Cq>T@o161WC3;)Zp zxK$9_an=KoGPcQ^fW<t~CK#TA94u|MqK8qw93i#Bpr_<8pYz1yN36GuASj{XSXKfC zG)(!kG{vFacxz!Pwx$HvI!+T<lcobto>P&n(%b=B#WM$`WEn&XM+DpBMRQ(Ui-JKj z)yz!groZ*qD(f0KMnt+d9N!eOcr9{2M^Jb|42Hpz<+-2CXb+h>NAC)Rdq_vFi;RqM zP8cJt3)LAScj@=UG%dK&iRR+*b!WU*dDMOr;<}bH{8mhJDMTzma~Fg4x77Wa<clxO z*U8VLf<9I{TiR($>Vh#}$@1BSKToz+-aZtNOB*8X^)I-JhQ=rIVoH?KsWg)Dctijk z1!BCB(UF|<N2Grls)}Y&^TSGv{NQ@n{*4-c>C8@$8-Y-HM4mq8%drrmOBJiG)II)2 zVV`!xZ<5M5Su+`zA<iZWGm}+ZN4J3f=%akwLC44o6Y*UW*EGwMqW6fki;^5u>H4G! zyR(^-#X3yZXOt7x>NtduStNkUSN^Ju`v79B@%AYSHTvy5qsCaa{%)Zs5c)x?K>;WS zF1(~<6~v7(H7Kf@LG`bD@p#Nc6Y`(#enh!<yx)t%VfU|8pUFmwB4N@TJ~PLC@$^<Z zh$9mHt2s!^%*K5PohL1#3vBt3PWnMQkD`&;fnLXAn@>WP+_0EVKj-4x{%F$|YtRu= z&?*~0;#>NIeUV`0PL=d>#B_mBE9u0a2`uMLAa-f?+r7wp`MDHCd8ZMk`K`YPjIe?H z)#4?if<D}7Itg_laCKto5Jf&mq5-pDXyEPaTOFC<k%*>yYiq%dfi%iq>6D0XAK;qA z`N4fTKk7;!a=*z{AnnCRB9-Fk@_&vmvO%04wriTvI342Tmjb=7ox6T&TyNr&hsFAS zr=;=|Y@rcjwl(-;&iFLnQQM)+nq{vE^i;5{=`l`|AB{+~s(jWw@IVgToyCV}xyw(C zy!|C=i&j=zIJiun?d5C_vMIwx7mOe-6_wy$5?5kWx8wFH#IWIDS=-zmy8|=X9-9*- zR}m#zA}yv130%xRbtu83&e_4tZChSpp+SioyMe_DqJ9*M6kv^05xNG1h-=qqkUX@i zB<_KWA57bkMh|8<jgN<rpJIBnIei+2`Wn3{7$gu>eJ`eTbuj4e*xqrlJil)$no_M} znf-=7-s!LRo_M%gVCUas-HQ3W>Uyl(Z6C?yR^jEc;xqKP@AJyaK4`+c`FyiY9W;)x zbuSw05vc%={r=VQ{@**TdLT~{4SLB4x5r3y8jMCj?`XRJ#rkPQ35cl}wMLE=qsWp~ z+~Mc0bfEr{vAS?>Ykvpbzy9E5KJyTvOh{50F+c5Udl^<CL`zjyoc^%>`K#*ml<?@? znD|P~i*{k)gXK#kAtgmeJmVA&dijPm$dxz}DO?Qmx?J{%`z>_tbaDMC`+H*U*%=Rb zfU!y>k1h7LEXLE}yubnGR~FuK%*C7RfZZRINt3X8&MMR7;wHyy-y+1Dz*g{ptraa% zIzSUZ!^UMjtq`EQ`C3T-m-my@7P^cHR1IjN0`Abj|8{=PRREtAU}g2G21PlGf2l^e zU1AdSUHR#=Q>NRJFq|D?oAM;#vC#i+d<6K|Ywrz!Wt1r3E)74g!<_q%=MlXrpa%G- zB*6J`USf@B2wot}M0K*&2YAgS`>I;v>a#$;zt4>v3n06_N}^AG{sJ&HfMt&HwhYA( zfZR%e<1v9B5<nIoAxDIti}~!q;)Bu!VStb9+D%6C+JEKsUsNt;#o#IepCF?aP^|nY z9*$@a9bq1ckr;E1Lq_E82p5ozZnDwK%%`@4)A+jgMlVEqytfBNm)o$HCkz{ZEY)$| z)Sv*cPd7}MBP>}zmu+MlXy;#KK(=Ti@RO0*|KAOIuL3yWnY(Nb<}RKY|JxW(c@>HA z?%nl){rj&*^L)DVUvkOC7f!vNX7Bfm%mn?7*BCKR6v;MqM1|d_pc}T284T`g3A21( zrXcyQF9lKjw6_5669ek{1j!VVS%8dR`N;Y}zofzv3Sa`)PY)QA%TTr~ua-n$*;u;T z$s>WOC&>Y<d@8~MV60$l$XWW?*5i9Nb3P^<3#Hj?VoY$kR2eob#m|R*q)|c$!LA!~ zsZ}?WP3qY`5FskLveD1?L~;HRSFOsyh4-}~srSMf-lIA(B_AHqB6sVI>X~Z!UDwuR z2Z@(x?Iru0?XMH+%YwyWRu1dW$O9L5hEKDGLQdaZ-gkdn&zy%g8JpB1JyoV_9ap*= z<j_kHJx<)nPm`#qC;X1m3KaOHv$rlJ^@3(UNP@dohG`4kbMJH%$r?SHmqbSFA2BUR z$qe5+wk_o8WBa={>Jqgny}+4@oSBaM0nL0Sl9C^{ZyoaFBTr_RwY-Il-j_!Y<c~F9 zDGt^AV9A;NB7ayy9ssl6VCC0k9az6LD8?cs-NXV|A6Eh66~IiEkpR*y<^)FM+2?r% z)n6{Qw|B++U2p2{>}V92#6i*4<2CL?$QZXCQLNT)LV4Kvk;)bq@qc}S0u;9c*k>X_ zfqLbZ#G8XAP=2xF7=P{v4uo2+S5@|(iE=2FWI=(wj1)M5WSb+lHoZk*E^KGtJ*nS` zf_x9<(E*k|?T@ga4duoL)VM|DZ(bvl_oU`Bc(~Vh@>9U2XfN*D(_0*Ihs*UW{kK%V zUpA&&NC1qe1p=}uui>}^)_N1X`@f7KpTmv3u}-(=z~Pn`^ewP#g4ZubzhSri{lZ`W znA^aa78%{=srjU8E1CBSE7TLdTqQ^BB>3swfj+~(y(46=-wa{SzWKLx;fs>%{(7^$ zn!%7>Aq5LzGW-9J-68OFTj52>6pD5yh3H=r)&N++y)z4f4g3hei$X2|6jPE%jlmqz zzw<yPf=^OLCxbB^i81OrJUxR+<{bROF!|9<vZHm>a;z7BIn>KbWsCl7$|wzGRIqqX zHiERYI=C^FVF}fD^!69bCd$DYmfFxl3QtPeMJ=iiDQ!t~TZJShXmBsr<|JFVON|D( zn@|Z)z_n&kHmDD%gd6>Z?czK(`o2xSL9XP*lAf+EQ1FO`+Q^%<!m7`=u=`&wjxA{# z5*rgz;^ecfXnTw_;lAv}&0bSrDM==6m+mrn<VHDnlfbr7IqC=8or;(mzmiDQ2Txez zp&D8Sr|i0lhdQLy_o$@_f}6pfM=7VEiBF}EM9hjo?m8*Ix8&Y!KF*Q<nR$A8A~CV6 z^KfJYBBV&N`3}?P(Tan)eLxM_T73BVmEmiIg(=cyi*l0tUc`~t6F6<qfs2)K0GJXs zi^WYKACR3xhyVk&pGCfNpiN!dHT%2mF=_v(`Xm{GhR5<2g={rr=fFrWNKQ^ynE8zH zUwf!31InEm+|ouE<Cb(pVHacbC-Br7Eci<_iF|=NuF*rOda*4?Mi!^U$a#Yu$EI<{ zeS(lds)ZBrO9ygHL-Efl#{4cKnmp~czljFe)gY>9^8z&fWT5ew^7#Z<*b@!|JJmCt zaynA9w5<;p!&wi@d*%f1QX{foU4RWhN#M*M2!n#m5j8QC0*4-&ZdIctsmwQv(ve3+ z5G25`*$85<b<yZGqh4=U7Pb3ls$|Xb8-iW3UsTa>MC`;|D=6Aa$WGQl_k-)e{G^E` zq$gaLPa$3^kLyR(D(vPhB_uC5Oi}<qBP!YWnZ0}edn$dCC{Aq~=OWQvB+42$Zb7(= z>SYpW&ke;wY*){!m>yUS464rg?jES|Znd=@L?S7SgG8Ae_Y3pu@BjqI8<UB*;#}Uw zT5$NjCgxj3ZV<JId$0^mm7=@;WNZ*g+)}_1_Z4C0mqS06$hJL+m%B6XJ(1?y6dr|M zm#UgM;#K!RVT`tHWW^(68U;ZKVwui>B}|WvFgU1Syy7<N1((@&xzB3Oz;4qM7jkJz zs-5gem}+o__WP+hz^3Gb3<(RkekF8mY;PSJL&=nEC_drw8Dt&3dzyL&fNED`@olq7 z7goK+@9V$1eI)w<;Gth&fLBU*+{3XY{(psgdzGYt<mj^@PznN^mR2qTcYtOnj?2~{ zz&hOiNEpiE10`kY4<(14i$<_<o`#+SaYwTbiy`|J@^*Y<m^hfTAKZv;8+B7ohNm>; zZM}c~nw#5Nn!<E37%V(iP0*V$bquv+m%1|MBPrw;{#CcGk)$y$WtNtbWwquHz~?2* z)qP}==lP+C9hgYP0+Ta+I6G>YWT2GWh~MoJIKy#MN-7Fc#m-%9{F#JwoxgG}x7`48 z{?*ZN3AobhF3u`gb-pHiNNu$h*22)7NUWD%DpjqFC_oYex?Gj#QFN7ID?p_`G3)wj zKybbqSP$q_^nY@!bYxv*wc+H9aRg%!&>Q4sd2ccfVeklT7k1!{wFcpm(>@iWt5~LL zJc+?$%TtotsIK6&a-b1O(~^G7%^?co9V72@wEDbLql|)9Jpj9?h(E}u`)m9JAqe3O z6&Sn9MiDfMR<$TqhXL$3){2Q}+$P&idW1g{J)w&y(G%+Zrefda1M3xbb>FBSMZyK3 z^X}BcAn<iveqw9rzBz?YhNyIpli+jbb(5#QC5M6H!|R&;s?YyeJw<51)=~ERX~djC zy0@HQhN%NSxY)RY4m=g<t*vz73nKJJwWSBeSJGmiO@0!>1W$K8=>*ijTC?+2fvBx| zNrt;)b-rpb3ZQ<kB*#Jgf%6aNoJ2Vg7Bsm0KB4m(>ABu+qwP#v;RQ?Wst4_kHd%pT zDmcn_8?1%1E+Q=u<Xn^)kgN;zf+YD*`G-<vKYXnhsW5F*4PW8a(bzWd(_D_{Llq?B zv9@=iR49uGx(n^-lj)A;PfOeh`oKbx$kBZK6NNxnRTl?UgVei;K2E=A42@;i@1-zF zl+{o&u)@C`<p!J1LW#7OQ$<69&eZX{%M8XB-iibF<df)9)vyUEqVXLJ3ddhLeJcmF zKv@(DBo@8g>*`&;y$qeX<>0uKydA+)a3UyhUaR6KWx3Ra?5WCA=%Ma*<>*5RZ+cpo z(AEz2ahriv8r7(xcuffGPre@2PbSnIy2IVoYTX*11yR^=%6Jo%ccA-CM#*f1>ZZf8 z*MO3l2D=X6?WvtuBxcr|HoHxUOY_7#9ZA>7SkXo3H9v?#(&Jp|(9(48p#`#&ePim` z_Zp&3Z|8e;<u>}c8&r;Am}yZSm4@!q2I3=&VQj`qK5AYe-H~{f)n*CEOEOzfKf}DK zB}`3av0#fKNp)32x1vCTY9MIjF^G@7*$8K?V(K8RBwpdYLH$PgH}<>pzxlK-rds{M z(QkC%U)HZBa@Fb`73L?z;j;8_*LO~WB3dtGcFw*CKu(BX<I^&)o^pUpyFdmFU0YM> zYf=jkECCeSHHBNu$GTOQD<JtEx!h>wZbJu_Ol<s-t;$Q*I1ao*uz*)`8i)vn^?W#8 z2ZiUsLg;qj0VBJ%nwwb#B`uVi;)m}g19_}WQ?~XnBn?Vc37gb3LNc2t_f5(AXKi|M zSgjwkQ%<^7iDGkP$)7Zwa1KZ0=zj&wHXVnJ6-D}-O+J=;^$5dK=;!qZ3O;F?)QT`W z$T1}gGx<wAI*PlozkApd3i6fu@<1yFKs~cBKYTtvBqEMhSAn|><^4xR#Egqx*((CW z3xd}&3^o_UMFWO^xge_s9oDzZ(cgT{bWMrtXQk`yt%ZZlVhu^UKS3&wryEU^2yIhf zx>>y|i~i0A*jI?xOT%DZ$ZOf)!VT?!@tV8G5v`)ox4M+%IHLTbs9|DoP2Jean(8oc zj;6MoC|ggWDTKP?^D411GsHM(CtA$y<hltVM(ihRzm$&59s|PSM%@b<L#^{RZ=H9A zz5IsqBCits!_xVg@dN8ZOEI|86soQAma}<i46F<GZm#K*^>8b%bW5Zc*koH_h9o<h zP(!(H^3$ge2ARt2_=JfeJJOiX|FLeIX`g=f+Zpv+SA5s1@y*Lo#dY`hPq)IrmG2cq zsF{}2#3+eE>P2_41Jmcphz7lkvwkr<1);nRr~SAUuYiLmz&J^a3fTAIfZ3Su74*M~ zhnm#h3}g@*!!VOxol+|VsB=33VlSfyka6J8h>+If9{=|mm9Q~5d}6YeyfjiTr-@_F z9Qi63NabXK{uoD_gYB%T_^GI&7o)<|w1#}NM?qml@ev<)z~K0K4T~{3D_TxyCOsUr zAS@m`Jch<4fgd7?^R8M5O{2L6-JTC@63bg;XdaT(VLevI&r7YWqO}KAil<jgt(CtF z$`xJBgqxiy9ICxNMwp>7wP~henh1<dm1;IXnEZYnj{`Jt;%HQeWkiL~RE!c=gh7yK zVEZJYUO6A<wclw-B6>&CyOnXV2$jTv!oH=~^GHH>G)i|367$-=lxB3OWQnqa&h}hz zC)ICzdHsizE~|{>e9cz$V~4a%>1E}ZWULKvF3R-v%}aj1*M5E<8^q^>iI!-O0B$H8 z9eXqQuk6hVpjH-M`z3b8Z8dy(e`7A>3&e`gea7~@KPBC`fS!-E*i)a=M#uliw#Iz* zmjL$fbRxnzXpuL%=3(Xq(NriQR^7iw`DUKY<<Ir#I@vWXkaS?cI9yGqpJ2kH<lgBK z!RW5h$9RmGgoqT*GD}^Sl|_LrP_&`(Wc?xopJAN{`n&B{E%P7B8Qow2(g$s4lhHg9 z@Qum#8<Uz&PfBX7j7Hfy0+CyHYm^Spb<D5GQ1QK)(brDgwMRVKTUvnnkvcyCB%-ot z^t>FkQ%OsEW@g9-1{e5c_u^Ju&4uX}4;$qK^LlD3Sp3jKxEF_-Fa3~3b6|$wzJ`(Q zWu0URyIRaeCCn};c+etC4r038rsyEbn^z9KlBb*<0r-27Ebb^e>-EwuaigJqbh8H) zzmdQUZ7hVfb<&D{II8ar{1C(N?%M=T+8?N?jN=cD8NR*m;u1kfv*AUnkz^XSo~D#X zL@hTThvV51_sHehJ{Z;FSA2u2rMqx!Xp)(im)4(XJ5gxPM}Id#`by-s{OJAJ4@E%Y z#7fzud|uCfJ=%o`2j4-16}>0c%=!>Tf~DQ`5+Pb(jbesM(3Y~WKYhg^3fm8`O}7rY z&^v9B$}hkJS;?;MpoY%RnijGeA#)_7xE1D0vLST)f#dK;gH-A7Jc@&TM_rswMJ6f_ z8~cIH)Iq-tC_E19B8*%y#MCMEf$3Xj*e0I%2HuSD6cv)IhiMWq&s57oQRe57xHl{6 zhLI=V95b%7*!Ap|)YgH}30CdNfqa5OmRh~_*INXzT1g=S=XboOTOM^Y3*1|m1thjl z93K74f|<U{zy&Ah2uEQ3Lb|$%)wIM1Ob&qc|8;5k3=}lIdxQl~B(=*yAvLthn7;ca zQc&d8^IupVv!AoBex|=*z5IUZ2P_LDWNaF!bDQ|o&V0yTS+H6~8h?gTB2%!pdKn)k z6?!|<-o8if?Fhy2l0C_z4CDKP0TmX(hxGFE-${9Ck;8P6qcJ!!8BGb(9>929z+pc) z$K!0z_x|`Y%s99H&*HBoBW>c3IChgVTav2Dz`638<a(j3Z2S~tTB28|c?-W|jQBte z?GoW8nv-Sm44UfpSWaTWC?9slbznV-f4m49NF|QkX*wud^k<)-dC524YrTAaebve6 zIllP%o_ey*z~TyvoW5Yq#r-|(u6#-Va1{O}SuT?)!MT;Z^Kc{M<LaP0Yr>3JnCoRp zzD9iM(n<F&9I6QNx~`znP{^ewd!Di2S~~0|9jvpaL#RyN;^yS{L)sV!{`bFxAva%k z;~6FH262sam@?lU|1Pz>Tr#I?_RMDj6=%^-U$-~M1&hxtl<Mn_ha=(Ycy?}D^83f! zybE}I>sAQ~izAVr3O~9zUof3zRQsvqc=AUER2kQ_b$8e%i?g*XTUqf<2DT}8UI)&T zwPVWgVhP*(nAsdXFb;LrVP71Z5x$)R_mMZ+SXP-gy5G5mp=?4I5mUK~<;JMjiMcU( z{%)*NAz<O;dtgoK#K7}=4v8>$hb?dM4qmY2uSw9YtRLT>|FOgb3P$ex+DpPGOy2dT zdVRw28N&Sf^3Ue%F=4Ic!1u!Uz8%PP+%w9VUjbRk5g+KAP?`PclZ4CdB5n0XH_w8? zX6yL0Os>U`yi~ogkxo40x~gT8suW*ce{%N1@TRg=Oce3E4?Hk9z!*E@^I9Z)(3qy# zYdcs#+m2`Wv}A<INt7;d@-MOfv3_hIy;qV@_eVj4U<`@^njgv?GEc%}_TQz20KyKq zW9hqHpJWnap@s=lGz6ksOS?ife##|~_UV-AY%lHFVYG(pit|8c4M*YVKziDkuL9*7 z%f`K+ftI)(Tm%zOO|0@yG{QYAyV`aHn=G@t3-t)Z@f}tHHyT<iSmt@-(o+I&O*6g9 zFx1r0&`>%)sgJvgS!Hakd(p`rv&noVN;!EBaP>CZ#l1A8`VVTPh>D(_p*c-z&5k~} zyqhgK@9yPWwf7kyy*~K?eTWC1c5vgGcTBSIP-C(PF<J>$hor;Ugc?gP61eEO>#W8v zSZuhN<R#QZ@N`E{!ubjZEMP~cNm->%PURTLK+cH}EhPi(wzzA+0ar@jB>q1mW$L78 z)}nExNPpz>FxjO!M8PV7Ki@dtemrOs`gO2Q5>-0l1y?b~zPtB^HQ0>@m?d^Un=DJR zwp5wSvap{0-Yky-Jmr9l;8*fm<4_D#3$^+{js14cu3y;xBdIdp_IO28Od>x*deytl z1X`YQy`!F&j#e)v9t@xM0Bb#K=T8vmHTHBu+_;Cbu|N3j#m|}XUx_kS!`TZeLxa04 zk8a9FO3Js`PH0>J`7K*_77=po3Mx{&NDlEyM6lw>6Pfo4RlbGY@MV@+)-b;WT;t8Q zk$stPry8QIimKL^Zgw|w#_T<&pBwjkgN`f0v^-%q8{eYn=QdDJcRoDZQ}jt-OSCjd zRDU`aOFrMuhsKax2orAI1A{Fk5Q<>D6*%dmq3cBJ2&mdD$_13ol~+6g{o9R73-2h; z=1E76){UzEDct8JrQfY*zUPL|)4m9mQX<7DM@5})D4GBy4JBE{l(35T*_Cnh_>yd^ zMEl$k`4VIP#H0M_Z?p%~gr2>RPro%j?Ctx`svQm1cw8H27p0^9+K+2Z`!bd%FrV2x z<~e3LxpfqIpZ0Q;uH=h@<X-hW5_?JWd)#_n(vi>cD=L{n==H|2sIhsmSPzz0RA%qf zgy-86LnPjtl?=!1x%*g?DVEIJgZ$Nx21k)^wl?4wno&85a^U}pRRwryTL75`0wY); z(CZk^$<n0&xZqfED_%}{JDRRAHG;(C+=bs7jX+7G&%=(FeRp=}Uk1IN|M)(=du*Ja zv;=Y$l%it;V*KEeXwdwmt3ZHZW-A=1GT+9z9y8EMiHBI&t!w^HX(>Z!z!@Kmlo{9H zOTwW*vpxOh`pF^g+*(5D#SA!IjQ)RCEYeCq^Eu|t<C+L<r*IeeESG+SS&FFwmrY)7 zpR2m@NZR1}LBjRu<m}ZLj{FIFI*4S00Imf>;lS>Nh{T0{wWu+Q|K?Pih>r9>DU1L2 zuEZr42oxk!l%fcc?v!?}P|#grM$)6g98Ddq-lPCet60Ov3*Vde7m4To+APwX@<Zf3 z^`LyrIqz`J^uG^Oqof^Ex=E+IgM|6cZPw0hq%VfzYnN+q-xaz}Ma~P4JsoUqUz0eP zz^Rx?12{%JLC9r1Z``!mmQA)#t9_uGmRA@ZWvmqxbR$;MlsyCFKxr~X@5+Al+I_gl zbLhvcBp_`k#Rdb!&CF5fN@y}na8`>M*6?bcUGHPcHpQDoze3FL{NEzk&mW&0==OS0 z^Y^}nrV+iO5srS8e~kcw$H0sRM0zr4A}K3qQMHbj(SgO{r_dd(F_JEDTWMzVHii4s zXG-_c6Ux7=)ptiPvoALiFTlf@jPSI?=aoX{?zo0}6A8#Q@5>&{(^+Z*7o(Zf&2Emt z_JPups5wcrKHp}T23mGedX*m*(}}=QV*;J~DcgpE>Q9AcNd1&#iCV{Elsitby>y%+ zJku>i)_=adA_o4mFL42&Lic}afJcQr064~?y={*~V6B2a?l>GTZ;fPPM@SyS&bOc7 zWbkEpZe993%)LCloV+|MzZ%uofUq*G4^)lP@IrndmvdaYD=N%PRU3SHk#}wMd#DQk zqsRS*ltU8w7jrh$Fp^^7E!-~nT!_epxNbY@lL|=Lb1L3_(7Gb5X8Xvv8VmWPbl!&J zn=?4-W~AiB3(w)LB!r~<5#*oIo~AymB%arE@#Ghc+0UT=`>^TY5c%hY#eG++CiLb2 zR_S-UbnH|o$tc@*P<s(lMa?29`$BUJO68UUK1rhob>_h3A~GWM`Q^A3(fO_H+)Xt- zqhb=i{2M2JMI#2*5%=c^i@P8a{su0dKjDi*q*A}kzF!ospN1HioA2J9zige&Kgo@2 zpZ?Y8t6VVgILZ=t@+1v!GC!RjZ*}=<L$8>`w)lZ~n+8J*$9S$b{$ZH9gJlbXC=N#K z`w<4Es=)_1B{kaw<4>8ahDa5v`}_3cZzCD!X86{0@Bd{#UavjQ`#y>c9i06hkpau! z9P0(afj_(rrEUEFbr8XjS}=Fh5N``7xU#msTMNfB&aZd$`wjIMz9MX0vSR1p?T!y! zib4a`xS!R!bYzj%=FE%7i>hDjy)>F>`nhD~86~Cjcmw|7jjq9z-w5)ab!<yMj(nsJ z+1&#_{hEE}+dxnlOy@V|N+tjCD>}8cyh!)gmv)5<#4I20Xvx7J^op*I@4TV*9c6u; zq<S*@rsM74P5O^PpW)ah5+9e}Ytwh2JuQdrJ%?{LvKENQ{C?+ipVO<1gLl+*SHAYr zDnYlq-~M<hk*oCrpj~dNU%!@Jb;9ZQmO73=G-0*qmI?Yf_6*jEg7Ho=Aw2|vZ(JNQ zI(puOaEM1{Py-f!BBKUWjHuL+i&286w31N-(_(phAug3rynf+w(u$akPz@An0?xXN zA_J~COJ1;|G7<%Dqy`$ow;zOoA*$pU;U*Eq*<!6ZwfOrT60UKbZw8p9G=?t<U1R9Z zqss=uJTqoObGN9c99dkhJhIqQQglPnM#U{qKb&%Rx;iJp%w6gJ7R<sMWxzrm&s><> z%W(Qc3bEq$JMO#?y=bU?yXSDezj6$c-rGMkhbDC4LU)=|Tt)=Y3Ov62!iZSznz$G& znKESRxSA-f9l;BUHW%sqB_V|Jov6Q|nu{bSE+xtnq;WX#X2i9ro3WirJdAp*PD8*0 z&6HkE*!sq!M|2-F{Rb7J;YWr{%A31XC)jLH@8k2WO*VeRRt7WR3Jnjyf%$O)YEXg+ z1REvZAt{zRE*u9UcKirafjP1ZXk;~d6Gv)Gvn_nrSlbDKo!edrj@N#WR;GyLnY(ha z+e!w!$%SioTM__7<>kS*do2?&_#9lAI01uhcaQv;8+;&{KgPQk)N@Z)M02NC^C9*& ztM>P@W5lCfW=azJz-PwmoGsJ3b;7Bnllpms40;OT(jE<}rQjK;Ud2@akNF68pJP<Y zlyRGET3}zcLm$aLg<&LaA<a&i`VZeDA#Q#9*b3%#B-e~Wg3jse>g|H&f143u%(_Y& z^O6Zd$O8>8&kwaGlJYTf6}e3b7fb6!cNBLCtrl%Spt+2OqQnY=zM%U@IeI}mNzkht zZ|b>A#fIPSp=P<r`LtGAoTV@)>I#EUB*3Ze7{nV)cT4}B)`QrC@St>@uiz7{i$H2) z<L#17H9?=FqgfVTHubwi;-=V6IMSalz^?{_DL3x^mPURwN|R!s%aYFrMX3?)T}^Ox z(Q&KYD~emSpz4Zsa+&nmXPB}bSjA>xBp@}>M7)(v$c;h&K<l743aV;<_7uNew4nTf z$+Ip>CHbo_Y9#QHqX8x&H^(FYKq;KU$FQH$S2T=|1Z`x(bYl7g%>!C|+3(-KjZ?;e zk6;px8BGF~*827-CuX8vkZn%+z=waX8-Bg!tkef61momGieJFxXh`UOh%z9){0IKC z{<2<=qd$GsmJh0Ht>wu4k6q>Ct=D5m?Kfm+FE?k;W3L;Wm%(fZErLN!C^oeUe50d+ zw<b5(AxHJL47Nk6^dTpK>FYuOilybwz6?Z##bXghbH5fX1pYAh(EY$|s1j`&yBlW> zeIB<P2UY0Kh-#ULepj7C$j0V}uaFfh36=}jVAnqd#VHaGM8tt;8at(5x&!c4ZZg;y zd7}%A-DwIoZL$Pv{epq8rVWBSyd4vw9C&<`o`?254MX*@V@Wga_X=<ys@{7Xsgf?A z3%-$fw7+sDg{YG5ccPj?v=;h*(N}X%$*~6We?!nj$3}V442h-)&L65!H({EPM#zJU zLkS5WjuyKCmrXowC@ct4e^Mh$bwZ5hB^5?eA_(K^${wu!6jfX=Nxx8y@K*jKlJ*B{ zi*8c$v}_!5u7%z&pA;qCMNw9E$e7tH%7t5LslyDsm)A8Xc;GA8bbdyz%bmhdaB5*& z)|o;Ldc+q<s%Z3D`S7T-ffAB_QyPq}s38|cVnrBq9}MjITT`#KU9JeEH{b?`vqt5* zsLzwGw|T$3h@w61C%LvB#?ofo4idgUw=;j!Ryu8V-0Ui6;An7sY+>yiZQbk?(tfnO zLA?F=&?kn62ZN5N4hw$!{hhx)WX)iZ3I66p4&C0L1zJCl?e6^kFlc?y${ChM64sge zw+TlnCe#}ZA0-R@LCQeW;7N(dpF$Gmc&l(*K{HcRM5a)-&lb}zho}j0M<IZGZA?50 z_zOV}ono;x>%_cFhC3}7KEW(b-8t3RE0(s%&(Qehstu}o`=lwV5sVnW6i%iuxP#8r zszLC$a0N((cO34d<Cv#1nceB!TDQwiSV+d^X<qnm$Rp#N+`BV2GDi{V44rDSY%$<2 zgGe{L5Qbn4^gf~%jbcC{)?2yiWDSxUtRUg=sHarojk<m{PwocU4rWVL5E)^rxnyD- z@n_;sI^&r=^Lb=OzM4fgVa0CVMCznh$Ag4Cog|Q`*EbeCTW{x&c(1pX_<ov3&=43x z6op2VW`PzHze4-`=n&0@CMS5eDzp`779ylZ)vRW8ZK4s<4SSg_=)H=EJfbV$d7t*H z6zjK=-Xgz`$DcsOKR$I0C(mua9ta8kw4yJaX8pP87P9+2Dtd7v|HqW(19U$(WfX)0 z(J9_kaO}a6wVx>I73e|>f*F36EY5T#CE8jZg%fUG=l!bEy}=+Jj3kvCB8f?Q@ceN0 z``*-wF1BlF5(ZsqMEmLsDI~0N67k-7a196$mM$sa^V*-a-X8wk_1ZQzLT)5hL&&Gt zrLNG25+$%nI9u6lG2Z^h>45tPne3Je??j1bA}lYjZqv07GA8jg9JF_c(oMwv7-Sq1 zbVpSOW+utAQ+wf_$-bW{ZaIvqiTeI25e{0{<GA+ib_Z3hxq4Fn=TD;x)3FJnXz3pg z6IRwilLv9AlkWS+Y@zSf&AOr{f00HYPseu#!pO?Nb1uOh`S<!Pr_9(jTn!ve!wj48 zr>zQ~x)Db|BoRY`vwU@anhtVzsqL`6^=m8R1jB(1WCnIMgUsk|=bL*VMl=c8BE*Ue zQV)$p>8C-+`GRp^4VZ+Z{5d6ZbR^;3>a&yw_x_B2;XTnMJ{$e<5k8Zm>Q$$uZZD;i zHK)Hr#_4t5<EV;#k%pq?%bVXQk8PSQR(0Hzl?5B6C4%@xj%J7qy}6LUkJsIs=ghU} z(X^KM%~(g*!n`=Taa$>fpQ+Z8V>^E;HvECqC<?L-YmI`bu>L6M;fRJCVP}C#G;eXp zty+h*c@0S+g9CEq$D>iR^6MeG9VBfO#U`X%Q)y>$tlWMo!wwzAOh)K>70cgBNI6_( zc*Drdwtq@ixmUK8t;<`%N$O<UccFfv0|)ir`oo|{8nXl^O=Kyh^A8R%m3=JMs?-fW zNkQjbznCbc@rx^pCsjtqtWR}`XH=eJugk9eD`~;vN$G#f-I15)zTZ;SWlPDg^pNK; zSAY*@XNXP9#yG^$htUXT%OBt$YodiJIHcBnR}WY^ILJf-6OIb!PQ5;@I0s>d8KjDb zR8vCC=mYC%z%t+uzZ~h@xWLujkXC)TitLk%f69t}*GR;QgdZ5`*<c7cF<BxvlL)n> z$`0K3nJaz(fTi6;Vw)RU@>)u}?3$v5qNj#$)-U^mtg_0wT%KJ&jmg?guL7}LUMyAr zh+X!BV20n!SP}u53o0h0x_pufY{(*g20D~NN&_nXwpUUGDI<E)^toB~ddMOaok<V= zx6hNOPH73;HAH|a$Ogv1@uv|izS|-m$yWj>9LESYyrsHdrssPymAskg_h`NzUp5k~ zfrYs|@INDbp!?CpBFlpz0ryb0ZQKek_sL3<T7$X@#WDKGuF&}4ExYL`(F2Bd6vd>R zHUj^Su`^G%*IuTZf|!Z!CjKPv{yWUMwD$t(xPsg^b8JXGg{nAOG6PaG>~5V!Z{64Z z^&n0JetuiVTJ95+`+?UT@K`7@j>#G0O#SuUYZJ`aJP#1KTP6x&5gsekk*5WA@|H12 zG>~7?G-oIWX9kHZ16eVZ-o;=3xm?4jkWbr$@B?+7y946NN@BPexaC9t{!yu!aPO1U zga=&sOK)xrX-3pWvb*cHzcUX;>Nn#?`58au7<5FY^tDPEzQTTv>%%hra?<PQLCd~a zy9I&u>46LmuD~cdK;iJHF_Pe-tXYZKzLT-T5HcNW*CnZZ0Vlu(*2~spoa==CjP8|& zvFYpss>!_IaLY~RXisYATw$O^)nBsj?H>{}1Bq>nVWA66{p=x~hpokE(0?|+Uc!5; zCaws{Mzvs*X2W{>#E+;+VB_TD85YAnAEjesP_`)=yyrOlKU}?aSk&JaH9FKVba!_R zN=bt>2uQ~u2t$K}k^+KscMa0rHKc?JLpMl+h@?^yf;9Mk`2Ozu-22@Bd4`#D_St9c zwbx!}lj&a@4N3P8p7I<$M@GU&Mjs2273z<k`$WidN?3{WlXRy%A?VGi>pJ>!bAYFf zN0w-&{vt#y@fmqlYG-1Y4>oPE%Wo1TNI8B0`(@sy$WL8m(;M;$^Y>|0hgZMyFH9IK zv@F@t;aB3_J*`}7Bn+4|7!I(W^WbU-n#|i3H*7u*FE;M^P_X1z`5~^cvbOx{=DsPk zH(01AoZaN=5tuEN25j9P($_o1;dt8zNBUEd=&<NQMQ*a4UHzG|=fWVvIZxi;rtBPi zKNUvotpU2%BE@BfVZ|DP3)ES0UT8f;VHWx0{)NPDY4aV)D^^U<08YEy3A+a%t`@Te zh}0h`2*O6IWr1{8R6jxhcG{HUh{hV|QNKi}K?j|<X=+H}GG?HfkUriOWL|Ly;R<r` zdPF)34h7AxkXoax$ITX4NS$!mjiMVkA3ausqSf3`o~=q1qa&RU*K4WPUCgEKrR?(m zc~+x6N^(zmgUbuqK)oJLPg4GrP;5Q6vO^g}f?XN%(WPb3n;s|KJ%-OKgO>BFEWhr% zwi@?&mSUZ1SNxl_qh;M;`i4m<wFVl3K7KRpK)#^}?T*lGNC;|h|1Wn<l(%06zX2M5 zu!=F@WWxQT=L6o#B~K7fLqRykMvI+;+lz3K&20jvh#%A+XQUM)1>7l0zuKiEs3jxW z$~Pr9mNx3~sm9CbWo(<C<Gxl2KKK1qJsKA|F&Wh(q0F|4J$~RK<YCdFx-M+xY?#c2 zVYn0BL}qPrN56wdh0M=eb@d+8>Tl9gOn$(>>@@IbR1ccQ>aU>us#K||iohfkX#m9* zYo9Fa1<pkhoe@bT%drR3m<A*ixZsaaMM~m=NK<*MVfD)rwVG)i?x4R8gJU6mdqI6! zU;I3S8;n{*8`KpoFD^M;E*|fFeocA3*2@svw~#AP`&b?CvGdY0gdZ&(3j>X|dS>Yw z)w!SeimbfVddOYVo!WQ*qvhgw#Gqap&zroOn9KWxK$X?kbHXDJSREQIKtN<@Owt4A zA*9^lhABe^NJC2v!{~khaASD#B|Bn)G^Fle?-3shr$TEHI%uAGfHb-V710yYm(`+` z2Xihiujw)3wy!zF(fD?#fd-YNR6pe&NqHnHTXe_yP3M<EbG`N_JxJhxgK)J`1@VPd zzO|2^<<r_FP8Tn4IV^~;jzK_9HvZ0OU$wExWYjkk&!kWMo*f`zEI7Tv`T54_g!Vfd zo8Rn(X8$#mymoe<|F4cz1Hodp%p28&NO%nsj7fM?Iyd3NXt6H2G|(Oqa?@dW!}^{p zS)p`;4TlX`caai5SD!k!HZ&OqueqXg^Rg%F<`tZO1w!OBEOXU5=QkI<+h}aXzV<uH zC+HrT)Hc$Enq=BlJdNP5&9WaP8%ul)ES8CPzhPL+maNXWG6a*foA)3z6f{~5Q3UTZ zh}Lp6=fBI$&>>OX-n-}X_8L?gD)S)_fWe^^O(}iL+=_*QMmJ+AeOZiFH54+bM$IzE zI!AXNAlMa21X^YigU<IlH1rp%B#HJ#GLqtd@^yiK*Jwjlh=%Y-eu|mWI<!L4V^`ZC z1xP3xRIu+>($kXqCX=}ktO@5-XboG@90*M#g}pMYb8ll<&AADX6(R7yAGOU5K{ePJ zXR=eo@MnX}Y+5t7^mR!itTrn>zNB}sl=7l{m`sw`EfbW=bb9>1^35pHkvd2j9j+X# zVj<KW5==UPE=0ib?tLu?82I!*EX<JzWk;lt(!xnRo7o$<D=Y*Xkfey+{9t#^1`rHS z*($h!(TR(b(x@lXsoxq685K7t>}&f?97q^SRXLYKb=Q!8_B^I9hr@Rcj``fH=+TXM z*4S0OOMD-FXUnxBe$`7D&i12nEKLMQRgl%|caVMBd6{;8)w-v}5w>albX)@f)TTFV zCe4+pCEEw_5eK2pP9JTM&a7d5Jp_0kO8X`i>khH#^*8K6FV>=;q)Di<&u{R5`cBbU z$e?Js``eYV+J2;}^<>m9P~<Tfwnxg>fg`Jw#FD08;iwWuEaSdCl8!mgx<V4WHRD7* zZ0E7+`->zk2c(ezXRn7^rIHH9f~sPv9y5O7H|*ES6bkQmb+}^~Z+^0qjFCce8KZL( zR?8}27yq6_CrBiuFWNAZ|KeJY4w5wB@Yc&KJXv0vHf);1fo3w7BFew^B<{dfn_WAk zi;Q?wo>e+F>Kes^UMIOsS;Uca`z6Y3($lNA2SnC)^6F>#FDB>$8G7FF%bITv?r9KC z1$rs;E{U@0@Cvd$-TlD(2M7z=FGODiy#``s>}>2jM0#a=YvQLk3|B-F6AA8yDH<tY zKwGEO#iJU?iTBgxjV~xB>8vR(UBALtbOjLj;lDi?pA4i38%@sMqr+vyyF%!A<>iMn zdbpPMbNXwZ2|u^OvbZ+5PM3U{?8#CUB5L8cTRNKY*gn8SL1u^fRWvmLARV3XKR{}R z*(i;Yeo1jSnxE>;;Zq{!kmFvD+GrYo3-|#?J>KKq+MS-3DU#_+=4xP0rs}4DvRo$c z!6xrnXo_Ddi;SY2KoI-e@(>;ipLML1>AuC-iD`IGXXq0gY}|!(9~DRTi{oA*eR4h; zirdsTr*<mOP{Z=XpL#~BU;Pr&YgLkcwn5YLWbn+rsOk(ZG#ouz^(oTd9I);j@Qv<F zbJ!WRxEIP#zw8(zOGvs=v$cy$2ht&B9cx-NvRl;M-GV*~Vqt@4M8ZpmpoZ47u3R!w z$HupWCBeRzR=>-r4YT|NJ`{=W2M?eFrJSxHuz;MRAW9tEZ@**`3W?(keXJUuKNc|3 z&cyXQXv6wsICv-jgS$h-q90B3gFxXh=qY#lh`V%tQJuP`7T(7lwVKZcFQDXxCgPNw zKMcFFs6<SPo!gM;C6E#tDdxW9Y=%VbgJ`1ez1`j5;BRHT(=x0>vLCuF$R?u#o<asK zBU7G%YAm(Dcsr<uk(@lW29<28>BlL1_LooJe_-T-aBW=!_BTJ3f@6-g2H3Z&y?I%- zZhrieol^g-gJ2=9iX@bbVN)V<+vpL|#on#(xzp-V+Y7OqmPuAmDVOsqQNT70<;hhi zC0uOt{k_~m0|%0D>EGlPTUN8%IAfAVLw_VdBlsg>%HqfG7nno;KEgM8%SP%n&K%9b z8|M|R{B;9JQl-r0L@tM6&rAy_!huAU(9?p|opo;w*h{uynYQ?o)FvNi-^YB%whks6 zk10)x->kN{tMUS~L`{v~9CbbYH&pU-yLKV)<kQR#|I_hzX(1Be+;#n}f%Wjt;^NId zGHoS&Kh1XV&N1Np)6v<PJy0O(kH>*=SrOjhK=gut)_zM@Vk=2;;^{yCwlIBdne?i3 z?}a{mBt9K+__rsEF=1*e6vzq(ZA@lms%!GIf#+i1ZG2RJ%BOU2!+hC3ROnJ<qAdkI zdxYPoj9+eS5%71fy8eF5URJSA#?#wjD}+|Jk?JfbkBT^K%kSOMXEE$u&UW&4P?d`9 zw18QZ+Tx(NfUKQ7smvdqgDNmgGTTQ*6Qn|lL0|b^j$$G^Z9-`F)<%FF1BbzPE16wr zgV|bH*(P<1vaMRTSmo<Xz{U3r`+!+pRX4L!v>NE2boP0`6#N6aS(*xt8cN!dX|z%W zV?_A9N*-4O_iN_2SL$}M!%?$5W%RXkZZ(r>HRPMKEmr-wH8Fe4O%ufN_V(AjW0*-` z7zPH$ue^74M2*__`6As#GE;Wye!u(F)#XYs7bg<J*DpU<C+PM9$t9&UT^1IQZWx9H znD#&kOqeY_^adVW2VQ*)GJ<o2p*G0C)p(56m{vYkyIR!HekbNzMH(*i;P2rLdFb2G zedus3K3pb#5Au|!_AZlgPh3)s;~734cPY0+?pmKy3OBzCPv~jx3v~NX#B@;FWLAIS zH9b7s$SeZ-BX{-k4GOD*HJM;>Q$Z2O5e;yx{O9?-!^^VKKE_a1d__qu9-H~NS{i3z z`P(;%gxyG|0#^LXp=apsJ$v#Jq$UYI3|+rlzttcgcOD3>G<}NbBI#~y?|Y-9S`i*w z%Zz49OxnTcLccX&aoca<shsxn%@$-S5cLWUC6$dyEIg6J48mHN!JlElhq4W<1u+iY zjOu`%<b)<Bow>7E`GYJAXj)hfbyrN@WTR24PESVR4+`O-$GutAJDv9XJYXZ&a_Tu> zV^XXe;$(@R88(J32Wlpultd#x=Rwd^7g{sw%|5ut2>R*K5`_Ss5|pS$Gq8Vo^CeB? z()bi2;(kR<|H(Kt83E_G_)bA+nvf8<#R^HjK7U5B6Dc%&;oRg^gr*4+Ag0cEi!Y?W z_@)~zD<>M!xulL2FC3H=f2`D9^9tunbR)&9R$wbRH1I(445dVr_uJ{>u+VD2#jm|j z`NQSB0owdKI21qJR{DZpaNhdquAf0f&jNrjf>h+!S|;u@cxdU^#S;#~f(xhIRPhv9 zKpN5rg+v6Xy6de!1)L^iNWH?pS&nkmbIx>;Ttfa^O+-eW`N)zg(+)XpZ0D4iQI3O< z{jY7T@2~gD^WS&u-%Y&zV*PtUL*i|rL`h_j-^3r4N9JninZgwcF;gK4Xfh5zLjHit z+TQy3hEBi2fS$9&13bjGyj-W4BW>#4_R;;}k-rQ#3%w+q(gLl%b<;<)O@lu4D`{3@ za10fSMG{@`JX+hoC$S#f9g|NY5+~`ptchs!%yY&z|1m$zOpd;|F;Kg#DDOp4jFjR~ z=fQ+g)>sQ@KbK`IV-im($45s@xp(Ir>ft@{v&)n731W1|c#~P<Ttb2V+t(%du!nfk zM4*9i`AN)fJTkN%mPI~m@>7^fgZb7oAnUq{-Qm~Q9rC2y8t|?2x@uv)PgxGZ)u#t^ zx0L+Aa|lo_4rm>!r?W}r<&^!e7lOouWf#=1Za47_W$FWT2QJ)eSO?Z&>6K2cA+IVG z-k@ZqyVTfCR-FhYh+wo;E>wfIlEQ0UvZsGY6&`o1`E<zPXy(i2b{V5c{9@7Yu;4+q z)k$V=N*4I$F^$;VV?rD9)}G|*Uz%9}O)CM-1MBIHHh3ic@2mP>>C0f%eRfPcJTt2c zn_R48RI)+Q<?#z`elTp2UU&5g2;o$?&2+OkxLDqy9<r`d<gK7)kS2D$s2GWKo>?6i z`c>HkQbJmX6NLDHJRHU(qK1rODe&2-L{%XIDj0n_7;rb<_bSsr%nN>T(zukPQG&N! za`DZaZyu+=VkdxZ=?zrAiD3ScJRefJfgL<5(e%P1!1y*!Q|O^#BcNxDK=1cib}S!W z7{P!b-0{MD8i=frtzs09`H2<kh6d!-It9c|Eh8Bswr7vCR!bW?o#)Le4I`1!=O}e; zwdWL!^d5;BltWssA9Klr*Ne^Ne|4khJ=8){t4iEVHQmE9_%lc$h{y=Iqv``h-uR6% z2wD^7?!|-&3;%dy`ZAnuo(?nM7nlZji5n7x6^b>0J~&K<7l+kWOv2i**qlSmI2zHD zXOh_b{LbwtOqRNa8aoKymj*js3JY#ZM$|jGba_^#qm>c!5$(Ub+ceFMEcYqLMg#FM zzu?B^9&l=&!%>5@j8s4UXyJd-e;-SAyWuC2io^H=D?j*;$0h-?56&}7_ESSqWq&rN zxZ#P&UAV~!YYTBwLpP%^&3m;k)z5;$?f#NnZ(zlFPm6Vv?uUNeJOB3jmrt8r5@&F# zPMr{Khf7Z%_185nak`DJ+Vi2@bRxvr=YY5k`x1^jfAz|DLM6E?krFf_&??EZ3$gB= zianOvvnYFpAIf5ut)9{+aam?0JYA2L5B%CmgqvM<AQdD(<QG`;;s!??E*~N5{d)>< z9IpV+YMvf@$ZHc`qj!?7Pd)oEthjieM9}D+pi(T@SXJdd=4Y}+m3gPEC)Y1eJ`|)z zTdZcpLNHTITC6K#PX=;wpi#k)30YDHSNFk$NE&5Mgas&NVH^W~WI@UYP-U<3D6J8o zQl^UjD+G!i3Gz~0JydpnTN8#G8(ynpq#$54=?t3RTa6|P$4A^16cQinG`y1cUDJA$ zO8>e87?a9EnXwA=$v!^0kBu~w52ubDl2SbyM3PrgokkiIH((J8F01x0kJDJN-bfcl zUJefGs+8+s2#vsATYl~K$jpt&jivHzj>30YQ6R?7Z($>sV{a9d|B80BF{O$mX%lm! zDk!{~N;cR6YgmDS)2?N?a@H@v9oH4BAQ(#ie3IG_9@%J322fI4d&V8Aq&dZZiDkr3 zgg4x%^)~-)4JV1FS5fMWwrYV{h-j9Bu+qz!rHYvyiy7B-89!orVqulem*pq#$AoXX zw!fV5$3re^exQ~`522nq{&1_`*iAzw8e*@0+I<LknE!&aMi-Dwe=K-)%RtZs8i{1| z<E~f^2erbu*A{VCqVidjXuE&s<IIe`R*D$KZ*#fUBz-wXPiCJ9?9BW#FwEUO5hETQ z$%~HwA$ml(sn&m5{3h*QK29jI#6oL;Bai!dL6o{p9Y~%L9d6QUXhT!b>-s1@jG6T~ z<-g6n4d1t;`?(A#sjES-nFVUN;Tohl%-Q2ZKBrdB(3ks--?V^7-dlOlnicDUbHX>{ zjHiD5+=?<g_4Ef%Tvx;`X+?0QM1_hT>#|(_3rU54pjR8t<6ePWh4qqo(^Q%d2A5D4 z1m&)L_qik@H1Z4kLq;&b@84K&YxH76%VJgm0$zUH-8Zym+y57)+@HE$2&J8DRZG}> zoS0jh2_dvpR#GfrJ<D9kD4aV$*j!^W4719A#hG=L>|17V4GmrV%WZNN>S9R$RW36C zv$9Vn#8;1Q(Vho1NF;j+Czmb=!_IiGqDk~Oyh!$DX|n9M$t!{47uG^LH3$7;Dm&b& zGXgZlhKL;W<LF(_M9-LK3W+_7RU)B?eWwi?j;SWXkehZGMjeZ7J2wRm6NVGa9cA5P zG*rCBuUrv+X}aS6U?o%zI5HcNL^tcn=6RU)`nU3%?pqo%DDSo<(}y1)22ax5m{E4D z2A&l&Z8OueSlm_H*n+V$NpaC5XXu1YPQxrB?Y{GWT<Otjix2}+9)EHUFE%?yfT1lC z6QCKAo=>T@LxMGhNMiaLqlrCBD-K_1KpvP9)0fObtu6K5>6JKAON{Srr*ta14_O-! z(%%{`cMCDYlVI5Zyr&44@nGZ!&6h-=jrgX5QOF&JC%v6D1ei$9%O@ClI!OhT5YjG8 zVM;jR{SVz77|ofzi#4U|r<#8XcijS4ewm0M9b!8N)qU#D>f&8px*DEMp>$3%oE)@~ z#8&y|hH-D1DNZp-g;^bh%<p{Ps(N(Na0`gA@)8r{7)NrJ9fhD{O37UuN3RwUm_;nt ziBAQIXP4A(#B6a8yiqzGE?~PMx3?4@D_iTt_|v<Jd9oRE;EKgrkc^*J5QJNT!Y34S zPude_?Weg=gR-@NKEX%Zu&P-F!bN>t`zD7RaGcl#65a*Bm9~;jn$}ot^%7cysHK7k znqx$zQtYYYaGSAVs2qZBQq+8fY6sR&L;vj2XPOb1-B$PdJPR1A#1R?w_n$#7JW0wF zx8_Q=j_AU!WAs&Peh@C+kgRF^3<&(I&%Cd}6#ICS?YzQUxqR5M?;-pQmwE#d3fE}p zP5q-6R!lJpuT+c6&2SS?WS+b%jl?5u0tgZG|EFh?T<U5v46lV4kx=R?Fbu!MN93$5 zfnd(KVja5F8hHTG`+5Ul#0fx9^mIgoLQHD)4c`kb?k+z!2M|=$>^l~6ajii;=r8PB zTniYs+m_+@jBnPig5jv7)LSCDGl|x#Ff0h#O)jiWU-?u?N+41*zEj*(DslCg$qIdC zcC;^}qI%UvZ6PI!$<#Wf<T0^8Rk8qy_zuu!cwAf!pq>Nz;XDRxJRdf&hSniEEFqKv zsI(tzhH*5bTT|?)o8r`NMQr;JC{p9;47jX}y-<>F;7)c&1IQ<N?;b)BCA(2_F47@0 zMXnc)vi>_3@X2K$Yjs$I77d!s-fSU3!S(He=co^hHn-2GU&@W{)67m<LLU|<E%S+6 z?7K8std?#`Av!Bh0sh^XPe+txgM%sWi6txUJn5vN2m`w5R2CL5F2!QE>Xn_&X&Ky6 z=RF#Z5`c66)Kp7x<zx2UC{pBP-^swhO!xX@&I4-TkKJ-*szHgvrk)uxL4UEPrAkp( zAES6_YA!UuqfR&!^=N#BAWGBqU$RjR5oX_)M#dz1V2=;wZ4I9F!=cNCXOo~BW_e3A zq+Oi`sOI)(mN`*WyDDco)TEWDY0(c?fAC>{{f0pr_`tMlX*JqQ!<-dM<TW-8v>^F; zSWKv)Ut80X61OJ@qmuw9g1SbmuwI>Sop?a+l>#ywCWHa4qKfY4jB9x#S9d7mk?)Xw zrFKN_yJ<JP$L=EP;^@fMMbNGaz|qRbG;n2EpzjG;)}@C|86sl<9;1k_p4DbQg$_|0 z7GVMhbW{MN$_;gW=Q2c4-3=Sb(FZ|aS((<2Nw|9jrVwb?Ob8uvQ&-#HU*jViQ@*7$ zm*uIY-kUo1nmKW}n%>#lNWmY7&A1f-fE$h3=OMF1!Lh0#6vN-$kXu3htrPf0&n!-G zLQ4q_)z?)hh=Jd1y1O+2j@}M}eSie|62t#yup@++AMr_unBbrSly+W-GaFw3-66l` zw|kBF$eKBrL3+86#&PSDeKYhjq#0pgi;;Y9o2q2n{?p?BP<JW7>ZIJrJ)vSzN&!(K zv5(0HP`JQiri*>5x8XK0S17DzW=4cOA*b;M!O#YZR#^C099;YHl3>k2-rPG5<pPw? z&5(ums0eiUa~_b<`!GV|S{*&+i2O-;W*dz4tSH;PH{id_38CV|R>e(C9)l$fY+$rx z!YDbs`zb}|S+-?GX_6u@;^pr3iMNae+VsY>5yUJ#1l4zOJ}%5F&+apiNC7Y;N`ebt z!UhQD-&>Esqiz7~vt%U?;COm5q{JO(OU6>52@t<y96`#vA6T%EL0+@`+RzumVRfSN zR$h;&xv6WG5?kouOR!Btc#4WfufNX5ot@EKfB0pZelGWH%WF>xw_sV<rLz0$Yft59 zyK)XePk&Kb%ngmgPdL_g+YA|$j7pGKSY>Xvnz?gaP&`2dWT##LcouWl*-utv=J}ps zw;_&?LVWbQlF$)zO<Y<ozoMMJskzqu((<>^m^eAGBJ2LNDEfs|gv%a{a`9g1#Ciqt z)q2H${U-?C3`hnu4h=3bwev?FAi62bq%EOuzUnmoTIhq{@n#={zEG|JTy>YyGN!&F zK`@}!tq(3DK%RqU2s$jWcJm7tV&DXz8Uhy&#{Jw5|MGyAJ0!ghsYO8Fi9|LuX)?Jb z4a$hkE?XV-oG@)l({bnBnV6gGW>YKa-rD)Q4Q2`3LKOY*wAS-or9^S`wV+OSg%6(g zPVs?vcn);@?3g>@ROUM+@zM6P4l4>l9GDNsorG6nsmYjRd03_&-cU<G0~`oSQo<d5 zd;}WhHw1u-=GnIItdK}4J;`rXJ#(M+op8b%9B`wEJo}B3V03t7>p6p_gvh86f^a$5 zD|{wQG_IWH*^<;VH$?Xd?2!I6sXGr-ZZJ-P+I5HQ5%U)b-a#dFlJ4kJtr~C7E)%r6 zw@Gdk3e<kTt&KOVHa>Z<j|FOGir|kcDbV4TU|M38GohjsrCtBX=r^i64S-dhboW%) zqhpA1-}-wKKqC0lTsw+X6jifXUiWcT3YxKn(ppc*+B-%!v37_o5AdiLk9IIxM)ssL z;oK(%^n{1LP$Dl}xKel8t)yLpem_&2OSXwd5$U2!yz!x==NcCV3z2S>u0vc3a5=a* zJvg+3>y=8i&$!cw;T#c<7#u|Myd?9oR-Xq6fP+P(0J7bAg>BM)uV`~?j3qN=#()lf zvO{r^PfAYvfJWGW?s$(<8`1`7bpQunT$S<AIYcfYwBJZl-;sia-6*JTE40+-aM_sy z+9;ci0<x0ed_n#@oPF~GEbm?`pr=D!gGDC@oST+6Yigb|-@nJBw*fB>Uai>Y2jm1H zw%ROiH>j?zKOY4oYP*-KStjWw)PGtzjTTg{yaq|4>#2vTr99D-YAQZsgG8GQf%x%A zUdnDnvAK5Ld6&n^ek8XyD`U04<ru~hJ3l{f)K(|M$i;iqCg;Kyz$j%Vx4t`(G8NA^ zj4S4S0P|L(>P2}ft4l||P1a{Sr6|p=gFp;vB<-;{AFq~Xm{*mhVDE;JX(f^1!sO=I zuZ$9U)I}LNO4!`;RLrSkv6Xl!md8-16H-UnfWStX>Ln&Cxy`4)^QOBb<#ITd)9gBU z*p*SH-ai7~o(C(@Q%!GIM_6^;o$G5%XA(GK{Cyz1)kUu6>ffgm>M0j98k+Sf1f?@} z^f?HBh`0N0R4%5*_xo3Qd2bqLrSRl3)y$I0WR#NJtDry5k|u3vh*f%kF%~_?Sj>8e zduCsXLd~!+`J_}S_&__P|G%vL(2%0Xj^zmR?%lKVXw$V1uuF|jdQQ!!b~`qppb$d{ z)XlxLJr9K&8uD6{0_1c^W?jxx_}Zxt=c|rm{_Pf*?~N*1=*zwzW0}Ig4w@#7PS>P$ z@cnU#g7I~zZE6(BiaG1QT)#5Yt0`PBvJqunl%xrffB6V)=O=y06x`_LbPYYbe+5xb zOVat}&+OMm?}j`Ev2;i#fIO=9Xx*u<{U-(*r7s-;*)CRP<DBTResN6L=OIyUQ@WwJ znsA)o6+O?|VKkDZsbmL9PvV7^3QxXhC>%<xDZpqy(Hd_!l%6LYCv>hvEGkjsI^$N1 zj^*pKrLyX<lO;t(a{Gt&QjY&Dn2Gl=p^c?JS{@(5V7%Zy_r^stvf7zuCeoytl&pI# z@_D9Sq;5am*j%t%PuDHcUtOB@w#Y%4hyndQg$mc(@*rasW8nIwsr>)Y=>Y(p-b`df zgT24dfr;GOV@!hK&NE++fB^9%)}5^wR1h|+iw+gVfMPpwKdVVWy?}&<N54@{#Yfzq zHH1c`iWiaRxDZKf5m!Kv;YRDZ-ph`XUbiQMr|GwSw8hPHV>!>cb(kHbgqVs2j%CCq zU~O+$mOPYyC7tFo7~HqHZ7!lPJ+_in^=im2+%x3xCG+$_Y*$TzfJ17-4YC9LmI4Ec zhW9I`^?e7x9mDZfunedeXB_F*YKFHCOEs@M0nJ28o7hVdg+I=SIGU_CH`rE$kn)i! z%g^qwB+ey5g5H~@MU&0nC5tT+4NaYn@YVOV;WTeFs=sn6Cf4c~!S?|kK&t5X9!Tdi z&T}8(v04yMsP9M+<|h(g11*kt+V@hv5(scxDHiEg$A3u+7p$Zm@8~<LLqn2IMt%DJ z$?lR?Pxe$82aWPLR~re}3P^nj<AcySV-sb_P{aR~zK2&s@^7EW0<gE+P?1xCpZykx z9WiC-z(L*(q!-esd@Bx_R@bEywj5tlr53GfIiN3=n%)$+Optwk5Q#l+dVWmv<|(&9 zEM+PNq(}cCXh1+kWD{ZYB*GPW1tw$kW<4+oYUQhI3!yN4!7#tDfIY|-gw<?iKV9++ z9p>OPU(-&El6Shhzki>5H~;ZVxPm)|LQptSQeqTU@L`PGBw(og?9_~8B#yGoEr_a~ z<qQjN^Fb#30}Htk(?`nEO?x#3veeCqenF}jX^|0O{D}msBZeCOH8;kTbW&I4k<HJs zOcr>L2`>SX+T&aMSmc$uvnf};e<K<tvB_X?7d2A`ziDeNNJEuW1|Ymx5C+OX^n#q` zstlt|KF;m(I}RxAECi{@OjpiT8(U+3)L;@`5mm~B(AdZ-UJF0uZ55&Jj^blL^H5ET z?IbW&kt&m+BK@K42}w6;hhCemX4pigHCf>^C<gR!>%G}F18!_BrW?E_16{1<7p|vr zwu4EgFgAD;RBaf$rb+JG@`;Z$1H_J7Odov?GNyr})nXzU{g36}L6>%hjXiJ_Z~$F% z&*`wa(0rDt*Am(a2v3L&3|o_cT6`h3-Ue87Wyjr#_rIMidfSTYD_m$?rP1q#K%+Vs zbxx;0#|6TZIB>d?sXL~8nS{3i5A^e^$v|`U4pwSYm-l}*)a&Ip1&4FZMpp4DH<yO= zZ*n{)PEy1$pijw{d4iP1R1+EbmA1o!;Tb>CD1T}&J-Zm{dAYV=7x73}N|;x0zi9V+ zjew{3fyUVo2+wE^gh%Ix1s8nn`zqO1`eCu;gt~#+Iu1*l{C^7g;k+e)_2o{9o&sr5 z^F__BIl#cMQ2cpqIb&y062k2<)bPu%NN_4?NW&Jy4jdZ~Ck4aCrP{w0P-+zGJ8E(Y z$D6_4V1u9X=!D=J*sxuK3?ADNVpsNvvj+8-Q$uBa%k8n_dTf#U<l#K=0S8X6vTMSa zSqRMo@BT_|7@mM2lm%|MqJ(D3!Zoy(t#R+175nP?WD_16u*aG%V{0gU7W?i=*58wg zQf2@|ORO)aHr$jQl!&mzL)iqM=_mJ14F`<N{*055X;~n|`oqkflb|?Z=@TwcoO?Dz zn??6^Wl?bHU%JIrI__j-a@x0D$U=pjJQ*>I0Wmyz+LIRy0Q*WcA_IyOCB$Qk3E8|? zEi^T?=W5D=P!a7FQa<8J!u5f^DGq8VqnY$R>5LTr`c$sx^fOJ2tnoyVxnc->{n7#r zM$Ua1b(Kdd1lU=#YapEer$J|oaD>r>Il?grmGS56<t@_bfHl^zq#fahDLXLL@N0&t zzu^YQX5nh8_EY0xH_0~PSX1E77d?0J7>BpWl~C)<-QF;HFIoca$F7|E0NnJTqKyK~ z)BJ#LAfR(rY+)z-u$G?7n1i7vx+BE#+QCv&z-al?JIC5*B8P$v>|Ra_6{?KBN*~wC z2s(PWQ@!2ATIG)YzFe%nGeOxi)wHn+!g%#x(Ggoe$*%(>d1-Zg8+<p7&VSNFRd7hf zNNJyyt|PWKfw=@7$GXFQDvL9qz2qqko>C7Mh$=hm#s!8cy3Z*36LU4FnpWdC0rL$I zq9BC^s-!`)!T6PGQW7Ut@+wEjHU>8?^3feQ<%3sz*<0ErotM&{Q0cQ9MQ&)}HVqBD z9a9)){s=^fz+=9-eX|H~v7<xDIk9h00Hy`hHJZJ#;id*{F#_i(+}bel_Uyit)Xv^` z1&d)N?wf+#m8EXjACy(G5R23k1!}yDceJWxCn#Pt#F^?S=JPm>B=f^7@-SS6AZD&L z5PARL0GpE3ADwkF9Ba11B%O}3d4=D~UXrfs=1;ow(TU9lzAz^o%^3%g7<Rv_L|uG; z%k*fVikm+zD652W#7$!(#((4luTQk}tBT*wMoJ|KH>mCFm(F^IlAhDxQ&6s(Sa`h7 z`lEO!gAff5?Dn9$W5=x4Fb3dY$sL^LF~W%8;zGNOC;oieITA_K9bxQtFRlEz*abbK z83p6y6f?SIW&SAsvLf{B&iuHfB>oUi_{gm-Mr>LvxFK~7OAwZb-XjGX>{0FT9wC7K zCk>?-@OTUY6mynPERT;w2#}E@t3l1zLc_3;Og63y-+f!wl}y#vmhh5xZf*|l2H(@4 zOX-nKOs>{Ck(UAbviGJ33xv^mvO>4h5j^I&s@g2p0^b@U44er4Tf^m#O=b5VdaoSi zBP<|vP}v9^2kuM3l5I?~k!P;dBox{*j6Z*Kj&dKd_uh&ybdA4Vabbm`At(jWk?7!R zpfm|UzK{t)^exe1x$4Uzbh3t<Llvo8l|vXUv(R47Ihb~^(%ro2?$Lcl*}I;oxKUmI z(RrqV6_97-QYb1iyRYm5Cd4n4#Y-%$vOMV&mfkl#(v2-KZ<?_!%Xc3LWYc_*o&5g= zyNf6E0QqF3NVYBopg-jXl^-h@LEAboPGH1r-*S+)U&#Ty?+DDs^9|yMqDDw*&Ak0f zJKKB=zHdJi>BB$>Ylh9K9lE<yb-UBoOesM^ImiGWrA?h$<1GDmDDZo^p#lgR=pZe@ zcO-5Q2kGehL+w};t-g4>eURZx=A}<67yVN3ubq2UKZ=vtM8uypH@}B}7PT5wJA4pV zK_yZ;1CZp{)p2Jge^G!C(oGv)!<r&>E{{z+S1y1!l~G-CU#$QzR;T6qR$X}5$i=5w z_IdrVy*-ldELW}zXr|#vafk5oSNFt+?~4ZLM5tMpHiAS9x!zLO+{=SC&L~VdrYfF? zsTcz)wGZ#Q;S%%QrbBQZaw80ItX*(jH_$zLa`X!i&LQp949+8$d@(+eO!773p9!vZ z(%t$+RMDOw4Y_P%P<R6J!{Nywll^XfVoB#_1vX}j)tE<O>%I+~w{gw$=EQ&O{OpJu zxLu@3x?>&$W5i*_;;@2hI0XxJwUV*9@{VVisU>oL5Vhh4lvvc4KnxjDLtBGTR{8=L zdBpHL|0Y`AOf|KHpq5lq%~|Ol+vMXDV4#SjszhjRDtTFE1D*8~*;n<OPSKlELLs4a zo#s`R)*igapX3CzDTR5hix=nt_%2JRsVvd1`mM67X40_P@5}q0@FvalLXbge-~+?7 z<k%xJX8a+7FcX3Y=7T9$s2wJRa$rMSz3h+&p|$`nqD=}w?rlB7hRU*$6&jIbq1;<@ z{tW`^#Q6_j#-&1|1x~7R#i<|Hsvk)i5eHKY$yq6HG>ufMHa<Pm>F{kq`*EyM(dI9& zL!!=TxZXT&rc<n%u&9JC+w(qV<kc4$=xg?7yR0W)7dkfe1M`^Uf_kP0(0?dG@HdhN z6jfE&RJ<l~BuWV0fCx`zpkA}Yzk6ghoKv5EJhM^DNTL=DxlFw(@HR+3lRY9Wi3wqu znPk6a;LsRKDaA^8&>;RtD%~c7D0kE?X#ok=2;315WJK<8R^IbKt93L2Q*L~o?#7Y| z*${?Gd96b!oNo8#NzZQA4Ns5f98~J5qvM{4Z@_%l;}HHiyr_;jE2lWdEX{FO^Y#b{ z<mOIg{?(Yh+V|qnCw^NgU3b4<3yY6;YV6mf%803lhh1JTr=mFC@aocjW(L<dDFw}1 zT#XpF{-q(&csXVfKr<}kt`QZt=d1TxXcl<ciklWqM><@#h6yU8XLJc{p6Lgnzf$TC zEZGZYfKUvwWdf8>&8eN#&_NWf4e~vI)K{c(RZdm3jy!TJ^a-`YnHPwXgRmck`#fyo zLYmyES-^4x+o|__LOH5LL*H9^n)<X$bB}tJ`R<>Z&zT~TOxjZu^ZJKJ!`xB8YpV=U zT0LVMbln$p(|EkLjeFM*kCq$-{=30u^kL=+dlubm(R79>0rURm@^La<fsm4;a5GKs z@c8eT@MMX<dvu#+A4j>l-q!o0cRx1KLxg#RQcruiOK~`6KH!jXR-idLwAhW)x?U{~ z%BrkQJ-se|>b_zBhg7mt7$1}4-wD&dhH0qYpJ=W;$VE_b+;z3u4p@c0*{Xm5SY3S7 z6qvRS_##2c_Bk^vb68Yn-9AFgz+KKBzXE7`o*C`150(h9k~}vyrb?WSMt9N#<M`Ua z8N|J|(~TuRihSPZ$I=SH_IuFl1Z!$s<~L~Xea0XZ4;t>iuQ6%z!PGK&t{m4yYW8X+ zr#2-a#~k-2t=R2;K<o=DO!|D$I#}FnSM<nAMz1NliYU0Re`vYIsZ!bAaKXerH{3G$ z+wj_O@|g{>Fa1CGjQl4xWo3*vJo+lkJ(IM;$xGkahTl=meDIG|kIlS9Jv>t@lD+x# zcAe;%f$|rRdwSZt1ky=vYhX6)1yz|P=!Q;UAXsG_P6H1P3~SihGEdQ|C%A_5q;v`b zGh?0_Of?`l7LLck);-?Hg)>=UXnRv|9rMzwOSlV>J>)oP`db6raj-_1xoPx9?bIqH zu(HGpV`fL2@^g>8Cf#k<>92P;zd!DGrL1t$cO7=@cRzB#Djz6LWbfJZyT53sA_LR- zhfCWyZ6<#BXIqE80+TrTQM+83WmKqpIm#&!&DLIw&V%TBe=g63)0F&gqn*@N4#V}! z)lcCGamDe0m_fHVsa7-z<uwXpGkK`~(qlF9TC*4jaj_Iqh5n$~eG&`}z5c)Z3r&GQ z4~_fE^SThjTRwQi>+WnuJ5?=`epu^%NPp+>(5@iqYq4taDQN+_3=J`UXHQ>_-WP@I zBGETtnrVAf@+R_g54L_1{kOsDXq-Y3abW%M$kLd$41G0mPlfKY5WZlD&2FL1PaGXZ z42W3)=9tIB2(Dz+{m^d`?DTVNai3w1j5ooYwWr4JN)}hqUrEm!G<c2miig)c^Vf+G z5v5!hc2chESfQd%Px{CXp8lQHf3*(4zJrf!?xD-gs(D2!Guf?f^in)eW!4R(>+q4l zR&LmnEA&3JR)!u_u?}1p<e~ko-gscV&4Po_BPl~I4sxSD_-B?Nih9<PEG=Q!=r|nh znjD)C3rTtx7P&SV+ja91okf+={^}R5_WG}r>;3xE#C-43{u4wO|NT@czK=y3c>3St zz`^(Hgu{V^U+&JoB~(lpdq#ZVCkM$)KjnObJ3km-u5y45Xvy5HZ;zb6vk?v`W&Crw zQl#oBe#6E)MY_XIfQ-vgGIKk55LivA{d%e5go~FVw!G`J&R$~HbyoTq$5<CVbRGiV zZBj{;dkSav<iAQMdU|{O(_>cdrB2kPXtciSzr&+@*AHKozsP@+q#-tNx3FN6V&z@2 z{mzYr?;dXfZo~Vxt#X9Jz`!sz*Jdbf=Ai6tC7+=f2HCl(ds(Jhm77T;t8d5b5pnK> zdnKOQmytPpmV8EpFv$SJ=tP|t0hL|&Dlzw*)X^t>d&>!*nd7t5sbC>snk5HMHJ;WM zg9EzU{wq%-aT>&T7YE$@jf!ZLoIT-Kq1)mxj?n%G&Fxa(BMCxau7wb-hAXgkt0AsV zoorohH`Ep!%P&HLAcP6P{Uv`ip&|aryrW<tAng_kO&28@z{OC2oMKK$uHj%xQ5{7+ zy+jdRR{I^c{~`n$%=sJI#3C3vYX9Q@giKhJ->+>9MRHT$&-x4_-U|)&;-k^FeIdWq zZ39oJT%hj?patm)kh`0`89CbKCe<XW(ki7H(^Y_|-e%w$38)|cd-Ct^$M4?RE(JO! z-NnsBnYcFo++nfCH87O%f>sljd<na=FKP@Mqi+IW9>Z8maPcJ_gAD6c;ra)h{>rfT zi??Y>LJ@U3*5W%U{Uo%Dy07Dh3+f++T7L2m+-5n|1=AIa43SzyUvEW8d?0p6;YrCP zW~_&WD~N9>-yDnewB&IuFR06KdWXc*eU&NFZ2zoJXdl3SK-G;EHmG@jz0fsbo0V@s zq78mTIaPlP&(6dbn1Ug~Cuh~-JYV4lK2BPS2N_9!-rk(dPY*=mA1yXm)1g7@o=F!o z5FvqmsfO6H9+)+^7n2U>KF3E0ATZ+VcmTYJ>VfVUNPGtp*>%jgkwPYf>01b@C=Hyv zQYmhxtd^}nwjR+iW4!mzX)yMs$<;rr!9ee*e?5Q-oB;z`O}2z4uXP)&kg~qn!z39& z@vm#MF6<FnaSlLHeZuY(sYCH{Y0y`3N3hwM+%~%I{2ZW$7h0PMh0SkgSggkN()^u< z$2}nrpTzwzsl{6%Hw*r^W<3yBhz5oc6BRXLA`2QpFqNDlZ1GaImUl`RYwH4@(_lg? zbAzL-Gp7L=fE1&>et3k_lS2w8H|qnwE64@oT#)=M&8~R%w+~moZ4N>J+`m1UD@8T8 zv+nK{_1)F1c=8VvZf5o#D*-gax6kjL$+!!B%H1nvXz9Sp#$2Z>ZS~$ZLO&;-OK}6c zdT&~Bkhnd05!=^k8cU8t7#8G1H;x87ITP(h&u`D2YQCiqP?9A5_i%$`Lz-+HZQ0*u zLa3f@8iqN)0IF(eCIo{CYD6LlF>3fc*lPPBA|@3W&iFh5#-Rj3v1nU}5YNL1XO0ab zH{jy|MFYGFlJpwIn~rob4*sE_DX?tS?c05exlakV#e7Fu*<!ElECPQlq6u<bK2B$I z$6X5ich@iyZb^HY+D}dO^yxpTSVM(r|3nDbe0<LNz9#zwrEt2Ad_Cx0|53;hH7Zkw zs$l&Q(iu&SuJ$;MEHonWOG_-KUw3QCvP?=e@z$U$-_`ijQb&pQEz@2TIRh0($N{GX z*;Um{DjJGw7h&pp@;46j`8b|Bxm4ELq{GwE_A_iTD3nkV5^%J+x=#61ZzVuRsoT?F zxo(E-+daI;IqlPaU8e!t7+*<Cg7v{Uec7T)YB1d<6ZC!L_$7SZr@)wPRfSscB}h45 zzwA+QvROn1`b|MTklFvCP0HP$1UcN!JHU#6kbDP%839OrO&W=eENm%Q9{v2E?3S6e zz5KN$E56K1vCZV`*XuwL8UsW(qYYA$uNtzX5H!a{wm$N2zDR(;d%_m&JD`S}|M7$9 z^feU+50?qqKs?=`sZ`+g{bp}0ViQ`wshrO+i}7ZpzR7{pKU#d~3vp;+-mR&iOt-`d zZe7fp^JNTAr2cIwX}Rt`668%EOkw>aaJz!oi5U|ba+1Ih2VsIBw~DlsJrQ%}KJ~>C zylNaa2bayJB2wZ~9#e<MK75<#ab78G4u_e-_C+6GT|k1unMA7RFtL2Nsmy&Wg)3`z zTXHtswg>!d|CXi4)i8wWq&0c}9)?#u7c=?gbAR<KyF$*yN+V=$6OuP8K!#sA+B`_K z6^XDE3gR7CjBFoQ{AC=z_$|U!Pkggie-lbZs)tEmx&Jnk5yw#RmkurV6@w!s&5UB` z3B`qX-ji7BMXJ2wm_D1RK;)i5*2I>267g}uN2>EDk@1K(Nml*|5<jWWeP2J*etjp* z3{r|nV3-F_KPPy3E2S=7ObG(E<bRYWdWXR#oB&Mg)%Z&&23=$(3j&wWR20h=oCgcT zI6Bbn!rLJjTyG2cq}oS;i6FzUf@*iN?pFcqZxb0_#5~of54t>3yn|sQ{iDN;FR?a{ zNB=c`w)*Wey6ldmYQ<QM2%yqByk$F`9Q`2})i<F@7#<!U>J{ifctGy`r}Wh;dEibZ zjF598LUWO$5tehnn@~t!x(a>j_XYzuqGIYjixwW0{*wai3j4p#c89SRx2y)ik{d}g z3J5so>Q9NGt}aah|7n8}OH2nY#Xi<hS{bX#j92zHeTd=t-nGEBn~q%PH9BfsrAHPD z&T=++B;r94ODe6ksi@7~4v8ty+J^{1P8A$aG(~~X?)YQHhTk}0BRmng=K`&~yo{1_ zwj<+JvlO~`!jamNqo13JZ%drK8yKTSHYlT5gEH=Byrkp^E+_gmd0o$lgav6@uS1_F z(j5^ASjy2OY2mpR)!KqB0#5EZyfC%k{v5;iyG%8=*wmEotHwOQNlfHyNsJwrG`5~| zqz?u7^RUv?o7CXcn^P;~;uZ~1zJTTn09thv-zY6sK>hsI0nSR^ZDndrw$4`|flW)m z+HU<RPBV-@$sq0gCx+?ZTY@gM-Ocxjs<t5wZTN$nad<i=EuE8GW+b)|6WY52mm%vH z74N5hZ;>_QcU7EK{=Vo7V1K#%XujC8wZ!{dE6<thUDI<WZ7;yH2g)x%GJ-v-b!hs3 zImnj}9At3a$at_yuYm+%NO)@J^DudU+Zg^1%q@lmt9*_@{^jiP883Jn#{zXTaI>Jv z`(w=hMT3-ThwX&tsMB|%imw;<YrgG}!^q7XmdZFHJjB@lL&@3SRW~NUNs!HZI@d+^ z*7+9d-#TDZF?-17#=qO$`gLh`ip7m$SJ&l>svEzQN8<E2;nVDV{HVlo4k){8=oe9m z&v%B?V^en)=MxwcReLKNJV*U!I^^#Tegf9gd=1LhM=A&3VWEpiF(hBYELwV5lz0>Y zGRO);iEG}$YT;}(l`3$UFYvGfdLff7(Y_id5c=c#_m8{WcYCt7hbB#5Uf0)eG4kVL zqU**UU%$W_Er!_62w?T-3&#jdqSTASN<Jzg8}%d{Q*OxmuxDO`iO|KTY^}EF#U^3! zjjujCM0Slih)hKtD7^`jCNc|bi^%&y{oYU>{~tJ5j+q!@gQ@ZCu>C7HW_1A^c%!Oh zs0C7JL=nP~2+kN8j#qI^sjn(^*F;v~0#sPXcB#7q@+mnqeS`+iRFn9X;3kSSJNGJ1 zsIWqjg%|>SM_&6iC5WaxiWK#STj7PWqdR|3=J%&M$iwE4bjo*mF9}G5EU`vairZ6f z#woJFB+!K1c-E3Yjk|CCc^HI}n6+0G51$jv3?n4zFi3EwjaW5ikr?Jy5aG-UK<Xfu zaY@QV3EGK_#Q0znD7}<UwH$~MB6O})C`PA0Pl^ZS{!<CVCR|>H@o=FX`DP-D#N69{ zhx_3p<+x#CkXWt5I%Nn7xD;qvb0nTBafe{llMXhfzC(m=vtNi{^SyP~_CS`v+bJ!H zcwl$Wk(B>#wphnS2V;as2&j&+d;FzGc}-{k`#kY>Dd5Tv#rn+i6ZreWW-f6`%<A;Z z0vFmd$At86B172Ka!7}R@5PYkNVu^{$~#pY5=5ffpCZpPv+Ra-6z`Nq3uG-Y^l`$^ zcgY%Uiv}G6e=2O+iq<gZ0wuTY4cy6d)hyrN*{3m8_~U0?s4Tyq%#%5JDT3ndQuQ*I z{4M>kQUt6J1UZzP)dAl{4Y8FF@}#i}{_IN;MVtx)>zF^%VUrANR01YK2BnLCfl47V z5{e=A=D@1Ph+}nL;g0GMB*v4>f82in2dLuLPQA0OZY*uD_%Zj3Z{t2S2Mc?p5BzZz zvk{*K0qe(1j0t?y61M`i)*SXe%7&bUzPhJQI%aAc;(?{{$IvQ#`$d>ZWll(lvIYgz zH{P3_>upY-pj3Ck?J!q<bHA{Tn^hEfYz0Y#eA;N|25x+Oi@J?KymI+;1kh0NaxSYZ zY?ze2(aDQ*aSNHR6G$H@$W&y$BFAq#iL=YUEU`X}^A*8vDGIe0S=}GA=L-|;K+ERg z(j)IcA?g0P`fs@ze9ZJ3rdgL8r&v=0R7P0P1D<gfBERc_)kUH&zoA83qNbCRLsNRr zUj#!2zkXROnjl;vGGC<D^pQ2rE1n|Itb6%rL4zkx@nSKi*R4zXX_qGl_AAJL2PHdV z-)3e?nMHvI#;DBA_4WqNgBB|~fQ#@zY9h@JBsAQO(JAvyqL2zmT-^EN+2PNxM3##y zZNEl9UUvQj#0o*Yx(4Z!zd!z9Y_()n-hN@n7;yI0UvGJ=Ws$f7=#yYe_=o6gNrWrC zrr;^IS>()iZoK_7%H+3G*m>B&r!1=UnAsAutActb>*}1hL~TWKzb4d;TN&TP59m$D zDmSoLec1cr(ljor+2-wxgDN_QRR1;(77ad6&nL;$?tqYUm!LC~0aHK4N;t7!PU2r5 zd&NJQ*Lg1TJLwMtG(^74-o|QAFB*93y%zDx_(h-BRGnvIl7R93`gE?(Ml>%oj5+*) zT{@k6wx>;&KlgX|aW2``DaMl$YpjRpP$3x^4k&UWnU8>!r))jS2H(JKaS<;RkV3^@ z%f}i-fWR{(W2H}LZ=X?_jeztwzypbElygI|n%ojZ|HPSZWtjU_j*O$fT09xa7*pgB zGV-vLH+EOH90}Dis11fSQ{;!#F!%a!eisKEXO_}SIA_@wj8*d7e$&?Jb-lm4d}01$ z!OP|AyS^76%HEg`(_HE4h{a26Jw<(lXI2%S|9&0#?qIPYN(EYEM=zWyM`oq_UWF6p z-1DlcT%$qMd81uNk~lpmQR-0KMUCX6v~O%o7w^?ULPJ7kDX*S>2W%VfR3kEn^ROid z<IeQI3=jsK?88c)bYa%#?vXDI1CTZF7EVS253*w2EX6P__xhjk<X?5{z7(uBU3y4* zRw#A+wD6Uup$qNxs6+E3S(_Kg-LmXDb2PRIgt?#NEQ5Ik8JCs~$zC#LEwJglRTf&R zYkV~kvr0kH#y+%T3Ns<eIz{PfWNwm1#p-;g$~sXAg4jLlUwjqQ3fU5+h3d0e^7@RD znndn)k`xJpI|Y8<6ZZ=nUf&%B)+-Ct`avi$t{)th0!yO~bX6Jpm9A(^u2abE3*e~J z4~vfFxjUjaTRlC-N>+b_r{zseO*4HbBz__J!6%M@>%~}+Wp4yYt43(RDoYMd#NO4I zjSdU_S3Vszy1L5IYzxUlwweF;ynxATC>`SBRchgxa8w{%{v1^mrITpn0rZ1h6Vj>U zDczBzAwb3`wr?{atlb|fp=8OWz79@(hf(UD^B8N8)o|yA!U6p*y0qfSj^Hl9roLVE zE%(o_a@UU2Mm>J@oo}G;SWd6f$i$WcU6WYcy~-zpjQ-4t@iRLY44veW_;VZ-DbBGG zCQU7l8)ZzJNxQB%zCaUWi1J*(hj^`E?Z!TU9TiK!iVdku%OPnbUKbtKDpRk)`9GAs zc{tSn-!EPvLxr(Mwi!EP3uVc^?@N}6XppjoLH1+}#=h_So_&Ohh(TrFi6TpOQlUbs z^BSM;eV^}rpL2facm8vAT^aL!zn16ou|2Kq&TYoryr(Eb=pWI7%9`ntrts?PQ1F=g z4G2G<gv&0f^CC&esSZ9$$9!xLlz6K~;~%T?&Jxz)y`_B=dU{YEg3CxgdQ^MYfs)b9 zI}W4nVf2ll)>GBo)lXmZ*0Ck!rS9q=hq@z~%hO=I38q;~=c#mu)!uo|;nllroAO*5 zv0t-k*pjF}ZkyvJE6&g(l5-{V!fH7={#1#vw#>*7;HtS!=N?+B-D~Ygr>Xh&>21o% zO0|w(JYD5_td^_qnXy27i(+0xv4sHm61`SMtpafu10(|u9L+hu+t5dcZP92s9Ne$2 zeTE*-0p36+ezgs@{NNw6c##pA&rK6Vo2QRlhc``4G6~sRXVTNdKZa(hGa6&|osf(v zvm3c-y_0p11Hl|O%!f>|6p~G!WpJbN-^B|FA)B&kifHj~-uDG-SjHrtCzb-T+!zP4 z>OVBL+N=Jf)9`!gZ&{i3DsuU-LiD2LV@{d%i!67v$1&lFqeGHsMK1{B?hdwqPVmvq z&|jT=n7HIntu6H9ggmiH16xEU-9AICJ>Avjo9T-*u&~Wk`qzJ;>+}cQ>NUBjF&=X+ zr8m8D!!b^hwR;j6oRR{~M-*&DVocn{xIN%|GDh8`12P=~Ce)6FcusUNAKi6t-7K%O zehKG5o2k=fO_#|5i{S8$eZ9Ji^Dn`8$Y&n|Tx7X;Vy(p+4GR=XZ5z(XJxB7d^*~qS z#eKF+=Lsj{;?XznPfmwoP{f09Q8f;3io<VT61Ju^*p(DON|ivqIX>Y>{vfC{qbqZH z%)ZR-F$@{2Fa;XWBYuoWr2I;KZ;VZGQN_{)TyoS{L7Fldw2{ZH)9ouiN}%9ixd>Gi z#Yj3PeY(|C+k}&5DeWnZ%aCQBw)Fn?nyImzq24g$c;e2Vy$m7_C_ZF$C(s_p8cQJg zjp+8{XC)@GLQcfb#_{tZjjDkp=GN@OnIm#??4HE(%@VSVTlbh1ii{|O&qbK&5bO%z z$OBSgeZt!=W^uL7+mQ%Kj*X9jUwnSzzScF3>)4bc0`J#{89v%eA*M@Za@tTRrdW`L ziMMNed4b2XVQZBkqG<GKN03;XEUoO)EET?#k4`K%#tsuOkf}A4c=RYQa{v8p%UXR^ zSl_$?Qo;#`k|K>ES$rY&^fKJLVO?a8(0VUO^DE(;5l!1Wm`1)mO)?kHZ7kOUs}HGj z_*0YKW))@I0)E+I2wc48e8GMN)3+%E-T7{~H62xS_qn~a>9$|HFY}VkRPb8H7;Eh_ zCHp)0d<m0`GjyF+;zKQt7@L;oJoi_|lDrur1x1n)mURh!=UUgrGZj3)=xZ6KZ0qHY z&5N`U?|xR|%Ez(Rly~u~m<;BvC<yZ)#o%QX@34>w(wdr?{he%9gtYks$pBq5!j|P_ zbuC>A^Ar{A&=+4pzMtV)Lg$r}N*JP{&M7@PA^vkks*%aoHfW8Qm8!Lvljc9|Qm@Rq z*V&1e2`4gGPzI^rWXVxeHTEP%-r_cWVwQ#j>A<y1y5oZlyhuV7UdYkhGDb`r&GZtT z{89xg83)H&n`JZ9P#FupWisZ!H8~S;#9ETSB~Ci5rOUU7BjJ-Apf&D`=;=!BTBUCa zYCit8wiyIpsA`BwslW5Fn_BnvA2w%(e?FcHYMwmD$D_UbQ=3pMAki;_q(MYNs!4@z z;%~=@3H`VsLII6NjcLfJ9iDL=)+mWe`DNX7tcvw?kz!0xtLxJH#Kl;BdivpLiqQDn z6&sg{(cBryQItg%W{UD<73fUL%h0YE_2fWWqCziw<w42VQsvkaP3ZI$c<jq<Z+^qc z_P&k;VqZd9%((QunKE4y+Fx!<iLJOtZ<`;Mra__Y9*J@&LyvR+<ik-<Pr^%Q9lg0V zN~rnCb)9|~pd){$U5Ps{YmzJUuQtMsIgVJ6nWv$Yqi@I1IGe$cdyXEJxpR)Gyhl}* zf^SKytAJFz+R8>SQsb`?-c<1Z<6yk(w@av8>)%4YZyHJFcq0Xv22zAIPyZ@YD$?>o zR20ge9#&f{*}}LqxXZzh^tB}D#K@1-ML@Ff7>AOvxxU|P(fVN!#<#;7(D9D4J-d-S z%J^AZ!|3&tc{;{M@(W%92n}kv9lZRH8Pz|<9HPVqg%gsliZ#dIoe(>CMcJpV0WB6E z+X)NDOqt`vnw@$<19ppmrb<tqQ(soYKV_{ENi)U@{+J_Bq*L7NYifJ_&C0Gd2*PfE zreV3K;HH-j)uhtG)~54siFVbXip%Xd-7Q8d*CNbg0UZOz`Z4<ic}9*J+1B?<P~rkG z!b6~pd2`k=G#Cet8c8*2uSdjMcF~NcX0lIygn&*C%nnPFYpIYynt%m?kEE~p6O)fh zd&%A_C24qt{HlJY#C?MY`22l7=1S3ylRW^<j^*B__Hs}a72a(8#mO`jB(%2v%M<Fz z*r4*N``H8X^n=OqzV+=kR{4XvCvn{l{$PT(B%dOsl@D+H>7w*NyFbP7aMW1lL~!?6 z@0pbiVNuPr98LOR3PTO(obyL01_)zZdmw!g1>=sOF4`COwWLaYLtSRPHT2zWued1s zv<S17gtFA9%-0{}IuE!4-fN=5@TYlw+g?9`97MMmRc#{)=llSC2iT=KRM@2_%Uueu zeTHSX5$0CG-+|)MAx;0<Y!BJp+e#kc4Cbh{x|hIk+>L&38-vi%X{30unr>AnZKI}t zh4Q^v$fvmL`PbZ7yy*LhvS~5@3dT!hwc^w0F;&*}N*Pt-4kC-0Woq;Y{O0!SpR+FM z<J)jo!&52jQlzGlpF+vmN8uu`iKOjvw2(<<M3o$v7WRi$7eUa@it{8)x%FSW>47it zsyW>v1QtofJ~kHBE6F@9C8)R>L1c2hBUy=YBt(J(@&52uli*7<72^;o=(o)Q>zoz~ zjtgyY8+WNEOV+mAema`}^61_8aDL#fKOkPCUGqR@YvLJFzUA9AqUB5ch~sXKKaXje z!C|V}_$280&eMUXIF>%a^)AUdvTQOLd&?e-m)clpyeqgsX`Vh`cyvY1$oWcRuln!B z>mXp_OWS^?ND*7M_HSkgYx{2k^`pYet6!J8o6nVzm@Q_}ii1xn@LQ%>yZI?=voD2j zo95?2NXWvgU_gav4%1^^vof@<v6^KhW>s#ISY@G{s4~K*9<+VaFmO9L{3gPt-_Ei{ zMOeyI^-D^zD-iMYdd*-VR-j8roAv0vWT<d-S9a7>#+<loF(?^wAr5s&cjYlkJ`+3! zd$XA|O=v5tZ5?Qqb!tuzxU`!_c*jZ%PyHAz-_P;=6QKSkV+)<WagAg20)$l8zmkbj znd!-))hksTWHnJAPg9`AwMf(UtFpdE{VPcW9TO_zx+9de3#PKdd^zDVNr8OekGoEm z`P5GLmwTeZCH*h6ONLY2l$5P6bMv_p{l<Az`W-ex%;`5say&l#l<@OUQaQ2iDlY(a z7?3<?MFFL0vRl^UapQSrpSY({gGJLt&z9*ADMJMLkhv_TgKS*TKR{@r?}eY~bE$7P z#~EBrDXeNKeBBYRgFiiquU&fAS6&pOf;GY4h&F<${QqoP%kpV#Lt{7tYZ`}TQ{y+S z&j#V1F!oJi8!mqW)zG&8SWzVVajko>OK&1<)r5v+B<p_u=DWYJNLIUakHt`O+D~5N zw0B)*@V0t44j02l&*|_=SoeYpT^2%Td`-49Xd_iFVW$a1N|?mX`depjOjJ<Aw7f-S zLjdL9zz_*am603!7ppy|H=Py897?vkx;TxiGBf3TMV4;pdw=<8&9~QFA3Q|5-Tw3A z#K#%oJFvSl1f5?VVB<8r2NGY(X3V&F@KQLFV5uV|KW0G2nNEboQ#HU(j|>P9o+o@T zrZ`;~cJx4r$k)nf>xT0X)ZTsSgr_zyM^*BW3Q4d8>#zc_&Fp?f1WKka?^^LSHU4<A zUlaUYE{vYIQOfj71!7!}H8zB9JiaLWjYPpvW|e*>lY-IsMzv<LEvuA0HC|-d&gwzS zDwcw7FtpcpAz-`q%ZpD`4IBl-+I)Fx<xH>}E7vpWLZ8u2kPl&BcyKz*l1#8XjJZ$B z=JA~T5{vioW<`v}7zc0uqhqJ!;!I8#=jJJM34#js#Gl#P7O4EYN4*5v@80)508qgI z3uT}rONvo?u0NK$Qg>T~4)GcecA&w`6~2LIcL{PI<WFzJcs95sp|zsibQmYu$Mz5$ z^;MXuEmj019e{mQP+slbDOSYZTpD-13U<eW5?n~&KndV2sH@Uf{Y&j8*-x?FyMARg z`Eu6Uox?6B$e@5*?z@h=f`^n{)GV1AKaxgz;5@M@3a<}<Qlp7O?WzEh*J>29X;yl_ zxv8o2+ND5{MezOIojV&O6gIsU`BC(5m-;ED6GBexsYo@)^tgrYih0(ot=$`MoOBz1 zjnuz&V)PtH@U`_~=Db!PCDENHn4Fnp<5F_6?R$KVicNNM{^8c;l~^Zr_9A^79cs31 zy<3H*@^4k6TAxP7*PmA8oUs~F9m@8ulFnoUq!<2>TmbN&IyRswJB%miyjM++V^d<7 z114<}&MMzshF$?xt1Zu^Z4$np>NbLJZ=4|uw@_%1kfsc{IDs^aqAYa%_Wi}D_$xR3 zzTQ{Z&#Hg)y}GnaHvuLeqs}jzD8{R&S$K<u!VkzLcAkBBpqH}sU~e7Ivbq120T=)F zr}%zh7!~|ee!ibO4{1!y8&1vX6(yE}C(1!<nA{726U<R{1W49Hs`SRUg~4CN-dwx7 z*Knuf(UUuaD|0X#oq(4c#W7k?`+LtH%=eDow-moA*;XI&d%L)FR1T_e2dQAZ<}J^B zy-;FLd91t8MNbS56`5)HXR#O0c$o`Us1b_e>WuLaDnW(ASPF9jC8+P%OI8hb#a^&r zqy{Oc@BTvh<XU32<n;CRX%G?5pr7Hb6$3iXP-C&R#7An&^vSWaBrFV`b!SP=a{{#( zmpp5HaXXYgEK&I;BnyPSEK=H(T&%ah3oj+*8Qc#!?B*!OD$7aJkkAfLL|Qj%xkmmj zyaD|#<Yxpu#)dXrzbhkb_xx_Nu9eA_eD^t;uZ799tuqwwX{|hE*$;kxSore;*i#~y zKAN4C<L=qC(lD5+eg0ABxr~FOodW!9X!KC1$`h(8l}WMb;wu|LY<bqFa1?|Q))mS? z1^`+fvTd6qRLhLSkOJ~53ve{>Hk*4R8in4o?#<a+nByI#U@APQxaO2!u}zGyOPEz- zthW~F0CDZJ(QvnPD^k8|rP{j5)bERYRdD=kQKs;&s)`R|E6Z-!dMe^`5YGh?VwX?? zsfKl>i;(g8X4BVX8)N+>P3b|zPmyJd>2Pw@&)A1N@#<cwqp$Pn$YR=?mR1zX9?~zZ zyr)^h+K^;NT^HU<#uRgsxtlzFU3TDjFH~NdX07b#<BbJ=*JLlwk^07Ur~7-m{_gp= zGL>GTtI~s+qpcizsaK-ft{n9pSM!~o_Zu4qyHrrB)(<5RCl>V$Rs_z-jf$}Z;)ao` zA1a%AFF82u0v(^pjDVP{;-$~TTXDs}Kp(mb=csXc<GW&s?OD8ScCR5MLJO<YKYv=2 zCc@D8Y|0XdwzzNduclNK0hgL@LkHKR!#}kfX>>v37m+Pv8^UH})h@R5Fwh?9Q$nwG zEZD}#lb`-c5X@9Xa@dqw^>;!QOI+)W*K75&Sx%-J_?|k)|4U;7F<)C@-|%CoKYhLs z%qrNIeZeNlD>ha;S!={ID|yaMGFt#yr=H0W$X;P017OcMH16x!ncO%HIzC@a2AiVV zWny)!)cOD3lst^4u_aay=R%*T`vun$*Tqw(%yUbX%<7rzs4`=f@eeR0z`G^;ep4)m zkr8PP?iSzLN%%^qPNQ$K+>WRO%caw2NV9<_trjjZhL|f8s%Q~fNiI;8S~a{N`z4XI zlq+%L+;_}$S2Iy&3}C(Z4Ct<oZg5bh>#Sb9{PEjATlZWje;P@sfFKeMz-O&}{;sk8 zmFivl8q~ZKnUL_08&)tC-Wt@b<0Pf|XMUAP$d?gKV%q`U5OHOKufP_Ml2LOc)4g^{ z^-FbPF2L?t=)iX1N4iBq=yD<k$*Xf15bG#`zTmszJ=%nRG``hT16noX#m9;K=U1o@ z;A%*3w6CyAMt|iR=znab)NsT`m5#?7)^&q?KzrAT%6xYve+{Kg0JIOg3I5pkJm$2H zSK`c_%c(()?Fzh?EY;qvN>Q!GLad^w-<K;FtRY+U!-DY9q%m(k0?3T?!oxJa7T=Tq zc=Vjeur<CGReML(r`*2uHA!ZGX<(>DNp8{Du7#;zQH(Knuoxy3XPtg|5crsEjKvEH zAlZWH|Ml)Tk^Z0trZoRAltp4W8ry>5ITCE>!r1pYN(%kY;?Dz3efrKuWn5Y6QuI}s z!Xahg+ZL%{e-KR0F}lSPpHmh%PQ21r>PQg^jWo95C<gkPrOK4RDaR(wo4Q!YKkL=| zE4Qy)%gg_d;=<NK3I?>}$#QOLZa5>>3qQySTY578df;$1M~si5eq}Dy39O~6tuO$f zO%a=NuwYo>ddYLuGRTz{A#Iy*$ZS15Xw@%hlpN?OSexZU{IQi}IbHRIbeH33L&Dz7 zfR&L>!FWQ>c$cFl8uHz-nX$-~Ww3#^WK4xBox<EC#^c~(Mt@SuOI2)|WDRxhoSb20 z?mtV%ct-|2o?_G(N{wATvxmGuoFIs_b)cNKZ<_04J8z+ikGMt1cIBuUR{p2xgph)z zB8@Lb0YJPIH7^9(tibYFa$Sv*eTwPQY09CiFN=p@BcS*oi!rBzo1U9S%C(GWfrE*Y zxVj_N0F3Ul@gED|vO4k-^qIGSbjw63YAP1qQ&MF9pFkS(XC2m<HU6R)c|J<UK&S4$ zV4ctWU46~4E{gW^k{w{6#D&jxzeoO_B-B}utGrb#IsHmqee<v`<){=n{SpY^AD}v3 zc)=2gRrM(_#j-<r)UQ$EFRa3HWrBv_3}Gbi^mMr^uC`$}V!aaPGjy0t1LOOl*acsw z`DbUq$*Tpfs7vc<@0tKan~cjOAb{onc0Rge((=p{))xq1(qKX$(5V3_EvhxFu%y8F zbiXR&k4?e3>)5P-G%GP?3aop<&nXet4@sY4aMR9~VVu;V1V2g&)v9N5x5QY>^jX7H zvNfPxb%Oe&)q{Q36$g=uC$=Cn4Ya!<fFBCk&sp$$WbY}dK#c!03|gieKr{~C`Fm{f zrIw`dQ~rN^Dl2?2dCnz9ej+!Fj7YD>X-JR_z`6j?C7sr<4PkUkRmD<wuDMEPOSjOq zAud3-f<XOq2UPM8@R995-p7o@U3<R)P{uJ6n03b^lRc0$*#X9Ulwodt%D(l=Oxr?U zSQ2mfNF$E@$tku5QNtO@AOTg<?Br<R%HoKx)+0EF15_(cW5Pt{8UfxXPXT>TE~Jls zKDP0drNlT6j-UXaO0*UGO<i$sBOCy~<iG(4jdovs!)(d3`El*K&mPS0<HFxRKZ6ux z4*#C4D{jx_gqEtEh|HV4>h&P!R$D#%^7oJX&)Q)HJd4$8h8Eq<P%yvx>60hY>}rJU zyCue!>V)k7hts}(&XN8io9qE7Se|tdb;F<qEoB}7kul>Xn$*a5n-v9rKx{U0AH;Ho zPg&gg4ZKd3uZsO@!Gz-a_8%-0ipOIKNdFZ5Ye0Ga>Z<2*&q0@dwq#|<-#>J`dZ=&! zQB$!<_6~+w=K;ao;2p0asmP1WDj}9uR{A&5j^KSSQTxt1Fg-ih9Z6mB{NoB}%4Y3i zgflxp<8F{AJC)<nlf<RzOy~X5!p8q~&dHDG9rB-IC7N(4zrWXq)Y^MaA2Bm0+}P{2 zbg6w!2^z{DsRB1|{KZ@lxvco;1n7ea@Vcocr-?0;>pu&hkiEW=e<e<k9MnoKP(ctV zfi<e8BqVEw>8`G5lt}hjh@^30c))bJ|AMb6jgjm2EQ7}pL3$gcbbV#mmgUzjRzn0F zjA`C^bmX8C35KM!rNPz~01$F4ID7!oHuE=$l6`zSFn`tie)$OK7d_EA;He`xXIMX+ z1t5t?x`h3ki<{bfxgO{4z|2@3!90a~*}3>!l)w8{Hz*(<fo|~6GE+xkq^q3`j^(Wd zj>XlGJQ!@fCfp5)S41JaYIT^pTl@EEUVji!DW!)yI#}`o*-w|Q&!O~%6uEq2f8(Dw z*uO;=f+;XBsCOFO7hVOav#nI+1Bb94u#bQ6@%RUrDK?FVm{)<ek&OrjZc0wU)k3!v z)_|Hx2<g<YK1=y86@)q7SraO&<`<$6o%l!C%yK6y%XcC8`bDM3$BFxO>WY<}CPQGA zY!VNNV_CZ%9I+9C;Q>BS(bCe=8HsWw!-N-y&Fq5-^|!1DGXR^CEeCz3aQv?s`vfP4 znTvPUhx4oq@QYqG5o+8bkRcV!I6UGPktMeIOWc}2-n&T6kB@hmGu9RA!;!AIpk}a_ z1>gQ9atb4len_|_7eIw_Qi9jz7Q|O&K{J0#^MJnpi4(bv)VT&fjnjp2Ss8GfO&Fe> zh@zinS_VL35EligA^MtYs@N!f)!ncueM)oZi9+t5Ner}nWI_XkEfZ$-Cw3!1Pr_*i z(S3I(MBenw$HJ^c*x~f6U%P=s2*LA%b9L>bqk%iJ$-UX6<XQIpU1U#>eZc$DA>9iq zjsy7GGp+MWH#Q*Tdv&Rb4`i<f{@B^0DO%<CSdQYee05ICW$?ykX^M1@_*>TQ10cmM zRUds?lAw?+17O$gxa%Jwd3(kXPiJ>>Ht$iQRhasNEZ4p0Om=iHtoU{-9vEc-#opM| z4KO>UBJDF4_RnKS5q$sL&R8NyYRTvO4xXESh$@41Wlhn*G)hE%=%tQ^L-tt_d_<tM zB?VxnJY)mSkU%ZM)*WtSF_qYr6^;>Oy-Nm#YVdMq`JaH9y|bipIV!m5Awa#FiUHW> z{`>noCik!KG3Z7%e>lZ75nS03@zXQF=f0M@Kb(t}wTrv7j0UROhCUMN8--b<Yew(# zL;m<L$MW0mWCaJfdnd47&Er*JvNLnGQ0`1Em1MLA2;ZyiP3A0jPjRrtwbY~wuHJI^ zef(X50OzU3qKcN9U;9!tKJ!_QUlJKUtsSIWuHPaQ^JtVfQGwm96Ik`%OE${?QnJaZ zWzr$8RvQ4^tpXm$E+3F)W)9xopDwva3GzQU>7N|Y)BvoM3gZyrxn28Qg)80CSpXh; zG^)5at9`>zl=YU52R-kg!J^O_$Ec_<CgUqZ@lAI43BV|?yUvJJ6qhu7-<;573*0D* zoCzz*BIW4w_br@g(_}UkZ9ho9Oj|+nZ5%G!4W}Y_KhikQbU)8$I`jaS+dx5^(HcBs z8!6Dhb^@*fU!0LVcXrgVx`^WJZ&|L8E{DE@4nXsvP~qwxw|=O;$yrA{IDG&#2mvI& z+UVu?iHJTnGMBq%gybM~q04cyYMDo<u{R^dX0vHtct>93HI`-~N)3wY9UV$@TfkIQ z{vL9FlyXCmp0`{*^Rda8|18&_*xAw6rXqh5&L{V`9#=C4(1uD}VrT;r4_o79O3-VA zNVz8rH6X@~DSWUd{yVdl7Va}p9oorj@A4aB5x2a)E)ouPG6`ppoM-igF>>WcUqE^q z=bb)TJ~H+P*yxDcrRo;eK51AX+Gm-M+r=ACVzrj+c(bf(2Kgpf9JQ$}tlXsdD;=&; zguc@0mmuMu{3YpQLmWQ>hZNs;UIt!m;|&SO^l}ujNW!G8qsD58B^<jRs4E%-cltq3 zDX5t#1VCn5A%t{#tVW}W3>jHWx*&3oMc4;Tz9;usmuPeD+0lA*wKg=UFk39eh_jz^ z;)i&~ma1udZ-!P_IL{2N;DsEeNv%kD{q48v99PNh=ptw=k>`3y-^N`bKO3-BS+O-p zSVppj-|&4}2_a*gyV+NHKNgmqve$i4C6eE;*Vs=4pM5=ae<)Xm4*vRR{1UYO*)Yz_ z_s!)J2>Hd!ok5L4tC2|)Z?G>oo1%iG3ZP8bi^As>(W713um?$JHTd@T9lW{c7jepX zMonU^PlJ$YG0fJ))5BAVO&%qvH*_hGP2%SGT!0IaHD@DTBrQ|IzDxhF@*W;)DC4jW zc5|Uai6`bp(mDeSIu8)W%W$POPVq|m$-@Q~>y~e2`8WSGFI{+n<RbQBNh`ntsUqA} zIwSFo;8gkF5y$^cQy|#v<iXxrv9JDT@H%2}(wVF@hVsMJo0Y}|T1FMZ6}}r$0gRi4 z`Hn8e^7mH&XwcuWmLW24dsLiob^<5|LzVtrs8X<N2}mYOQ1}v_j`0t{x&XBz1J-a} z<^PKKg<Oeys1`?h6wSW^Om5qgdkO#G43HAzW%tp`R{*z05Aa0H-%iX<m>IN)y>=R& zsvjm}ZYOEkOSnn^s8M|Wl8MYiv;_{I9Pu5fJIn>|dxmL>o?jmKc}V=z=mUT7tMIjC z2q2rrq$txrg^kcd(rfWo$+pEUcUN{zWZ2cE@0|7*2FmysFEnUUL;k+7b$%~EWUZ6| zX+>4Tj|A~y0?41B5P6;N^n;K*wh@Gps%%zi9ISKn>h+4W1_#*`7LxW@YT95|VjPGh zA%IvMhd~iSKxZg&uk*39@r?VL)32C9k_&&w)oGE$Qc$7G7&}E{tDAuVodRXLG(brE zGIf9ovG%s$eeJ10jhD1<i)C~`Ul4_PZS&p(U0@;??STeRvP%8gq0DoLd)G<s)QN^1 z4bYQ%JLH7>A6#DuqAM^7v387n^Yz?7#NH>gvd7=znIsFB#c^SbcRO+8sU?FREQ}VQ zNE%RC@(b|PHI$hK^qILneyzDha#nK2QL<iL%if*^j=V%zJ|q1g4gnNqJ1sFm_&Vke z4;AduOm`6L?N_}LWTJu`B>YT=;6kUmDU`<&L#gTHa%l5D?)<P;0sRz#)r^X1l|)ci zcCmd`_d;OG!sU{)M6ttQYkwTl)5@$tt0mq)(#^VcFR+y2<hS@naem2<EMKeM`ZII_ zO^-bFLr&3+6_gZ%1{AdNl;$dUl$wsAp(@ttoVodq|3iH$MpmKgEbV1gC?DZicxf4F zwKlA4?I)8uF0pz#Q=Z|;TO*w&E(eRxjt|W~KF@J~m9;mu%J<9owye%&+n77l1QX~R z)>q!&7r2<Dy3(&%zaQ;e%Q?lBAOO`8qBN(gohGk#mfW%%VPGP=TW-uupnX{^tS#{t zW2p^(#M~=uhNN)&HVE;x2&rjJ@T<(2mE9s(KGEL2T@J!ms5*?=R4ZvyuG02*7%?ZR z`;`yGEAIo{lP4pQuX=3N%5?Vd?8EhIW}0n;3x6^?PRbst4=G=4f?(T0y|>BMrIL4U z9NW2Z#%3S!9j;{b1q}PD@VK-^_2XO3TA7UNo`IX1&H`#wU2(|O152#L@A4bor<^Yw z=6vvd&_bRyG?OiOjdk<9!XEO?&3lmpX)Htbzv7(~eEfnoy#<h2N13+{cIR`@@~fmV zf^msO&p!slm}q%Z-wzTg$y=S!&G_}H5%N5s?grCr4*u%eVHHcCBvYcQpU^H_@Tab= zyZXJ-G&X;|!?xcj2wd(Y&B2pHrO2&3Hz4IiWQN0w3~ZST+PkmqMkLo!%J@_wC$C39 z<A{X60a5vz8nH^VM1q&O631(>>pRBy2$xtq+!g`u^ckD>0C7U~JDzhuk7t;6ZpACd z?b*^L;dG_Sduv4OTa(R)o-U}&F4p<*>lA~JpU}S9rsik{v3v!k^I%Z`Dj@Pf>n86# zlb?wuVS1%1@vh6D{`GYhc7bB+gF5qY^e*{;lLY1cE4f1SJ6%Krsb(K_sdE@;PM#TL zJ-t!q`eb6kdqThEoSqRa^w|pA)yTaMq-V4I0LhRk(BEsp0KW}b+^oxzjz%(sWu=-v zr(NT-IZ6)(1K+oLue5Oh38w5V1yDIsG@Hz8V~Si~4-&grc9p$J`FHCIpx({uBMln9 zZJuK^ooyHjS3%ghr*@=b-`H#0_JbJwsrkdp#6umf_Jp;DyHEb#yV%dW;GcB(p+e&S zt&5#>oGgJbnSed;iJz7w)+U!|jSW({aVD7nx0$L7(ermAtKv`VwvbMVG2|+CEQn-# zcv;s62Qrx=m>Q|>CaS9mcQsLK>6bh7nyxW=P?a;>CP_W{B&2?EI|;K3IHnZgfG19Z zB*#ix%6i?O2W4)HWZQ+)KrG;U5eKZ}QFw0J?#-9|Qja}y!N{`g@{h~suecVj@X;g8 zxqesYKk)kYx@z;{9q8XZ-3*IA8h`DxyN%CS{Tvt^Y#LEowd0)}eOKX8IAN%mCzE@1 z=hE2(HIaMp_u_QR{GJ9r^<k%^%OqTnzDD~ROPLvcjleUfL`>Q$iia{?y{5+0AbaHx z={EufG)KnCb1%)Ep=eautXv=44~vR1N9{MheZ?v~#Dk-aH@?gXNk4~UdUi8JYhw3Z zeZfQY;Zo#H#B9C4HzJq}TRa2%a<9FYLd9R|^ZK0ENc&R6m2m~5oUE=X1Bv%wG1=au zv~M7fSQP*KQ`Wc(UEU>tgDcTQ-5sN=H^j#p`zef`C1>@R_jy+aQ_&*PI~PD?-n;yo zvaj8ZgzJGIwxp}iR9Zh-eoG_y4Qh2wZ469iDj2+w#nkOS0{RvGjpTYUZnv~MvfDPq zgf!p`wDRV)ORZTW@8sSC_EYcWHfO(_>m=~UK@L_w869GN<y`q$-?El{+hqG8jXs#v zchkbgfgh|PSr`VD6ecy&Cx4yAj4GW0@eXc^8~t}Zek@UspKKxnM*>B>Ov^fu;~!9y z>6W3-H!X!t)iKY0Wf(ix@#iy((uw0@XD9%JxW54ocRT`{sFgnM90Zz#BLEIOcZR<Y z_2|M%JU79V&0nR%y;7PFx^43n{tzM|KnMU*@FN{`a;qiU#6!)y9&}2X-+kXZ@$sae z&Ab`F*>g>E4tL|}9x<W17cSmBbbWz!cbTLCmYx10d-KBj6QvKJ4{ZhMYaCvK;yZC= z9#EAO*W$D#D^@Mz*T*SyeXvH2Uh|`}eZIL3U`M~}-~n3muE3_KRi$$wyvWv1<qve0 z1ZfZtb|0T5Y0?hh<mb{exELEr*uNQs$m0Sv1E<a^4pl~(o-zj`7A^_}sG*el)`X+Z zzIjS>%N_q`Dp)-vsBRqBR_ctgRM3wF2}F|ta3D<Ig55}z?G6;bgSAse`}VscxRtni zW0upt_=+8Ax82cKMyZQkb|Ygtt0ztR5C|h3RZ017(q&S5uYfOgH5?P!kg8<c+H#h{ zNQG96fPwqDb88i)%cS&)ON(F2)TAJcv-iXe_CaREYwwC4->Z$U5!H4O>jjs^NVUN3 z`A^zqqPXngI*&~)g?&#3$4`67dFM3`P9({zfp*bW2+4~)Dw8NoZXLU4aJO<>14&SE z+CQEq)3(3=9y)lSj6tdz?z3+NwTyk_tJt?Kko{tmb*Of4DMb01tk7vG%M|zwbmHgt z2G*1Q4d%Z<2~}_-(*-RluucddEA_*Y=QPc=Sjnx7sLV6^`BfMKMW~^~+`G1Qt>bV0 z0dorxS03~he{k=R4<?f(kx!FEpg@NplSo^uM5Dhg;cd`owvz&(pSTz^5uqi}fBmgh z?jq+zBJG!bz`u`&UUuD3@DLd#o95foT9;w{bhcSxmtw^+C%&){_mlI@4j}H;%Ke(V z&uDem^Ql1wY^C;|Y+Td4?NpX#l#uIwmsc}naHSKVqPU0Z87OwS-4|T%64|$6XQ+RN zs*RH`M@;*8Z;HG+w9C72w3C}HTkg{3vls*o%ndVBBs|5GxtP50&gGgHqyD6HS4ZH- zTkHK$oRiKpMrlH|RO&Mk08w>U?Xi2V$?DnjuH%mnF1wCGg4v`~+p~Nv{=n$@r<V)A z>ynS9Dnctntkn*YF*9uvE|x^NgA#<O3pW#eB+|m)2s)}*iE5ZitOk(7@)uozt`WgZ zLo^=E=ev#?Y6RyVkT}biqP~mX#QUWP4E1{H8KHD3#~EHQIbFZ_&>qVoYCJ@Gm1SeP z_DaqfEj_`$#HqR?md{_Plz5FQj2<`PhQ%b<-amW8;zA=8hB?fux+tg=FhMC)(@E+n z*}m6Dz%*q2RPwGV?7a8`$Y<Oj&uOwo6?AuHO`>033N^aMa9PUPG=Nhp;$}7ts!751 zQ*n$4oUy$21w>CGq_%l_IYr5~|NNq4sgjfG`Po~Hn2Sz3MH`URq?H3S=Cy-i8u!(2 zwTP>Y9-F;|>*G-e7uj#j@LfnVz47j)`skiXk6;Ya%B`8fOH$f&n);RIPHs}N9?g+3 z(nCK_Htnd_AWqSz4{pw=>ac&xB#koX&E>671vcobIun~J@N~xW1z}z0%VAOaBn1zh zdtF&TE5V7B{IP3{g(K~V#u;tgXcCiJ%t;>iR-sxh>)^=17yhc(R*Xqp_s@K#xXU2G zdR}`p@v_4a&V&9S_I9J~IfFz@*!yRKaU4!bypRjUPrpuCLc9SOcobWBfnVOTv6ke> z8OMZ1+<SU;A}Bzrvupyp{!8gL>5M9YEcH{D@Mu})SI+?sbE>6%JNG}?cUrqX`q6HX z)YR4LDvQPY%&A_8J}{D)zh6);8lMrsdEZ%m`s>YgmpUq9OH<fL`+tKDqO5sjkO}|E zT8;n1T3xylhaQe|H+ilr{f$!(!Sn)$DxQRXT*zPWILo1zzapU2>wdJFp&7qyHoyC> zXS->=%*7pneUQPFL<AC63yt%biO>Zn@)nWv0(2P40^AhR=Hb>ruc*HYVc^kYK=fHe zF)*?MI_BTJI%@{I7aUmAxgw5Ef}rI~SLu5-*GgQ)=Ps^RT5Dt#<t|C-+>>3pA<c+M zWRwEveced$8<F`g|IzS02A1u7c?1qk%c?ie9GmbB*+pz)IBK-_A?g2n;ZfD=d^ci$ z7?3-HP(#9yWMnRWTPrqFET6|FmuYO@cD&-z{m{^K2iD9#>bV;TejBMBy=@Vrt;tT- z;bPMyIgl(&(qht>;}m$}LBoz0k_N3uGPm!0+<TfLX~rGH5{TS2Lb8Y1Q`0)#&*%#` z@0*Sy`A9woiuN~r{bGFoi)t<)JT^{XDs(l0&N{2HS}AiCFByv%YRrj6FzvtW8x~Zc z<-1=+1N)Um<emwRsrh{s)y@;6Aq0(*qHOS>Jvsqd$ky-J6ywU`Dru>YE^x+>{S74p zf>OAOyk)IAe@;Y=>9DIMkWSKq`@E-bz6`yyVgvJi>U0RkWr(ItFo(+VGt%m4{l#?- z>mr#lsB{O3@OQUOai_`)O?=`rc9ong+indNTRxs|4;=swZT?BtPtqk24tm9g`w4LG z<iIG5`jtF>q&65L6*Fp%%))%XEbNQ+tz=CAhz8kaBenTD50IbR^>A<v^OMc&{&oI9 zaW2OwV{71V<NByKs%16ZD>&!JyKcruI)UUHHgY?qE9}kNM<6TA<+_#eN^qjXdt&S= zgX~ybXIPw0w%>@!9p#Tcx%VDvh^XU%B#g~(F?0s<$$C7W?+Q_G2ZggDjqz0qKr6Zn zY8gN%?S%1^j2)4>n7D-B%d#F@OI)XV`4ppGO#u}=>r#_9cONKtNn`$}S-@op3(@V> z?DLknYZG1eqSEk)O5Qlc-Sh0KFy<&_eZ78!S>m2iM9Uv4rFT>ytn>D#0mIySwyh(L zlul^scw+v97|-7ECBt<KhPS3|*VKw)_W~zH_?Aoda}U4t?oU{%rsnGC8-*W_IKmY9 zoMz!W8^GKh87#u+Xt^TMKZF(N?(7HiBlh0?T*^NIOZrsb!8oJ4wPKKh0b0sb>gfX( z4uq*tM*l67@A+eOJq?cWK)K>ojB3cZmOCfoAsd~j0H9$a6)Du(;PDt*_EGgH0eBic zr~<VG1CA7TpN{IS%dL=)ODX%?GPkSyO&x8l27CPVr|_q%PoS3j)iZ9rz49=xb9<dH z{>i-xbL)l#*)K@Bl{d9O!1`ioeSW(AX2@6i)tdd`4f_5s#;vLkllRj0D!R<~Zs*D# z$^QDb&-px{{>v3Y;`pBK)^~wv?9{7Q<$*$9!sI%eYyZZQ#wY(}JJLAwj#KcjoFLO* z2w{Re;IL>IcmHuMzx|ffMD<pR!@XHiRj>(Hw1Kvy9Pm1EaBnI`HU1$&6>t&OW}}8& zyqth^Zp_gpCh^T1Ni{qR=Ji>RIhI>=aBd<b^RkzGJNw%OnA(OIrGt&Bv;&Y07DFwu zorP5blkH2^Wm%J5C5KTr@B4i+p^Run2k?CcF(EaEpV@R4%goB4f{-nNM@53sbtn>5 z_)O8!i(C0YdwtR|Rn)7LjO0991fr2=T~@43(ez9B2*@v@zZL|#gsl4B)WHphJ+(># zPdaiL3`7%bc0Ba9WzG}TxcxpFchOzIqS3gLxi`**vXY*&;&D<tb-&rFa}fReDZow* zD+4rj$|3z$L~)#+{gv`}K|q>%q+=*nUtG#H@oT4%I>)2q+U#Ary5wdJjHawWKiS&P zUf)E)MM3EopwU;kY64eb_)PRlAc~Pi)xV$Q!h`LD`8g*{Ww6XIc@w@E2bc&83s0(b zy)h3iOow{+`=o5pO0+0vqCW#plm3H%s8SE*ZN>s91D}tENVE1Wja@&>C326RrS3=< zy6B+&jr8247`G0<H3m(YPX=5qNO_><-XbNqOd-v5?Y2Xj8Go1?d)VUuz=fqN9!)M! zG8FdmzAiuD_PV}mkWrB2l;u+3^{u)0?C(FnfBlN5Q<^+>=(s2Yt}p=VlmXe$gc4Oc zeGT?h^phX)f3!RV;nST>aQLI&3CXBie;0kKqhEXQKGOajL*2b7)Er$|tm?1u_Z`)f zA-z=6KkHM6se8&_F$IATa>b!G`xE<GlOB+9v>;U922Urc)LBq!BlAD|WRWu`qeFUA zSd?!%2rxQNB!+U<tQL;b=~+sdY%U%wErwB>S1Nyrrh}5%dP(PgUh{uT<F@jfd;GjQ ziaIr8EP~Xo@LVqE;|IiXUaTs~3}1levG&!E=K8UaWp6YxPtu82!aw7s$0z`;i`tvr zF%qJ>BCfz=3z$#K^34PnQ?3ev^}$0{G1M6*N^>>xCucrOCpo5=#Suroc_iHC%h?~d zh%c7S#PJU@@tCZ-KU@B6Fr2amHVaupq=P^p@2BYdB-eQVWGrya-x5ic9X#fCk<fQL zGbUXn>ukY_GXN`igyO(>B_dEWR?jf+r6#X5ir4VfHSJr{AJ9)dwgJMT+yY!^u^fMT z!dFei;^yn9ur{w3OyAX6GfdhG@UX$M;mdE?d~^TAOINCB@33x>B#8SmS`O;_x1X!K z|4751HIe)S=|GGKnA~=6kG=sWby;h?SdpjWqV~dRzn}pfzKJgsQU5QtlT}jPooE`E zKI_1aPBY}K5V=t0e+UiaFG0KZP!?(BmRKMf{2b)tH?MPjyy5Wg)Ze5=t*IDcnXh!Y ze}qOv>sOdftGk9d{8ymP-21!VM4wg(2z683_L(v}$rkcZ4R+}0g=yEl?TT21sX*eW z*KtLJm$sm7<wdSxjQCxwop>+hG@4%Q8&&*G!&F{|J7nPbs$vO-W}4-XC>5Zj>XJ)j zZVUOontz)FTa4;t-jsT-wsO6xTE_}n)LqWCDX&s65#|Yo-Un~$-dQfI&huJrp`ZTy z*u96CGD_#!X*EkgED%oE{T1FbFf_{~a?9plGKRCOe>*>*9+W5N`{2my+@(F#1rMOs z?@p%-Z4nJxx_~#NL+smASnT9}xI_??;c{vp^rlH~<9`((gf2a#wAg3;(yx{qBKUCD zAw#x+#(<SUMseXJwx5F0B2(rDiQYCk%dPvuhhqm&sGSu;iu|~(hZdy|ESDj_fGOkl zy%KkiC_KE?u<j|CW{)Y81i~JU$3wG@lAdTjzZSeI_8#Bkkn*FSvccNj>NKtpvCj=} z*^lezmoC2A8+XW#0z&#g_keKD^{>;uxY3Sz0|WRIHB*DFBvN*!8y`WO39f!h6|d** zw}6aCJ6}L!rl1AT)^je8cD)MZK;+gSQ?2{v9sfKs34I<m#+6#Ghjt<Ub=2f&oy4^m zKad2LK=H;4Dn0S>J(GcR!~ned$p?`SI|K0a8X<QKndcx-KreR5V@Mkf+yD4vA7?*2 zQ<?CX#jqCuqY3G6c-vxq)Fh~T1C}Dzerg5Uw|$tsU*Hx=#w~(OVrEDc=XurZzB&>$ z(kr)s9uSs)Vq^}jNu))5gZ*L5q`ngNSNU-+XIep0J;UA9`tS<tywH&SG-U0UBvH0~ zXw!kOn(${d<8De>x0P!{_>U5qBjz+Zgxl*p_;jB{kQNz$C8{~TTzkZf2DKXmDo8G* zjW%>+$)?LW&$1(U6L0xaj$9~;R;Nct53dE>Bx0byBT5Vf$-w$QTvEXr=t$)%FJD}} zL2}(NHVr~hoLHd{Fs;Zs+1+QTfPZvut5R1unE=XQ6ofQ}n+;&L&lMttXb{3=j;7cY zJv=cM{&VQNZlKy9y6}=6!;_v!hlnrEc#aic^HWvQ3P;`g^09pu>r}6lYGjv2k<KGT zhu{T7>xqQ;<E}ue+SSH_--us3<7F2Jn)Rb!<@+a&@>Ihz&#Delr1#SGjG1y;;1~G? z2!eB58@N|0i@5v#BSz$n<lzba%yi$woF!@xEp#+DO4lJr@>j`a_Xj2N=G6_526#jz z8uOh7Q2-U!^oycM&%gfqdOL^W8?|lv-`J}lTydm#GEPf&L}J1~<)`QO8R_ZDk}Dft z>v_KH@166$kIi<JiayYn?O2HoGHNh+(7vwKxmE|W+2i)`k22jOO+UHnf&1~70+3O8 zr*$?F7!)7}-Zm4Wkx7m46qg3{MJaOyoC-)IysM;6a^O21VHK(x$-sATEYZ|;T%#4S z%9r4JdE}euCa_1$0#QvV)8DS_)I?f?atZgFqRT!P%#v5Y+>sXb?QS&duZatfE#j$Q zU8LdgC(5aO^3k1NUOxA^>hp7V{&)Y9yiRhuh6S6?r146*$J0j%#pIK!_(9s<>m#bz z(p@xVxc4KiF#iZClH<i4za&_gP|6#45x9Z6k~G-`+J#4GRg2}oc!NW=pL-|AUy|+} zr{Ea+2H0gg^$M>uZWGlx;V+7kr`hsIZSJ()lIUanS)CVX`9ibQZ~K)J)u5y8l?^i^ zN>9%Cx?Gvg@1-fZ>N;dK*)Oi}{KU<7weG0(gPd%c#}`!XEMdB2wgUxpd;3Jjya3t_ z_1mJPkG!i8DW_jlI_ykM#pK+55_>`_%cw0$qa5?S_Nt{j2`}Nj2XG_thS6ldKK7xl zsmKp-2KU6^$aO_7QFL+UZhQgV8cq6?1>+KR>|?%$XI}?KD-1avPQ@!KXM-kE7I=)w zUGh@`A4pcQ0-CH&{RvGGQMM{bs(UJ1WhTm2dCJggM9C!@J@Sug)!eC)HSe-0EDk#H zPO>8Ux=yy)XZ8MKeY$amQqJ@WPeXna1BYfrPbVC6TUVrodxAZ?bck7kXS0iZS^v%U z*Jz=-#c%@r>a_pF*S&`|L-n$7(X0G>0~D?2E$nfO6TlgLn4!HpeQ(@1ze~I)laqDu zDB<rRHQFyLB6UU{cb&tX>Ky!IkLZnF9tr=cF|Pr87Fh424R*S#YDOI1OqU67;nrW9 zQW9l&BCZD|0IDz2B<xH`vO`(qSye>GYcQ;VT%sT;0;iW~Twnj7@oG+@(!Dh-XX*mi ztF5UQ0LI&v3H2$vd+r(tW98^i3Fs9zTGtOhn}Kul|EOm5p;fcS3kVb}33jGuHL~?| z)h9^$&S-lR0+Qz@B*uq-PZADi6V8u9xjvQ0xP8EdLQ85!NVG#n?b}99VoSO93^8@o zeTTdu#Vw<1Yn%_!BCX1miswG5BX#bzkCf%2Wc)IQ5sF;w><_MAj8d=Z=46l%8$WZ9 zxbcvS87)#gb|e}WKV_q+Y)KDZVMrw_U5zPl?#U4?U=!<fHU4{MKgBtuTdYp)israP z3LyZX4&}~CMUTR|el;3neaAX<sLZo4JWQ^S<bO{ixI6d$K1ZvKtM9~xnmX#HZ~PAH zO+dIyk5Bz>+$LqCr&1#`>FDE3LU)_Tci@Y<Nbgz4j(sYyRJc_Dxge@uhA&jYKMgUV z(D=&Y^;0X-&LNzuj{v_}b@DUA_soOngE{ThHkF<mha)+*QMXw|&OHvo_tqopE_-Rs zhw~Ahqitg!G|Ciqzk1N~%kQ_+fZy8}7LKTz^9f6Bms2uz?p$m6`m%H>aD_oyG`XIk zY)HOUj7=$0X>rMeH?M68vh8tvaP#NzQ=W|M(8z;Op%DSyCjJi1In9TV?<@XBHW@tP zKa`%tw8NCp$~%J(!o;cGl2!2C5O$mA8n*T(^?zdtu}FK1Xn&B)i_W(5Sd~E@F*kUL zh`ux{%@py}-n=nF``hzl@^D^EUk7DPXH?*$M;fxXezU>0#I8QRWZc#U<PGb%Ld5F$ z>IjLZr%A?IM(3<)u9j@$N^Gg$w=@MW-wlas&xM;uac^@JDboX3RsRf(4l62$Dxtn{ zg5toHDA``g7~%T23>-#!c+h*wbbv8()I2c3o8+A5X-TL_l%{%C2t1(-90-O$M#AwE zA&$oCaJ=nN|H<4w*RWN=^@8M9PV)Cv!GUR_4hBc#Z>UHMK21Fu*XEn8#(Zb$aud9> zKwmU3Y8~i?wA)RH=y^d3Wf2j*U9^}*!6I!$vaeg`mS-WCRu8fAf`83<_@d==z*8SZ zYJiE-BaTqbld?eTywub~E_4YxTtflvs$Q8~RKfaF0hm68wPvnwUIw}E%JQGtIv==^ zvd^F8)@0pz<rw->hwtKNzTb$2ock>A1s7VF{15Y$wNzZvVb8e?sZ(K!vnSq^9|9^Z z&L7p8&<kdrv4g*FTMA6&h~H%Of4={6bXuLiMUy9^Zbe3*rRpfx+xW-}?qWnDT*}U# zSfJw15i}=TkP@^GY75b3`=r=Zy{89TDn~vB#(yjXHmdn_hM&xbU}O~mq=U8~?iWhN z&-umrs@W@bvNBCNIDFb6%5I{wB9G-NG1%nPc3M#a$+3<RBic?qJR|L6F23M$Q%|ZH zrb?yQOEmc`IBLTLv?0qacG-Ds+#M->8Eemo)b)KX0Ez&QZ&o^AOSeB{LHobRio{sT zqO4`eW9|{jF(D8QuR~PzmI4L((%W@~*Og?;G8CYAG0*__CL)^wJa|GKIDkEBC|`n@ zh3tN)piU;y2l~HCbcXWgn5ggC)|@<`0I47zJ$?=%*S>nuP7<y9vJuqNrP0*pCOfkw z5C&k*PN&5?+S8I%2X3v@vDQRYjyb}}w>^Q_9Y$LH1m)>RybxweDtRtJ&ky#2F9qNM z?;c~Uws05F&gvw;B!akU0!U{HLVv7A0qtAxx6P!fVtD~LZc)j4CC*%iafcey?6-=V zbx9igz9O*Scjim@wd8o{cNW_}P=IZnR%p?vsPPx4R<+<(7pNt{*@udeR7jkqOh#>k z+ZX(2NAG*hG(ekwT}BNl$x?QIZ*wb&B~FCCNy<QsLnV{Cd0)-eLS;)!ZOP`mp17;? zXrc0;fTB_Vpq6ubMSN{TcoVhTr57cWY;UHoeK`ehIY)OjO04frpi0J^lYg1gAr7e# zy$VPM=+>CCu*$6D-7@sOiE-ANRFL@uGuQ<RSE9Z(=2SGlZz6NyZ&e!dm!#`+l6k^D zOL5q9xjMz~Ry>s&(ZNu!g8aP)H{YJWu=g)hMG*bJ$AlE4c)k&87>jE0(f^3+0agfH zo0N>DBMQh1St!pev4J;dSbq6r#Glm@yPRLlis(vZt!B@_5j1mJS*34sA(m<%|K^f# z*oyO)e6%60*?2wnnYHvtWQirDZeerGfh)>N)@M}gdY7kZ4Cmd!9&YO?3h~EpsH~p7 zf0onLz;eOwSI)~}PO8P7xFhK?`%4_8|Jdk%@PTjw*nirobYJIJwEh=6mE-?5{UZX6 zSHnB@gD|jSRXEZd&uEGBn0#U^mPu!L!}#^ulZVUW{GcQk@-nrL-}+r8uBnqkS^Z6W zNO|keRpn;6G$rE(MM3#$$t!7xU*{jr7=(Y-!w=RyaV!^f3VHx^x|ERRC?7D-*w`#C z3jhclZ#IZTxq2XSWjTU4^uD<`tMCSHO_g$rN3h-vn3SzwJ}i4xb9}nElnUiFq2{Vs zVSL79Umh=+5VJZMVZ14&fP7-EU76bg()0hN?y3Bjx@VcDh`#1ueyz%x@5Xo71jW16 zjdDyESAp6#d=*Dw>=&;-x%%BXmD~OpAXxU6KK+@6-V`n-9~l~=ogWW~yhIFYV9#F? zsJ&l2ZxS|5s@p~DoFYV8V%gHxk@7s#-i8NX&0vlUy*hZTqc1tFEMw1-HULwXoo&2t zIP+1n>>oQL4H1Z=0tdr*wp27w&r<=R&~}5r_U={UqwXsQ==6WLFX-bES%D4XAEQ@B zBqWdeqY?vK{o3&l?&Oy&)m80XT1IJ4Zo9CkwJ1e@txgtVN#ixY?WxX-+pYy%H4S2n z>)n-m&x6Xk9$1m;dM(-#2|0OK@!NigQ%%XI)<h~P$_Z}YOjd~~YBWMAHn|=QF{;y9 zhqoP(YCqAWweQ~BrX%iYrNVC@O~aMwyVcYp=s*}_wKg}MaANwM{m~#m0nl0Ys~RQG zO&MzH!i}-uHgT!s4Tt0`hzk6eGe}EVAIu_=@|=|tRll)4|ML0MF&@o0W{HT$d43E_ zDrB3$k2!)v)dKZBFH*~#*DJ^&n2jpEgk}lMzs|WAATY3n<BBKd6jP9~16za`A00wx zBeN_E1@k2$szAASeOtAHm|%%s=XnN{<qkch?Q4MHK8bS=3aek*{>M!AOAy&lz_ii_ z<Ex08-xHckSpr<hcxqaq(k%NZ>q^EYaIo?Gr}C%*rh;VOsTwzp!4LM$-&emT`}9(_ z{wv&p7j5$1Uc)FG#<Mi88+%~pzg({N`2C-i3YTg?wGxMV{aCBWMN@jI;YYD*_*W;Z zqA{r2hBqub=3TU!w&k)}nm<L_zN*yFnUKZMg<ATPJyc0=%_v5-I6qasCNJUU!P8%c z+gc=qy|Z$cmk><u2C5vn;2}|KBBydLG=c%F2@&2Frs)5p;R6Ue3p6)?ygNmXFc6@M zWx5k2evzc%?fT}-EXcb4B3V8e72U+WR^gm@eokC-k9tREcGt4NI56lnQ)-iE+Hbyg zZPJ((&+0omfkf;EhOD7jh2PdHzag-7_pO{%blIphmF7xPDE2GN+=v76w}B;8CB2Fo zqzSx~8&Swo9ZekSduu}G@INX$3#h2xw%sc^bb}({ASI!+0umx1-7z3BARU5qBQUgt zG}0wC;2@yV3?SXDB7!i4C`vb+XY~KR-}jyKp0&<lvDBrqXUDVmexCcjuHPjq0|Jgs z@2P%tSnhp+d|=S3+Xd?Nr8NkZ#D@sp29H1QAUsC0|IbxD%rGjk){Q`-?@R8|=sa+d zjId=h5YLgwg{1+-<B32)rtGOrNvZ+$!SS$nEAH*5()25kmlTQ#ELD3SYm>5beOEHc z#AcsGN3sU_0G<*x+SoFhgR(5mJjhq<X~3uhJ*)_aQ|y!74SV|qplzSfd3w{X(7)`= zznrEy-;S}2`+BnxT@z47izEkiFoOUVc&d3L_I--SC^rdI^`d=>MRhTuq96XOl_@O> z;YMBkDi~m+)1+kO;|9}rj=q*k2P&~9y?9!_aLC3sI#f|0;C9|^OZH4I!kwMKm^3P( z2VMO{g!cNN5S%OYRccqWtCwb!VIQgO@5(T38yVnGE;(qpvU8KW(AE{w|0!c0BgJl= ztE(X@{%Wkw<Na>hfB+7GBE?kSwkpHlyBHd(Kt6qs>tN1KPaIYriedV<tMRuTDl`?0 zDJMo2O{`9XqX>do&Q0$x7?Ytz7V8bmaSxkEa`?48W5HB!#2plDJ^3T(qlEbYH-LZw zmT;*L?48<(qSZdbFFgSZ%TNA?$5F)HZRW4XQITq1;Udi#yhNE323AS-OdRXj25W$P z;Qkann6WA!^soNi^q~?2w4ffLlhkpKFgyR<p@1I_$s49c7XBwyL<~h*j8rV#^SdhR zpJRqUH3SrmDV>dFprD<g{sT#=<&=lKPSOqgSL5FuCG@{H{#|TCr{W7Wq92#8dcXph zo-20hi=wndzJP12v8mz~2?yfTFS>R1pa-eX6=^_3^_H4d&57}_PWOS$1i)<KpbKlf z6WC~hoUuP?PE`(Z@wh8im~t)g`Tk?~MlkHL0LYIbYOgTLo31P!-a06D^D&1wEdMbO zWe13JUDerP3c^4RQ-+-`g3DoHh{ZvmTE0E~(f|11(?-9gjzqwrYlEg>Y3)5qt8WQc z1aUg6_J4|X(tU38vRZ9;7!n^4esy(Ytchgj{iy=p7g9WW;9&cs5bq-dj?I4~HOBSg zwX{3*z?3!>W`VA;5_y^0f0G+l2mWTpt~^<?&0rSst^2%-Msr~&dce0YvsC6aSB?ku z-nkd>GXN5X@xAs9kpOET>DTEd)yNW4XWlq`eakb6e8O4c^_OW@&6`F>LA!T-rh=J4 z?d#fSE9hJi+#X{{AZc=bPraVuNPj9<u&y)U$;H`0=}XBcd>j;NO&*Ul8SBmg5f6Ph z<Bk*Zfp#%WwESCG>L2ZKIOJzo2_E0440-hTT!{u=LPtxWOu%-hHQ%Z|K!BYd!tzr9 z@&<T2S=e?3q_X9Ft#zUkG-U-JXX*KhYMvaBKk^DX5ET3h64B0qtt$19ajlZ#;kvBZ zNN(~sP;I^`>igrS{yd@POv1L5NHbkJiMei5)pT1WNE?0k6gU;`_c)~2I>NQj4x*;| z+r$ERae<Mk1CUwlAAgQueU_A^(<Z9yz^SGj0r-qVqGJOWr(|M_=5M+i`CTl6e5J|3 zOfBlq{9Ero%)f<t#{a|o8+6GT<WcMmJDL_3=Vwsm)7OJd$$2R4BE=&vH9xw|{PUNV z-OsNAXj-TkT@>vC^Pn_I+klUMH88CCyl)zH^DT@v*ddo9o4dnW5_Ag~g+7PYU6}Az zEwt8zk{J#({Z#nGm3Nr#*5z^WBc^gOb)q$TLF~?*rZo%kE|ZU02f9JmHHBr~>FGzV z^XGZyA}R2i-`p8fF3Coo%3i+M)3#~<K=8ek_FiMkt>4F(gQ(cos}E^TMWY8x9;W2D zwB9){cU{!pH#nbMcW-}&mGQ|+`zW~2vR}lFe{H3RoIZaF1#TS#L;)pl4<y_2FPEji z)I+M^^$ynyX#Z`aO$`Gct;{Jop!=U+rnDIQ+vR`gAo7w5SeSs)bb3dhe#NluICZ)p zhSeMmykzGfy{EWsASPbBG?P_#$a`xE_;9oynSxljWBZkzx(SWP!#tJ9H^5d>{r+2w z8t6fMF>pL=oHlmUjwQJDt!QDnwTHzY9uB4@{^b;SA}t;u(-50DlcCw1G)k9Bym9n# zXaqvJB6~}xMPYP&Tn=B6PAULsKY#(w1;^{tcOXx?m9}Z@3=#?lKl&`im9IX?VZGRN z*Y|wWOA+;`>F3*P6F=mC5gkr&q?-UdgN22QbWyo(sfx-yAP_y?UGHqza5g*_W0vqJ z+kXor;%<R+ai_9o^3FXj0ZZ46JwWmBC0phA+ZA^m$|ug_(^5E%et{?Z*5w*Ts-EjU zS#M|#LRR}F2PtT|7bbNzOJ*k{kHZ^5#;T`2RxBu7o8&K#_FVDam?jf7R>&)>P>$v~ zqeD%47MA%vaeEb5XeyZ3<}E|&EaeFw%n%$ja;~59+g+=fa~rr>v02rtxiB_vfIV8{ z1l3@bN%j_?%aoQT2H2MWv^*o;(su-;Feq=Ta8}w1yaW$;uAX8Q5aJD7(y(HSz=h>` z18g}ATnWR%mNaS5zZKH-R*<o(z(%Q-nW*guJ6p@?XR4zzZp6jNAx;%{mQ=sUrYh4z zmt;)ME`YT8Bk<<*kc;Cf(~;k+k-o?}X0`lD7SqWj;5g0KOZj>GQz9*1frYdX#pf7d zW`J$wFpj!9h%*9-BGfXCWELtgY*l?o^9mXlxc}p$+K!yig?|f<4Yh#!M=mwF*SxL( z!KCvsG0ZL8l!<X09bu>EdUG>WDS`WDU=tuAW^8_G@+Ly7Z19XLzhyg($zN07%~hq4 zC-g`Vn{$0&=3+7ra6#i0mlk&SA|6wDB-^(|@Axkt%SGj<Y`nU77L!QZNuL@3aPUS~ z<3E%v?Pf;wr?YZfh6f#*`(o(MI4tW1Sg9yJx2csbnNx`^LL+w*+j~Sb!&!Pkkkf0k z@!K>h3+(ef{aRO3g;$dmfF+fZ%+e*1pJA@<P+q${1)eJ7DZsC&)INLn8wddD)X8Pb zDL)Ura<fA?pX+O?rYHSrP3<t&izlM#M2Y-xErfgjhc<wu0%4q85e+_XG=)t)#5r7F z?=OzzR_c;Az!qH(1l-VMcyvybrV?ba&Gy_`y>dGL<JwFWf9M{#72hxp_FcRMXLRCq z06E&_)?nB=(<$CbYJSU>g9Z7+r}9a!o7Xd2fjUZDr1B^@aDD^yHY+i}CR3(M>!!$$ z<*777(?h4s0GK8vavft802*O54+U2jXcT*20vsz}*LKDcNW0nKz1p<G+YCP(nHOvd zIy-g-j?atj=eu%mTt7@LIi#~Hagn!8)+~fJH`m`0p-_c9YY|6RSNV4hB#Ae_t;cz- zxC&-NTS|6R2_MBiJ9R#Qx#d5*Eqaed1>JSfdLUIzhpXi=r219@cydqIs5#`lFq;BH zZ;zxxSp?PfJ<pxtIDG~q0<ni9Dn~k}wZ#{<mlVFP>l|O`YoNAEhc#nm7rk=yR5-NX z_)bdgfOXD7FtrrjdY;Uwn*J<SlN~FJ{;o^(Uw#>${d-gYFMgSnFpf|KUGg*tJu@|s zRw_gR9o_ne!PgB(cm;QYyp9Od7v*A(rFKUjfK%J{1*`gR3P)0&EmkI|9zGM82I(T6 zcaP!UFi~OV^RIA@@d-~|v*24_#hm)2?jPQ_vTVG!7xVs6kfL!4vCVngSH2K?uT8bj zB9k9J3UYD5AU;W5b-WK9AW0qg;u41-=+#;xRPQ&y`F?hs2WIwOZSb+b#z0NsMUJf1 zSR`LB23XPPl*%q)W%U#5Bow)&3J8-ul@(cz1Eo6(;^(c_%`;~LsDjAct-9a!Rk-*8 z^;FgGh3@&cK2I#(UiP@fcX2H$p0=B0^`KXiIU%kaBgl3L+CCOs*PKw7y9^IDz{+g; zHR61h$bDlUH2K6anmJ<2RN*rAfxH$fX^}o#MIqzeB38o}Ra@T0Pl{ZWdB_0?gKzl% zrXi{X^I{Y6hS<krOdJ4#sfV__?R>XE^J$b8vB5unqT_-=qG^!NiV;7(V^95{I3bvW zNdGr(97`vj%#bmSBB%zP<0|_9)?_KTd`3c|{b2TC*@9uxUPzL@?}tKoDka~A*(3CL zmTWZRO|-=ET2Tw<(N!xx`$jyiZUFnH34a)JURr8MUzlA)wzpjQP4p&u`&X;X)FToK z38OcUQUW4Y<XPXFxRTt;7ZJZ(c!#UD-$S0;x7ID^1+VnU#}R4;3?;Go3L!P!{zl9M zV(Mnu^3wMY5ilQMz07oQ&p%}m>|q$X?ZO!_&_#+gk7p83Dph!t%GBFn-MAwD-o$sf z{_4FGbJ8Gd?25LU=#+r+WE1o`87XEevLCr}D68#OEi!)p2ChjnVQ7iZ+?}=~^)fL@ zE(YSz5)ZXE^{2lGwdMBnF3=7#PGvn!r{zs6FC7o{x2`bc!`OG@Q;$9@c!x!15)O7` z5gFtz=Sq`;B72PrwtA~26qBfkBKHETm?*86Vft4UW_f7%sQ6xDRedjK*oueV*=HF2 zL(E}j<D>tlkn)a>jeRV#EHg-vj-2Kz4&vHqA<{W9MEmg0ON6dYZl(Z4u7*%4dLo<X zPVwW|-tu&~jnB<Dl%Ff=YA>etZ@(7>4zvgfKSrS~V8CZaBbPBM7pWI@?ZP++xmoCu z>?h&K{hP&4iK%<l7)j3^SD6j29F@iPDbw{*3Lm9^DOJPC<feMf;m&Z2)++V~$Il9Y zVR?*SEbV48(RwOdSOr|A!_tcOva{~nlG26c0c&+xK<yBpQ?tvsA6Os*-Y5t4-@@aH z3tnRgzaa~<1`)-6oU6R4R3UgmaWStl&zHNfOj&4<>)yTE<WSiwVa{WTkT*NFy|a&` zIYcq57*!7-b13kO$w)eQ^@Bq<d6z|e-5FHjMxXf3AG+Jf0R9<AgUK+O?MQhr_4lp7 zURHut+`2uV8*dsvpMFMtpnvqccIk;^LSmbxEspHj9{l&|-B$_iY3Dl=)16=qOb<E- zukhp8<W(7=_`J|R?A20ehsb4K;7@AeBqWIkt>JkceN-boD2IVHS;<RUHm4w&8?fe> zsE=E<A2hl2qKWKc%v+A*Y$%yBX|T?rWFH^jojh*kd#5u4gCK+c*)nO1t`S1MOD$+) z&;0J~=-nulGtQ=1rW-mlnMLw!tysAk-#2T`TeK$qZ3`>1{iq0_#J;?s)=ZrtJIYgf z17nM~W$e<j=X2(+o}pP5I`b@f{JlzZ!}_%eI|U6vs9HJF3?bV^P@29KGaimHQJPFG zESe#5d$B@u%K}GV)<xb-PvQn-ZL{fDHC6hBP@m~~A2%7E^3^<rQ-$5aWmzrdZejt# zH%im-JH|{Yi*yj&8)oGj6Vp=PFwXWWcS2RW5OVFDUDEh*50-V(nW9wLyPJUqO(G1? zAIra%``*7FfM0$?(Ka${^4@PYdJc-PZe=?Y6hXDy&Hi66i~!1W!SDEu;}3|%!@f>N z)fY0P_lVXz6J<ON-k;6jjjSYu%Fs9RcT<djex|t~&AIjH2!60N@*?lzC{JyteM6#d zO8^v<hO6K=2}!=|?EYmv?K}{%di5MGF0F)2w29~NDltYZrG^2}8lcyFsLoynk}?Zl zRHce8e+O7Ln*}wSL_;Wz7LutX{0JYlaD_t_FW>s$QXS3E_GC?Ga4|VJ7Rm&XF%Z@I zaYQ9g@c2~50;g@YImM2#E$h^A_*aq5w)su}_duO>7+repd8ST#)Ns4rsA)FwkWQPh z(&55PwkcF-taF>)Tgy!mEO#Vv%Lng;l{Bw>D1?mu4!$S;;8a-M@QB%an%@+&yDpX< zsw<$oNEV_Y8_K}-A;4eo?m$K??u(8JSq766gq6Txu7U}hS>@?K^$})aS6g!Sn$%+O zu^)LC2c{d{m-vDfisSWBR_)vVQwI~?q1z1)3rp{bGuZ(yV)pw4a;^n#X?$8v7Sh{8 z6jngb?h_iY#?&MC`<cV)){`fNp}K0`Ub7F?m+l<#x_Y!)(MUDkn_mkyAwE+UYFlP` z`jFjv3$^8PX~);j_Y((oUeNKnRoK?4K$WEyh5}c0r*wE{h~a2rVI(grgE)C``E}B; zdzao8#wDcX>0KD@yZP2vM}KZHT&xE$R(Ui0|Kb6p26+xSbE{Mmk&vIu8oz}|sHOvR zf9jui*!9TWvJ^P29eB;p#UYA?L6QO2RxUw95Ik+v)&Ax7-si1PVqW>%8xylq4yTIp zeK~HAcJ^B<jvUxvc6xC#q^w5oZqQzV@NGinK*3abvt0dwyXAyzn5i|ffg><baA?a# z!=j1ku?25VX_zt=NK=BXtPaQ_x-TXR`8!_R>VMatp5_y5o0al&XkxzLjI=K;{CIX8 zHOF0c`g~kUvh=h438{g%al%NiIZ4@Sg<m{Z^MeA^J2#&p3QzD_Dv4!$zqIMwTIoT7 zAruOTO4=Fvg=F9t>t!7#VEL8gzdSWglurqLDtmi;@R&7XTatHjNA`H_`q#y8K0UaA z4F)LgNdTTmhwm8U4BDI4P|ySWZ+aHcj*F+}`5!epcUI(wWeskZXn9r-Bs)WC4mwvR zqB8~O@-`vcE<JeaN&GkQ1-64v{!cIq8_Y)phE_?QBM~D@;QF89i#$2Rt<+kdFV7)N zd|rPFRw?~dXcanuqIdulH4=f+=$BmPo~%0|$xU>~y4fA4@PBB<fEQE*VP<R2GeFtr z2dkER$Yp4H#O84<jO{dH>r4N+cE&CbX`)8^N$8?tq+wr*;U!{ZDsHSs(5FmJ_r+nR zJkl@#C%y{#1KPy$g@2<R$~^%<tiwL~Py7my2O|vo%F+MD%g9V_a!0Lv6jAy&K+NjD z0Ai`j<k;C~Q>ooVB4<OT26+`Vn-hn0#;nM1`_hQPS7>P%ekjP>S?BJsnPF2)o|9CL z68PKd`4`E-I2W6c;?^39&!FN+W$+O&U{|DJBEVK>2_RyjHvjfxfR5@Pidew^MiKk} zb5#5-N#ih25<2R9AmqJ?UGMxixIkAm6Pq6Sbk`)7KMCLhPMHx9UEur1Mkav#nS@tq z5GsN{z16jQMG(+w)<?bikHH!M)64=yW?T)Gdhv0Jm47&5F-(6^G&niDAmoNaWl2Z; z27qR-SA*eNsgFxk0(z$@E0h*VpuY=BA;U;|Hod6doRN^&zZ5YkiG(q`zg+?W#-D6i z1b@B$Y7lyWjr+6O299rRE0%v5&VgNRKQxR}6pzTBqhaM6M@hT7{o*Te``Z})mrEh@ zUoHiKN`NLr7XF_ug@425Lg9Pm2neA8EwX|F2#_snY(e^um54+hT-~8+l&`i@CCarB z0&Feiz_$69-AIZ7RPM1qYn49)vG9NGKDks3ijmDJq^0-|jUV`7j^OIALDXG+Qq%{$ zy<E)lt$)Cby8nO~KVU;%{$YqcbjE7`!R^E>^@kb;ew-04F`Ein&Nt;Vmj8J3`|*Ht zffIX*R_Y=4JI;(Y)0BMV&z7cpUs6KFfr?{JK^ivmJmFtRv*8zEQ+4^;2s`B)#o*+T zC>HPTipXbh!mU5#+H#4*>cH`007dV+v2cu5J%lE7YO;`W@q{_;pY|UFYvfa}%LZ;y zU};RFFwg)n#V9&JiSMe`i*;>wLnRp_z_W5THF?fjM5T7D%nh~1)S?$9K#P=>8u9*f zJh3X+n~c5hjK!)bX21?uYyLY?k(`P?Rw{W>!@b6~)WQg@qa*dOgs|T|oq`^qe6GY1 z>>joPbPzz~IM~}a+&}|-jxT_^NP|>Z=Hkjf;~uL@d4!g06+*vBmNenkMJaW<ksDBR zcti<+6NiBGtUx<L$JSDgls8!vuw58;;ZGP#eEPn<-Nn<XLol&mU1|Q^K>{R(^MJtQ z>Kqz^OK1joQElgYuOIXn|H)t~Q&39s9|*u#t%vYl-DHu=m}VQqBGmaT0VAFoAApae zV9}x0!rmMW-Z|+JqN2KhSK%~AxDo77b7ii>C%_!EqyWd16vUUh;<TCpZF1Z3)a%ec zCmOCz4J_SX6pOsvZgT@88ZlKPJ#<n9k0c?YSWm-7ga_QKg$O5^JZw$<=kmM>pi)M3 zh-so7gb7vu0@ya^8mg+Q+*by-9?{Fc)aYE$xi|>m8;spQXuCMeyErZV0}7j)05GF{ zK)GsNd4M`T_$A}9HhP~Zg7m5zs0k6E{~jv$en8Fxgh+b-7I#P8Y;DRb;{W(K2ZCX) zhFExw`BOexzGWd=KIW_-Zj~}^#O`Z(^!QCFp!m!??Bc>EpGez|<PI^lJon|5+3vj| z%<BW<B<kIkx+*=aZ#%$~$x}!9%UwXTjTedP0QE9=z-B%J0IlAHGVz~N&de!Sz5-tP zAuwIrlk;|#U>jafHUQ%|lEj!2Ngjv2YeJ{IgKBJfVbSVg52+j=z(G|9(EkY2Xt-3) zO_(x2AXP4cf5aWChtMT?fSVkPopfUKlSNf${k}~!&3bXzgXMmK-(*g)`%s(N)=4h; zn<$E{phqN;AVu@ti34UZzh(bbCPser#ohPoz(+9b=?^T-^<}xZFPz9{Zi;*K?Ir~6 z-XK2!UHT((w+D;*fLAaw)4DIZ8AOSU|Ffr9$Q}J3xcyuEUO9xYqZ}aX^Kp4k^=aq& zkM*62aW&Z1gNvLyD-!i594u*WLklI6!@~wb7@=23<#QIyH1BQUZOnlpp)qm3C3Pb< zhxHunxJ|vsyTRqD+~iAQ7B0r(6qPkfCwvP43qm4ka=qnnBJaGoWlEEL?TYr;sjMaY z^)FdhxCV7-JUY`~NZBz<pk%)v?c`l#$98|%nm^nPS!;OJ0!h5?*?yVOZncqwz`Q}a zv0{F7CUQOR?1wE=yd*}F`yQypNcru8^M4il=vrLPT?SpIH|k+n@8y39nj9t)?~2a8 zf@)(?uHnWAra>_>fOrIIG63Laqa57YXaMNpJM%t8hASTe=AQNl-XC-XLvkf25UlzH zd-I&p;Al&y%z}<Epn|L+3~cR;83^y*rVC)Usi4O?K*hVA-+g&?bj`VLY-dC!FQP@` z-j+PS#QEWpcpU>3dJYtD>Z6{z7T(32J}bdS25^D~2ftIN|KkxLS*@UF_Wx0X4UW#d zc~x_#AZw{7!S>r)QNlU!;*YS+kpWOYGV4jB@*`1E(Q=A;u1|D3RB3~G@)5JCV&Y&_ zLoGhZGcR>`{hB}HH9sPrNH=kde)m$;aax79s<>*i_2fz3&EoGVx*B5vy+#%Aqa84$ zVK$l8p>R(R?Bs_M*;=mNY4tJyMUAg24W1<m<0;sggT6$}sJ5JcT)ZY7Kp}xlAL>wj z=o2wU=0$ezyYwC|Ea>m!DcrF183hzxB*d4-pHn{4uodsxVGqc%9X5b>AczFGygCZ8 zu`PoZgBMtr5IEi#dxCQN9oEwY!T^lt@LMe!NB#vMoL}7l+%jTQ&`RLVpnrkGgx~)m zfHWIh_l-(fxi}gLHuL`Cxk!vnhwr_nnwpiA1;_^nHJpgB&1j4Ow4n?j^ROgx3f{Gk zwX2}g$uZ;v{zEtc)vw1GfN@|x?!YrQ>WUUtX9eJ8mWfgIy@F$8^Fc0AT6ApuNk4Gr z9Ia$wB_AH@2jQv*(~n$o0JIXTxw-Zxg`{L+aqi<XD8{b5X|K-UbTK`-2aE)V{g?2k zBhQ7-mXkFrD2$;HgVp=kHxHVT8^3ZOE;=+do=q<R@Q|yp;x<AIge&H8gRzDVcAlfu z4yL>xw=+Ynvj|q<eU2&IHqoJ=&UveGjct-@{BvK{O6s5lsq%!5qsAdmiDb5PpoB1$ z{jMhn_zKY1+W?U@rr>zHjAwBjd6=(Vr^<{x1ARHVkK+!B%|l|J)r2UT!o%0r?39pR zAap`SL~hM;xUJb&fc>ew?EAQ7b`B*h-{l7xahbx`llg-~;sFak(B0Shb^%Bk*U5X> zfM2{F0O|;)gxw`TV3G%)L?#X2Q{9!>@nl|j64!#3=b&H@?GwD>7`3}2_kd75zd#KI z&5{8`k(U%b-*}tFAO^Nr;-q{OB|c#18lWQNP<r6cynSd!Q!QZJWl^&8O69@w0w39H zj)LGro-2LY&LR%j%q1}-{KeF8KnR=($wqdaM}*)p%BCpuvr}!{P9$XCcLYEl9_DHr zB!B&O{Hatk544$1fL#ill@@Hof*90UNtMcT8uplM<wxU2^-_0Sm_`FGb#go4`b&VD za9ffqlh~B_E!tyIr`>0kLL#%ZFh*RQSyWZt6}*oX-&=AC@b?yK(4UtU-`cuz{CcuF z8^kl<Jq64+i~2L3!<9R2H#t}7l>EYEj*@WPjSzKG2XizfaqFPk(*C^PLmil(WzKyl zk;7Qn7-(GLDu8fD5HmA`4&9;6o+AOvzm>`Bq54Z<AWINw3|64DeBz?AAXP@gr5LzN zo%GP(_~SS32oaICi?5h{nwuj{Pl8$V$g)vA@1l+`L`d9nm<E*n<stFxlg@x%CLC%h zXgJ9MCwF{Pq&%K>QF|;q?+`5{^ZxA=e-Z2cl;A!JY%p3ySCmuqm33tF`x-(IAz`{5 z7LCYDOf-p54^fFW(7ua?e*wOfuSdh)*^rUkk8L|&bHc38*#`tyP~t>ZOewNZsy>nX zxkyo+q3rt<w6SxbBMi&Tb-npsntk|@PiN<#_#Sa80s8wOc7+C^ddrTd3hn6X3oMpH zfEJ`cA&^f_R)io#RvRScffHg95PCBKCNf5fw=eMhALg$IIaQ@b7Qxfd6uBJ0^XS!Z z&ZN!ff<j7EhxD*HibFp>zx%cS+2!>Tn@|lz<9aSSU^c_xhAqj*?nyl95Z4lWrRUpm zmnMFMTw$ANI~sDSZaeqWWjoDFM62|M3`3sWFHG%a6A5p5y2<A7%C6t+UA}^o1~L72 zs+U(!EGXFHfI1cLW{qrUbaqq%em);EpISs(a>aE$BP~DtHZEGlTvlz0D7uiO@iTd| z+cy?ErQxO&v5aH_wnJjx{7h;-%P7^`Eg)KK_!)MNkQLE{gwwgB6!jnmg&>JXl{kf# z&)9&cN3jSi0GoUTed-{9c2GrQO~nX!DlZJon^xWNV>42O(hiLw-vuo-7R41Ax1V^8 z(^)>(sRC&l-@zndaDCPi*C*3~%B0JRB>&rQ&(a((OK!H#wd}O6`+W{G5NW>-JZ*8V z1{#sc`FsO5dJMU~Mjf_OyDm(FxRG;TfmqyqAw}g{<bhqQ@JI^tND15$1bGa;7^3Tn z9ZSKZ%$!Eamm4kn=KzMz;Ju^e<g2Xkoah_@nlX*Q_Gpnf|2Kp-9nwV7Z-N`ERC~@n z-$YqS8@b=#A34rD8nn%bh{NDH4vEf?hEAceEHmvNMnL%zrNs%u=Q`j)hnn_*)Co>~ z6wmt4y652a?Zz)>TnOCh#UO*JVRq+%I8asY(ePPcM^nRjitA4H22bV4o2;*Nu>{a3 z>h!j8-Wi}LQenvhc{E*+90Iu|+?yeR+sl3Ic1zyBhb4d6No&=S+>ccN;dXK}$~U6R zL=iU@FJI}G#HbR6O33b^)YE(Q;&)}`+1KCVzL2KWd)yU8CBU;o+7UY5cUJ-}z0wJv z_gNxap{z$JKxfb-AGt(8>>R~&kR|5_?6*hD0Y*cr>->b4ylHHuzOC*23q0uG5Y$R~ zJg%={BLnF*D;K8tD{MxV9^=vbNK$k5=ELyY0U<tRUMzT(VOXkCAwBem!qrVM4me?n zc}J<atGuu&%Ee-bmeonZ*pW}hh;KmuR0XoQ?j2;ghl*N<5E}sH<Bv-V#LG%sg?j@{ zEh?h|rD%l`yMs+p*Soh~zUhCS<RFLH`TXwlCINfK_1oU`NrYjf_?1Q2&+8y`6rj)L zk@tBg2P`d-%Ng);Kyn3kJTUFnj&iNend2p<2MD5IH;|2FDdJa2%jYGM051nlN##u@ zeGEjO-!_Ob&4H>A{$*@q`-R<=y}VN9&pUL@z1&XK;+WX&7{Tl2%i{S}Exv_Jam>Ay zB{Z_)u;;Op*#VU}0my(nj+wW)$$MkrZj3!waI6Gq(NLo67VI<0y!3dE+E`U|C_G0R zMah<OL_60l4x?j5UfBNPOIezWzkX^++$j{1S#$RnWx#XVaQDn1r(e|>LnteoKVK;+ znGQK)Yfe`#QcfzBZ+!|?HI)kVYYwaDfgnY{!wc|8a0VI`!y4V7-Z@$m0?M(9i*O_L zuy~S&PP9(dDl?LgiSH3rw+CZz+f#)fP^*}AQrQp-$s;g1h{|T%OteeqR`@cg1E-RM z9GTmox+}v<a4N6hO=mv|DM`=$5;H0Ziz+R$(-TSih2Ac8v(hsy7-YW82jR0qoj#Du zfSv1U;NqpJy=$)+r?b!&hIKOL$&n?dUx^M-E>?RRV#vImwH?15%ui1QMYt+J2rFSz zOK@ly9S$rmwh7;$@;MF673CzuJ@GXQre)}(beDe<9oin+{YF<D8pfee6kA9K-IN+A zy?Z@bQx7h>)s~N-l!GYOhn0wuxuR5fY#e?N6%4W=A)dx#VRS^uZ{)U?M~RXKh>9AI zR}ab49#OH4gZ|J}2%o;MCyc6MH<^E>-AP*rMhjy%BXk#4gFxBUaa4t2Q+^nV{nQOK zaU>*=$e@xJos`M+gvvqp0kpzCvE0rrkBxD_0O5#YlP4g-At5*Ts+fI)^fko7vTv0z zMD)okE7W^7HDT<|86tR4Z#F5R5{!Cq{!yTwM@^!QshE%~A@!Xi^mu8nJ7Ss?O~>po z;vI+c?q>lrq7skPktVLFh|-T}HtZJ6sWe>44H~$fh0|HwFhHmV#x+$zK16~u+}2DC z&O8qj-=v6>j%PT(g)8b9jpyjCzIk}%En8PT6B4or$ApH3KOQL$2U~*P+vjWKDZ0$( zj?$Z*g?1c{*NVd&<P@Y}^IdNY5dt;HL7=pKjs!sUDdM;i@-zmR&@h^30(~4D0)D(8 z40Btm(iV~Ee?tfcU96_@LwR(eiJ{(CojXGt`ycfNlI({SIO=s{<`nWhdr)${%#KQ5 zC$$)IZXm)$d4EE^!7d=Q;8Q78cqAKl@4^DlN^EzZ9aDq-ImUolL-(g|n^K?CT#KaG z!OrU&Qo>rx(VJ3tj;hBR8XFK{sl4kk0z){l*h4X)dfDz~oBJgv`@{R>$NQ<II52|= zRIRP*UEVqi-w^B9kU%<mx6S+T2LBOPl+|g=D%^5CMhkBm$x7zjc(JB!czhjucJZgj zYFCpD-+V30timBVxsQZUxkUzAUq!|+9{i5cvTdSh@DHIAG0+RI7fWe4;o%EZD5Ehz z1oE$%Reo2od3G1JwDa}qxX0eU>6uXDI6f3?lpE#6BAME3aJJ{*oS_q9O>WSV1`kh^ z+z)d_&C$r2QdKJusB-o<Tx62cTf#KpMl)+F{z_}_5HPCmrG={ys!pDRku>QSHv`tf zB9hZzm;9b(`nz3&AL1#^W;^wa{IaM^^wgU|5ctO!EkX_5_q%f=k}!!^)kwktk+d)V ziUcI&X%2jzooevRFnk*DT)@l?oVj5}Y-9VHJRc?GylPj$ZW0`S@zkRvZ^l-(@qRpm zDgu;Tod2XyqX_|dn#zs4u!`y!$scqDxdHKwif1vXZ%j~vt9&z}jUo;Xs4($BcMie1 zq<0&uE?;@gWeM@=v76NCP8=U!4x7HMpWf0QS{(grxlU0NqR$Xb5uSKL?ynRT(&#3L z%&!*EosJ$HKZEOqW861+P<~SEb&X@cCWn>hk$DY%wZzEy_*>Wkljw12b@iR|2dlN> z+l3!$U(L|T<!lO%yq8<MCH25m-RznlipLT*k0!=Z?ZKm0<BPQjPi!JWmYgrUPp+Pq zynGWd-u8r7%5Ohg{LcU^t}I&YuKGphk~SWud1Ia>emTGB^2vQ>2vSS%J086Og0l+6 zx+_Xn>j%ny5%n6J5Wa&L)KF?eQ?`HEwfZn|%<I*dzKw>*47UU$6tFv(@@#oLw5ln2 z#-UYLSdytvJFdj?RZ!5^h|w`hCcfQgpJ?RpP$;&!f=6=RzZ!ynz%9OIO9nMF4{CeT znX)^X&|1Ps{0<t@t;;i;zX}yLr~Dn_>qg}B{-?{fnSFh|<#}&O#5a{RvRxy?rdm64 ze8ocaXP@xOr5fOqH4MDQBXq1CX~+r-FKg<r+oXf4Ax9^{N9QEEzmxXPJZ~6h5W*L% z@yfY-!+em0vj*%mWfIPbL-!|sozdTWFWpi<8FI`lO0zO=R$J2Ur#8vmHS&B>#yh68 zhTaw>V?zygg@#$<@ZNI2L#WzgfN<V~Le==3h#dJNO6pDXhEkJX=mrTiZ=J?{o`hZS zVmCj2)$EJ2M8G{?sgon3+T$h~M78B4UfL$1cBu73w?Xu{b_n)K%s%(!y^y!Q;S<%n z)>WyZ?Oib})Zby(3_eV)YFfpZm*3(DdlW2WF&>^(Q6q7m0Xx2WgKthfiPL^m(sI`F zQZqgc1FzvBIjKO7m(ZWwcWfUgr6*?eK(RXA38|+iH{fQZTdLstZg!ODnjG(r3dn1c z%&3*?`K|~>G4e%-e#MTMa*qq0w;7}kM~kTLFK>8BJs>$D)xi|l+XG6;z?^}S@}C|P z3?8UnjvIWasD7mO_OMTl>U+N=4E5R-`jCr#&eNpB^c{jHaXOL?dj54rq{|sb3ClWG z-wWK_*yRfCb_?8OTf2@jF$!aO*fnK)=Aj+;l0T;VIK~dSn4DzD^_-heB4|;l@!I(W z_CpbKzK1?DTe@vdFEg8yj&?Kb3#+9C3$9ZubeHo^32@uB)5vvw_C&Gjh1Bazf@hyz z;R__8W77wep3M>e;`2kOg+ks5WAOGz?0vuweT$H=Q03N5y%`W7cV3%$%FsQeG+(ZH zes^<*|Hz2<4&SF5&Fsdd^lGyf_XG42*T}ipNZ#2_m(2dU%)w*y#ct2`2Ie3pZ%6mM zww-l=^<@04_V?+p6RMG4(g8l}D?e{A+;X`a5HO!+s+(4QreNc?eNxj$IAlJsd}6(w zN9&oYf5L-@Dm)0IZ<mYoS9<@hGO#3!3vnO*la$;5My04ub|qMVkXNp>2F0=K42!a8 zP&vSV%Td=k5^VX4FRl1p0XOoVtb1f;vZt$U+c*W;N&#o`4-1=!QO?0bSi?hu^oQs( znTq4@llJd%EB#fHUb{Z<3^H9c6b<^Qa@%Zy;kEW4@!Q$6=Tb^W>B5r!0|PRo^h5Bz zUH8rrH5uW1p;;OZ@5>k2UnO7ha{5$bp@45ABZ3@V(}dLC5hHHAF-r64>bya%BqI3k zGcSS#i)fz)xC*X}LNmpVOvc3R4P(<vN6)J2sd{ge!Fqv!RtJJ1@$v(Fkxl4Yob}13 z=0fZ_IT_JzAa61IrR*!^?ds}x!u_(7!bmAnIBe49_tMRty4zSIJ3r#G+3qyG-icj3 zw7$_&wxeo%P<|u3_c9r+@v|$L^LkHuwaMYB36!C%u_P|A6M_dQt9G0#cPgBy(t1!q zhTU<6=cR4g?p*z*9aXmno|TxKo_?${1;A77?ut@|>*D?|%$tWs%wsk4$Pyfv9*E82 z?tFH7k~Q=s1RgfzBoIvIQ`v56vq|ip7Shto$3}QY`e}*di(aCvq~Hd-);9}w+IAWW zr9}&NsF?=c99OuZ-nMse<ljSYG?@AR=}n|!38CPc68;xFGGh@(<%F;x0;HTf{PyKY zS?WvY74SIx4JR9#%=-w!;;18L71{){gKNp13>`~%l63p8jTEoeFE?vwLHeq1CX2X< zo6sVAF}$+tF|)^VElWq&JiFE?6dHNnK`w$Gk-tBDV1@i@u}n;_<wZnPqY7ERRj|!h zAT)mFLh~>-8OHY5H0HUd#??v|ko=cy<1<N|@Hx4tr-u+;cX0^+wT0eX3d`wXc*~l{ z^_C^?h8TKKVvI9%swb@eZ5ycB_zzHfD}UqD=p(u!nGXA?CtUWS;2Ex8?T9MhC0q`j z02-dJmj%iNR2GZO{<-+z47^gQs`Ah;^NCF1K6!07x*Q_x{Be`ISv9|)s6o}>^JU7b z@Sj^B$(AppINUorhL><H54ILrbh_3Sw)&u$nCa!RtGQa^`OWvoh@<Lx3!$aLlvjdF zSlT<b^?fgq3>bcYM&NsCW1rZdK{d)_@7*<`;Pgj`enF)9lxYX6F?g*Urki%GR5`j+ zqEeD!5ZHCP3)|<<^(hk2%aqS4z89T+g1;7<tK|Rj?C9sGxiomKSkq;jX~)Yo1{|mQ z3srh&bY)E@p6M0yZc|2xr%?*!UYsJgYlNc7@B?p=>IwQ>{OTv6I37<ww)M9SDQdd< zV2s16ab8Fme7WOW!}J1I*bUEx*&~klO^t$lm*j-Ty*+;3Ww&!E_4@O@4{;cgeBj>f zwnFXw%_RO_y^A057Zblmy=dD&=3|aa`Rt@~TR2Xxw(BLBO~bS%^9ZI*U+0DcQP{WE zJEOQRMUnF%cYar2;?wge38ZUulMM4HsgNuU#OzM-TAQZ^g;e*u7!#r{vD=^;1NDzq z;AhM<yhWR>O0(&rB7`K}{Z|ZxYv%68M2G*N?(XVmr+=<+vXjE`6%*W~=W*1Y#dXkT zbf-kmJMy!K_d4Cxfvl+aRkxAvX8peiINsoANkD~L@loeu&Z7z5DoKQ38vBak`kD`6 ztElRrz<(bj<BVBg#LBX0VfL_m!Vm6OL?-p6mAVA)ah37$iSltAJoFnc)PG(RyaA4Z z11|nK9tZYw=PsmCB^ZS)Nm}~3PpHj=yx3OgNXiQ^FbcP>(|#`w1BL|K0?*+VPom)d zHxW)ubg0q$MZa~K8hTWYVZVC1a8Lp@R>(V-_^zl9cJ#>2_e+}Xt~gkS*QI1AkRGuq z$6h(odO>8keU0+BijG6uRpu6&u}O`ef4{e;#dg@ZoSHIr-pOxX&gnc}AOA))KU&dX z;80ZAWEM*H3}GnttKucx$M9QMZgsZv$UxX|l&WE7Yf`n)yjfDU%1;`E7~xL}`kR=? zBNxygykhaxCA_<uieCyUksdCeQ9|EaH>laJ4miU`db+kJ5F6?4DqJsN$FPKU*c$2M zDJf%>p&quhR1TZVFb*cU7jG>aqGG?jSg?<7f8)y6lStn{ab>Tx)%JF>yoavk9kGAL zlb1t6B|XO0>q2CAQhJL|jLlVrpYxs90CAswl-IN>qhWt$p^$ZZ#OM^R3%y=Sab=Q+ zXISk|1;e#uMX>ju65f@{l+|0Y-u^`)*6v^`H^qz$*fX*&k=%1Gk-YHmcu%>((S#71 z_I?SIfUT-Gv64TQsyl|Qg}lp3*z?<|@iLfJl@H`A`u>Fe#VWgfNu1s0L~1*Z**?8` zilJWA=dUcu?&m6)gqgR0$3OU0Y$d!;+_tP|(`&_mx=hHc?7PX{y%)ODcJ=lOym6I7 zO^v@y8vX8ggiqfgJQ%t^nBUrR_F><bsikuNd||kir=ET>vfs2w0(RBYn~vV2#OvBa zs*|~s$h-*-KEVj<bX4);+f0}cJ*Po~d&v&L{8z<D;a_h_MvRTts$&ArO<$bAJ03lK zE5y*2ksnv5wSt+_Wp1N(uQ^jO`h4;4z1;70h*o~ts6N$G@m@z>-!G_vu524mlUHlK zf-=lN<=1y<yURAcbNXxF3%m<>fAY@W$Wr(?ypR><++cTUL-NHd7h9!Z0e-nr$QcWv zqpfAZJ{$CT__WK)4|TrF1Gg;Hkka4d1#0HLn;lo&_HuEo5o6t;il~7j2b%|A5Y`R7 zFa3V_%ElH*mC;z^C^T}=9{+8U6Uu2hX1F-8dsBa(J?G(#;N8ehTTknM-*_;`cQn)T zX>4-ZPo+TeMlq-Mu|5wOn%mAZ>23ae>g*-cmgF&BJv$6MX$XD30?%{)HK1VbA=#;D k$o-X7&E3@<HGgy#T<G%-ew|}M;1c*!R?v{ImV<}>FVP1sw*UYD literal 174152 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 AK>z>% diff --git a/Doc/using/mac_installer_09_custom_install_free_threaded.png b/Doc/using/mac_installer_09_custom_install_free_threaded.png index 0f69c55eddb228bac62345bded45b539003af6ea..e867e422e42e4850091f82373e123d1da817c3de 100644 GIT binary patch literal 187689 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 ZXYDSmil|WwyAtr<*hxoMhax*X`9I~a0*n9v literal 192812 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 Qfsd!Ds;g4^*evva04QZv6#xJL From 7676f956e2bf83925f1f6ae3f7b59bc28add805b Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 22 Jul 2026 14:38:47 +0200 Subject: [PATCH 796/818] [3.15] gh-154460: Do not use wcsftime() on OpenBSD (GH-154461) (GH-154474) (cherry picked from commit f195b2e3edec8f770abdd013906379bf49176a5b) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> Co-authored-by: Stan Ulbrych <stan@python.org> --- .../Library/2026-07-22-13-00-00.gh-issue-154460.wCsFtM.rst | 2 ++ Modules/timemodule.c | 7 +++++++ 2 files changed, 9 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2026-07-22-13-00-00.gh-issue-154460.wCsFtM.rst diff --git a/Misc/NEWS.d/next/Library/2026-07-22-13-00-00.gh-issue-154460.wCsFtM.rst b/Misc/NEWS.d/next/Library/2026-07-22-13-00-00.gh-issue-154460.wCsFtM.rst new file mode 100644 index 00000000000000..b0a7058f0519ff --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-22-13-00-00.gh-issue-154460.wCsFtM.rst @@ -0,0 +1,2 @@ +Fix :func:`time.strftime` and :meth:`datetime.datetime.strftime` returning a +wrong ISO 8601 week number (``%V``) on OpenBSD. diff --git a/Modules/timemodule.c b/Modules/timemodule.c index d90bf1f2ef90ed..70d7e1b3713687 100644 --- a/Modules/timemodule.c +++ b/Modules/timemodule.c @@ -763,6 +763,13 @@ Other codes may be available on your platform. See documentation for\n\ the C library strftime function.\n" #ifdef HAVE_STRFTIME +// gh-154460: OpenBSD's wcsftime() computes %V incorrectly: it returns 53 +// whenever the ISO 8601 week belongs to a different year than tm_year. +// strftime() is not affected. +#ifdef __OpenBSD__ +# undef HAVE_WCSFTIME +#endif + #ifdef HAVE_WCSFTIME #define time_char wchar_t #define format_time wcsftime From e9d9fd9c80592631a0378bf22623c549e621c7bc Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 22 Jul 2026 14:41:16 +0200 Subject: [PATCH 797/818] [3.15] gh-154431: Fix data race in `sys.audithook` (GH-154462) (#154477) gh-154431: Fix data race in `sys.audithook` (GH-154462) (cherry picked from commit 596cd5c5d7b6ada3e50c6499447eb90a065769ad) Co-authored-by: sobolevn <mail@sobolevn.me> --- Include/internal/pycore_interp_structs.h | 1 + Lib/test/test_free_threading/test_sys.py | 14 ++++++++++ ...-07-22-12-42-53.gh-issue-154431.U2kXXZ.rst | 1 + Python/pystate.c | 1 + Python/sysmodule.c | 26 +++++++++++++------ 5 files changed, 35 insertions(+), 8 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-07-22-12-42-53.gh-issue-154431.U2kXXZ.rst diff --git a/Include/internal/pycore_interp_structs.h b/Include/internal/pycore_interp_structs.h index d8e83cf2ff5c9a..c1bf1770266681 100644 --- a/Include/internal/pycore_interp_structs.h +++ b/Include/internal/pycore_interp_structs.h @@ -988,6 +988,7 @@ struct _is { struct _obmalloc_state *obmalloc; PyObject *audit_hooks; + PyMutex audit_hooks_mutex; PyType_WatchCallback type_watchers[TYPE_MAX_WATCHERS]; PyCode_WatchCallback code_watchers[CODE_MAX_WATCHERS]; PyContext_WatchCallback context_watchers[CONTEXT_MAX_WATCHERS]; diff --git a/Lib/test/test_free_threading/test_sys.py b/Lib/test/test_free_threading/test_sys.py index 271fdd13c62b66..b8ba933cb01adc 100644 --- a/Lib/test/test_free_threading/test_sys.py +++ b/Lib/test/test_free_threading/test_sys.py @@ -44,6 +44,20 @@ def worker(worker_id): workers = [lambda: worker(i) for i in range(5)] threading_helper.run_concurrently(workers) + def test_sys_audit_hooks(self): + def _hook(*args): + return None + + def adder(): + for _ in range(100): + sys.addaudithook(_hook) + + def auditor(): + for _ in range(2000): + sys.audit("fusil.tsan.test") + + threading_helper.run_concurrently([adder, auditor]) + if __name__ == "__main__": unittest.main() diff --git a/Misc/NEWS.d/next/Library/2026-07-22-12-42-53.gh-issue-154431.U2kXXZ.rst b/Misc/NEWS.d/next/Library/2026-07-22-12-42-53.gh-issue-154431.U2kXXZ.rst new file mode 100644 index 00000000000000..a56c3b3a6f21f3 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-22-12-42-53.gh-issue-154431.U2kXXZ.rst @@ -0,0 +1 @@ +Fixes a data race in free-threading build in :func:`sys.addaudithook`. diff --git a/Python/pystate.c b/Python/pystate.c index 8349df1b573952..185957f6343ba6 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -580,6 +580,7 @@ init_interpreter(PyInterpreterState *interp, llist_init(&interp->mem_free_queue.head); llist_init(&interp->asyncio_tasks_head); interp->asyncio_tasks_lock = (PyMutex){0}; + interp->audit_hooks_mutex = (PyMutex){0}; for (int i = 0; i < _PY_MONITORING_UNGROUPED_EVENTS; i++) { interp->monitors.tools[i] = 0; } diff --git a/Python/sysmodule.c b/Python/sysmodule.c index aa9ff9e9a455de..5140ad86d49923 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -236,7 +236,7 @@ should_audit(PyInterpreterState *interp) return 0; } return (interp->runtime->audit_hooks.head - || interp->audit_hooks + || FT_ATOMIC_LOAD_PTR_ACQUIRE(interp->audit_hooks) || PyDTrace_AUDIT_ENABLED()); } @@ -306,13 +306,14 @@ sys_audit_tstate(PyThreadState *ts, const char *event, } /* Call interpreter hooks */ - if (is->audit_hooks) { + PyObject *audit_hooks = FT_ATOMIC_LOAD_PTR_ACQUIRE(is->audit_hooks); + if (audit_hooks) { eventName = PyUnicode_FromString(event); if (!eventName) { goto exit; } - hooks = PyObject_GetIter(is->audit_hooks); + hooks = PyObject_GetIter(audit_hooks); if (!hooks) { goto exit; } @@ -536,20 +537,29 @@ sys_addaudithook_impl(PyObject *module, PyObject *hook) } PyInterpreterState *interp = tstate->interp; + PyMutex mutex = interp->audit_hooks_mutex; + PyMutex_Lock(&mutex); + if (interp->audit_hooks == NULL) { - interp->audit_hooks = PyList_New(0); - if (interp->audit_hooks == NULL) { - return NULL; + PyObject *new_list = PyList_New(0); + if (new_list == NULL) { + goto error; } /* Avoid having our list of hooks show up in the GC module */ - PyObject_GC_UnTrack(interp->audit_hooks); + PyObject_GC_UnTrack(new_list); + FT_ATOMIC_STORE_PTR_RELEASE(interp->audit_hooks, new_list); } if (PyList_Append(interp->audit_hooks, hook) < 0) { - return NULL; + goto error; } + PyMutex_Unlock(&mutex); Py_RETURN_NONE; + +error: + PyMutex_Unlock(&mutex); + return NULL; } /*[clinic input] From b84c4cc489a3ac70e5bde91e723a0858d8020193 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 22 Jul 2026 15:16:23 +0200 Subject: [PATCH 798/818] [3.15] gh-150076: Fix the documented signature of warnings.deprecated (GH-153879) (#154487) gh-150076: Fix the documented signature of warnings.deprecated (GH-153879) (cherry picked from commit 56ad3bca75a408b45b5326980b35b8a2ba8113db) Co-authored-by: Vyron Vasileiadis <hi@fedonman.com> Co-authored-by: Jelle Zijlstra <jelle.zijlstra@gmail.com> --- Doc/library/warnings.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/warnings.rst b/Doc/library/warnings.rst index 9063bea96ccb0a..d5f89102d5853b 100644 --- a/Doc/library/warnings.rst +++ b/Doc/library/warnings.rst @@ -566,7 +566,7 @@ Available Functions and calls to :func:`simplefilter`. -.. decorator:: deprecated(msg, *, category=DeprecationWarning, stacklevel=1) +.. decorator:: deprecated(message, /, *, category=DeprecationWarning, stacklevel=1) Decorator to indicate that a class, function or overload is deprecated. From df36cf12d925231fdabb9aac2208508e7955367b Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 22 Jul 2026 17:08:46 +0200 Subject: [PATCH 799/818] [3.15] gh-154137: Fix handle leak in test_winapi (GH-154201) (#154202) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make sure that events handles are closed. (cherry picked from commit 1f9d20bbd4fed601e7caf76a12e52d35c8ae2b14) Co-authored-by: Victor Stinner <vstinner@python.org> Co-authored-by: Łukasz Langa <lukasz@langa.pl> --- Lib/test/test_winapi.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Lib/test/test_winapi.py b/Lib/test/test_winapi.py index a1c0b80d47e4d4..0ae03a3bf505f7 100644 --- a/Lib/test/test_winapi.py +++ b/Lib/test/test_winapi.py @@ -12,9 +12,16 @@ MAXIMUM_WAIT_OBJECTS = 64 MAXIMUM_BATCHED_WAIT_OBJECTS = (MAXIMUM_WAIT_OBJECTS - 1) ** 2 + +def close_events(events): + for handle in events: + _winapi.CloseHandle(handle) + + class WinAPIBatchedWaitForMultipleObjectsTests(unittest.TestCase): def _events_waitall_test(self, n): evts = [_winapi.CreateEventW(0, False, False, None) for _ in range(n)] + self.addCleanup(close_events, evts) with self.assertRaises(TimeoutError): _winapi.BatchedWaitForMultipleObjects(evts, True, 100) @@ -42,6 +49,7 @@ def _events_waitall_test(self, n): def _events_waitany_test(self, n): evts = [_winapi.CreateEventW(0, False, False, None) for _ in range(n)] + self.addCleanup(close_events, evts) with self.assertRaises(TimeoutError): _winapi.BatchedWaitForMultipleObjects(evts, False, 100) From f0728d31cde7b6d7928865fd1780b83ce0634413 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 22 Jul 2026 19:28:59 +0200 Subject: [PATCH 800/818] [3.15] gh-154443: Fix test_makedev on DragonFly BSD (GH-154444) (GH-154450) major() and minor() do not preserve NODEV on DragonFly BSD. (cherry picked from commit 2cf8e59a38251ff6dfbcd326104068be01c95385) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --- Lib/test/test_os/test_posix.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Lib/test/test_os/test_posix.py b/Lib/test/test_os/test_posix.py index 38066a5426090a..0371a35c13af48 100644 --- a/Lib/test/test_os/test_posix.py +++ b/Lib/test/test_os/test_posix.py @@ -822,8 +822,7 @@ def test_makedev(self): # a special case for NODEV, on others this is just an implementation # artifact. if (hasattr(posix, 'NODEV') and - sys.platform.startswith(('linux', 'macos', 'freebsd', 'dragonfly', - 'sunos'))): + sys.platform.startswith(('linux', 'macos', 'freebsd', 'sunos'))): NODEV = posix.NODEV self.assertEqual(posix.major(NODEV), NODEV) self.assertEqual(posix.minor(NODEV), NODEV) From 7dca47d7fade29d8d7e6725ed9782682cb9703ce Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 22 Jul 2026 19:54:26 +0200 Subject: [PATCH 801/818] [3.15] gh-153291: Fix data race in readline.get_completer() and get_pre_input_hook() (gh-153362) (gh-154418) The setters store these hooks while holding the module critical section (via set_hook's Py_XSETREF), but the getters read and Py_NewRef the same fields without it. Annotate both getters with @critical_section, matching the other readline functions (gh-126895). (cherry picked from commit 90b6a7992ae0ce6959eaa6b6401105582d866037) Co-authored-by: Harjoth Khara <harjoth.khara@gmail.com> Co-authored-by: Neil Schemenauer <nas-github@arctrix.com> --- Lib/test/test_free_threading/test_readline.py | 59 +++++++++++++++++++ Lib/test/test_readline.py | 24 -------- ...-07-08-00-00-00.gh-issue-153291.rdlnCS.rst | 4 ++ Modules/clinic/readline.c.h | 18 +++++- Modules/readline.c | 6 +- 5 files changed, 82 insertions(+), 29 deletions(-) create mode 100644 Lib/test/test_free_threading/test_readline.py create mode 100644 Misc/NEWS.d/next/Library/2026-07-08-00-00-00.gh-issue-153291.rdlnCS.rst diff --git a/Lib/test/test_free_threading/test_readline.py b/Lib/test/test_free_threading/test_readline.py new file mode 100644 index 00000000000000..f7aa9894031495 --- /dev/null +++ b/Lib/test/test_free_threading/test_readline.py @@ -0,0 +1,59 @@ +import unittest + +from test.support import import_helper +from test.support import threading_helper + +readline = import_helper.import_module("readline") + + +@threading_helper.requires_working_threading() +class TestReadlineRaces(unittest.TestCase): + def test_completer_delims_get_set(self): + def worker(): + for _ in range(100): + readline.get_completer_delims() + readline.set_completer_delims( + ' \t\n`@#%^&*()=+[{]}\\|;:\'",<>?') + readline.set_completer_delims( + ' \t\n`@#%^&*()=+[{]}\\|;:\'",<>?') + readline.get_completer_delims() + + threading_helper.run_concurrently(worker, nthreads=40) + + # get_completer()/get_pre_input_hook() must take the module critical + # section like their setters do; otherwise reading and Py_NewRef-ing the + # stored hook races the setter replacing it (gh-153291). + + def test_completer_get_set(self): + def setter(): + for _ in range(1000): + readline.set_completer(lambda text, state: None) + readline.set_completer(None) + + def getter(): + for _ in range(1000): + readline.get_completer() + + original = readline.get_completer() + self.addCleanup(readline.set_completer, original) + threading_helper.run_concurrently([setter] * 2 + [getter] * 6) + + @unittest.skipUnless(hasattr(readline, "set_pre_input_hook"), + "needs readline.set_pre_input_hook") + def test_pre_input_hook_get_set(self): + def setter(): + for _ in range(1000): + readline.set_pre_input_hook(lambda: None) + readline.set_pre_input_hook(None) + + def getter(): + for _ in range(1000): + readline.get_pre_input_hook() + + original = readline.get_pre_input_hook() + self.addCleanup(readline.set_pre_input_hook, original) + threading_helper.run_concurrently([setter] * 2 + [getter] * 6) + + +if __name__ == "__main__": + unittest.main() diff --git a/Lib/test/test_readline.py b/Lib/test/test_readline.py index 3982686dd10aec..430996937bc21a 100644 --- a/Lib/test/test_readline.py +++ b/Lib/test/test_readline.py @@ -7,10 +7,7 @@ import sys import tempfile import textwrap -import threading import unittest -from test import support -from test.support import threading_helper from test.support import verbose from test.support.import_helper import import_module from test.support.os_helper import unlink, temp_dir, TESTFN @@ -432,26 +429,5 @@ def my_hook(): self.assertIs(readline.get_pre_input_hook(), my_hook) -@unittest.skipUnless(support.Py_GIL_DISABLED, 'these tests can only possibly fail with GIL disabled') -class FreeThreadingTest(unittest.TestCase): - @threading_helper.reap_threads - @threading_helper.requires_working_threading() - def test_free_threading(self): - def completer_delims(b): - b.wait() - for _ in range(100): - readline.get_completer_delims() - readline.set_completer_delims(' \t\n`@#%^&*()=+[{]}\\|;:\'",<>?') - readline.set_completer_delims(' \t\n`@#%^&*()=+[{]}\\|;:\'",<>?') - readline.get_completer_delims() - - count = 40 - barrier = threading.Barrier(count) - threads = [threading.Thread(target=completer_delims, args=(barrier,)) for _ in range(count)] - - with threading_helper.start_threads(threads): - pass - - if __name__ == "__main__": unittest.main() diff --git a/Misc/NEWS.d/next/Library/2026-07-08-00-00-00.gh-issue-153291.rdlnCS.rst b/Misc/NEWS.d/next/Library/2026-07-08-00-00-00.gh-issue-153291.rdlnCS.rst new file mode 100644 index 00000000000000..dbe3cd417e0d60 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-08-00-00-00.gh-issue-153291.rdlnCS.rst @@ -0,0 +1,4 @@ +Fix a data race in :func:`readline.get_completer` and +:func:`readline.get_pre_input_hook` on the :term:`free-threaded <free +threading>` build: the getters read the stored hook without the critical +section that the corresponding setters hold. diff --git a/Modules/clinic/readline.c.h b/Modules/clinic/readline.c.h index dc9381e4b976ac..a7df757f3f6c85 100644 --- a/Modules/clinic/readline.c.h +++ b/Modules/clinic/readline.c.h @@ -366,7 +366,13 @@ readline_get_pre_input_hook_impl(PyObject *module); static PyObject * readline_get_pre_input_hook(PyObject *module, PyObject *Py_UNUSED(ignored)) { - return readline_get_pre_input_hook_impl(module); + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(module); + return_value = readline_get_pre_input_hook_impl(module); + Py_END_CRITICAL_SECTION(); + + return return_value; } #endif /* defined(HAVE_RL_PRE_INPUT_HOOK) */ @@ -651,7 +657,13 @@ readline_get_completer_impl(PyObject *module); static PyObject * readline_get_completer(PyObject *module, PyObject *Py_UNUSED(ignored)) { - return readline_get_completer_impl(module); + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(module); + return_value = readline_get_completer_impl(module); + Py_END_CRITICAL_SECTION(); + + return return_value; } PyDoc_STRVAR(readline_get_history_item__doc__, @@ -823,4 +835,4 @@ readline_redisplay(PyObject *module, PyObject *Py_UNUSED(ignored)) #ifndef READLINE_CLEAR_HISTORY_METHODDEF #define READLINE_CLEAR_HISTORY_METHODDEF #endif /* !defined(READLINE_CLEAR_HISTORY_METHODDEF) */ -/*[clinic end generated code: output=4bd95070973cd0e2 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=acf4e4c35191cf09 input=a9049054013a1b77]*/ diff --git a/Modules/readline.c b/Modules/readline.c index c580d2022fccf3..9d4904d0085b8e 100644 --- a/Modules/readline.c +++ b/Modules/readline.c @@ -578,6 +578,7 @@ readline_set_pre_input_hook_impl(PyObject *module, PyObject *function) /* Get pre-input hook */ /*[clinic input] +@critical_section readline.get_pre_input_hook Get the current pre-input hook function. @@ -585,7 +586,7 @@ Get the current pre-input hook function. static PyObject * readline_get_pre_input_hook_impl(PyObject *module) -/*[clinic end generated code: output=ad56b77a8e8981ca input=fb1e1b1fbd94e4e5]*/ +/*[clinic end generated code: output=ad56b77a8e8981ca input=fbbf0106bd015414]*/ { readlinestate *state = get_readline_state(module); if (state->pre_input_hook == NULL) { @@ -886,6 +887,7 @@ readline_set_completer_impl(PyObject *module, PyObject *function) } /*[clinic input] +@critical_section readline.get_completer Get the current completer function. @@ -893,7 +895,7 @@ Get the current completer function. static PyObject * readline_get_completer_impl(PyObject *module) -/*[clinic end generated code: output=6e6bbd8226d14475 input=6457522e56d70d13]*/ +/*[clinic end generated code: output=6e6bbd8226d14475 input=0df9ba4107115c44]*/ { readlinestate *state = get_readline_state(module); if (state->completer == NULL) { From 6bc3e6ca8b1df7ae21534bc4804dc081465f6faf Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka <storchaka@gmail.com> Date: Thu, 23 Jul 2026 01:46:41 +0300 Subject: [PATCH 802/818] [3.15] gh-154272: Skip more forkserver tests if the start method is unavailable (GH-154499) (GH-154505) Two tests were still not skipped: they were only guarded against Cygwin and Windows. (cherry picked from commit a2a846678e54b1b5defdccd451c573679094ff02) Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --- Lib/test/test_concurrent_futures/test_init.py | 3 +++ Lib/test/test_profiling/test_tracing_profiler.py | 5 +++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_concurrent_futures/test_init.py b/Lib/test/test_concurrent_futures/test_init.py index 5ea543bf748982..c9fedc7213256c 100644 --- a/Lib/test/test_concurrent_futures/test_init.py +++ b/Lib/test/test_concurrent_futures/test_init.py @@ -1,5 +1,6 @@ import contextlib import logging +import multiprocessing import queue import time import unittest @@ -147,6 +148,8 @@ def test_spawn(self): self._test(ProcessPoolSpawnFailingInitializerTest) @support.skip_if_sanitizer("TSAN doesn't support threads after fork", thread=True) + @unittest.skipUnless("forkserver" in multiprocessing.get_all_start_methods(), + "forkserver start method is not available") def test_forkserver(self): self._test(ProcessPoolForkserverFailingInitializerTest) diff --git a/Lib/test/test_profiling/test_tracing_profiler.py b/Lib/test/test_profiling/test_tracing_profiler.py index 8a7070142b60ee..6a4d968f12ef15 100644 --- a/Lib/test/test_profiling/test_tracing_profiler.py +++ b/Lib/test/test_profiling/test_tracing_profiler.py @@ -1,4 +1,5 @@ """Test suite for the cProfile module.""" +import multiprocessing import sys import unittest @@ -220,8 +221,8 @@ def test_process_spawn_pickle(self): # gh-140729: test use Process in cProfile. self._test_process_run_pickle('spawn') - @unittest.skipIf(sys.platform == 'win32', - "No 'forkserver' start method on Windows") + @unittest.skipUnless("forkserver" in multiprocessing.get_all_start_methods(), + "forkserver start method is not available") def test_process_forkserver_pickle(self): # gh-140729: test use Process in cProfile. self._test_process_run_pickle('forkserver') From a47c03d5f14e710421c24ea645abe16380d18af0 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 23 Jul 2026 08:36:47 +0200 Subject: [PATCH 803/818] [3.15] gh-154502: Disable junk filling in the OpenBSD allocator in test_capi (GH-154503) (GH-154513) (cherry picked from commit 206788a6dd23b79fc38fde9a7100293d7efcc37c) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --- Lib/test/test_capi/test_mem.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_capi/test_mem.py b/Lib/test/test_capi/test_mem.py index 66ab072733e17b..e6389b4e0c1e92 100644 --- a/Lib/test/test_capi/test_mem.py +++ b/Lib/test/test_capi/test_mem.py @@ -24,9 +24,12 @@ def check(self, code): out = assert_python_failure( '-c', code, PYTHONMALLOC=self.PYTHONMALLOC, - # FreeBSD: instruct jemalloc to not fill freed() memory - # with junk byte 0x5a, see JEMALLOC(3) + # Instruct the system allocator to not fill freed() memory + # with junk bytes: + # FreeBSD: jemalloc, see JEMALLOC(3). MALLOC_CONF="junk:false", + # OpenBSD: see MALLOC.CONF(5). + MALLOC_OPTIONS="j", ) stderr = out.err return stderr.decode('ascii', 'replace') @@ -102,7 +105,9 @@ def check_pyobject_is_freed(self, func_name): assert_python_ok( '-c', code, PYTHONMALLOC=self.PYTHONMALLOC, + # See the comment in check() above. MALLOC_CONF="junk:false", + MALLOC_OPTIONS="j", ) def test_pyobject_null_is_freed(self): From 41d7b3cf49a8486eb9d267d95d3159c1c4e79745 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 23 Jul 2026 09:48:12 +0200 Subject: [PATCH 804/818] [3.15] gh-151949: Fix Sphinx reference warnings in `Doc/library/lzma.rst` (GH-153878) (#154127) * gh-151949: Fix Sphinx reference warnings in `Doc/library/lzma.rst` (GH-153878) The lzma module constants (FORMAT_*, CHECK_*, PRESET_*, FILTER_*, MODE_* and MF_*) were referenced with the :const: role throughout the module documentation but were never defined as reference targets, producing "reference target not found" warnings under nitpicky mode. Document these public constants with .. data:: directives, following the convention used by the signal, socket and ssl modules, so the existing references resolve. The now-redundant inline descriptions of the format and check constants are condensed into linked references. (cherry picked from commit 1530b38c82f8f09c3c29b2829cd1d8c1db830761) Co-authored-by: Vyron Vasileiadis <hi@fedonman.com> * Fix nitpicks --------- Co-authored-by: Vyron Vasileiadis <hi@fedonman.com> Co-authored-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> --- Doc/library/lzma.rst | 143 +++++++++++++++++++++++++++++++++---------- Doc/tools/.nitignore | 1 - 2 files changed, 111 insertions(+), 33 deletions(-) diff --git a/Doc/library/lzma.rst b/Doc/library/lzma.rst index 6cede00b218678..c72136f0da878d 100644 --- a/Doc/library/lzma.rst +++ b/Doc/library/lzma.rst @@ -152,35 +152,14 @@ Compressing and decompressing data in memory :func:`compress`. The *format* argument specifies what container format should be used. - Possible values are: - - * :const:`FORMAT_XZ`: The ``.xz`` container format. - This is the default format. - - * :const:`FORMAT_ALONE`: The legacy ``.lzma`` container format. - This format is more limited than ``.xz`` -- it does not support integrity - checks or multiple filters. - - * :const:`FORMAT_RAW`: A raw data stream, not using any container format. - This format specifier does not support integrity checks, and requires that - you always specify a custom filter chain (for both compression and - decompression). Additionally, data compressed in this manner cannot be - decompressed using :const:`FORMAT_AUTO` (see :class:`LZMADecompressor`). + Possible values are :const:`FORMAT_XZ` (the default), + :const:`FORMAT_ALONE` and :const:`FORMAT_RAW`. The *check* argument specifies the type of integrity check to include in the compressed data. This check is used when decompressing, to ensure that the - data has not been corrupted. Possible values are: - - * :const:`CHECK_NONE`: No integrity check. - This is the default (and the only acceptable value) for - :const:`FORMAT_ALONE` and :const:`FORMAT_RAW`. - - * :const:`CHECK_CRC32`: 32-bit Cyclic Redundancy Check. - - * :const:`CHECK_CRC64`: 64-bit Cyclic Redundancy Check. - This is the default for :const:`FORMAT_XZ`. - - * :const:`CHECK_SHA256`: 256-bit Secure Hash Algorithm. + data has not been corrupted. Possible values are :const:`CHECK_NONE`, + :const:`CHECK_CRC32`, :const:`CHECK_CRC64` (the default for + :const:`FORMAT_XZ`) and :const:`CHECK_SHA256`. If the specified check is not supported, an :class:`LZMAError` is raised. @@ -356,12 +335,12 @@ options. Valid filter IDs are as follows: * Branch-Call-Jump (BCJ) filters: - * :const:`FILTER_X86` - * :const:`FILTER_IA64` - * :const:`FILTER_ARM` - * :const:`FILTER_ARMTHUMB` - * :const:`FILTER_POWERPC` - * :const:`FILTER_SPARC` + * :const:`!FILTER_X86` + * :const:`!FILTER_IA64` + * :const:`!FILTER_ARM` + * :const:`!FILTER_ARMTHUMB` + * :const:`!FILTER_POWERPC` + * :const:`!FILTER_SPARC` A filter chain can consist of up to 4 filters, and cannot be empty. The last filter in the chain must be a compression filter, and any other filters must be @@ -398,6 +377,106 @@ These filters support one option, ``start_offset``. This specifies the address that should be mapped to the beginning of the input data. The default is 0. +Constants +--------- + +The following module-level constants are provided for use as the *format*, +*check*, *preset* and *filters* arguments of the classes and functions above. + +Container formats: + +.. data:: FORMAT_XZ + + The ``.xz`` container format. + +.. data:: FORMAT_ALONE + + The legacy ``.lzma`` container format. This format is more limited than + ``.xz`` -- it does not support integrity checks or multiple filters. + +.. data:: FORMAT_RAW + + A raw data stream, not using any container format. This format specifier + does not support integrity checks, and requires that you always specify a + custom filter chain (for both compression and decompression). Additionally, + data compressed in this manner cannot be decompressed using + :const:`FORMAT_AUTO`. + +.. data:: FORMAT_AUTO + + Used for decompression only. The container format is detected + automatically, so that both ``.xz`` and ``.lzma`` files can be decompressed. + +Integrity checks: + +.. data:: CHECK_NONE + + No integrity check. This is the default (and the only acceptable value) for + :const:`FORMAT_ALONE` and :const:`FORMAT_RAW`. + +.. data:: CHECK_CRC32 + + A 32-bit Cyclic Redundancy Check. + +.. data:: CHECK_CRC64 + + A 64-bit Cyclic Redundancy Check. This is the default for + :const:`FORMAT_XZ`. + +.. data:: CHECK_SHA256 + + A 256-bit Secure Hash Algorithm. + +.. data:: CHECK_UNKNOWN + + The integrity check used by a stream could not yet be determined. This may + be the value of the :attr:`LZMADecompressor.check` attribute until enough of + the input has been decoded. + +.. data:: CHECK_ID_MAX + + The largest supported integrity-check ID. + +Compression presets: + +.. data:: PRESET_DEFAULT + + The default compression preset, equivalent to preset level ``6``. + +.. data:: PRESET_EXTREME + + A flag that may be bitwise OR-ed with a preset level (``0`` to ``9``) to + select a slower but more thorough variant of that preset. + +Filter IDs and options: + +.. data:: FILTER_LZMA1 + FILTER_LZMA2 + + The LZMA1 and LZMA2 compression filters. :const:`FILTER_LZMA1` is for use + with :const:`FORMAT_ALONE`, while :const:`FILTER_LZMA2` is for use with + :const:`FORMAT_XZ` and :const:`FORMAT_RAW`. + +.. data:: FILTER_DELTA + + The delta filter. + +.. data:: MODE_FAST + MODE_NORMAL + + Compression modes that may be used as the ``mode`` option of a filter + specifier (see :ref:`filter-chain-specs`). + +.. data:: MF_HC3 + MF_HC4 + MF_BT2 + MF_BT3 + MF_BT4 + + Match finders that may be used as the ``mf`` option of a filter specifier + (see :ref:`filter-chain-specs`). + + Examples -------- diff --git a/Doc/tools/.nitignore b/Doc/tools/.nitignore index c5d47489596611..ab592cfa5a1bbb 100644 --- a/Doc/tools/.nitignore +++ b/Doc/tools/.nitignore @@ -12,7 +12,6 @@ Doc/library/email.parser.rst Doc/library/importlib.rst Doc/library/logging.config.rst Doc/library/logging.handlers.rst -Doc/library/lzma.rst Doc/library/mmap.rst Doc/library/multiprocessing.rst Doc/library/optparse.rst From aed19a7cd3bae1cbbf8b1069e6bbf85147b844eb Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 23 Jul 2026 13:15:08 +0200 Subject: [PATCH 805/818] [3.15] gh-139445: Skip pyrepl tests if the terminal is not supported (GH-154497) (GH-154529) They were only skipped if TERM was unset or "dumb", but pyrepl also needs the terminal to have several capabilities. (cherry picked from commit 7745710bec7f6de899e97d6f87528035e8977d85) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --- Lib/test/test_pyrepl/test_pyrepl.py | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_pyrepl/test_pyrepl.py b/Lib/test/test_pyrepl/test_pyrepl.py index 4240a3c3174959..04a7a1b7f56751 100644 --- a/Lib/test/test_pyrepl/test_pyrepl.py +++ b/Lib/test/test_pyrepl/test_pyrepl.py @@ -13,7 +13,7 @@ import tempfile from functools import partial from pkgutil import ModuleInfo -from unittest import TestCase, skipUnless, skipIf, SkipTest +from unittest import TestCase, skipUnless, SkipTest from unittest.mock import Mock, patch import warnings from test.support import ( @@ -37,6 +37,7 @@ code_to_events, ) from _colorize import ANSIColors, get_theme +from _pyrepl import terminfo from _pyrepl.console import Event from _pyrepl.completing_reader import stripcolor from _pyrepl._module_completer import ( @@ -1998,8 +1999,20 @@ def test_dumb_terminal_exits_cleanly(self): self.assertNotIn("Traceback", output) +def supports_pyrepl(): + # pyrepl falls back to the basic REPL if the terminal lacks any of the + # capabilities which UnixConsole requires. This covers an unset or + # "dumb" TERM as well, they are resolved to the "dumb" capabilities. + try: + info = terminfo.TermInfo(None) + except Exception: + return False + return all(info.get(cap) is not None + for cap in ("bel", "clear", "cup", "el")) + + @skipUnless(pty, "requires pty") -@skipIf((os.environ.get("TERM") or "dumb") == "dumb", "can't use pyrepl in dumb terminal") +@skipUnless(supports_pyrepl(), "can't use pyrepl in this terminal") class TestMain(ReplTestCase): def setUp(self): # Cleanup from PYTHON* variables to isolate from local From 5bf6a7449f4a7a796a034bebaf0f65da762b128a Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 24 Jul 2026 13:31:10 +0200 Subject: [PATCH 806/818] [3.15] gh-153761: Fix asyncio sock_accept() dropping a connection when cancelled (GH-153762) (#153829) Co-authored-by: Timofei <128279579+deadlovelll@users.noreply.github.com> --- Lib/asyncio/selector_events.py | 3 ++ Lib/test/test_asyncio/test_sock_lowlevel.py | 43 +++++++++++++++++++ ...-07-15-14-24-18.gh-issue-153761.8jqs67.rst | 1 + 3 files changed, 47 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2026-07-15-14-24-18.gh-issue-153761.8jqs67.rst diff --git a/Lib/asyncio/selector_events.py b/Lib/asyncio/selector_events.py index 7e2c0b99e87e49..f3d2f4eea4d1d9 100644 --- a/Lib/asyncio/selector_events.py +++ b/Lib/asyncio/selector_events.py @@ -717,6 +717,9 @@ async def sock_accept(self, sock): return await fut def _sock_accept(self, fut, sock): + # gh-153761: _sock_accept must not scheduled with already cancelled future + if fut.done(): + return fd = sock.fileno() try: conn, address = sock.accept() diff --git a/Lib/test/test_asyncio/test_sock_lowlevel.py b/Lib/test/test_asyncio/test_sock_lowlevel.py index f32dcd589e2de2..8380342e294712 100644 --- a/Lib/test/test_asyncio/test_sock_lowlevel.py +++ b/Lib/test/test_asyncio/test_sock_lowlevel.py @@ -1,5 +1,6 @@ import socket import asyncio +import select import sys import unittest @@ -257,6 +258,38 @@ async def _basetest_sock_connect_racing(self, listener, sock): self.skipTest(skip_reason) + async def _basetest_sock_accept_racing(self, listener, sock): + # gh-153761: cancelling sock_accept() must not let a scheduled + # _sock_accept run on the cancelled future. + listener.setblocking(False) + listener.bind(('127.0.0.1', 0)) + listener.listen(1) + addr = listener.getsockname() + + errors = [] + self.loop.set_exception_handler(lambda loop, ctx: errors.append(ctx)) + task = asyncio.create_task(self.loop.sock_accept(listener)) + await asyncio.sleep(0) + + sock.connect(addr) + select.select([listener], [], [], support.SHORT_TIMEOUT) + + self.loop.call_soon(task.cancel) + await asyncio.sleep(0) + await asyncio.sleep(0) + + with self.assertRaises(asyncio.CancelledError): + await task + self.assertEqual(errors, []) + + # The pending connection must survive + conn, conn_addr = await self.loop.sock_accept(listener) + with conn: + self.assertEqual(conn_addr, sock.getsockname()) + sock.setblocking(False) + await self.loop.sock_sendall(conn, b'ping') + self.assertEqual(await self.loop.sock_recv(sock, 4), b'ping') + def test_sock_client_racing(self): with test_utils.run_test_server() as httpd: sock = socket.socket() @@ -280,6 +313,16 @@ def test_sock_client_connect_racing(self): self.loop.run_until_complete(asyncio.wait_for( self._basetest_sock_connect_racing(listener, sock), 10)) + def test_sock_accept_racing(self): + if sys.platform == 'win32': + if isinstance(self.loop, asyncio.ProactorEventLoop): + raise unittest.SkipTest('Not relevant to ProactorEventLoop') + listener = socket.socket() + sock = socket.socket() + with listener, sock: + self.loop.run_until_complete(asyncio.wait_for( + self._basetest_sock_accept_racing(listener, sock), 10)) + async def _basetest_huge_content(self, address): sock = socket.socket() sock.setblocking(False) diff --git a/Misc/NEWS.d/next/Library/2026-07-15-14-24-18.gh-issue-153761.8jqs67.rst b/Misc/NEWS.d/next/Library/2026-07-15-14-24-18.gh-issue-153761.8jqs67.rst new file mode 100644 index 00000000000000..68e007e66e0396 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-15-14-24-18.gh-issue-153761.8jqs67.rst @@ -0,0 +1 @@ +Fix cancelling :meth:`asyncio.loop.sock_accept` dropping a pending connection. From a5d357c9dac21b2146f02ca4b13747eab09711b6 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 24 Jul 2026 13:46:47 +0200 Subject: [PATCH 807/818] [3.15] gh-154435: Fix os.posix_fadvise() and os.posix_fallocate() on DragonFly BSD (GH-154436) (GH-154451) They return -1 and set errno instead of returning the error number, so OSError was raised with a meaningless error code. (cherry picked from commit 08a0d10709f04cf03260e5e852381cecb1c531e1) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --- .../2026-07-22-10-30-08.gh-issue-154435.xCxm0T.rst | 3 +++ Modules/posixmodule.c | 8 ++++++++ 2 files changed, 11 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2026-07-22-10-30-08.gh-issue-154435.xCxm0T.rst diff --git a/Misc/NEWS.d/next/Library/2026-07-22-10-30-08.gh-issue-154435.xCxm0T.rst b/Misc/NEWS.d/next/Library/2026-07-22-10-30-08.gh-issue-154435.xCxm0T.rst new file mode 100644 index 00000000000000..b468e929b1ca18 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-22-10-30-08.gh-issue-154435.xCxm0T.rst @@ -0,0 +1,3 @@ +Fix :func:`os.posix_fadvise` and :func:`os.posix_fallocate` on DragonFly BSD: +they raised :exc:`OSError` with a meaningless error code, +because these functions return -1 and set ``errno`` there. diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index d4390370cc2f75..d995fefe1adbe8 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -13475,6 +13475,10 @@ os_posix_fallocate_impl(PyObject *module, int fd, Py_off_t offset, Py_BEGIN_ALLOW_THREADS result = posix_fallocate(fd, offset, length); Py_END_ALLOW_THREADS + // DragonFly BSD returns -1 and sets errno. + if (result == -1) { + result = errno; + } } while (result == EINTR && !(async_err = PyErr_CheckSignals())); if (result == 0) @@ -13522,6 +13526,10 @@ os_posix_fadvise_impl(PyObject *module, int fd, Py_off_t offset, Py_BEGIN_ALLOW_THREADS result = posix_fadvise(fd, offset, length, advice); Py_END_ALLOW_THREADS + // DragonFly BSD returns -1 and sets errno. + if (result == -1) { + result = errno; + } } while (result == EINTR && !(async_err = PyErr_CheckSignals())); if (result == 0) From 3915f1e6c5215a676495aa7c8b3163bb210576f1 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 24 Jul 2026 14:50:14 +0200 Subject: [PATCH 808/818] [3.15] gh-154582: Fix test_invalid_utf8_arg in non-UTF-8 multibyte locales (GH-154584) (GH-154601) Arbitrary bytes round-trip through surrogateescape only in UTF-8 and single-byte encodings, not in a stateful multibyte encoding such as EUC-JP. (cherry picked from commit b1e530ebf3b68e884ab37882d690d95e5d82aef5) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --- Lib/test/test_cmd_line.py | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_cmd_line.py b/Lib/test/test_cmd_line.py index a8645af26b25d8..bf8ac2bbac309f 100644 --- a/Lib/test/test_cmd_line.py +++ b/Lib/test/test_cmd_line.py @@ -2,6 +2,7 @@ # Most tests are executed with environment variables ignored # See test_cmd_line_script.py for testing of script execution +import locale import os import re import subprocess @@ -369,9 +370,27 @@ def run_no_utf8_mode(arg): ) test_args = [valid_utf8, invalid_utf8] - for run_cmd in (run_default, run_c_locale, run_utf8_mode, - run_no_utf8_mode): - with self.subTest(run_cmd=run_cmd): + for run_cmd, encoding in ( + (run_default, sys.getfilesystemencoding()), + (run_c_locale, None), + (run_utf8_mode, None), + (run_no_utf8_mode, locale.getencoding()) + ): + with self.subTest(run_cmd=run_cmd.__name__): + # Arbitrary bytes round-trip through surrogateescape only in + # UTF-8 and single-byte encodings, not in a multibyte encoding + # such as EUC-JP. + if encoding is not None: + try: + lossless = len(bytes(range(256)).decode( + encoding, 'surrogateescape')) == 256 + except UnicodeError: + lossless = False + else: + lossless = True + if not lossless: + self.skipTest(f'{encoding} cannot losslessly ' + f'round-trip arbitrary bytes') for arg in test_args: proc = run_cmd(arg) self.assertEqual(proc.stdout.rstrip(), ascii(arg)) From f921edf0f1494af3d5a474b554b451fb6a576996 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 24 Jul 2026 16:00:09 +0200 Subject: [PATCH 809/818] [3.15] gh-146011: Fix use-after-free in `signaldict_repr` after deletion (GH-153784) (#154599) gh-146011: Fix use-after-free in `signaldict_repr` after deletion (GH-153784) (cherry picked from commit 41a087acc2d04c5bc3db93b5367456f05ae400a4) Co-authored-by: Brij Kapadia <97006829+brijkapadia@users.noreply.github.com> Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com> Co-authored-by: Victor Stinner <vstinner@python.org> --- Lib/test/test_decimal.py | 9 +++++++++ .../2026-07-15-21-56-40.gh-issue-146011.nWmHif.rst | 2 ++ Modules/_decimal/_decimal.c | 14 ++++++++++++++ 3 files changed, 25 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2026-07-15-21-56-40.gh-issue-146011.nWmHif.rst diff --git a/Lib/test/test_decimal.py b/Lib/test/test_decimal.py index a04ed0c83c07c4..1c723b25784da1 100644 --- a/Lib/test/test_decimal.py +++ b/Lib/test/test_decimal.py @@ -4147,6 +4147,15 @@ def test_float_operation_default(self): @requires_cdecimal class CContextFlags(ContextFlags, unittest.TestCase): decimal = C + + def test_signaldict_repr(self): + Context = self.decimal.Context + ctx = Context(prec=7) + mapping = ctx.flags + del ctx + with self.assertRaisesRegex(ValueError, 'invalid signal dict'): + repr(mapping) + class PyContextFlags(ContextFlags, unittest.TestCase): decimal = P diff --git a/Misc/NEWS.d/next/Library/2026-07-15-21-56-40.gh-issue-146011.nWmHif.rst b/Misc/NEWS.d/next/Library/2026-07-15-21-56-40.gh-issue-146011.nWmHif.rst new file mode 100644 index 00000000000000..0cac0257040bd6 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-15-21-56-40.gh-issue-146011.nWmHif.rst @@ -0,0 +1,2 @@ +Fix a heap-use-after-free in the C implementation of :mod:`decimal` +when calling :func:`repr` after deleting the :class:`~decimal.Context`. diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index 7a3240a3636a9c..8f3c9694db247d 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -1499,6 +1499,20 @@ static int context_clear(PyObject *op) { PyDecContextObject *self = _PyDecContextObject_CAST(op); + /* Since traps and flags hold a borrowed reference to the + flags stored in the context object, these references need + to be cleared when the context object is deallocated + because traps and flags can survive. See gh-146011. */ + PyDecSignalDictObject *traps = _PyDecSignalDictObject_CAST(self->traps); + PyDecSignalDictObject *flags = _PyDecSignalDictObject_CAST(self->flags); + + if (traps != NULL) { + traps->flags = NULL; + } + if (flags != NULL) { + flags->flags = NULL; + } + Py_CLEAR(self->traps); Py_CLEAR(self->flags); return 0; From b6f24be08d02a1f1b505a0f227221e48e86ead42 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 24 Jul 2026 17:31:45 +0200 Subject: [PATCH 810/818] [3.15] gh-76595: Add tests for PyCapsule_Import() (GH-154588) (GH-154619) Add _testcapi helpers to create a capsule with an arbitrary name and to call PyCapsule_Import(), and Python tests covering the current behavior: only the first component of the dotted name is imported, the rest are attribute lookups. (cherry picked from commit d24d9d0f1d1177cd6f130a4bd59c1c267a0f8d1f) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> --- Lib/test/test_capi/test_capsule.py | 181 ++++++++++++++++++ ...6-07-24-12-00-00.gh-issue-76595.KfF5xR.rst | 1 + Modules/Setup.stdlib.in | 2 +- Modules/_testlimitedcapi.c | 3 + Modules/_testlimitedcapi/capsule.c | 63 ++++++ Modules/_testlimitedcapi/parts.h | 1 + PCbuild/_testlimitedcapi.vcxproj | 1 + PCbuild/_testlimitedcapi.vcxproj.filters | 1 + 8 files changed, 252 insertions(+), 1 deletion(-) create mode 100644 Lib/test/test_capi/test_capsule.py create mode 100644 Misc/NEWS.d/next/Tests/2026-07-24-12-00-00.gh-issue-76595.KfF5xR.rst create mode 100644 Modules/_testlimitedcapi/capsule.c diff --git a/Lib/test/test_capi/test_capsule.py b/Lib/test/test_capi/test_capsule.py new file mode 100644 index 00000000000000..981caf3fad426b --- /dev/null +++ b/Lib/test/test_capi/test_capsule.py @@ -0,0 +1,181 @@ +import importlib +import os +import sys +import textwrap +import unittest +from test.support import import_helper, os_helper + +_testlimitedcapi = import_helper.import_module('_testlimitedcapi') + + +class CapsuleImportTests(unittest.TestCase): + """Tests for PyCapsule_Import().""" + + @classmethod + def setUpClass(cls): + tmp = cls.tmp = cls.enterClassContext(os_helper.temp_dir()) + cls.enterClassContext(import_helper.DirsOnSysPath(tmp)) + cls.write_file(os.path.join(tmp, 'capsule_mod.py'), ''' + import _testlimitedcapi + + capsule = _testlimitedcapi.capsule_new('capsule_mod.capsule') + капсула = _testlimitedcapi.capsule_new('capsule_mod.капсула') + mismatched = _testlimitedcapi.capsule_new('other.name') + nonutf8 = _testlimitedcapi.capsule_new(b'capsule_mod.nonutf8\\xff') + nullname = _testlimitedcapi.capsule_new(None) + not_capsule = 42 + + class ns: + nested = _testlimitedcapi.capsule_new('capsule_mod.ns.nested') + + def __getattr__(name): + if name == 'bad_attr': + raise FloatingPointError('bad attribute') + raise AttributeError(name) + ''') + pkg = os.path.join(tmp, 'capsule_pkg') + os.mkdir(pkg) + cls.write_file(os.path.join(pkg, '__init__.py'), '') + cls.write_file(os.path.join(pkg, 'sub.py'), ''' + import _testlimitedcapi + + capsule = _testlimitedcapi.capsule_new('capsule_pkg.sub.capsule') + ''') + autopkg = os.path.join(tmp, 'capsule_autopkg') + os.mkdir(autopkg) + cls.write_file(os.path.join(autopkg, '__init__.py'), 'from . import sub\n') + cls.write_file(os.path.join(autopkg, 'sub.py'), ''' + import _testlimitedcapi + + capsule = _testlimitedcapi.capsule_new('capsule_autopkg.sub.capsule') + ''') + cls.write_file(os.path.join(tmp, 'capsule_broken.py'), '1/0\n') + importlib.invalidate_caches() + + def setUp(self): + for name in ('capsule_mod', 'capsule_pkg.sub', 'capsule_pkg', + 'capsule_autopkg.sub', 'capsule_autopkg', + 'capsule_broken'): + self.addCleanup(import_helper.unload, name) + + @staticmethod + def write_file(path, source): + with open(path, 'w', encoding='utf-8') as f: + f.write(textwrap.dedent(source)) + + def check_import(self, name, no_block=0): + # _testlimitedcapi.PyCapsule_Import() returns the name stored as the + # pointer by _testlimitedcapi.capsule_new(). + self.assertEqual(_testlimitedcapi.PyCapsule_Import(name, no_block), name) + + def test_import(self): + # The module is imported if not already imported. + self.assertNotIn('capsule_mod', sys.modules) + self.check_import('capsule_mod.capsule') + # Attributes after the first component are plain attribute lookups. + self.check_import('capsule_mod.ns.nested') + # Non-ASCII capsule and attribute name. + self.check_import('capsule_mod.капсула') + # The no_block argument is ignored. + self.check_import('capsule_mod.capsule', 1) + + @unittest.skipUnless(os_helper.TESTFN_NONASCII, + 'requires non-ASCII file name support') + def test_non_ascii_module_name(self): + name = os_helper.TESTFN_NONASCII + self.write_file(os.path.join(self.tmp, name + '.py'), f''' + import _testlimitedcapi + + capsule = _testlimitedcapi.capsule_new('{name}.capsule') + ''') + importlib.invalidate_caches() + self.addCleanup(import_helper.unload, name) + self.check_import(f'{name}.capsule') + + def test_submodule(self): + # Only the first component is imported; a submodule not imported + # by its package is not found. + self.assertRaises(AttributeError, + _testlimitedcapi.PyCapsule_Import, 'capsule_pkg.sub.capsule') + # It is found after explicit import. + importlib.import_module('capsule_pkg.sub') + self.check_import('capsule_pkg.sub.capsule') + # A submodule imported by its package is found. + self.check_import('capsule_autopkg.sub.capsule') + + def test_invalid_name(self): + pycapsule_import = _testlimitedcapi.PyCapsule_Import + # Non-existing module. + self.assertRaisesRegex(ImportError, + 'PyCapsule_Import could not import module "capsule_nonexistent"', + pycapsule_import, 'capsule_nonexistent.capsule') + # Non-UTF-8 module name. + self.assertRaisesRegex(ImportError, + 'PyCapsule_Import could not import module', + pycapsule_import, b'\xff\xfe.capsule') + # Empty module name. + self.assertRaisesRegex(ImportError, + 'PyCapsule_Import could not import module ""', + pycapsule_import, '.capsule_mod.capsule') + # Empty name. + self.assertRaisesRegex(ImportError, + 'PyCapsule_Import could not import module ""', + pycapsule_import, '') + # Only a dot. + self.assertRaisesRegex(ImportError, + 'PyCapsule_Import could not import module ""', + pycapsule_import, '.') + # Non-existing attribute. + self.assertRaises(AttributeError, + pycapsule_import, 'capsule_mod.nonexistent') + # Empty attribute name. + self.assertRaises(AttributeError, pycapsule_import, 'capsule_mod.') + # Consecutive dots. + self.assertRaises(AttributeError, + pycapsule_import, 'capsule_mod..capsule') + # Attribute of an object which is not a module. + self.assertRaises(AttributeError, + pycapsule_import, 'capsule_mod.not_capsule.capsule') + # No attribute name. + self.assertRaisesRegex(AttributeError, 'is not valid', + pycapsule_import, 'capsule_mod') + + # CRASHES pycapsule_import(NULL) + + def test_invalid_capsule(self): + pycapsule_import = _testlimitedcapi.PyCapsule_Import + # The attribute is not a capsule. + self.assertRaisesRegex(AttributeError, 'is not valid', + pycapsule_import, 'capsule_mod.not_capsule') + # The capsule name does not match the requested name. + self.assertRaisesRegex(AttributeError, 'is not valid', + pycapsule_import, 'capsule_mod.mismatched') + # The capsule name contains a byte not decodable from UTF-8. + self.assertRaisesRegex(AttributeError, 'is not valid', + pycapsule_import, 'capsule_mod.nonutf8') + # Even the exactly matching name fails: the attribute lookup + # requires a name decodable from UTF-8. + self.assertRaises(UnicodeDecodeError, + pycapsule_import, b'capsule_mod.nonutf8\xff') + # The capsule name is NULL. + self.assertRaisesRegex(AttributeError, 'is not valid', + pycapsule_import, 'capsule_mod.nullname') + + def test_error_from_import(self): + # The exception raised during importing the module is replaced + # with generic ImportError. + with self.assertRaises(ImportError) as cm: + _testlimitedcapi.PyCapsule_Import('capsule_broken.capsule') + self.assertEqual(str(cm.exception), + 'PyCapsule_Import could not import ' + 'module "capsule_broken"') + + def test_error_from_attribute_lookup(self): + self.assertRaises(FloatingPointError, + _testlimitedcapi.PyCapsule_Import, 'capsule_mod.bad_attr') + self.assertRaises(FloatingPointError, + _testlimitedcapi.PyCapsule_Import, 'capsule_mod.bad_attr.capsule') + + +if __name__ == "__main__": + unittest.main() diff --git a/Misc/NEWS.d/next/Tests/2026-07-24-12-00-00.gh-issue-76595.KfF5xR.rst b/Misc/NEWS.d/next/Tests/2026-07-24-12-00-00.gh-issue-76595.KfF5xR.rst new file mode 100644 index 00000000000000..c344ee2f2cb30b --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2026-07-24-12-00-00.gh-issue-76595.KfF5xR.rst @@ -0,0 +1 @@ +Add C API tests for :c:func:`PyCapsule_Import`. diff --git a/Modules/Setup.stdlib.in b/Modules/Setup.stdlib.in index 139c4ecf99ab4b..99e9d5e2595f61 100644 --- a/Modules/Setup.stdlib.in +++ b/Modules/Setup.stdlib.in @@ -176,7 +176,7 @@ @MODULE__TESTBUFFER_TRUE@_testbuffer _testbuffer.c @MODULE__TESTINTERNALCAPI_TRUE@_testinternalcapi _testinternalcapi.c _testinternalcapi/test_lock.c _testinternalcapi/pytime.c _testinternalcapi/set.c _testinternalcapi/test_critical_sections.c _testinternalcapi/complex.c _testinternalcapi/interpreter.c _testinternalcapi/tuple.c @MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c _testcapi/heaptype.c _testcapi/abstract.c _testcapi/unicode.c _testcapi/dict.c _testcapi/set.c _testcapi/list.c _testcapi/tuple.c _testcapi/getargs.c _testcapi/datetime.c _testcapi/docstring.c _testcapi/mem.c _testcapi/watchers.c _testcapi/long.c _testcapi/float.c _testcapi/complex.c _testcapi/numbers.c _testcapi/structmember.c _testcapi/exceptions.c _testcapi/code.c _testcapi/buffer.c _testcapi/pyatomic.c _testcapi/run.c _testcapi/file.c _testcapi/codec.c _testcapi/immortal.c _testcapi/gc.c _testcapi/hash.c _testcapi/time.c _testcapi/bytes.c _testcapi/object.c _testcapi/modsupport.c _testcapi/monitoring.c _testcapi/config.c _testcapi/import.c _testcapi/frame.c _testcapi/type.c _testcapi/function.c _testcapi/module.c _testcapi/weakref.c -@MODULE__TESTLIMITEDCAPI_TRUE@_testlimitedcapi _testlimitedcapi.c _testlimitedcapi/abstract.c _testlimitedcapi/bytearray.c _testlimitedcapi/bytes.c _testlimitedcapi/codec.c _testlimitedcapi/complex.c _testlimitedcapi/dict.c _testlimitedcapi/eval.c _testlimitedcapi/float.c _testlimitedcapi/heaptype_relative.c _testlimitedcapi/import.c _testlimitedcapi/list.c _testlimitedcapi/long.c _testlimitedcapi/object.c _testlimitedcapi/pyos.c _testlimitedcapi/set.c _testlimitedcapi/slots.c _testlimitedcapi/sys.c _testlimitedcapi/threadstate.c _testlimitedcapi/tuple.c _testlimitedcapi/unicode.c _testlimitedcapi/vectorcall_limited.c _testlimitedcapi/version.c _testlimitedcapi/file.c _testlimitedcapi/weakref.c _testlimitedcapi/run.c +@MODULE__TESTLIMITEDCAPI_TRUE@_testlimitedcapi _testlimitedcapi.c _testlimitedcapi/abstract.c _testlimitedcapi/bytearray.c _testlimitedcapi/bytes.c _testlimitedcapi/capsule.c _testlimitedcapi/codec.c _testlimitedcapi/complex.c _testlimitedcapi/dict.c _testlimitedcapi/eval.c _testlimitedcapi/float.c _testlimitedcapi/heaptype_relative.c _testlimitedcapi/import.c _testlimitedcapi/list.c _testlimitedcapi/long.c _testlimitedcapi/object.c _testlimitedcapi/pyos.c _testlimitedcapi/set.c _testlimitedcapi/slots.c _testlimitedcapi/sys.c _testlimitedcapi/threadstate.c _testlimitedcapi/tuple.c _testlimitedcapi/unicode.c _testlimitedcapi/vectorcall_limited.c _testlimitedcapi/version.c _testlimitedcapi/file.c _testlimitedcapi/weakref.c _testlimitedcapi/run.c @MODULE__TESTCLINIC_TRUE@_testclinic _testclinic.c @MODULE__TESTCLINIC_LIMITED_TRUE@_testclinic_limited _testclinic_limited.c diff --git a/Modules/_testlimitedcapi.c b/Modules/_testlimitedcapi.c index 8ce704502af010..0a562ea9c03110 100644 --- a/Modules/_testlimitedcapi.c +++ b/Modules/_testlimitedcapi.c @@ -38,6 +38,9 @@ PyInit__testlimitedcapi(void) if (_PyTestLimitedCAPI_Init_Bytes(mod) < 0) { return NULL; } + if (_PyTestLimitedCAPI_Init_Capsule(mod) < 0) { + return NULL; + } if (_PyTestLimitedCAPI_Init_Codec(mod) < 0) { return NULL; } diff --git a/Modules/_testlimitedcapi/capsule.c b/Modules/_testlimitedcapi/capsule.c new file mode 100644 index 00000000000000..07b85823f399ba --- /dev/null +++ b/Modules/_testlimitedcapi/capsule.c @@ -0,0 +1,63 @@ +#include "parts.h" + +static void +capsule_destructor(PyObject *op) +{ + /* If non-NULL, the name and the pointer are the same allocation. */ + free((char *)PyCapsule_GetName(op)); +} + +static PyObject * +capsule_new(PyObject *self, PyObject *arg) +{ + const char *name; + Py_ssize_t size; + if (!PyArg_Parse(arg, "z#", &name, &size)) { + return NULL; + } + char *name_copy = NULL; + if (name != NULL) { + name_copy = strdup(name); + if (name_copy == NULL) { + return PyErr_NoMemory(); + } + } + static const char dummy = 0; + void *pointer = name_copy != NULL ? (void *)name_copy : (void *)&dummy; + PyObject *capsule = PyCapsule_New(pointer, name_copy, capsule_destructor); + if (capsule == NULL) { + free(name_copy); + } + return capsule; +} + +static PyObject * +pycapsule_import(PyObject *self, PyObject *args) +{ + const char *name; + Py_ssize_t size; + int no_block = 0; + if (!PyArg_ParseTuple(args, "z#|i", &name, &size, &no_block)) { + return NULL; + } + void *pointer = PyCapsule_Import(name, no_block); + if (pointer == NULL) { + return NULL; + } + /* Capsules created by capsule_new() store a copy of their name as the + pointer, so a successful import round-trips the name. Only use this + function with such capsules. */ + return PyUnicode_FromString((const char *)pointer); +} + +static PyMethodDef test_methods[] = { + {"capsule_new", capsule_new, METH_O}, + {"PyCapsule_Import", pycapsule_import, METH_VARARGS}, + {NULL}, +}; + +int +_PyTestLimitedCAPI_Init_Capsule(PyObject *m) +{ + return PyModule_AddFunctions(m, test_methods); +} diff --git a/Modules/_testlimitedcapi/parts.h b/Modules/_testlimitedcapi/parts.h index a11e0edb8311e3..32c1bbc1b71c97 100644 --- a/Modules/_testlimitedcapi/parts.h +++ b/Modules/_testlimitedcapi/parts.h @@ -25,6 +25,7 @@ int _PyTestLimitedCAPI_Init_Abstract(PyObject *module); int _PyTestLimitedCAPI_Init_ByteArray(PyObject *module); int _PyTestLimitedCAPI_Init_Bytes(PyObject *module); +int _PyTestLimitedCAPI_Init_Capsule(PyObject *module); int _PyTestLimitedCAPI_Init_Codec(PyObject *module); int _PyTestLimitedCAPI_Init_Complex(PyObject *module); int _PyTestLimitedCAPI_Init_Dict(PyObject *module); diff --git a/PCbuild/_testlimitedcapi.vcxproj b/PCbuild/_testlimitedcapi.vcxproj index 7ddcee6d9735ce..785bb151e08129 100644 --- a/PCbuild/_testlimitedcapi.vcxproj +++ b/PCbuild/_testlimitedcapi.vcxproj @@ -97,6 +97,7 @@ <ClCompile Include="..\Modules\_testlimitedcapi\abstract.c" /> <ClCompile Include="..\Modules\_testlimitedcapi\bytearray.c" /> <ClCompile Include="..\Modules\_testlimitedcapi\bytes.c" /> + <ClCompile Include="..\Modules\_testlimitedcapi\capsule.c" /> <ClCompile Include="..\Modules\_testlimitedcapi\codec.c" /> <ClCompile Include="..\Modules\_testlimitedcapi\complex.c" /> <ClCompile Include="..\Modules\_testlimitedcapi\dict.c" /> diff --git a/PCbuild/_testlimitedcapi.vcxproj.filters b/PCbuild/_testlimitedcapi.vcxproj.filters index 66a0a47d8e5548..51dc9950a10376 100644 --- a/PCbuild/_testlimitedcapi.vcxproj.filters +++ b/PCbuild/_testlimitedcapi.vcxproj.filters @@ -12,6 +12,7 @@ <ClCompile Include="..\Modules\_testlimitedcapi\abstract.c" /> <ClCompile Include="..\Modules\_testlimitedcapi\bytearray.c" /> <ClCompile Include="..\Modules\_testlimitedcapi\bytes.c" /> + <ClCompile Include="..\Modules\_testlimitedcapi\capsule.c" /> <ClCompile Include="..\Modules\_testlimitedcapi\codec.c" /> <ClCompile Include="..\Modules\_testlimitedcapi\complex.c" /> <ClCompile Include="..\Modules\_testlimitedcapi\dict.c" /> From 71361f331b30a34eb99e9c54ed37f96004fa9ea5 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 24 Jul 2026 18:31:56 +0200 Subject: [PATCH 811/818] [3.15] gh-154551: Fix ctypes.util.find_library() in non-UTF-8 locales (GH-154552) (GH-154555) _findLib_ld() failed to decode the localized "ld" stderr in the locale encoding. (cherry picked from commit 66e313f471516bfa04c5c8966c159fafe6be082e) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --- Lib/ctypes/util.py | 3 +-- .../Library/2026-07-23-19-45-00.gh-issue-154551.Ct7pL9.rst | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-07-23-19-45-00.gh-issue-154551.Ct7pL9.rst diff --git a/Lib/ctypes/util.py b/Lib/ctypes/util.py index 35ac5b6bfd6a37..93dceb3d586b06 100644 --- a/Lib/ctypes/util.py +++ b/Lib/ctypes/util.py @@ -422,8 +422,7 @@ def _findLib_ld(name): result = None try: p = subprocess.Popen(cmd, stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - universal_newlines=True) + stderr=subprocess.PIPE) out, _ = p.communicate() res = re.findall(expr, os.fsdecode(out)) for file in res: diff --git a/Misc/NEWS.d/next/Library/2026-07-23-19-45-00.gh-issue-154551.Ct7pL9.rst b/Misc/NEWS.d/next/Library/2026-07-23-19-45-00.gh-issue-154551.Ct7pL9.rst new file mode 100644 index 00000000000000..c4db19d89364e0 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-23-19-45-00.gh-issue-154551.Ct7pL9.rst @@ -0,0 +1 @@ +Fix :func:`ctypes.util.find_library` returning ``None`` in non-UTF-8 locales. From 99f684403a4afce526fb2258f7c5170a267b5d1a Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 24 Jul 2026 18:50:18 +0200 Subject: [PATCH 812/818] [3.15] gh-103847: fix some asyncio subprocess cancellation bugs (GH-146571) (#154633) gh-103847: fix some asyncio subprocess cancellation bugs (GH-146571) (cherry picked from commit f429fb36a16134a2a0e839d0f385eb8fee280de4) Co-authored-by: Kumar Aditya <kumaraditya@python.org> --- Lib/asyncio/base_subprocess.py | 18 +++++++++++++++--- Lib/asyncio/unix_events.py | 2 +- Lib/asyncio/windows_events.py | 2 +- Lib/test/test_asyncio/test_subprocess.py | 5 +---- 4 files changed, 18 insertions(+), 9 deletions(-) diff --git a/Lib/asyncio/base_subprocess.py b/Lib/asyncio/base_subprocess.py index 98e72f212aa203..0423bc100b2d93 100644 --- a/Lib/asyncio/base_subprocess.py +++ b/Lib/asyncio/base_subprocess.py @@ -22,7 +22,7 @@ def __init__(self, loop, protocol, args, shell, self._proc = None self._pid = None self._returncode = None - self._exit_waiters = [] + self._exit_waiters = set() self._pending_calls = collections.deque() self._pipes = {} self._finished = False @@ -211,6 +211,14 @@ async def _connect_pipes(self, waiter): except (SystemExit, KeyboardInterrupt): raise except BaseException as exc: + # Close any pipes that were already connected before the + # error/cancellation to avoid leaking file descriptors. + for proto in self._pipes.values(): + if proto is not None: + proto.pipe.close() + for raw_pipe in (proc.stdin, proc.stdout, proc.stderr): + if raw_pipe is not None: + raw_pipe.close() if waiter is not None and not waiter.cancelled(): waiter.set_exception(exc) else: @@ -260,8 +268,12 @@ async def _wait(self): return self._returncode waiter = self._loop.create_future() - self._exit_waiters.append(waiter) - return await waiter + self._exit_waiters.add(waiter) + try: + return await waiter + finally: + if self._exit_waiters is not None: + self._exit_waiters.discard(waiter) def _try_finish(self): assert not self._finished diff --git a/Lib/asyncio/unix_events.py b/Lib/asyncio/unix_events.py index bb82ba5ae10f2e..a0fc6c8e66e58a 100644 --- a/Lib/asyncio/unix_events.py +++ b/Lib/asyncio/unix_events.py @@ -212,7 +212,7 @@ async def _make_subprocess_transport(self, protocol, args, shell, raise except BaseException: transp.close() - await transp._wait() + await tasks.shield(transp._wait()) raise return transp diff --git a/Lib/asyncio/windows_events.py b/Lib/asyncio/windows_events.py index 0bf7732136f1f8..c905db1016807f 100644 --- a/Lib/asyncio/windows_events.py +++ b/Lib/asyncio/windows_events.py @@ -408,7 +408,7 @@ async def _make_subprocess_transport(self, protocol, args, shell, raise except BaseException: transp.close() - await transp._wait() + await tasks.shield(transp._wait()) raise return transp diff --git a/Lib/test/test_asyncio/test_subprocess.py b/Lib/test/test_asyncio/test_subprocess.py index 4ab4315f1efe82..aab92db872d6a9 100644 --- a/Lib/test/test_asyncio/test_subprocess.py +++ b/Lib/test/test_asyncio/test_subprocess.py @@ -11,7 +11,7 @@ from asyncio import subprocess from test.test_asyncio import utils as test_utils from test import support -from test.support import os_helper, warnings_helper, gc_collect +from test.support import os_helper, gc_collect if not support.has_subprocess_support: raise unittest.SkipTest("test module requires subprocess") @@ -919,7 +919,6 @@ async def main(): self.loop.run_until_complete(main()) - @warnings_helper.ignore_warnings(category=ResourceWarning) def test_subprocess_read_pipe_cancelled(self): async def main(): loop = asyncio.get_running_loop() @@ -930,7 +929,6 @@ async def main(): asyncio.run(main()) gc_collect() - @warnings_helper.ignore_warnings(category=ResourceWarning) def test_subprocess_write_pipe_cancelled(self): async def main(): loop = asyncio.get_running_loop() @@ -941,7 +939,6 @@ async def main(): asyncio.run(main()) gc_collect() - @warnings_helper.ignore_warnings(category=ResourceWarning) def test_subprocess_read_write_pipe_cancelled(self): async def main(): loop = asyncio.get_running_loop() From 370e67029b0e380c5caf47b89c34c09cb82ad9c8 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 24 Jul 2026 19:25:56 +0200 Subject: [PATCH 813/818] [3.15] gh-153419: Fix several issues around bytearray __init__ (GH-153498) (#154622) gh-153419: Fix several issues around bytearray __init__ (GH-153498) Introduce a bytearray_new() function to ensure that ob_bytes_object is always set on a bytearray. Resizing a bytearray to 0 length now explicitly sets the ob_bytes_object to the empty constant immortal. Add a check in the 'bytearray init from string' fast path to ensure there are no active exports. This fixes asserts/crashes on the following: - bytearray(1).__init__() - bytearray().__new__(bytearray).append(1) - a = bytearray(); b = memoryview(a); a.__init__('x', 'ascii') (cherry picked from commit d5c1b29658063d1ef9d66515d8e4cb9929126be7) Co-authored-by: Steve Stagg <stestagg@gmail.com> Co-authored-by: Cody Maloney <cmaloney@users.noreply.github.com> --- Lib/test/test_bytes.py | 40 ++++++++++++++++ ...-07-11-01-17-57.gh-issue-153419.U8HJOJ.rst | 1 + Objects/bytearrayobject.c | 48 ++++++++++++++----- Objects/bytesobject.c | 1 + 4 files changed, 78 insertions(+), 12 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-07-11-01-17-57.gh-issue-153419.U8HJOJ.rst diff --git a/Lib/test/test_bytes.py b/Lib/test/test_bytes.py index e211c3d15a4ed2..e3e703fef1eb5d 100644 --- a/Lib/test/test_bytes.py +++ b/Lib/test/test_bytes.py @@ -2197,6 +2197,46 @@ def __len__(self): self.assertRaises(BufferError, ba.hex, S(b':')) + def test_no_init_called(self): + # A bytearray created without calling bytearray.__init__ + # should not crash the interpreter (see gh-153419). + def bytearray_new(): + return bytearray.__new__(bytearray) + + bytearray_new().insert(0, 1) + bytearray_new().extend(b"x") + bytearray_new().extend([1, 2, 3]) + bytearray_new().resize(4) + bytearray_new().__init__(5) + bytearray_new().__init__(b"xyz") + bytearray_new().take_bytes() + bytearray_new().take_bytes(0) + + a = bytearray_new() + a.append(1) + + a = bytearray_new() + a += b"x" + + a = bytearray_new() + a[:] = b"xyz" + + def test_reinit_length(self): + # There is a shortcut taken when resizing, where alloc/2 < newsize. + # In this case, the existing buffer is reused, rather than reset. + # If this happens when newsize == 0 and alloc == 1, then various + # code assumptions can be violated. This test should catch those + # in debug builds. (see gh-153419) + a = bytearray(1) + a.__init__() + self.assertEqual(a, b"") + + def test_reinit_with_view(self): + a = bytearray() + with memoryview(a): + self.assertRaises(BufferError, a.__init__, "x", "ascii") + self.assertEqual(a, b"") + class AssortedBytesTest(unittest.TestCase): # diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-07-11-01-17-57.gh-issue-153419.U8HJOJ.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-07-11-01-17-57.gh-issue-153419.U8HJOJ.rst new file mode 100644 index 00000000000000..4459ec835395ea --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-07-11-01-17-57.gh-issue-153419.U8HJOJ.rst @@ -0,0 +1 @@ +Fix multiple :class:`bytearray` crashes and reference leaks caused by skipping :meth:`~object.__init__` and broken state setup code. diff --git a/Objects/bytearrayobject.c b/Objects/bytearrayobject.c index ca7956579e80bb..70e9e87210b60b 100644 --- a/Objects/bytearrayobject.c +++ b/Objects/bytearrayobject.c @@ -213,6 +213,9 @@ bytearray_resize_lock_held(PyObject *self, Py_ssize_t requested_size) { _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(self); PyByteArrayObject *obj = ((PyByteArrayObject *)self); + + assert(obj->ob_bytes_object != NULL); + /* All computations are done unsigned to avoid integer overflows (see issue #22335). */ size_t alloc = (size_t) obj->ob_alloc; @@ -236,6 +239,14 @@ bytearray_resize_lock_held(PyObject *self, Py_ssize_t requested_size) return -1; } + /* Resize to 0 resets to empty bytes (see issue #153419). */ + if (requested_size == 0) { + Py_SETREF(obj->ob_bytes_object, + Py_GetConstant(Py_CONSTANT_EMPTY_BYTES)); + bytearray_reinit_from_bytes(obj, 0, 0); + return 0; + } + if (size + logical_offset <= alloc) { /* Current buffer is large enough to host the requested size, decide on a strategy. */ @@ -902,6 +913,20 @@ bytearray_ass_subscript(PyObject *op, PyObject *index, PyObject *values) return ret; } +static PyObject * +bytearray_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PyObject *op = PyType_GenericNew(type, args, kwds); + if (op == NULL) { + return NULL; + } + PyByteArrayObject *self = _PyByteArray_CAST(op); + self->ob_bytes_object = Py_GetConstant(Py_CONSTANT_EMPTY_BYTES); + bytearray_reinit_from_bytes(self, 0, 0); + self->ob_exports = 0; + return op; +} + /*[clinic input] bytearray.__init__ @@ -920,20 +945,16 @@ bytearray___init___impl(PyByteArrayObject *self, PyObject *arg, PyObject *it; PyObject *(*iternext)(PyObject *); - /* First __init__; set ob_bytes_object so ob_bytes is always non-null. */ - if (self->ob_bytes_object == NULL) { - self->ob_bytes_object = Py_GetConstant(Py_CONSTANT_EMPTY_BYTES); - bytearray_reinit_from_bytes(self, 0, 0); - self->ob_exports = 0; + /* Disallow any __init__ call if the object is not resizable (has exports) + to make the handling of non-null `source` init values simpler. */ + if (!_canresize(self)) { + return -1; } - if (Py_SIZE(self) != 0) { - /* Empty previous contents (yes, do this first of all!) */ - if (PyByteArray_Resize((PyObject *)self, 0) < 0) - return -1; + /* Empty any previous contents (do this first of all!). */ + if (PyByteArray_Resize((PyObject *)self, 0) < 0) { + return -1; } - - /* Should be caused by first init or the resize to 0. */ assert(self->ob_bytes_object == Py_GetConstantBorrowed(Py_CONSTANT_EMPTY_BYTES)); assert(self->ob_exports == 0); @@ -1607,6 +1628,9 @@ bytearray_take_bytes_impl(PyByteArrayObject *self, PyObject *n) } if (_PyBytes_Resize(&self->ob_bytes_object, to_take) == -1) { + assert(self->ob_bytes_object == NULL); + self->ob_bytes_object = Py_GetConstant(Py_CONSTANT_EMPTY_BYTES); + bytearray_reinit_from_bytes(self, 0, 0); Py_DECREF(remaining); return NULL; } @@ -2937,7 +2961,7 @@ PyTypeObject PyByteArray_Type = { 0, /* tp_dictoffset */ bytearray___init__, /* tp_init */ PyType_GenericAlloc, /* tp_alloc */ - PyType_GenericNew, /* tp_new */ + bytearray_new, /* tp_new */ PyObject_Free, /* tp_free */ .tp_version_tag = _Py_TYPE_VERSION_BYTEARRAY, }; diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c index 1135770549c017..33dc66eec62990 100644 --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -3380,6 +3380,7 @@ _PyBytes_Resize(PyObject **pv, Py_ssize_t newsize) Py_DECREF(v); return (*pv == NULL) ? -1 : 0; } + assert(v != bytes_get_empty()); #ifdef Py_TRACE_REFS _Py_ForgetReference(v); From efbe54a2c6f0fa95d81c1f0736abbd698e922ff0 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 24 Jul 2026 19:55:12 +0200 Subject: [PATCH 814/818] [3.15] gh-154580: Fix python-gdb.py pretty-printing non-ASCII strings in non-UTF-8 locales (GH-154581) (GH-154635) The gdb pretty-printer used locale.getpreferredencoding() to decide whether to escape a character, but gdb writes its output in its host charset. Use gdb.host_charset() instead. test_strings had the same problem. (cherry picked from commit 6cb93bd039ec1c5e0909d2d75cfc4fb3641c693b) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --- Lib/test/test_gdb/test_pretty_print.py | 19 +++++++++---------- Lib/test/test_gdb/util.py | 2 +- ...-07-24-09-30-00.gh-issue-154580.Kp3nQ2.rst | 3 +++ Tools/gdb/libpython.py | 13 ++++++++----- 4 files changed, 21 insertions(+), 16 deletions(-) create mode 100644 Misc/NEWS.d/next/Tools-Demos/2026-07-24-09-30-00.gh-issue-154580.Kp3nQ2.rst diff --git a/Lib/test/test_gdb/test_pretty_print.py b/Lib/test/test_gdb/test_pretty_print.py index db3064e3df54c2..edb79ef86d31db 100644 --- a/Lib/test/test_gdb/test_pretty_print.py +++ b/Lib/test/test_gdb/test_pretty_print.py @@ -114,29 +114,28 @@ def test_bytes(self): @support.requires_resource('cpu') def test_strings(self): 'Verify the pretty-printing of unicode strings' - # We cannot simply call locale.getpreferredencoding() here, - # as GDB might have been linked against a different version - # of Python with a different encoding and coercion policy - # with respect to PEP 538 and PEP 540. + # gdb emits its output in the host charset, which is not necessarily the + # getpreferredencoding() of the (possibly differently coerced) embedded + # Python. stdout, stderr = run_gdb( '--eval-command', - 'python import locale; print(locale.getpreferredencoding())') + 'python import gdb; print(gdb.host_charset())') - encoding = stdout + encoding = stdout.strip() if stderr or not encoding: raise RuntimeError( - f'unable to determine the Python locale preferred encoding ' - f'of embedded Python in GDB\n' + f'unable to determine the host charset of gdb\n' f'stdout={stdout!r}\n' f'stderr={stderr!r}') def check_repr(text): try: text.encode(encoding) - except UnicodeEncodeError: + # LookupError or ValueError if the host charset is unknown or invalid. + except (UnicodeEncodeError, LookupError, ValueError): self.assertGdbRepr(text, ascii(text)) else: - self.assertGdbRepr(text) + self.assertGdbRepr(text, repr(text).encode(encoding).decode('ascii', 'surrogateescape')) self.assertGdbRepr('') self.assertGdbRepr('And now for something hopefully the same') diff --git a/Lib/test/test_gdb/util.py b/Lib/test/test_gdb/util.py index d903adcf2903f3..29c7e9ee8f0549 100644 --- a/Lib/test/test_gdb/util.py +++ b/Lib/test/test_gdb/util.py @@ -78,7 +78,7 @@ def run_gdb(*args, exitcode=0, check=True, **env_vars): stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, - encoding="utf8", errors="backslashreplace", + encoding="ascii", errors="surrogateescape", env=env) stdout = proc.stdout diff --git a/Misc/NEWS.d/next/Tools-Demos/2026-07-24-09-30-00.gh-issue-154580.Kp3nQ2.rst b/Misc/NEWS.d/next/Tools-Demos/2026-07-24-09-30-00.gh-issue-154580.Kp3nQ2.rst new file mode 100644 index 00000000000000..f6a039245b015e --- /dev/null +++ b/Misc/NEWS.d/next/Tools-Demos/2026-07-24-09-30-00.gh-issue-154580.Kp3nQ2.rst @@ -0,0 +1,3 @@ +Fix ``python-gdb.py`` raising :exc:`UnicodeEncodeError` when pretty-printing a +non-ASCII :class:`str` in a locale whose host charset cannot encode it, such as +any non-ASCII string in the C locale. diff --git a/Tools/gdb/libpython.py b/Tools/gdb/libpython.py index ba52ea2a30e0be..422e4f605920a0 100755 --- a/Tools/gdb/libpython.py +++ b/Tools/gdb/libpython.py @@ -43,7 +43,6 @@ import gdb import os -import locale import sys @@ -107,8 +106,6 @@ def interp_frame_has_tlbc_index(): USED_TAGS = 0b11 -ENCODING = locale.getpreferredencoding() - FRAME_INFO_OPTIMIZED_OUT = '(frame information optimized out)' UNABLE_READ_INFO_PYTHON_FRAME = 'Unable to read information on python frame' EVALFRAME = '_PyEval_EvalFrameDefault' @@ -1504,6 +1501,10 @@ def proxyval(self, visited): def write_repr(self, out, visited): # Write this out as a Python str literal + # gdb writes its output in the host charset, so a character is escaped + # unless it is printable and encodable in that charset. + encoding = gdb.host_charset() + # Get a PyUnicodeObject* within the Python gdb process: proxy = self.proxyval(visited) @@ -1551,8 +1552,10 @@ def write_repr(self, out, visited): printable = ucs.isprintable() if printable: try: - ucs.encode(ENCODING) - except UnicodeEncodeError: + ucs.encode(encoding) + # LookupError or ValueError if the host charset is unknown + # or invalid. + except (UnicodeEncodeError, LookupError, ValueError): printable = False # Map Unicode whitespace and control characters From fe08b7029b0698074a59d7c43c49c6a5ae85239d Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 24 Jul 2026 22:24:37 +0200 Subject: [PATCH 815/818] [3.15] GH-142035: Fix wrapping of colorized argparse help text (GH-154634) (#154644) GH-142035: Fix wrapping of colorized argparse help text (GH-154634) (cherry picked from commit 998fc4a973b2b5ac925d13e01693360c24803330) Co-authored-by: Savannah Ostrowski <savannah@python.org> Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com> Co-authored-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> --- Lib/argparse.py | 30 +++++++++- Lib/test/test_argparse.py | 56 +++++++++++++++++++ ...-07-24-15-54-35.gh-issue-142035.ZpNfl6.rst | 1 + 3 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2026-07-24-15-54-35.gh-issue-142035.ZpNfl6.rst diff --git a/Lib/argparse.py b/Lib/argparse.py index 29e6ebb9634261..42891516b3bb2a 100644 --- a/Lib/argparse.py +++ b/Lib/argparse.py @@ -776,7 +776,35 @@ def _split_lines(self, text, width): # The textwrap module is used only for formatting help. # Delay its import for speeding up the common usage of argparse. import textwrap - return textwrap.wrap(text, width) + decolored = self._decolor(text) + if decolored == text: + return textwrap.wrap(text, width) + + # gh-142035: colors inflate textwrap's length counts, so wrap + # the decolored text and re-apply colors per word; if textwrap + # split a word, keep the plain lines (colors can't be mapped). + plain = self._whitespace_matcher.sub(' ', decolored).strip() + if not plain: + # nothing visible to wrap (e.g. an empty interpolated value) + return [text] + plain_lines = textwrap.wrap(plain, width) + plain_words = plain.split() + colored_words = text.split() + # Drop escape-only tokens (e.g. an empty interpolated value). + if len(colored_words) != len(plain_words): + colored_words = [ + word for word in colored_words if self._decolor(word) + ] + colored_lines = [] + start = 0 + for plain_line in plain_lines: + plain_line_words = plain_line.split() + end = start + len(plain_line_words) + if plain_words[start:end] != plain_line_words: + return plain_lines + colored_lines.append(' '.join(colored_words[start:end])) + start = end + return colored_lines def _fill_text(self, text, width, indent): text = self._whitespace_matcher.sub(' ', text).strip() diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py index 1dc3f538f4ad8b..fbeb933841129e 100644 --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -7580,6 +7580,62 @@ def test_argparse_color_custom_usage(self): ), ) + def test_argparse_color_wrapping_matches_uncolored(self): + # gh-142035: color codes must not affect where help text wraps. + # Stripping the escapes from colored help must yield exactly the + # same text as the uncolored help across representative widths. + def build(color, path="output.txt"): + parser = argparse.ArgumentParser(prog="PROG", color=color) + parser.add_argument( + "--mode", + default="auto", + choices=("auto", "fast", "slow"), + help="select the operating mode from the available choices " + "%(choices)s and note the default is %(default)s here", + ) + parser.add_argument( + "--path", + default=path, + help="write output to %(default)s and continue processing", + ) + return parser + + env = self.enterContext(os_helper.EnvironmentVarGuard()) + paths = ( + "output.txt", + "/var/lib/application/cache/unusually_long_generated_filename", + "production-read-only-replica", + ) + for path in paths: + for columns in ("80", "60", "45", "30", "20"): + with self.subTest(path=path, columns=columns): + env["COLUMNS"] = columns + colored = build(color=True, path=path).format_help() + plain = build(color=False, path=path).format_help() + self.assertIn( + f"{self.theme.interpolated_value}auto" + f"{self.theme.reset}", + colored, + ) + self.assertEqual(_colorize.decolor(colored), plain) + + def test_argparse_color_preserved_when_wrapping_between_words(self): + parser = argparse.ArgumentParser(prog="PROG", color=True) + parser.add_argument( + "--mode", default="auto", + help="select the %(default)s operating mode from the available " + "options and continue with several more words", + ) + + env = self.enterContext(os_helper.EnvironmentVarGuard()) + env["COLUMNS"] = "40" + help_text = parser.format_help() + + self.assertIn( + f"{self.theme.interpolated_value}auto{self.theme.reset}", + help_text, + ) + def test_custom_formatter_function(self): def custom_formatter(prog): return argparse.RawTextHelpFormatter(prog, indent_increment=5) diff --git a/Misc/NEWS.d/next/Library/2026-07-24-15-54-35.gh-issue-142035.ZpNfl6.rst b/Misc/NEWS.d/next/Library/2026-07-24-15-54-35.gh-issue-142035.ZpNfl6.rst new file mode 100644 index 00000000000000..f11f3a9e55200d --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-24-15-54-35.gh-issue-142035.ZpNfl6.rst @@ -0,0 +1 @@ +Fix incorrect wrapping of :mod:`argparse` help text when color is enabled. From 848f0bafc689e5d76f9c20f8c96a2454fd32fd79 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 25 Jul 2026 00:06:49 +0200 Subject: [PATCH 816/818] [3.15] gh-153570: Fix use-after-free in bytearray.take_bytes() with a reentrant __index__ (GH-153572) (#154648) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gh-153570: Fix use-after-free in bytearray.take_bytes() with a reentrant __index__ (GH-153572) bytearray.take_bytes() cached the size before the argument's __index__ call and used it for the bounds check and the buffer reads, so an __index__ that resizes the bytearray left it reading freed memory. Re-read the size after __index__, matching bytearray.__setitem__ (GH-91153). (cherry picked from commit ee21d992d6117eb7f0c6087ecb93d90cd0ed610c) Co-authored-by: tonghuaroot (童话) <tonghuaroot@gmail.com> --- Lib/test/test_bytes.py | 29 +++++++++++++++++++ ...-07-11-15-30-00.gh-issue-153570.Kb7Xd2.rst | 2 ++ Objects/bytearrayobject.c | 2 ++ 3 files changed, 33 insertions(+) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-07-11-15-30-00.gh-issue-153570.Kb7Xd2.rst diff --git a/Lib/test/test_bytes.py b/Lib/test/test_bytes.py index e3e703fef1eb5d..720b38cb508cbe 100644 --- a/Lib/test/test_bytes.py +++ b/Lib/test/test_bytes.py @@ -1637,6 +1637,35 @@ def test_take_bytes_optimization(self): bytes_header_size = sys.getsizeof(b'') self.assertEqual(ba.__alloc__(), 499 + bytes_header_size) + def test_take_bytes_reentrant_resize(self): + # gh-153570: n.__index__() can resize the bytearray, so take_bytes() + # must re-read the size afterwards. It cached the size before the + # call and used it for the bounds check and the buffer reads, so a + # reentrant clear() returned freed memory (a use-after-free read). + def take(target, resize, n): + class Evil: + def __index__(self): + resize(target) + return n + return target.take_bytes(Evil()) + + # clear() during __index__: nothing is left to take. + ba = bytearray(b'abcdefgh') + with self.assertRaises(IndexError): + take(ba, lambda b: b.clear(), 8) + self.assertEqual(ba, b'') + + # shrink during __index__: n past the new size is out of range. + ba = bytearray(b'abcdefgh') + with self.assertRaises(IndexError): + take(ba, lambda b: b.__delitem__(slice(4, None)), 8) + self.assertEqual(ba, b'abcd') + + # grow during __index__: the take runs against the new, larger size. + ba = bytearray(b'abcd') + self.assertEqual(take(ba, lambda b: b.extend(b'efgh'), 8), b'abcdefgh') + self.assertEqual(ba, b'') + def test_setitem(self): def setitem_as_mapping(b, i, val): b[i] = val diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-07-11-15-30-00.gh-issue-153570.Kb7Xd2.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-07-11-15-30-00.gh-issue-153570.Kb7Xd2.rst new file mode 100644 index 00000000000000..655fd614d7f551 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-07-11-15-30-00.gh-issue-153570.Kb7Xd2.rst @@ -0,0 +1,2 @@ +Fix a use-after-free in :meth:`bytearray.take_bytes` when the argument's +:meth:`~object.__index__` method resizes the bytearray. Patch by tonghuaroot. diff --git a/Objects/bytearrayobject.c b/Objects/bytearrayobject.c index 70e9e87210b60b..b16fb8751f5f73 100644 --- a/Objects/bytearrayobject.c +++ b/Objects/bytearrayobject.c @@ -1576,6 +1576,8 @@ bytearray_take_bytes_impl(PyByteArrayObject *self, PyObject *n) if (to_take == -1 && PyErr_Occurred()) { return NULL; } + // n.__index__() may have resized self; use the current size. + size = Py_SIZE(self); if (to_take < 0) { to_take += size; } From 4245891a87cf48065074835c4e999eaf6939c05b Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 25 Jul 2026 01:01:47 +0200 Subject: [PATCH 817/818] [3.15] gh-134745: Remove dead code in `thread_nt.h` left by gh-134747 (GH-154338) (#154655) gh-134745: Remove dead code in `thread_nt.h` left by gh-134747 (GH-154338) (cherry picked from commit 9560bd8f3533ac16684dfe11283bb834af52f10f) Co-authored-by: Ivy Xu <fakeshadow1337@gmail.com> --- Python/thread_nt.h | 136 --------------------------------------------- 1 file changed, 136 deletions(-) diff --git a/Python/thread_nt.h b/Python/thread_nt.h index 9a29d14ef67678..086dab912ecfd7 100644 --- a/Python/thread_nt.h +++ b/Python/thread_nt.h @@ -11,142 +11,6 @@ #include <process.h> #endif -/* options */ -#ifndef _PY_USE_CV_LOCKS -#define _PY_USE_CV_LOCKS 1 /* use locks based on cond vars */ -#endif - -/* Now, define a non-recursive mutex using either condition variables - * and critical sections (fast) or using operating system mutexes - * (slow) - */ - -#if _PY_USE_CV_LOCKS - -#include "condvar.h" - -typedef struct _NRMUTEX -{ - PyMUTEX_T cs; - PyCOND_T cv; - int locked; -} NRMUTEX; -typedef NRMUTEX *PNRMUTEX; - -static PNRMUTEX -AllocNonRecursiveMutex(void) -{ - PNRMUTEX m = (PNRMUTEX)PyMem_RawMalloc(sizeof(NRMUTEX)); - if (!m) - return NULL; - if (PyCOND_INIT(&m->cv)) - goto fail; - if (PyMUTEX_INIT(&m->cs)) { - PyCOND_FINI(&m->cv); - goto fail; - } - m->locked = 0; - return m; -fail: - PyMem_RawFree(m); - return NULL; -} - -static VOID -FreeNonRecursiveMutex(PNRMUTEX mutex) -{ - if (mutex) { - PyCOND_FINI(&mutex->cv); - PyMUTEX_FINI(&mutex->cs); - PyMem_RawFree(mutex); - } -} - -static DWORD -EnterNonRecursiveMutex(PNRMUTEX mutex, DWORD milliseconds) -{ - DWORD result = WAIT_OBJECT_0; - if (PyMUTEX_LOCK(&mutex->cs)) - return WAIT_FAILED; - if (milliseconds == INFINITE) { - while (mutex->locked) { - if (PyCOND_WAIT(&mutex->cv, &mutex->cs)) { - result = WAIT_FAILED; - break; - } - } - } else if (milliseconds != 0) { - /* wait at least until the deadline */ - PyTime_t timeout = (PyTime_t)milliseconds * (1000 * 1000); - PyTime_t deadline = _PyDeadline_Init(timeout); - while (mutex->locked) { - PyTime_t microseconds = _PyTime_AsMicroseconds(timeout, - _PyTime_ROUND_TIMEOUT); - if (PyCOND_TIMEDWAIT(&mutex->cv, &mutex->cs, microseconds) < 0) { - result = WAIT_FAILED; - break; - } - - timeout = _PyDeadline_Get(deadline); - if (timeout <= 0) { - break; - } - } - } - if (!mutex->locked) { - mutex->locked = 1; - result = WAIT_OBJECT_0; - } else if (result == WAIT_OBJECT_0) - result = WAIT_TIMEOUT; - /* else, it is WAIT_FAILED */ - PyMUTEX_UNLOCK(&mutex->cs); /* must ignore result here */ - return result; -} - -static BOOL -LeaveNonRecursiveMutex(PNRMUTEX mutex) -{ - BOOL result; - if (PyMUTEX_LOCK(&mutex->cs)) - return FALSE; - mutex->locked = 0; - /* condvar APIs return 0 on success. We need to return TRUE on success. */ - result = !PyCOND_SIGNAL(&mutex->cv); - PyMUTEX_UNLOCK(&mutex->cs); - return result; -} - -#else /* if ! _PY_USE_CV_LOCKS */ - -/* NR-locks based on a kernel mutex */ -#define PNRMUTEX HANDLE - -static PNRMUTEX -AllocNonRecursiveMutex(void) -{ - return CreateSemaphore(NULL, 1, 1, NULL); -} - -static VOID -FreeNonRecursiveMutex(PNRMUTEX mutex) -{ - /* No in-use check */ - CloseHandle(mutex); -} - -static DWORD -EnterNonRecursiveMutex(PNRMUTEX mutex, DWORD milliseconds) -{ - return WaitForSingleObjectEx(mutex, milliseconds, FALSE); -} - -static BOOL -LeaveNonRecursiveMutex(PNRMUTEX mutex) -{ - return ReleaseSemaphore(mutex, 1, NULL); -} -#endif /* _PY_USE_CV_LOCKS */ - unsigned long PyThread_get_thread_ident(void); #ifdef PY_HAVE_THREAD_NATIVE_ID From 1f53f91c470a4e25082954876dcdc2f081a85e3e Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 25 Jul 2026 01:50:09 +0200 Subject: [PATCH 818/818] [3.15] gh-118150: warn in doc about results asymmetry for difflib junk (GH-153892) (GH-154658) (cherry picked from commit 59e67c284d3e8dcb708e473cfca02b1307c9cd0a) Co-authored-by: Lenormand Julien <lenormand.julien0@gmail.com> --- Doc/library/difflib.rst | 29 ++++++++----------- ...-07-17-22-33-43.gh-issue-118150.m7iFdP.rst | 2 ++ 2 files changed, 14 insertions(+), 17 deletions(-) create mode 100644 Misc/NEWS.d/next/Documentation/2026-07-17-22-33-43.gh-issue-118150.m7iFdP.rst diff --git a/Doc/library/difflib.rst b/Doc/library/difflib.rst index b828381e91e531..d6e31b5f6fbb3d 100644 --- a/Doc/library/difflib.rst +++ b/Doc/library/difflib.rst @@ -40,13 +40,18 @@ diffs. For comparing directories and files, see also, the :mod:`filecmp` module. complicated way on how many elements the sequences have in common; best case time is linear. - **Automatic junk heuristic:** :class:`SequenceMatcher` supports a heuristic that - automatically treats certain sequence items as junk. The heuristic counts how many - times each individual item appears in the sequence. If an item's duplicates (after - the first one) account for more than 1% of the sequence and the sequence is at least - 200 items long, this item is marked as "popular" and is treated as junk for - the purpose of sequence matching. This heuristic can be turned off by setting - the ``autojunk`` argument to ``False`` when creating the :class:`SequenceMatcher`. + **Junk**: :class:`SequenceMatcher` accepts an ``isjunk`` predicate and an + ``autojunk`` flag. Items that are considered as junk will not be considered + to find similar content blocks. This can produce better results for humans + (typically breaking on whitespace) and faster (because it reduces the number + of possible combinations). But it can also cause pathological cases where + too many items considered junk cause an unexpectedly large (but correct) + diff result. + You should consider tuning them or turning them off depending on your data. + Moreover, only the second sequence is inspected for junk. This causes the diff + output to not be symmetrical. + When ``autojunk=True``, it will consider as junk the items that account for more + than 1% of the sequence, if it is at least 200 items long. .. versionchanged:: 3.2 Added the *autojunk* parameter. @@ -558,16 +563,6 @@ The :class:`SequenceMatcher` class has this constructor: to try :meth:`quick_ratio` or :meth:`real_quick_ratio` first to get an upper bound. - .. note:: - - Caution: The result of a :meth:`ratio` call may depend on the order of - the arguments. For instance:: - - >>> SequenceMatcher(None, 'tide', 'diet').ratio() - 0.25 - >>> SequenceMatcher(None, 'diet', 'tide').ratio() - 0.5 - .. method:: quick_ratio() diff --git a/Misc/NEWS.d/next/Documentation/2026-07-17-22-33-43.gh-issue-118150.m7iFdP.rst b/Misc/NEWS.d/next/Documentation/2026-07-17-22-33-43.gh-issue-118150.m7iFdP.rst new file mode 100644 index 00000000000000..afa6007a46e174 --- /dev/null +++ b/Misc/NEWS.d/next/Documentation/2026-07-17-22-33-43.gh-issue-118150.m7iFdP.rst @@ -0,0 +1,2 @@ +Clarify in the :mod:`difflib` documentation what *junk* actually does, its +drawbacks, and how to control it.