diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index 4b77646e22db4ba..dca3e12ec18270c 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -7,11 +7,6 @@ updates:
labels:
- "skip issue"
- "skip news"
- ignore:
- - dependency-name: "*"
- update-types:
- - "version-update:semver-minor"
- - "version-update:semver-patch"
groups:
actions:
patterns:
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index e11e6aa6b6d3dc1..b9fbc8524550453 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -64,7 +64,7 @@ jobs:
run: |
apt update && apt install git -yq
git config --global --add safe.directory "$GITHUB_WORKSPACE"
- - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 1
persist-credentials: false
@@ -101,10 +101,10 @@ jobs:
needs: build-context
if: needs.build-context.outputs.run-tests == 'true'
steps:
- - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
+ - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: '3.x'
- name: Runner image version
@@ -281,7 +281,7 @@ jobs:
SSLLIB_DIR: ${{ github.workspace }}/multissl/${{ matrix.ssllib.name }}/${{ matrix.ssllib.version }}
LD_LIBRARY_PATH: ${{ github.workspace }}/multissl/${{ matrix.ssllib.name }}/${{ matrix.ssllib.version }}/lib
steps:
- - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Runner image version
@@ -292,7 +292,7 @@ jobs:
run: sudo ./.github/workflows/posix-deps-apt.sh
- name: 'Restore SSL library build'
id: cache-ssl-lib
- uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4
+ uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: ./multissl/${{ matrix.ssllib.name }}/${{ matrix.ssllib.version }}
key: ${{ matrix.os }}-multissl-${{ matrix.ssllib.name }}-${{ matrix.ssllib.version }}
@@ -340,7 +340,7 @@ jobs:
runs-on: ${{ matrix.runs-on }}
steps:
- - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Build and test
@@ -353,7 +353,7 @@ jobs:
timeout-minutes: 60
runs-on: macos-26
steps:
- - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
@@ -382,7 +382,7 @@ jobs:
OPENSSL_VER: 3.5.8
PYTHONSTRICTEXTENSIONBUILD: 1
steps:
- - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Register gcc problem matcher
@@ -396,7 +396,7 @@ jobs:
echo "LD_LIBRARY_PATH=${GITHUB_WORKSPACE}/multissl/openssl/${OPENSSL_VER}/lib" >> "$GITHUB_ENV"
- name: 'Restore OpenSSL build'
id: cache-openssl
- uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4
+ uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: ./multissl/openssl/${{ env.OPENSSL_VER }}
key: ${{ runner.os }}-multissl-openssl-${{ env.OPENSSL_VER }}
@@ -443,7 +443,7 @@ jobs:
./python -m venv "$VENV_LOC" && "$VENV_PYTHON" -m pip install -r "${GITHUB_WORKSPACE}/Tools/requirements-hypothesis.txt"
- name: 'Restore Hypothesis database'
id: cache-hypothesis-database
- uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4
+ uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: ${{ env.CPYTHON_BUILDDIR }}/.hypothesis/
key: hypothesis-database-${{ github.head_ref || github.run_id }}
@@ -470,7 +470,7 @@ jobs:
-x test_subprocess \
-x test_signal \
-x test_sysconfig
- - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
+ - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
if: always()
with:
name: hypothesis-example-db
@@ -497,7 +497,7 @@ jobs:
PYTHONSTRICTEXTENSIONBUILD: 1
ASAN_OPTIONS: detect_leaks=0:allocator_may_return_null=1:handle_segv=0
steps:
- - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Runner image version
@@ -513,7 +513,7 @@ jobs:
echo "LD_LIBRARY_PATH=${GITHUB_WORKSPACE}/multissl/openssl/${OPENSSL_VER}/lib" >> "$GITHUB_ENV"
- name: 'Restore OpenSSL build'
id: cache-openssl
- uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4
+ uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: ./multissl/openssl/${{ env.OPENSSL_VER }}
key: ${{ matrix.os }}-multissl-openssl-${{ env.OPENSSL_VER }}
@@ -560,7 +560,7 @@ jobs:
needs: build-context
if: needs.build-context.outputs.run-ubuntu == 'true'
steps:
- - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Runner image version
@@ -663,7 +663,7 @@ jobs:
steps:
- name: Check whether the needed jobs succeeded or failed
- uses: re-actors/alls-green@05ac9388f0aebcb5727afa17fcccfecd6f8ec5fe
+ uses: re-actors/alls-green@b5b5b37504aa4183270bd3d855c52a67f212be35
with:
allowed-failures: >-
build-android,
diff --git a/.github/workflows/jit.yml b/.github/workflows/jit.yml
index 813589c2bc14c8b..36fe3fb69a7e8a6 100644
--- a/.github/workflows/jit.yml
+++ b/.github/workflows/jit.yml
@@ -32,7 +32,7 @@ jobs:
runs-on: ubuntu-26.04
timeout-minutes: 60
steps:
- - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Install dependencies
@@ -72,10 +72,10 @@ jobs:
architecture: ARM64
runner: windows-11-arm
steps:
- - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
+ - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: '3.11'
# PCbuild downloads LLVM automatically:
@@ -106,10 +106,10 @@ jobs:
- target: aarch64-apple-darwin/clang
runner: macos-26
steps:
- - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
+ - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: '3.11'
- name: Install LLVM
@@ -149,10 +149,10 @@ jobs:
- target: aarch64-unknown-linux-gnu/gcc
runner: ubuntu-26.04-arm
steps:
- - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
+ - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: '3.11'
- name: Install dependencies
@@ -190,10 +190,10 @@ jobs:
use_clang: true
run_tests: false
steps:
- - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
+ - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: '3.11'
- name: Install dependencies
diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
index 8a79ea20d5f50bc..cd413cd4cfbaa0f 100644
--- a/.github/workflows/lint.yml
+++ b/.github/workflows/lint.yml
@@ -19,7 +19,7 @@ jobs:
timeout-minutes: 10
steps:
- - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- - uses: j178/prek-action@bdca6f102f98e2b4c7029491a53dfd366469e33d # v2.0.4
+ - uses: j178/prek-action@4e14d07f9231acabce116ccfca13b13dd9755ece # v3.0.0
diff --git a/.github/workflows/mypy.yml b/.github/workflows/mypy.yml
index 3cdce4f5952e3d0..2650e7a8116804e 100644
--- a/.github/workflows/mypy.yml
+++ b/.github/workflows/mypy.yml
@@ -66,10 +66,10 @@ jobs:
"Tools/peg_generator",
]
steps:
- - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- - uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
+ - uses: astral-sh/setup-uv@bec219d24cd3e171d82865faccec33120bb574f4 # v10.1.0
with:
python-version: "3.15"
activate-environment: true
diff --git a/.github/workflows/new-bugs-announce-notifier.yml b/.github/workflows/new-bugs-announce-notifier.yml
index 864d0f48904bcc3..640474273a9de33 100644
--- a/.github/workflows/new-bugs-announce-notifier.yml
+++ b/.github/workflows/new-bugs-announce-notifier.yml
@@ -15,7 +15,7 @@ jobs:
issues: read
timeout-minutes: 10
steps:
- - uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
+ - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: 20
- run: npm install mailgun.js form-data
diff --git a/.github/workflows/require-pr-label.yml b/.github/workflows/require-pr-label.yml
index 8af254c10786e1b..05c862c59181221 100644
--- a/.github/workflows/require-pr-label.yml
+++ b/.github/workflows/require-pr-label.yml
@@ -18,7 +18,7 @@ jobs:
steps:
- name: Check there's no DO-NOT-MERGE
- uses: mheap/github-action-required-labels@0ac283b4e65c1fb28ce6079dea5546ceca98ccbe # v5.5.2
+ uses: mheap/github-action-required-labels@23e10fde7e062233401931a0eece796cd9bf3177 # v5.6.0
with:
mode: exactly
count: 0
@@ -36,7 +36,7 @@ jobs:
steps:
# Check that the PR is not awaiting changes from the author due to previous review.
- name: Check there's no required changes
- uses: mheap/github-action-required-labels@0ac283b4e65c1fb28ce6079dea5546ceca98ccbe # v5.5.2
+ uses: mheap/github-action-required-labels@23e10fde7e062233401931a0eece796cd9bf3177 # v5.6.0
with:
mode: exactly
count: 0
@@ -45,7 +45,7 @@ jobs:
awaiting change review
- id: is-feature
name: Check whether this PR is a feature (contains a "type-feature" label)
- uses: mheap/github-action-required-labels@0ac283b4e65c1fb28ce6079dea5546ceca98ccbe # v5.5.2
+ uses: mheap/github-action-required-labels@23e10fde7e062233401931a0eece796cd9bf3177 # v5.6.0
with:
mode: exactly
count: 1
@@ -56,9 +56,12 @@ jobs:
- id: awaiting-merge
if: steps.is-feature.outputs.status == 'success'
name: Check for complete review
- uses: mheap/github-action-required-labels@0ac283b4e65c1fb28ce6079dea5546ceca98ccbe # v5.5.2
+ uses: mheap/github-action-required-labels@23e10fde7e062233401931a0eece796cd9bf3177 # v5.6.0
with:
mode: exactly
count: 1
labels: |
awaiting merge
+ message: >-
+ This PR is labelled type-feature. All features require approval from a
+ core team member before merge. Found: {{ applied }}
diff --git a/.github/workflows/reusable-check-c-api-docs.yml b/.github/workflows/reusable-check-c-api-docs.yml
index db030c80008b1ed..636c960df4a086b 100644
--- a/.github/workflows/reusable-check-c-api-docs.yml
+++ b/.github/workflows/reusable-check-c-api-docs.yml
@@ -15,10 +15,10 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
+ - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: '3.x'
- name: Check for undocumented C APIs
diff --git a/.github/workflows/reusable-check-html-ids.yml b/.github/workflows/reusable-check-html-ids.yml
index 41ba1288be1ecf4..d07659c96a20b03 100644
--- a/.github/workflows/reusable-check-html-ids.yml
+++ b/.github/workflows/reusable-check-html-ids.yml
@@ -16,7 +16,7 @@ jobs:
timeout-minutes: 30
steps:
- name: 'Check out PR head'
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
ref: ${{ github.event.pull_request.head.sha }}
@@ -43,7 +43,7 @@ jobs:
MERGE_BASE: ${{ steps.merge-base.outputs.sha }}
run: git worktree add /tmp/merge-base "$MERGE_BASE" --detach
- name: 'Set up Python'
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
+ uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: '3'
cache: 'pip'
diff --git a/.github/workflows/reusable-cifuzz.yml b/.github/workflows/reusable-cifuzz.yml
index 0d02232686339bf..4a05396f3463e9f 100644
--- a/.github/workflows/reusable-cifuzz.yml
+++ b/.github/workflows/reusable-cifuzz.yml
@@ -37,13 +37,13 @@ jobs:
sanitizer: ${{ inputs.sanitizer }}
- name: Upload crash
if: failure() && steps.build.outcome == 'success'
- uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: ${{ inputs.sanitizer }}-artifacts
path: ./out/artifacts
- name: Upload SARIF
if: always() && steps.build.outcome == 'success'
- uses: github/codeql-action/upload-sarif@38697555549f1db7851b81482ff19f1fa5c4fedc # v4.34.1
+ uses: github/codeql-action/upload-sarif@b96794f015dfd88f77b49b1c93e0fa7110f94c63 # v4.38.0
with:
sarif_file: cifuzz-sarif/results.sarif
checkout_path: cifuzz-sarif
diff --git a/.github/workflows/reusable-context.yml b/.github/workflows/reusable-context.yml
index c998cbff181dd12..dedfdb3e552f2f7 100644
--- a/.github/workflows/reusable-context.yml
+++ b/.github/workflows/reusable-context.yml
@@ -73,14 +73,14 @@ jobs:
run-windows-tests: ${{ steps.changes.outputs.run-windows-tests }}
steps:
- name: Set up Python
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
+ uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: "3"
- run: >-
echo '${{ github.event_name }}'
- - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
ref: >-
diff --git a/.github/workflows/reusable-docs.yml b/.github/workflows/reusable-docs.yml
index c7f7663e3162ba2..e13c43526bc1907 100644
--- a/.github/workflows/reusable-docs.yml
+++ b/.github/workflows/reusable-docs.yml
@@ -38,7 +38,7 @@ jobs:
refspec_pr: '+${{ github.event.pull_request.head.sha }}:remotes/origin/${{ github.event.pull_request.head.ref }}'
steps:
- name: 'Check out latest PR branch commit'
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
ref: >-
@@ -63,7 +63,7 @@ jobs:
git fetch origin "${refspec_base}" --shallow-since="${DATE}" \
--no-tags --prune --no-recurse-submodules
- name: 'Set up Python'
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
+ uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: '3'
cache: 'pip'
@@ -94,7 +94,7 @@ jobs:
run: python Doc/tools/check-html-ids.py collect Doc/build/html -o Doc/build/html-ids-head.json.gz
- name: 'Upload HTML IDs'
if: github.event_name == 'pull_request'
- uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: html-ids-head
path: Doc/build/html-ids-head.json.gz
@@ -112,10 +112,10 @@ jobs:
runs-on: ubuntu-26.04
timeout-minutes: 60
steps:
- - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- - uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4
+ - uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: ~/.cache/pip
key: ubuntu-doc-${{ hashFiles('Doc/requirements.txt') }}
@@ -138,11 +138,11 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: 'Set up Python'
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
+ uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: '3'
cache: 'pip'
diff --git a/.github/workflows/reusable-emscripten.yml b/.github/workflows/reusable-emscripten.yml
index c8832342d9892da..18afdb5278a766e 100644
--- a/.github/workflows/reusable-emscripten.yml
+++ b/.github/workflows/reusable-emscripten.yml
@@ -15,7 +15,7 @@ jobs:
runs-on: ubuntu-26.04
timeout-minutes: 40
steps:
- - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: "Read Emscripten config"
@@ -41,18 +41,18 @@ jobs:
with open(os.environ["GITHUB_ENV"], "a") as f:
f.write(f"EMSDK_CACHE={emsdk_cache}\n")
- name: "Install Node.js"
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
+ uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: ${{ steps.emscripten-config.outputs.node-version }}
- name: "Cache Emscripten SDK"
id: emsdk-cache
- uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4
+ uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: ${{ env.EMSDK_CACHE }}
key: emsdk-${{ steps.emscripten-config.outputs.emscripten-version }}-${{ steps.emscripten-config.outputs.deps-hash }}
restore-keys: emsdk-${{ steps.emscripten-config.outputs.emscripten-version }}
- name: "Install Python"
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
+ uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: '3.x'
- name: "Runner image version"
diff --git a/.github/workflows/reusable-install.yml b/.github/workflows/reusable-install.yml
index 337da684882d29f..b8acf1a0fb1771e 100644
--- a/.github/workflows/reusable-install.yml
+++ b/.github/workflows/reusable-install.yml
@@ -17,7 +17,7 @@ jobs:
env:
PYTHONSTRICTEXTENSIONBUILD: 1
steps:
- - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Register gcc problem matcher
diff --git a/.github/workflows/reusable-macos.yml b/.github/workflows/reusable-macos.yml
index 5393e9e34040b95..2e6e4d6e4c69240 100644
--- a/.github/workflows/reusable-macos.yml
+++ b/.github/workflows/reusable-macos.yml
@@ -31,7 +31,7 @@ jobs:
PYTHONSTRICTEXTENSIONBUILD: 1
TERM: linux
steps:
- - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Runner image version
diff --git a/.github/workflows/reusable-san.yml b/.github/workflows/reusable-san.yml
index 449bddadf8b2c7c..7eb3ee919d2892c 100644
--- a/.github/workflows/reusable-san.yml
+++ b/.github/workflows/reusable-san.yml
@@ -30,7 +30,7 @@ jobs:
runs-on: ubuntu-26.04
timeout-minutes: 60
steps:
- - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Runner image version
@@ -75,7 +75,7 @@ jobs:
- name: 'Restore OpenSSL build (TSan)'
id: cache-openssl
if: inputs.sanitizer == 'TSan'
- uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4
+ uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: ./multissl/openssl/${{ env.OPENSSL_VER }}
key: ${{ env.IMAGE_OS_VERSION }}-multissl-openssl-tsan-${{ env.OPENSSL_VER }}
@@ -121,7 +121,7 @@ jobs:
run: find "${GITHUB_WORKSPACE}" -name 'san_log.*' | xargs head -n 1000
- name: Archive logs
if: always()
- uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: >-
${{ inputs.sanitizer }}-logs-${{
diff --git a/.github/workflows/reusable-test-lazy-imports-all.yml b/.github/workflows/reusable-test-lazy-imports-all.yml
index 3754308e89cad4b..c0851aeddc59aef 100644
--- a/.github/workflows/reusable-test-lazy-imports-all.yml
+++ b/.github/workflows/reusable-test-lazy-imports-all.yml
@@ -26,7 +26,7 @@ jobs:
env:
EXCLUDE_FILE: Lib/test/lazy_imports_all_exclude.txt
steps:
- - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Register gcc problem matcher
diff --git a/.github/workflows/reusable-ubuntu.yml b/.github/workflows/reusable-ubuntu.yml
index 97a0c22517e32ce..ba12e82218d1a53 100644
--- a/.github/workflows/reusable-ubuntu.yml
+++ b/.github/workflows/reusable-ubuntu.yml
@@ -39,7 +39,7 @@ jobs:
PYTHONSTRICTEXTENSIONBUILD: 1
TERM: linux
steps:
- - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Register gcc problem matcher
@@ -59,7 +59,7 @@ jobs:
echo "LD_LIBRARY_PATH=${GITHUB_WORKSPACE}/multissl/openssl/${OPENSSL_VER}/lib" >> "$GITHUB_ENV"
- name: 'Restore OpenSSL build'
id: cache-openssl
- uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4
+ uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: ./multissl/openssl/${{ env.OPENSSL_VER }}
key: ${{ inputs.os }}-multissl-openssl-${{ env.OPENSSL_VER }}
diff --git a/.github/workflows/reusable-wasi.yml b/.github/workflows/reusable-wasi.yml
index fd263e8aafd8f58..e4b3794346207d2 100644
--- a/.github/workflows/reusable-wasi.yml
+++ b/.github/workflows/reusable-wasi.yml
@@ -18,7 +18,7 @@ jobs:
WASMTIME_VERSION: 48.0.2
CROSS_BUILD_WASI: cross-build/wasm32-wasip1
steps:
- - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
# No problem resolver registered as one doesn't currently exist for Clang.
@@ -39,12 +39,12 @@ jobs:
shell: python
- name: "Install WASI SDK"
id: install-wasi-sdk
- uses: bytecodealliance/setup-wasi-sdk-action@b2de090b44eb70013ee96b393727d473b35e1728
+ uses: bytecodealliance/setup-wasi-sdk-action@77d09f3df1e8da344d8403cf8631af8977938b4c
with:
version: ${{ steps.wasi-sdk-version.outputs.version }}
add-to-path: false
- name: "Install Python"
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
+ uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: '3.x'
- name: "Runner image version"
diff --git a/.github/workflows/reusable-windows.yml b/.github/workflows/reusable-windows.yml
index b1b711be4538fda..4be4bc05fa6d0d1 100644
--- a/.github/workflows/reusable-windows.yml
+++ b/.github/workflows/reusable-windows.yml
@@ -31,7 +31,7 @@ jobs:
env:
ARCH: ${{ inputs.arch }}
steps:
- - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Register MSVC problem matcher
diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml
index 0283e9f621dcf05..c6094947cf98f67 100644
--- a/.github/workflows/stale.yml
+++ b/.github/workflows/stale.yml
@@ -18,7 +18,7 @@ jobs:
steps:
- name: "Check PRs"
- uses: actions/stale@b5d41d4e1d5dceea10e7104786b73624c18a190f # v10.2.0
+ uses: actions/stale@4391f3da665fdf50b6810c1a66712fb9ba21aa93 # v11.0.0
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
stale-pr-message: 'This PR is stale because it has been open for 90 days with no activity.'
diff --git a/.github/workflows/tail-call.yml b/.github/workflows/tail-call.yml
index 81e8235f236ea70..ccededfc397b369 100644
--- a/.github/workflows/tail-call.yml
+++ b/.github/workflows/tail-call.yml
@@ -36,10 +36,10 @@ jobs:
- target: aarch64-apple-darwin/clang
runner: macos-26
steps:
- - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
+ - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: '3.11'
- name: Install dependencies
@@ -75,10 +75,10 @@ jobs:
runner: ubuntu-26.04-arm
configure_flags: --with-pydebug
steps:
- - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
+ - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: '3.11'
- name: Build
diff --git a/.github/workflows/verify-ensurepip-wheels.yml b/.github/workflows/verify-ensurepip-wheels.yml
index 7def8c9e78abb8d..4d0c5d21d5def23 100644
--- a/.github/workflows/verify-ensurepip-wheels.yml
+++ b/.github/workflows/verify-ensurepip-wheels.yml
@@ -25,10 +25,10 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
+ - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: '3'
- name: Compare checksum of bundled wheels to the ones published on PyPI
diff --git a/.github/workflows/verify-expat.yml b/.github/workflows/verify-expat.yml
index b96e71b487dbe57..7a1046059e0ba89 100644
--- a/.github/workflows/verify-expat.yml
+++ b/.github/workflows/verify-expat.yml
@@ -23,7 +23,7 @@ jobs:
runs-on: ubuntu-slim
timeout-minutes: 5
steps:
- - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Download and verify bundled libexpat files
diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst
index c88c10030fb3697..58f61a06d0512c6 100644
--- a/Doc/library/argparse.rst
+++ b/Doc/library/argparse.rst
@@ -791,9 +791,9 @@ how the command-line arguments should be handled. The supplied actions are:
* ``'append'`` - This appends each argument value to a list.
It is useful for allowing an option to be specified multiple times.
- If the default value is a non-empty list, the parsed value will start
- with the default list's elements and any values from the command line
- will be appended after those default values. Example usage::
+ If the default value is a non-empty list, the parsed value for the option
+ will start with the default list's elements and any values from the
+ command line will be appended after those default values. Example usage::
>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('--foo', action='append', default=['0'])
@@ -818,12 +818,16 @@ how the command-line arguments should be handled. The supplied actions are:
value ``'+'`` or ``'*'``.
Note that when nargs_ is ``None`` (the default) or ``'?'``, each
character of the argument string will be appended to the list.
+ If the default value is a non-empty list, the parsed value for the option
+ will start with the default list's elements and any values from the
+ command line will be appended after those default values.
Example usage::
>>> parser = argparse.ArgumentParser()
- >>> parser.add_argument("--foo", action="extend", nargs="+", type=str)
+ >>> parser.add_argument("--foo", action="extend", nargs="+", type=str,
+ ... default=["d1"])
>>> parser.parse_args(["--foo", "f1", "--foo", "f2", "f3", "f4"])
- Namespace(foo=['f1', 'f2', 'f3', 'f4'])
+ Namespace(foo=['d1', 'f1', 'f2', 'f3', 'f4'])
.. versionadded:: 3.8
diff --git a/Doc/using/configure.rst b/Doc/using/configure.rst
index 88b5f35a7967967..5b1676e504a6283 100644
--- a/Doc/using/configure.rst
+++ b/Doc/using/configure.rst
@@ -95,8 +95,7 @@ Dependencies to build optional modules are:
-
- :mod:`curses`
* - `OpenSSL `_
- - | 3.0.18 recommended
- | (1.1.1 minimum)
+ - [8]_
- :mod:`ssl`, :mod:`hashlib` [6]_
* - `SQLite `_
- 3.15.2
@@ -131,6 +130,14 @@ Dependencies to build optional modules are:
See :option:`--with-builtin-hashlib-hashes` for *forcing* usage of OpenSSL.
.. [7] See :option:`--with-zlib` for choosing the backend for the
:mod:`zlib` module.
+.. [8] OpenSSL 1.1.1 is the minimum possible version to build against,
+ but the series is end-of-life and no longer receives public security
+ fixes. Use the latest patch release of a currently supported LTS
+ release series (see the `OpenSSL Roadmap
+ `__), or the package
+ provided by your operating system if available. Other libraries that
+ offer an API compatible with OpenSSL 1.1.1 or later may work, but are
+ not officially supported.
Note that the table does not include all optional modules; in particular,
platform-specific modules like :mod:`winreg` are not listed here.
diff --git a/Lib/test/test_class.py b/Lib/test/test_class.py
index 3fdc87700f99adf..0ba3956be065a8d 100644
--- a/Lib/test/test_class.py
+++ b/Lib/test/test_class.py
@@ -2,7 +2,7 @@
import unittest
from test import support
-from test.support import cpython_only, import_helper, isolation
+from test.support import cpython_only, import_helper
testmeths = [
@@ -1014,8 +1014,9 @@ class C:
C.a = X()
@support.nomemtest
- @isolation.runInSubprocess()
def test_detach_materialized_dict_no_memory(self):
+ import _testcapi
+
class A:
def __init__(self):
self.a = 1
@@ -1024,28 +1025,27 @@ def __init__(self):
# The failing allocation should be the one which detaches the
# dictionary from the object, but other allocations can happen
# first, so try to fail every one of the first allocations.
- raised = False
+ # Drop the last reference from C, so that nothing else (such as
+ # GC) runs between arming the failure and the deallocation.
+ seen = []
for n in range(20):
- a = A()
- d = a.__dict__
- try:
- with support.catch_unraisable_exception() as ex:
- with support.inject_memory_error_cm(n, n + 1):
- del a
- exc_type = ex.unraisable and ex.unraisable.exc_type
- except MemoryError:
- # The failing allocation was not in the deallocation code.
- continue
- if exc_type is not MemoryError:
- continue
- raised = True
- if "a" not in d:
- # The dictionary was cleared, as expected.
+ lst = [A()]
+ d = lst[0].__dict__
+ with support.catch_unraisable_exception() as ex:
+ _testcapi.call_with_nomemory(n, n + 1, lst.clear)
+ if ex.unraisable is None:
+ continue
+ exc_type = ex.unraisable.exc_type
+ err_msg = ex.unraisable.err_msg
+ seen.append((n, exc_type, err_msg))
+ if (exc_type is MemoryError and err_msg ==
+ 'Exception ignored while clearing an object managed dict'):
+ # The dictionary should have been cleared.
+ self.assertNotIn("a", d)
break
else:
- if not raised:
- self.fail("MemoryError was not raised during deallocation")
- self.fail("the dictionary was not cleared")
+ self.fail("MemoryError was not raised while detaching "
+ f"the dictionary: {seen}")
class DefinitionOrderTests(unittest.TestCase):
# PEP 520: Preserving Class Attribute Definition Order
diff --git a/Lib/test/test_clinic.py b/Lib/test/test_clinic.py
index c3ac61d9f5c5b41..3b440fed7f6ce8a 100644
--- a/Lib/test/test_clinic.py
+++ b/Lib/test/test_clinic.py
@@ -379,20 +379,19 @@ def test_vararg_after_star(self):
"""
self.expect_failure(block, err, lineno=6)
- def test_double_star_after_var_keyword(self):
- err = "Function 'my_test_func' has an invalid parameter declaration (**kwargs?): '**kwds: dict'"
+ def test_parameter_after_var_keyword(self):
+ err = "parameters cannot follow var-keyword parameter: 'invalid_arg: object'"
block = """
/*[clinic input]
my_test_func
- pos_arg: object
**kwds: dict
- **
+ invalid_arg: object
[clinic start generated code]*/
"""
self.expect_failure(block, err, lineno=5)
- def test_var_keyword_after_star(self):
+ def test_double_star_without_name(self):
err = "Function 'my_test_func' has an invalid parameter declaration: '**'"
block = """
/*[clinic input]
@@ -400,7 +399,6 @@ def test_var_keyword_after_star(self):
pos_arg: object
**
- **kwds: dict
[clinic start generated code]*/
"""
self.expect_failure(block, err, lineno=5)
@@ -2106,6 +2104,64 @@ def test_disallowed_grouping__no_matching_bracket(self):
err = "Function 'empty_group' has a ']' without a matching '['"
self.expect_failure(block, err)
+ def test_disallowed_grouping__varpos(self):
+ err = "cannot use optional groups with a var-positional parameter"
+ block = """
+ module foo
+ foo.bar
+ [
+ a: int
+ ]
+ *args: tuple
+ """
+ self.expect_failure(block, err, lineno=5)
+ block = """
+ module foo
+ foo.bar
+ a: int
+ *args: tuple
+ [
+ b: int
+ ]
+ """
+ self.expect_failure(block, err, lineno=4)
+
+ def test_disallowed_grouping__parameter_after_group(self):
+ # Only positional-only parameters can follow an optional group.
+ group_err = ("You cannot use optional groups ('[' and ']') unless all "
+ "parameters are positional-only ('/')")
+ kwds_err = ("cannot use a var-keyword parameter with pos-or-keyword "
+ "or keyword-only parameters")
+ dataset = (("""
+ module foo
+ foo.bar
+ [
+ a: int
+ b: int
+ ]
+ y: int
+ """, group_err), ("""
+ module foo
+ foo.bar
+ [
+ a: int
+ b: int
+ ]
+ *
+ y: int
+ """, group_err), ("""
+ module foo
+ foo.bar
+ [
+ a: int
+ b: int
+ ]
+ **kwds: dict
+ """, kwds_err))
+ for block, err in dataset:
+ with self.subTest(block=block):
+ self.expect_failure(block, err)
+
def test_disallowed_grouping__must_be_position_only(self):
dataset = ("""
with_kwds
@@ -2118,11 +2174,6 @@ def test_disallowed_grouping__must_be_position_only(self):
[
a: object
]
- """, """
- with_kwds
- [
- **kwds: dict
- ]
""")
err = (
"You cannot use optional groups ('[' and ']') unless all "
@@ -2632,38 +2683,50 @@ def test_slash_after_var_keyword(self):
block = """
module foo
foo.bar
- x: int
- y: int
**kwds: dict
- z: int
/
"""
- err = "Function 'bar' has an invalid parameter declaration (**kwargs?): '**kwds: dict'"
+ err = "parameters cannot follow var-keyword parameter: '/'"
self.expect_failure(block, err)
def test_star_after_var_keyword(self):
block = """
module foo
foo.bar
- x: int
- y: int
**kwds: dict
- z: int
*
"""
- err = "Function 'bar' has an invalid parameter declaration (**kwargs?): '**kwds: dict'"
+ err = "parameters cannot follow var-keyword parameter: '*'"
self.expect_failure(block, err)
def test_parameter_after_var_keyword(self):
block = """
module foo
foo.bar
- x: int
- y: int
**kwds: dict
z: int
"""
- err = "Function 'bar' has an invalid parameter declaration (**kwargs?): '**kwds: dict'"
+ err = "parameters cannot follow var-keyword parameter: 'z: int'"
+ self.expect_failure(block, err)
+
+ def test_group_with_var_keyword(self):
+ block = """
+ with_kwds
+ [
+ **kwds: dict
+ ]
+ """
+ err = "A var-keyword parameter cannot be in an optional group."
+ self.expect_failure(block, err)
+
+ def test_group_with_var_positional(self):
+ block = """
+ with_varpos
+ [
+ *args: tuple
+ ]
+ """
+ err = "A var-positional parameter cannot be in an optional group."
self.expect_failure(block, err)
def test_depr_star_must_come_after_slash(self):
@@ -2755,7 +2818,7 @@ def test_parameters_no_more_than_one_vararg(self):
self.expect_failure(block, err, lineno=3)
def test_parameters_no_more_than_one_var_keyword(self):
- err = "Encountered parameter line when not expecting parameters: **var_keyword_2: dict"
+ err = "parameters cannot follow var-keyword parameter: '**var_keyword_2: dict'"
block = """
module foo
foo.bar
@@ -3565,7 +3628,8 @@ def test_var_keyword_with_pos_or_kw(self):
x: int
**kwds: dict
"""
- err = "Function 'bar' has an invalid parameter declaration (**kwargs?): '**kwds: dict'"
+ err = ("Function 'bar' cannot use a var-keyword parameter with "
+ "pos-or-keyword or keyword-only parameters.")
self.expect_failure(block, err)
def test_var_keyword_with_kw_only(self):
@@ -3578,7 +3642,8 @@ def test_var_keyword_with_kw_only(self):
y: int
**kwds: dict
"""
- err = "Function 'bar' has an invalid parameter declaration (**kwargs?): '**kwds: dict'"
+ err = ("Function 'bar' cannot use a var-keyword parameter with "
+ "pos-or-keyword or keyword-only parameters.")
self.expect_failure(block, err)
def test_var_keyword_with_pos_or_kw_and_kw_only(self):
@@ -3592,7 +3657,8 @@ def test_var_keyword_with_pos_or_kw_and_kw_only(self):
z: int
**kwds: dict
"""
- err = "Function 'bar' has an invalid parameter declaration (**kwargs?): '**kwds: dict'"
+ err = ("Function 'bar' cannot use a var-keyword parameter with "
+ "pos-or-keyword or keyword-only parameters.")
self.expect_failure(block, err)
def test_allow_negative_accepted_by_py_ssize_t_converter_only(self):
diff --git a/Modules/_testcapi/mem.c b/Modules/_testcapi/mem.c
index ba1462481231b50..257568172de8b19 100644
--- a/Modules/_testcapi/mem.c
+++ b/Modules/_testcapi/mem.c
@@ -210,6 +210,39 @@ remove_mem_hooks(PyObject *self, PyObject *Py_UNUSED(ignored))
Py_RETURN_NONE;
}
+static PyObject *
+call_with_nomemory(PyObject *self, PyObject *args)
+{
+ /* Call func(*args) with memory allocation failing as in set_nomemory().
+ * No bytecode is executed between arming the failure and the call. */
+ Py_ssize_t nargs = PyTuple_GET_SIZE(args);
+ if (nargs < 3) {
+ PyErr_SetString(PyExc_TypeError,
+ "call_with_nomemory() requires at least 3 arguments");
+ return NULL;
+ }
+ int start = PyLong_AsInt(PyTuple_GET_ITEM(args, 0));
+ if (start == -1 && PyErr_Occurred()) {
+ return NULL;
+ }
+ int stop = PyLong_AsInt(PyTuple_GET_ITEM(args, 1));
+ if (stop == -1 && PyErr_Occurred()) {
+ return NULL;
+ }
+ PyObject *func = PyTuple_GET_ITEM(args, 2);
+ /* PyObject_Call() with a prebuilt tuple does not allocate,
+ * unlike PyObject_Vectorcall() for a callee without vectorcall. */
+ PyObject *callargs = PyTuple_GetSlice(args, 3, nargs);
+ if (callargs == NULL) {
+ return NULL;
+ }
+ fm_set_nomemory(start, stop);
+ PyObject *res = PyObject_Call(func, callargs, NULL);
+ fm_remove_hooks();
+ Py_DECREF(callargs);
+ return res;
+}
+
static PyObject *
test_setallocators(PyMemAllocatorDomain domain)
{
@@ -966,6 +999,8 @@ static PyMethodDef test_methods[] = {
PyDoc_STR("Remove memory hooks.")},
{"set_nomemory", set_nomemory, METH_VARARGS,
PyDoc_STR("set_nomemory(start:int, stop:int = 0)")},
+ {"call_with_nomemory", call_with_nomemory, METH_VARARGS,
+ PyDoc_STR("call_with_nomemory(start:int, stop:int, func, /, *args)")},
{"test_pymem_alloc0", test_pymem_alloc0, METH_NOARGS},
{"test_pymem_setallocators", test_pymem_setallocators, METH_NOARGS},
{"test_pymem_setrawallocators", test_pymem_setrawallocators, METH_NOARGS},
diff --git a/Parser/string_parser.c b/Parser/string_parser.c
index 20f523a262b225a..5df7ae8bec04b25 100644
--- a/Parser/string_parser.c
+++ b/Parser/string_parser.c
@@ -147,7 +147,7 @@ decode_unicode_with_escapes(Parser *parser, const char *s, size_t len, Token *t)
Py_ssize_t alloc = (Py_ssize_t)len * 6;
char *buf = PyMem_Malloc(alloc);
if (buf == NULL) {
- return NULL;
+ return PyErr_NoMemory();
}
p = buf;
end = s + len;
diff --git a/Tools/clinic/libclinic/dsl_parser.py b/Tools/clinic/libclinic/dsl_parser.py
index a798fac4f3fd096..514844af1d05b72 100644
--- a/Tools/clinic/libclinic/dsl_parser.py
+++ b/Tools/clinic/libclinic/dsl_parser.py
@@ -951,6 +951,9 @@ def state_parameter(self, line: str) -> None:
self.deprecated_until = self.parse_version(match[1], 'until')
line = match[2]
+ if not self.expecting_parameters:
+ fail(f'parameters cannot follow var-keyword parameter: {line!r}')
+
func = self.function
match line:
case '*':
@@ -967,10 +970,6 @@ def state_parameter(self, line: str) -> None:
def parse_parameter(self, line: str) -> None:
assert self.function is not None
- if not self.expecting_parameters:
- fail('Encountered parameter line when not expecting '
- f'parameters: {line}')
-
match self.parameter_state:
case ParamState.START | ParamState.REQUIRED:
self.to_required()
@@ -1021,8 +1020,9 @@ def parse_parameter(self, line: str) -> None:
for p in self.function.parameters.values()
)
if has_non_positional_param:
- fail(f"Function {self.function.name!r} has an "
- f"invalid parameter declaration (**kwargs?): {line!r}")
+ fail(f'Function {self.function.name!r} cannot use a var-keyword '
+ f'parameter with pos-or-keyword or keyword-only '
+ f'parameters.')
is_var_keyword = True
parameter = function_args.kwarg
else:
@@ -1161,8 +1161,20 @@ def bad_node(self, node: ast.AST) -> None:
kind: inspect._ParameterKind
if is_vararg:
+ if self.group_stack:
+ fail("A var-positional parameter cannot be in an optional "
+ "group.")
+ if any(p.group for p in self.function.parameters.values()):
+ # With "foo([a, b], *args)" the number of arguments does not
+ # tell whether the group is passed or all arguments belong
+ # to the var-positional parameter.
+ fail(f"Function {self.function.name!r} cannot use optional "
+ f"groups with a var-positional parameter.")
kind = inspect.Parameter.VAR_POSITIONAL
elif is_var_keyword:
+ if self.group_stack:
+ fail("A var-keyword parameter cannot be in an optional "
+ "group.")
kind = inspect.Parameter.VAR_KEYWORD
elif self.keyword_only:
kind = inspect.Parameter.KEYWORD_ONLY
@@ -1281,9 +1293,6 @@ def parse_star(self, function: Function, version: VersionTuple | None) -> None:
The 'version' parameter signifies the future version from which
the marker will take effect (None means it is already in effect).
"""
- if not self.expecting_parameters:
- fail("Encountered '*' when not expecting parameters")
-
if version is None:
self.check_previous_star()
self.check_remaining_star()
@@ -1303,6 +1312,9 @@ def parse_star(self, function: Function, version: VersionTuple | None) -> None:
def parse_opening_square_bracket(self, function: Function) -> None:
"""Parse opening parameter group symbol '['."""
+ if any(p.is_vararg() for p in function.parameters.values()):
+ fail(f"Function {function.name!r} cannot use optional groups "
+ f"with a var-positional parameter.")
# A group can only be nested in a group which does not contain
# parameters yet, but two groups on the same nesting level can
# follow each other.
@@ -1347,9 +1359,6 @@ def parse_slash(self, function: Function, version: VersionTuple | None) -> None:
The 'version' parameter signifies the future version from which
the marker will take effect (None means it is already in effect).
"""
- if not self.expecting_parameters:
- fail("Encountered '/' when not expecting parameters")
-
if version is None:
if self.deprecated_keyword:
fail(f"Function {function.name!r}: '/' must precede '/ [from ...]'")