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 ...]'")