Compare commits

...
Author SHA1 Message Date
Joe Rickerby 8d2b08b684 Bump version: v3.4.1 2026-04-02 14:57:41 +01:00
Matthieu Darbois 54b8a010d0 deprecation: cp313t (#2787)
Free-Threading Python 3.13 was experimental.
Now that Python 3.14 has been released with explicit support, we can schedule removal of Python 3.13 free-threading.
2026-04-02 14:39:47 +01:00
Henry Schreinerandpre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> 097806b6b1 tests: fully type the test suite (#2794)
* tests: fully type the test suite

* chore: require more typing

Signed-off-by: Henry Schreiner <henryfs@princeton.edu>

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

---------

Signed-off-by: Henry Schreiner <henryfs@princeton.edu>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2026-04-01 15:23:02 +01:00
Henry SchreinerandJoe Rickerby 643b30c796 fix: avoid PYTHON_VERSION breaking uv if set (#2795)
* fix: avoid PYTHON_VERSION breaking uv if set

* fix: also keep UV_PYTHON out

Signed-off-by: Henry Schreiner <henryfs@princeton.edu>

* fix: specify the python version in the uv command more often

Signed-off-by: Henry Schreiner <henryfs@princeton.edu>

* fix: revert env order change

Signed-off-by: Henry Schreiner <henryfs@princeton.edu>

* Update windows.py

Co-authored-by: Joe Rickerby <joerick@mac.com>

---------

Signed-off-by: Henry Schreiner <henryfs@princeton.edu>
Co-authored-by: Joe Rickerby <joerick@mac.com>
2026-03-28 11:28:39 -04:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> fffe2ca07d chore(deps): bump j178/prek-action from 1.1.1 to 2.0.0 in the actions group (#2802)
chore(deps): bump j178/prek-action in the actions group

Bumps the actions group with 1 update: [j178/prek-action](https://github.com/j178/prek-action).


Updates `j178/prek-action` from 1.1.1 to 2.0.0
- [Release notes](https://github.com/j178/prek-action/releases)
- [Commits](https://github.com/j178/prek-action/compare/0bb87d7f00b0c99306c8bcb8b8beba1eb581c037...79f765515bd648eb4d6bb1b17277b7cb22cb6468)

---
updated-dependencies:
- dependency-name: j178/prek-action
  dependency-version: 2.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: actions
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-28 11:28:12 -04:00
611194896a fix: zizmor "code injection via template expansion" (#2784)
* Refactor action.yml to avoid template expansion, composing command line in Python

* Remove more template expansion

* Make a string quoting that's compatible with pwsh

* Apply suggestions from code review

Co-authored-by: Matthieu Darbois <mayeut@users.noreply.github.com>

---------

Co-authored-by: Henry Schreiner <HenrySchreinerIII@gmail.com>
Co-authored-by: Matthieu Darbois <mayeut@users.noreply.github.com>
2026-03-27 11:49:38 -04:00
Henry Schreiner e478767d76 chore: remove some string types (#2798) 2026-03-27 08:43:58 -04:00
cibuildwheel-bot[bot]andcibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com> caf433b137 [Bot] Update dependencies (#2789)
Update dependencies

Co-authored-by: cibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com>
2026-03-24 23:52:21 -04:00
Henry Schreiner a257a3f789 chore: remove remaining future annotations (#2799) 2026-03-24 23:52:02 -04:00
Henry Schreiner 6df84da3e7 chore: some cleanup and checks (#2792)
* chore: clean up config a bit

* chore: add an extra check

* Apply suggestions from code review

Co-authored-by: Henry Schreiner <HenrySchreinerIII@gmail.com>
2026-03-24 23:51:49 -04:00
Agriya Khetarpal 5d52226105 ci: pin GitHub Actions + pre-commit hooks (#2744)
* Update and pin GitHub Actions

* Pin pre-commit hooks too

* adjustments (don't pin official actions)
2026-03-24 18:03:54 -04:00
Copilothenryiiicopilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
817878a5f9 feat: print selected build identifiers in preamble before build loop (#2785)
* Initial plan

* Print build identifier list in preamble before build loop

Co-authored-by: henryiii <4616906+henryiii@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: henryiii <4616906+henryiii@users.noreply.github.com>
2026-03-24 17:47:41 -04:00
Henry Schreiner cb1fdd0316 chore: use absolute imports (#2796)
chore: use abosolute imports

Signed-off-by: Henry Schreiner <henryfs@princeton.edu>
2026-03-24 09:20:41 -04:00
sedat4ras 8a2ca0ce78 docs: clarify that v3 major tag doesn't exist, minor version tags do (#2790) 2026-03-23 11:43:29 -04:00
cibuildwheel-bot[bot]andcibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com> 31f0d8a0db [Bot] Update dependencies (#2783)
Update dependencies

Co-authored-by: cibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com>
2026-03-18 06:56:31 +01:00
Joe Rickerby 35452dcd42 Add zizmor as a CI check (#2776)
* Add zizmor as a CI check

I'm curious about adding this tool, so experimenting with it here...

See #2770 for the impetus.

* Lie about a tag to see what happens

* Revert "Lie about a tag to see what happens"

This reverts commit f0e78b8c92c2d00f71d44e83d7904d8728427341.
2026-03-16 19:55:13 +00:00
Joe Rickerby 741be9402c Add GHA environment to update-dependencies workflow (#2778)
* Add GHA environment to update-dependencies workflow

See #2770

* activate the create-pull-request action to see if it works

* Revert "activate the create-pull-request action to see if it works"

This reverts commit b44f94d7a5c852b93b16157831b698f9c250628d.

* Only request the environment when we need it
2026-03-16 19:47:36 +00:00
Agriya Khetarpal a94d4faa11 Drop explicit build and virtualenv installation from Pyodide build tools (#2782) 2026-03-17 01:16:09 +05:30
Joe Rickerby fd19ae7e2f Merge branch '2.x' 2026-03-16 19:45:37 +00:00
Joe Rickerby e5486e0b83 Bump version: v2.23.4 2026-03-16 19:31:17 +00:00
ff9508a3e1 [2.x] Update virtualenv URLs to avoid blob URLs (#2775)
* [2.x] Update virtualenv URLs to avoid blob URLs

It looks like many people are hitting the HTTP 429 for old versions of cibuildwheel. These hosted versions of virtualenv should work, let's see...

* Write the correct version strings

* ci: some updates based on main branch

Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>

* ci: move to using latest images

Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>

* chore: fix up style checks

Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>

* ci: newer azure images too

Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>

* tests: use new SSL test from main

Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>

* Drop `build`'s installation from Pyodide build tools

---------

Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>
Co-authored-by: Henry Schreiner <henryschreineriii@gmail.com>
Co-authored-by: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com>
2026-03-16 19:24:46 +00:00
115 changed files with 1683 additions and 1005 deletions
+4 -4
View File
@@ -13,11 +13,11 @@ jobs:
dist: dist:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with: with:
persist-credentials: false persist-credentials: false
- uses: hynek/build-and-inspect-python-package@v2 - uses: hynek/build-and-inspect-python-package@efb823f52190ad02594531168b7a2d5790e66516 # v2.14.0
publish: publish:
needs: [dist] needs: [dist]
@@ -31,7 +31,7 @@ jobs:
attestations: write attestations: write
steps: steps:
- uses: actions/download-artifact@v8 - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with: with:
name: Packages name: Packages
path: dist path: dist
@@ -41,6 +41,6 @@ jobs:
with: with:
subject-path: "dist/cibuildwheel-*" subject-path: "dist/cibuildwheel-*"
- uses: pypa/gh-action-pypi-publish@release/v1 - uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e # v1.13.0
with: with:
attestations: true attestations: true
+34 -30
View File
@@ -39,35 +39,37 @@ jobs:
name: Linters (mypy, ruff, etc.) name: Linters (mypy, ruff, etc.)
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with: with:
persist-credentials: false persist-credentials: false
- uses: actions/setup-python@v6 - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
id: python id: python
with: with:
python-version: "3.x" python-version: "3.x"
- uses: j178/prek-action@v1 - uses: j178/prek-action@79f765515bd648eb4d6bb1b17277b7cb22cb6468 # v2.0.0
- name: PyLint checks - name: PyLint checks
run: pipx run --python "${{ steps.python.outputs.python-path }}" nox -s pylint -- --output-format=github run: pipx run --python "${STEPS_PYTHON_OUTPUTS_PYTHON_PATH}" nox -s pylint -- --output-format=github
env:
STEPS_PYTHON_OUTPUTS_PYTHON_PATH: ${{ steps.python.outputs.python-path }}
sample: sample:
name: Generate a sample project name: Generate a sample project
needs: lint needs: lint
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with: with:
persist-credentials: false persist-credentials: false
- uses: actions/setup-python@v6 - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
name: Install Python name: Install Python
with: with:
python-version: "3.x" python-version: "3.x"
- uses: astral-sh/setup-uv@v7 - uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0
- name: Install dependencies - name: Install dependencies
run: uv sync --no-dev --group test run: uv sync --no-dev --group test
- name: Generate a sample project - name: Generate a sample project
run: uv run --no-sync -m test.test_projects test.test_0_basic.basic_project sample_proj run: uv run --no-sync -m test.test_projects test.test_0_basic.basic_project sample_proj
- uses: actions/upload-artifact@v7 - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with: with:
name: sample_proj name: sample_proj
path: sample_proj path: sample_proj
@@ -117,16 +119,16 @@ jobs:
test_select: android test_select: android
timeout-minutes: 180 timeout-minutes: 180
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with: with:
persist-credentials: false persist-credentials: false
- uses: actions/setup-python@v6 - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
name: Install Python ${{ matrix.python_version }} name: Install Python ${{ matrix.python_version }}
with: with:
python-version: ${{ matrix.python_version }} python-version: ${{ matrix.python_version }}
allow-prereleases: true allow-prereleases: true
- uses: astral-sh/setup-uv@v7 - uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0
- name: Free up disk space - name: Free up disk space
if: runner.os == 'Linux' && matrix.test_select != 'android' if: runner.os == 'Linux' && matrix.test_select != 'android'
@@ -139,7 +141,7 @@ jobs:
# for oci_container unit tests # for oci_container unit tests
- name: Set up QEMU - name: Set up QEMU
if: runner.os == 'Linux' if: runner.os == 'Linux'
uses: docker/setup-qemu-action@v4 uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4.0.0
- name: Set up Xcode - name: Set up Xcode
if: ${{ startsWith(matrix.os, 'macos-15') }} if: ${{ startsWith(matrix.os, 'macos-15') }}
@@ -150,12 +152,12 @@ jobs:
- name: Install dependencies - name: Install dependencies
run: uv sync --no-dev --group test run: uv sync --no-dev --group test
- uses: joerick/pr-labels-action@v1.0.9 - uses: joerick/pr-labels-action@0543b277721e852d821c6738d449f2f4dea03d5f # v1.0.9
- name: Set CIBW_ENABLE - name: Set CIBW_ENABLE
shell: bash shell: bash
run: | run: |
if [[ "${{ github.ref_name }}" == "main" ]]; then if [[ "$GITHUB_REF_NAME" == "main" ]]; then
CIBW_ENABLE=all CIBW_ENABLE=all
else else
# get the default CIBW_ENABLE value from the test module # get the default CIBW_ENABLE value from the test module
@@ -172,7 +174,7 @@ jobs:
echo "CIBW_ENABLE=${CIBW_ENABLE}" >> $GITHUB_ENV echo "CIBW_ENABLE=${CIBW_ENABLE}" >> $GITHUB_ENV
- name: Download a sample project - name: Download a sample project
uses: actions/download-artifact@v8 uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with: with:
name: sample_proj name: sample_proj
path: sample_proj path: sample_proj
@@ -230,7 +232,7 @@ jobs:
run: | run: |
test $(find wheelhouse_only -name '*.whl' | wc -l) -eq 1 test $(find wheelhouse_only -name '*.whl' | wc -l) -eq 1
- uses: actions/upload-artifact@v7 - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with: with:
name: cibw-wheels-${{ matrix.os }}-${{ strategy.job-index }} name: cibw-wheels-${{ matrix.os }}-${{ strategy.job-index }}
path: wheelhouse/*.whl path: wheelhouse/*.whl
@@ -247,13 +249,13 @@ jobs:
outputs: outputs:
archs: ${{ steps.archs.outputs.archs }} archs: ${{ steps.archs.outputs.archs }}
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with: with:
persist-credentials: false persist-credentials: false
- uses: actions/setup-python@v6 - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with: with:
python-version: "3.x" python-version: "3.x"
- uses: astral-sh/setup-uv@v7 - uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0
- name: Install dependencies - name: Install dependencies
run: uv sync --no-dev --group test run: uv sync --no-dev --group test
- name: Get qemu emulated architectures - name: Get qemu emulated architectures
@@ -272,21 +274,23 @@ jobs:
matrix: matrix:
arch: ${{ fromJSON(needs.emulated-archs.outputs.archs) }} arch: ${{ fromJSON(needs.emulated-archs.outputs.archs) }}
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with: with:
persist-credentials: false persist-credentials: false
- uses: actions/setup-python@v6 - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with: with:
python-version: "3.x" python-version: "3.x"
- uses: astral-sh/setup-uv@v7 - uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0
- name: Install dependencies - name: Install dependencies
run: uv sync --no-dev --group test run: uv sync --no-dev --group test
- name: Set up QEMU - name: Set up QEMU
uses: docker/setup-qemu-action@v4 uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4.0.0
- name: Run the emulation tests - name: Run the emulation tests
run: uv run --no-sync pytest --run-emulation ${{ matrix.arch }} test/test_emulation.py env:
MATRIX_ARCH: ${{ matrix.arch }}
run: uv run --no-sync pytest --run-emulation "$MATRIX_ARCH" test/test_emulation.py
test-pyodide: test-pyodide:
name: Test pyodide name: Test pyodide
@@ -294,20 +298,20 @@ jobs:
runs-on: ubuntu-24.04 runs-on: ubuntu-24.04
timeout-minutes: 180 timeout-minutes: 180
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with: with:
persist-credentials: false persist-credentials: false
- uses: actions/setup-python@v6 - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
name: Install Python 3.12 name: Install Python 3.12
with: with:
python-version: '3.12' python-version: '3.12'
- uses: astral-sh/setup-uv@v7 - uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0
- name: Install dependencies - name: Install dependencies
run: uv sync --no-dev --group test run: uv sync --no-dev --group test
- name: Download a sample project - name: Download a sample project
uses: actions/download-artifact@v8 uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with: with:
name: sample_proj name: sample_proj
path: sample_proj path: sample_proj
@@ -344,11 +348,11 @@ jobs:
- os: macos-15 - os: macos-15
test_select: android test_select: android
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with: with:
persist-credentials: false persist-credentials: false
- name: Download a sample project - name: Download a sample project
uses: actions/download-artifact@v8 uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with: with:
name: sample_proj name: sample_proj
path: sample_proj path: sample_proj
+5 -4
View File
@@ -23,22 +23,23 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions: permissions:
contents: write contents: write
environment: ${{ github.ref == 'refs/heads/main' && github.repository == 'pypa/cibuildwheel' && 'update-dependencies-workflow' || '' }}
steps: steps:
# we use this step to grab a Github App auth token, so that PRs generated by this workflow # we use this step to grab a Github App auth token, so that PRs generated by this workflow
# run the GHA tests. # run the GHA tests.
- uses: actions/create-github-app-token@v2 - uses: actions/create-github-app-token@f8d387b68d61c58ab83c6c016672934102569859 # v3.0.0
id: generate-token id: generate-token
if: github.ref == 'refs/heads/main' && github.repository == 'pypa/cibuildwheel' if: github.ref == 'refs/heads/main' && github.repository == 'pypa/cibuildwheel'
with: with:
app-id: ${{ secrets.CIBUILDWHEEL_BOT_APP_ID }} app-id: ${{ secrets.CIBUILDWHEEL_BOT_APP_ID }}
private-key: ${{ secrets.CIBUILDWHEEL_BOT_APP_PRIVATE_KEY }} private-key: ${{ secrets.CIBUILDWHEEL_BOT_APP_PRIVATE_KEY }}
- uses: actions/checkout@v6 - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with: with:
persist-credentials: false persist-credentials: false
- uses: wntrblm/nox@2026.02.09 - uses: wntrblm/nox@5a277b752f6094150e25237d47c34168e2b7526e # 2026.02.09
- name: "Run update: dependencies" - name: "Run update: dependencies"
run: nox --force-color -s update_constraints run: nox --force-color -s update_constraints
@@ -49,7 +50,7 @@ jobs:
- name: Create Pull Request - name: Create Pull Request
if: github.ref == 'refs/heads/main' && github.repository == 'pypa/cibuildwheel' if: github.ref == 'refs/heads/main' && github.repository == 'pypa/cibuildwheel'
uses: peter-evans/create-pull-request@v8 uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 # v8.1.0
with: with:
commit-message: Update dependencies commit-message: Update dependencies
title: '[Bot] Update dependencies' title: '[Bot] Update dependencies'
+2 -2
View File
@@ -21,12 +21,12 @@ jobs:
permissions: permissions:
contents: write contents: write
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with: with:
persist-credentials: false persist-credentials: false
- name: Update the ${{ env.TAG_NAME }} tag - name: Update the ${{ env.TAG_NAME }} tag
id: update-major-minor-tag id: update-major-minor-tag
uses: joerick/update-vX.Y-tag-action@v1.0 uses: joerick/update-vX.Y-tag-action@c4cefb60c33b82e4aa73a469e4acf30ee48d5812 # v1.0.2
with: with:
source-tag: ${{ env.TAG_NAME }} source-tag: ${{ env.TAG_NAME }}
+24
View File
@@ -0,0 +1,24 @@
name: zizmor - GitHub Actions Security Analysis
on:
push:
branches: ["main"]
pull_request:
branches: ["**"]
permissions: {}
jobs:
zizmor:
name: Run zizmor 🌈
runs-on: ubuntu-latest
permissions:
security-events: write
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Run zizmor 🌈
uses: zizmorcore/zizmor-action@71321a20a9ded102f6e9ce5718a2fcec2c4f70d8 # v0.5.2
+7
View File
@@ -112,3 +112,10 @@ site/
# PyCharm # PyCharm
.idea/ .idea/
# Lockfiles
*.lock
*.pylock
# OS files
.DS_Store
+8 -9
View File
@@ -3,7 +3,7 @@ ci:
repos: repos:
- repo: https://github.com/pre-commit/pre-commit-hooks - repo: https://github.com/pre-commit/pre-commit-hooks
rev: v6.0.0 rev: 3e8a8703264a2f4a69428a0aa4dcb512790b2c8c # frozen: v6.0.0
hooks: hooks:
- id: check-case-conflict - id: check-case-conflict
- id: check-merge-conflict - id: check-merge-conflict
@@ -16,14 +16,14 @@ repos:
- id: trailing-whitespace - id: trailing-whitespace
- repo: https://github.com/astral-sh/ruff-pre-commit - repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.15.5 rev: 4924b0e01e032fea073ad04a1c5cfa7e4add0afb # frozen: v0.15.6
hooks: hooks:
- id: ruff-check - id: ruff-check
args: ["--fix", "--show-fixes"] args: ["--fix"]
- id: ruff-format - id: ruff-format
- repo: https://github.com/pre-commit/mirrors-mypy - repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.19.1 rev: a66e98df7b4aeeb3724184b332785976d062b92e # frozen: v1.19.1
hooks: hooks:
- id: mypy - id: mypy
name: mypy 3.11 on cibuildwheel/ name: mypy 3.11 on cibuildwheel/
@@ -56,7 +56,7 @@ repos:
additional_dependencies: *mypy-dependencies additional_dependencies: *mypy-dependencies
- repo: https://github.com/shellcheck-py/shellcheck-py - repo: https://github.com/shellcheck-py/shellcheck-py
rev: v0.11.0.1 rev: 745eface02aef23e168a8afb6b5737818efbea95 # frozen: v0.11.0.1
hooks: hooks:
- id: shellcheck - id: shellcheck
@@ -77,7 +77,7 @@ repos:
additional_dependencies: [cogapp>=3.5] additional_dependencies: [cogapp>=3.5]
- repo: https://github.com/codespell-project/codespell - repo: https://github.com/codespell-project/codespell
rev: v2.4.2 rev: 2ccb47ff45ad361a21071a7eedda4c37e6ae8c5a # frozen: v2.4.2
hooks: hooks:
- id: codespell - id: codespell
args: ["-w"] args: ["-w"]
@@ -85,14 +85,13 @@ repos:
- repo: https://github.com/python-jsonschema/check-jsonschema - repo: https://github.com/python-jsonschema/check-jsonschema
rev: 0.37.0 rev: 9f48a48aa91a6040d749ad68ec70907d907a5a7f # frozen: 0.37.0
hooks: hooks:
- id: check-dependabot - id: check-dependabot
- id: check-github-actions - id: check-github-actions
- id: check-github-workflows - id: check-github-workflows
- id: check-gitlab-ci - id: check-gitlab-ci
# Disabled due to schema issue for now: - id: check-readthedocs
# - id: check-readthedocs
- id: check-travis - id: check-travis
- id: check-jsonschema - id: check-jsonschema
name: Check projects name: Check projects
+12 -13
View File
@@ -99,7 +99,7 @@ jobs:
- uses: actions/setup-python@v6 - uses: actions/setup-python@v6
- name: Install cibuildwheel - name: Install cibuildwheel
run: python -m pip install cibuildwheel==3.4.0 run: python -m pip install cibuildwheel==3.4.1
- name: Build wheels - name: Build wheels
run: python -m cibuildwheel --output-dir wheelhouse run: python -m cibuildwheel --output-dir wheelhouse
@@ -235,6 +235,16 @@ Changelog
<!-- [[[cog from readme_changelog import mini_changelog; print(mini_changelog()) ]]] --> <!-- [[[cog from readme_changelog import mini_changelog; print(mini_changelog()) ]]] -->
### v3.4.1
_2 April 2026_
- ⚠️ Building for the experimental CPython 3.13 free-threading variant is now deprecated. That functionality will be removed in the next minor release. The [`enable`](https://cibuildwheel.pypa.io/en/stable/options/#enable) option `cpython-freethreading` is therefore also deprecated. Builds specifying `enable = "all"` no longer select `cpython-freethreading`. CPython 3.14 free-threading support remains available without the `enable` flag. (#2787)
- 🐛 iOS builds will no longer skip `repair-wheel-command` if it's defined in config (#2761)
- 🐛 Fix bug causing `uv` to fail when environments define PYTHON_VERSION or UV_PYTHON, conflicting with our venvs (#2795)
- ✨ cibuildwheel prints the selected build identifiers at the start of the build. (#2785)
- 🔐 The GitHub Action now references other actions with a full SHA (#2744)
### v3.4.0 ### v3.4.0
_5 March 2026_ _5 March 2026_
@@ -274,18 +284,7 @@ _12 October 2025_
- 🐛 Fix the default MACOSX_DEPLOYMENT_TARGET on Python 3.14 (#2613) - 🐛 Fix the default MACOSX_DEPLOYMENT_TARGET on Python 3.14 (#2613)
- 📚 Docs improvements (#2617) - 📚 Docs improvements (#2617)
### v3.2.0 <!-- [[[end]]] (sum: NOLMd9iLDC) -->
_22 September 2025_
- ✨ Adds GraalPy v25 (Python 3.12) support (#2597)
- 🛠 Update to CPython 3.14.0rc3 (#2602)
- 🛠 Adds CPython 3.14.0 prerelease support for Android, and a number of improvements to Android builds (#2568, #2591)
- 🛠 Improvements to testing on Android, passing environment markers when installing the venv, and providing more debug output when build-verbosity is set (#2575)
- ⚠️ PyPy 3.10 was moved to `pypy-eol` in the `enable` option, as it is now end-of-life. (#2521)
- 📚 Docs improvements (#2574, #2601, #2598)
<!-- [[[end]]] (sum: aO1wNWSgKa) -->
--- ---
+46 -20
View File
@@ -36,9 +36,10 @@ runs:
- id: cibw - id: cibw
run: | run: |
# Install cibuildwheel # Install cibuildwheel and build the command line
"${{ steps.python.outputs.python-path }}" -u << "EOF" "$PYTHON" -u << "EOF"
import os import os
import shlex
import shutil import shutil
import sys import sys
import venv import venv
@@ -46,7 +47,7 @@ runs:
from pathlib import Path from pathlib import Path
from subprocess import run from subprocess import run
EXTRAS = set(e.strip() for e in "${{ inputs.extras }}".split(",") if e.strip()) EXTRAS = set(e.strip() for e in os.environ.get("INPUT_EXTRAS", "").split(",") if e.strip())
class EnvBuilder(venv.EnvBuilder): class EnvBuilder(venv.EnvBuilder):
@@ -59,14 +60,14 @@ runs:
def post_setup(self, context): def post_setup(self, context):
super().post_setup(context) super().post_setup(context)
self.bin_path = Path(context.env_exe).parent self.bin_path = Path(context.env_exe).parent
install_spec = r"${{ github.action_path }}" install_spec = os.environ["GITHUB_ACTION_PATH"]
if EXTRAS: if EXTRAS:
install_spec += f"[{','.join(sorted(EXTRAS))}]" install_spec += f"[{','.join(sorted(EXTRAS))}]"
run([sys.executable, "-m", "pip", "--python", context.env_exe, "install", install_spec], check=True) run([sys.executable, "-m", "pip", "--python", context.env_exe, "install", install_spec], check=True)
print("::group::Install cibuildwheel") print("::group::Install cibuildwheel")
venv_path = Path(r"${{ runner.temp }}") / "cibw" venv_path = Path(os.environ["RUNNER_TEMP"]) / "cibw"
if venv_path.exists(): if venv_path.exists():
shutil.rmtree(venv_path) shutil.rmtree(venv_path)
@@ -88,34 +89,59 @@ runs:
cibw_bin = [p for p in builder.bin_path.glob("cibuildwheel*") if p.stem == "cibuildwheel"][0] cibw_bin = [p for p in builder.bin_path.glob("cibuildwheel*") if p.stem == "cibuildwheel"][0]
# Build the command line
cmd_args = [str(cibw_bin), os.environ["INPUT_PACKAGE_DIR"]]
if output_dir := os.environ.get("INPUT_OUTPUT_DIR"):
cmd_args += ["--output-dir", output_dir]
if config_file := os.environ.get("INPUT_CONFIG_FILE"):
cmd_args += ["--config-file", config_file]
if only := os.environ.get("INPUT_ONLY"):
cmd_args += ["--only", only]
cmd_bash = shlex.join(cmd_args)
def pwsh_quote(text):
# Wrap in single quotes and double-up any existing single quotes
return "'" + str(text).replace("'", "''") + "'"
# Prepend '& ' so PowerShell executes the quoted binary path
cmd_pwsh = "& " + " ".join(pwsh_quote(arg) for arg in cmd_args)
with open(os.environ["GITHUB_OUTPUT"], "at") as f: with open(os.environ["GITHUB_OUTPUT"], "at") as f:
f.write(f"cibw-bin={cibw_bin}\n")
f.write(f"prepend-path={clean_bin_path}\n") f.write(f"prepend-path={clean_bin_path}\n")
f.write(f"cmd-bash={cmd_bash}\n")
f.write(f"cmd-pwsh={cmd_pwsh}\n")
print("::endgroup::") print("::endgroup::")
EOF EOF
shell: bash shell: bash
env:
PYTHON: ${{ steps.python.outputs.python-path }}
INPUT_PACKAGE_DIR: ${{ inputs.package-dir }}
INPUT_OUTPUT_DIR: ${{ inputs.output-dir }}
INPUT_CONFIG_FILE: ${{ inputs.config-file }}
INPUT_ONLY: ${{ inputs.only }}
INPUT_EXTRAS: ${{ inputs.extras }}
# Redirecting stderr to stdout to fix interleaving issue in Actions. # Redirecting stderr to stdout to fix interleaving issue in Actions.
- run: | - run: |
export PATH="${{ steps.cibw.outputs.prepend-path }}:$PATH" export PATH="$CIBW_PREPEND_PATH:$PATH"
eval "$CIBW_CMD_BASH" 2>&1
"${{ steps.cibw.outputs.cibw-bin }}" \
"${{ inputs.package-dir }}" \
${{ inputs.output-dir != '' && format('--output-dir "{0}"', inputs.output-dir) || ''}} \
${{ inputs.config-file != '' && format('--config-file "{0}"', inputs.config-file) || ''}} \
${{ inputs.only != '' && format('--only "{0}"', inputs.only) || ''}} \
2>&1
shell: bash shell: bash
if: runner.os != 'Windows' if: runner.os != 'Windows'
env:
CIBW_PREPEND_PATH: ${{ steps.cibw.outputs.prepend-path }}
CIBW_CMD_BASH: ${{ steps.cibw.outputs.cmd-bash }}
# Windows needs powershell to interact nicely with Meson # Windows needs powershell to interact nicely with Meson
- run: | - run: |
$env:PATH = "${{ steps.cibw.outputs.prepend-path }};$env:PATH" $env:PATH = "$env:CIBW_PREPEND_PATH;$env:PATH"
& "${{ steps.cibw.outputs.cibw-bin }}" ` Invoke-Expression $env:CIBW_CMD_PWSH
"${{ inputs.package-dir }}" `
${{ inputs.output-dir != '' && format('--output-dir "{0}"', inputs.output-dir) || ''}} `
${{ inputs.config-file != '' && format('--config-file "{0}"', inputs.config-file) || ''}} `
${{ inputs.only != '' && format('--only "{0}"', inputs.only) || ''}}
shell: pwsh shell: pwsh
if: runner.os == 'Windows' if: runner.os == 'Windows'
env:
CIBW_PREPEND_PATH: ${{ steps.cibw.outputs.prepend-path }}
CIBW_CMD_PWSH: ${{ steps.cibw.outputs.cmd-pwsh }}
+1 -1
View File
@@ -1 +1 @@
__version__ = "3.4.0" __version__ = "3.4.1"
+13 -7
View File
@@ -15,7 +15,6 @@ from tempfile import mkdtemp
from typing import Any, Literal, TextIO from typing import Any, Literal, TextIO
import cibuildwheel import cibuildwheel
import cibuildwheel.util
from cibuildwheel import errors from cibuildwheel import errors
from cibuildwheel.architecture import Architecture, allowed_architectures_check from cibuildwheel.architecture import Architecture, allowed_architectures_check
from cibuildwheel.ci import CIProvider, detect_ci_provider, fix_ansi_codes_for_github_actions from cibuildwheel.ci import CIProvider, detect_ci_provider, fix_ansi_codes_for_github_actions
@@ -53,7 +52,7 @@ class Unbuffered:
self.stream.writelines(data) self.stream.writelines(data)
self.stream.flush() self.stream.flush()
def __getattr__(self, attr: str) -> Any: def __getattr__(self, attr: str) -> Any: # noqa: ANN401
return getattr(self.stream, attr) return getattr(self.stream, attr)
@@ -432,17 +431,17 @@ def print_preamble(platform: str, options: Options, identifiers: Sequence[str])
msg = "\n".join(error_list) msg = "\n".join(error_list)
raise errors.ConfigurationError(msg) raise errors.ConfigurationError(msg)
n = len(identifiers)
print(f"{n} build{'s' if n != 1 else ''} selected:")
print(", ".join(identifiers))
print()
print("Here we go!\n") print("Here we go!\n")
def detect_errors(*, options: Options, identifiers: Iterable[str]) -> Generator[str, None, None]: def detect_errors(*, options: Options, identifiers: Iterable[str]) -> Generator[str, None, None]:
# Check for deprecated CIBW_FREE_THREADED_SUPPORT environment variable # Check for deprecated CIBW_FREE_THREADED_SUPPORT environment variable
if "CIBW_FREE_THREADED_SUPPORT" in os.environ: if "CIBW_FREE_THREADED_SUPPORT" in os.environ:
yield ( yield "CIBW_FREE_THREADED_SUPPORT environment variable is no longer supported."
"CIBW_FREE_THREADED_SUPPORT environment variable is no longer supported. "
'Use tool.cibuildwheel.enable = ["cpython-freethreading"] in pyproject.toml '
"or set CIBW_ENABLE=cpython-freethreading instead."
)
# Deprecated {python} and {pip} # Deprecated {python} and {pip}
for option_name in ["test_command", "before_build"]: for option_name in ["test_command", "before_build"]:
@@ -469,6 +468,13 @@ def detect_warnings(*, options: Options) -> Generator[str, None, None]:
build_selector = options.globals.build_selector build_selector = options.globals.build_selector
test_selector = options.globals.test_selector test_selector = options.globals.test_selector
if EnableGroup.CPythonFreeThreading in build_selector.enable:
yield (
"'cpython-freethreading' enable is deprecated and will be removed in a future version. "
"It should be removed from tool.cibuildwheel.enable in pyproject.toml "
"or CIBW_ENABLE environment variable."
)
all_valid_identifiers = [ all_valid_identifiers = [
config.identifier config.identifier
for module in ALL_PLATFORM_MODULES.values() for module in ALL_PLATFORM_MODULES.values()
+49 -50
View File
@@ -6,11 +6,10 @@ import sys
import typing import typing
from collections.abc import Set from collections.abc import Set
from enum import StrEnum, auto from enum import StrEnum, auto
from typing import Final, Literal from typing import Final, Literal, Self
from cibuildwheel import errors from cibuildwheel import errors
from cibuildwheel.typing import PlatformName
from .typing import PlatformName
PRETTY_NAMES: Final[dict[PlatformName, str]] = { PRETTY_NAMES: Final[dict[PlatformName, str]] = {
"linux": "Linux", "linux": "Linux",
@@ -83,34 +82,34 @@ class Architecture(StrEnum):
arm64_iphonesimulator = auto() arm64_iphonesimulator = auto()
x86_64_iphonesimulator = auto() x86_64_iphonesimulator = auto()
@staticmethod @classmethod
def parse_config(config: str, platform: PlatformName) -> "set[Architecture]": def parse_config(cls, config: str, platform: PlatformName) -> set[Self]:
result = set() result = set()
for arch_str in re.split(r"[\s,]+", config): for arch_str in re.split(r"[\s,]+", config):
match arch_str: match arch_str:
case "auto": case "auto":
result |= Architecture.auto_archs(platform=platform) result |= cls.auto_archs(platform=platform)
case "native": case "native":
if native_arch := Architecture.native_arch(platform=platform): if native_arch := cls.native_arch(platform=platform):
result.add(native_arch) result.add(native_arch)
case "all": case "all":
result |= Architecture.all_archs(platform=platform) result |= cls.all_archs(platform=platform)
case "auto64": case "auto64":
result |= Architecture.bitness_archs(platform=platform, bitness="64") result |= cls.bitness_archs(platform=platform, bitness="64")
case "auto32": case "auto32":
result |= Architecture.bitness_archs(platform=platform, bitness="32") result |= cls.bitness_archs(platform=platform, bitness="32")
case _: case _:
try: try:
result.add(Architecture(arch_str)) result.add(cls(arch_str))
except ValueError as e: except ValueError as e:
msg = f"Invalid architecture '{arch_str}'" msg = f"Invalid architecture '{arch_str}'"
raise errors.ConfigurationError(msg) from e raise errors.ConfigurationError(msg) from e
return result return result
@staticmethod @classmethod
def native_arch(platform: PlatformName) -> "Architecture | None": def native_arch(cls, platform: PlatformName) -> Self | None:
native_machine = platform_module.machine() native_machine = platform_module.machine()
native_architecture = Architecture(native_machine) native_architecture = cls(native_machine)
# Cross-platform support. Used for --print-build-identifiers or docker builds. # Cross-platform support. Used for --print-build-identifiers or docker builds.
host_platform: PlatformName = ( host_platform: PlatformName = (
@@ -120,15 +119,15 @@ class Architecture(StrEnum):
) )
if platform == "pyodide": if platform == "pyodide":
return Architecture.wasm32 return cls.wasm32
elif platform == "ios": elif platform == "ios":
# Can only build for iOS on macOS. The "native" architecture is the # Can only build for iOS on macOS. The "native" architecture is the
# simulator for the macOS native platform. # simulator for the macOS native platform.
if host_platform == "macos": if host_platform == "macos":
if native_architecture == Architecture.x86_64: if native_architecture == cls.x86_64:
return Architecture.x86_64_iphonesimulator return cls.x86_64_iphonesimulator
else: else:
return Architecture.arm64_iphonesimulator return cls.arm64_iphonesimulator
else: else:
return None return None
@@ -140,64 +139,64 @@ class Architecture(StrEnum):
# can't build anything on this platform # can't build anything on this platform
return None return None
native_architecture = Architecture(synonym) native_architecture = cls(synonym)
return native_architecture return native_architecture
@staticmethod @classmethod
def auto_archs(platform: PlatformName) -> "set[Architecture]": def auto_archs(cls, platform: PlatformName) -> set[Self]:
native_arch = Architecture.native_arch(platform) native_arch = cls.native_arch(platform)
if native_arch is None: if native_arch is None:
return set() # can't build anything on this platform return set() # can't build anything on this platform
result = {native_arch} result = {native_arch}
match platform: match platform:
case "windows" if Architecture.AMD64 in result: case "windows" if cls.AMD64 in result:
result.add(Architecture.x86) result.add(cls.x86)
case "ios" if native_arch == Architecture.arm64_iphonesimulator: case "ios" if native_arch == cls.arm64_iphonesimulator:
# Also build the device wheel if we're on ARM64. # Also build the device wheel if we're on ARM64.
result.add(Architecture.arm64_iphoneos) result.add(cls.arm64_iphoneos)
return result return result
@staticmethod @classmethod
def all_archs(platform: PlatformName) -> "set[Architecture]": def all_archs(cls, platform: PlatformName) -> set[Self]:
all_archs_map = { all_archs_map = {
"linux": { "linux": {
Architecture.x86_64, cls.x86_64,
Architecture.i686, cls.i686,
Architecture.aarch64, cls.aarch64,
Architecture.ppc64le, cls.ppc64le,
Architecture.s390x, cls.s390x,
Architecture.armv7l, cls.armv7l,
Architecture.riscv64, cls.riscv64,
}, },
"macos": {Architecture.x86_64, Architecture.arm64, Architecture.universal2}, "macos": {cls.x86_64, cls.arm64, cls.universal2},
"windows": {Architecture.x86, Architecture.AMD64, Architecture.ARM64}, "windows": {cls.x86, cls.AMD64, cls.ARM64},
"pyodide": {Architecture.wasm32}, "pyodide": {cls.wasm32},
"android": {Architecture.x86_64, Architecture.arm64_v8a}, "android": {cls.x86_64, cls.arm64_v8a},
"ios": { "ios": {
Architecture.x86_64_iphonesimulator, cls.x86_64_iphonesimulator,
Architecture.arm64_iphonesimulator, cls.arm64_iphonesimulator,
Architecture.arm64_iphoneos, cls.arm64_iphoneos,
}, },
} }
return all_archs_map[platform] return all_archs_map[platform]
@staticmethod @classmethod
def bitness_archs(platform: PlatformName, bitness: Literal["64", "32"]) -> "set[Architecture]": def bitness_archs(cls, platform: PlatformName, bitness: Literal["64", "32"]) -> set[Self]:
# This map maps 64-bit architectures to their 32-bit equivalents. # This map maps 64-bit architectures to their 32-bit equivalents.
archs_map = { archs_map = {
Architecture.x86_64: Architecture.i686, cls.x86_64: cls.i686,
Architecture.AMD64: Architecture.x86, cls.AMD64: cls.x86,
Architecture.aarch64: Architecture.armv7l, cls.aarch64: cls.armv7l,
} }
native_arch = Architecture.native_arch(platform) native_arch = cls.native_arch(platform)
if native_arch is None: if native_arch is None:
return set() # can't build anything on this platform return set() # can't build anything on this platform
if native_arch == Architecture.wasm32: if native_arch == cls.wasm32:
return {native_arch} if bitness == "32" else set() return {native_arch} if bitness == "32" else set()
match bitness: match bitness:
@@ -207,7 +206,7 @@ class Architecture(StrEnum):
if native_arch in archs_map.values(): if native_arch in archs_map.values():
return {native_arch} return {native_arch}
elif native_arch in archs_map and platform in {"linux", "windows"}: elif native_arch in archs_map and platform in {"linux", "windows"}:
if native_arch == Architecture.aarch64 and not _check_aarch32_el0(): if native_arch == cls.aarch64 and not _check_aarch32_el0():
# If we're on aarch64, skip if we cannot build armv7l wheels. # If we're on aarch64, skip if we cannot build armv7l wheels.
return set() return set()
return {archs_map[native_arch]} return {archs_map[native_arch]}
+1 -1
View File
@@ -2,7 +2,7 @@ import os
import re import re
from enum import Enum from enum import Enum
from .util.helpers import strtobool from cibuildwheel.util.helpers import strtobool
ANSI_CODE_REGEX = re.compile(r"(\033\[[0-9;]*m)") ANSI_CODE_REGEX = re.compile(r"(\033\[[0-9;]*m)")
+2 -2
View File
@@ -5,7 +5,7 @@ from typing import Any, Protocol
import bashlex import bashlex
import bashlex.errors import bashlex.errors
from . import bashlex_eval from cibuildwheel import bashlex_eval
class EnvironmentParseError(Exception): class EnvironmentParseError(Exception):
@@ -131,7 +131,7 @@ class ParsedEnvironment:
def __repr__(self) -> str: def __repr__(self) -> str:
return f"{self.__class__.__name__}({[repr(a) for a in self.assignments]!r})" return f"{self.__class__.__name__}({[repr(a) for a in self.assignments]!r})"
def options_summary(self) -> Any: def options_summary(self) -> list[EnvironmentAssignment]:
return self.assignments return self.assignments
+1 -1
View File
@@ -62,7 +62,7 @@ def github_api_request(path: str, *, max_retries: int = 3) -> dict[str, Any]:
# pylint: disable=E1101 # pylint: disable=E1101
if ( if (
isinstance(e, urllib.error.HTTPError) isinstance(e, urllib.error.HTTPError)
and (e.code == 403 or e.code == 429) and (e.code in {403, 429})
and e.headers.get("x-ratelimit-remaining") == "0" and e.headers.get("x-ratelimit-remaining") == "0"
): ):
reset_time = int(e.headers.get("x-ratelimit-reset", 0)) reset_time = int(e.headers.get("x-ratelimit-reset", 0))
+2 -2
View File
@@ -4,8 +4,8 @@ import typing
from collections.abc import Sequence from collections.abc import Sequence
from typing import Literal, Self, get_args from typing import Literal, Self, get_args
from .logger import log from cibuildwheel.logger import log
from .util.helpers import parse_key_value_string from cibuildwheel.util.helpers import parse_key_value_string
BuildFrontendName = Literal["pip", "build", "build[uv]", "uv"] BuildFrontendName = Literal["pip", "build", "build[uv]", "uv"]
+2 -2
View File
@@ -15,10 +15,10 @@ from typing import IO, TYPE_CHECKING, AnyStr, Final, Literal
import humanize import humanize
from .ci import CIProvider, detect_ci_provider, filter_ansi_codes from cibuildwheel.ci import CIProvider, detect_ci_provider, filter_ansi_codes
if TYPE_CHECKING: if TYPE_CHECKING:
from .options import Options from cibuildwheel.options import Options
FoldPattern = tuple[str, str] FoldPattern = tuple[str, str]
DEFAULT_FOLD_PATTERN: Final[FoldPattern] = ("{name}", "") DEFAULT_FOLD_PATTERN: Final[FoldPattern] = ("{name}", "")
+7 -7
View File
@@ -16,12 +16,12 @@ from pathlib import Path, PurePath, PurePosixPath
from types import TracebackType from types import TracebackType
from typing import IO, Literal, Self, assert_never from typing import IO, Literal, Self, assert_never
from .ci import CIProvider, detect_ci_provider from cibuildwheel.ci import CIProvider, detect_ci_provider
from .errors import OCIEngineTooOldError from cibuildwheel.errors import OCIEngineTooOldError
from .logger import log from cibuildwheel.logger import log
from .typing import PathOrStr from cibuildwheel.typing import PathOrStr
from .util.cmd import call from cibuildwheel.util.cmd import call
from .util.helpers import FlexibleVersion, parse_key_value_string, strtobool from cibuildwheel.util.helpers import FlexibleVersion, parse_key_value_string, strtobool
ContainerEngineName = Literal["docker", "podman"] ContainerEngineName = Literal["docker", "podman"]
@@ -37,7 +37,7 @@ class OCIPlatform(Enum):
S390X = "linux/s390x" S390X = "linux/s390x"
@classmethod @classmethod
def native(cls) -> "OCIPlatform": def native(cls) -> Self:
"""Return the current OCI platform, or raise ValueError if unknown.""" """Return the current OCI platform, or raise ValueError if unknown."""
arch = platform.machine().lower() arch = platform.machine().lower()
mapping = { mapping = {
+17 -15
View File
@@ -14,18 +14,18 @@ from typing import Any, Final, Literal, Self, assert_never
from packaging.specifiers import SpecifierSet from packaging.specifiers import SpecifierSet
from . import errors from cibuildwheel import errors
from .architecture import Architecture from cibuildwheel.architecture import Architecture
from .environment import EnvironmentParseError, ParsedEnvironment, parse_environment from cibuildwheel.environment import EnvironmentParseError, ParsedEnvironment, parse_environment
from .frontend import BuildFrontendConfig from cibuildwheel.frontend import BuildFrontendConfig
from .logger import log from cibuildwheel.logger import log
from .oci_container import OCIContainerEngineConfig from cibuildwheel.oci_container import OCIContainerEngineConfig
from .projectfiles import get_requires_python_str, resolve_dependency_groups from cibuildwheel.projectfiles import get_requires_python_str, resolve_dependency_groups
from .selector import BuildSelector, EnableGroup, TestSelector, selector_matches from cibuildwheel.selector import BuildSelector, EnableGroup, TestSelector, selector_matches
from .typing import PLATFORMS, PlatformName from cibuildwheel.typing import PLATFORMS, PlatformName
from .util import resources from cibuildwheel.util import resources
from .util.helpers import format_safe, parse_key_value_string, strtobool, unwrap from cibuildwheel.util.helpers import format_safe, parse_key_value_string, strtobool, unwrap
from .util.packaging import DependencyConstraints from cibuildwheel.util.packaging import DependencyConstraints
MANYLINUX_ARCHS: Final[tuple[str, ...]] = ( MANYLINUX_ARCHS: Final[tuple[str, ...]] = (
"x86_64", "x86_64",
@@ -686,6 +686,8 @@ class Options:
skip_config = "" skip_config = ""
architectures = Architecture.all_archs(self.platform) architectures = Architecture.all_archs(self.platform)
enable |= EnableGroup.all_groups() enable |= EnableGroup.all_groups()
if args.only.startswith("cp313t-"):
enable.add(EnableGroup.CPythonFreeThreading)
build_selector = BuildSelector( build_selector = BuildSelector(
build_config=build_config, build_config=build_config,
@@ -987,8 +989,8 @@ class Options:
def option_summary( def option_summary(
self, self,
option_name: str, option_name: str,
option_value: Any, option_value: Any, # noqa: ANN401
default_value: Any, default_value: Any, # noqa: ANN401
overrides: Mapping[str, Any] | None = None, overrides: Mapping[str, Any] | None = None,
skip_unset: bool = False, skip_unset: bool = False,
) -> str | None: ) -> str | None:
@@ -1040,7 +1042,7 @@ class Options:
return value return value
@staticmethod @staticmethod
def option_summary_value(option_value: Any) -> str: def option_summary_value(option_value: Any) -> str: # noqa: ANN401
if hasattr(option_value, "options_summary"): if hasattr(option_value, "options_summary"):
option_value = option_value.options_summary() option_value = option_value.options_summary()
+7 -12
View File
@@ -1,19 +1,14 @@
from __future__ import annotations
import sys import sys
from typing import TYPE_CHECKING, Final, Protocol from collections.abc import Sequence
from pathlib import Path
from typing import Final, Protocol
from cibuildwheel import errors from cibuildwheel import errors
from cibuildwheel.architecture import Architecture
from cibuildwheel.options import Options
from cibuildwheel.platforms import android, ios, linux, macos, pyodide, windows from cibuildwheel.platforms import android, ios, linux, macos, pyodide, windows
from cibuildwheel.selector import BuildSelector
if TYPE_CHECKING: from cibuildwheel.typing import GenericPythonConfiguration, PlatformName
from collections.abc import Sequence
from pathlib import Path
from cibuildwheel.architecture import Architecture
from cibuildwheel.options import Options
from cibuildwheel.selector import BuildSelector
from cibuildwheel.typing import GenericPythonConfiguration, PlatformName
class PlatformModule(Protocol): class PlatformModule(Protocol):
+13 -13
View File
@@ -22,19 +22,19 @@ from elftools.common.exceptions import ELFError
from elftools.elf.elffile import ELFFile from elftools.elf.elffile import ELFFile
from filelock import FileLock from filelock import FileLock
from .. import errors, platforms # pylint: disable=cyclic-import from cibuildwheel import errors, platforms # pylint: disable=cyclic-import
from ..architecture import Architecture, arch_synonym from cibuildwheel.architecture import Architecture, arch_synonym
from ..frontend import get_build_frontend_extra_flags, parse_config_settings from cibuildwheel.frontend import get_build_frontend_extra_flags, parse_config_settings
from ..logger import log from cibuildwheel.logger import log
from ..options import BuildOptions, Options from cibuildwheel.options import BuildOptions, Options
from ..selector import BuildSelector from cibuildwheel.selector import BuildSelector
from ..util import resources from cibuildwheel.util import resources
from ..util.cmd import call, shell from cibuildwheel.util.cmd import call, shell
from ..util.file import CIBW_CACHE_PATH, copy_test_sources, download, move_file from cibuildwheel.util.file import CIBW_CACHE_PATH, copy_test_sources, download, move_file
from ..util.helpers import prepare_command from cibuildwheel.util.helpers import prepare_command
from ..util.packaging import find_compatible_wheel from cibuildwheel.util.packaging import find_compatible_wheel
from ..util.python_build_standalone import create_python_build_standalone_environment from cibuildwheel.util.python_build_standalone import create_python_build_standalone_environment
from ..venv import constraint_flags, find_uv, virtualenv from cibuildwheel.venv import constraint_flags, find_uv, virtualenv
ANDROID_TRIPLET = { ANDROID_TRIPLET = {
"arm64_v8a": "aarch64-linux-android", "arm64_v8a": "aarch64-linux-android",
+20 -33
View File
@@ -1,5 +1,3 @@
from __future__ import annotations
import dataclasses import dataclasses
import os import os
import platform import platform
@@ -8,39 +6,26 @@ import shutil
import subprocess import subprocess
import sys import sys
import textwrap import textwrap
from collections.abc import Sequence, Set
from pathlib import Path from pathlib import Path
from typing import TYPE_CHECKING, assert_never from typing import assert_never
from filelock import FileLock from filelock import FileLock
from .. import errors from cibuildwheel import errors
from ..frontend import ( from cibuildwheel.architecture import Architecture
BuildFrontendName, from cibuildwheel.environment import ParsedEnvironment
get_build_frontend_extra_flags, from cibuildwheel.frontend import BuildFrontendName, get_build_frontend_extra_flags
) from cibuildwheel.logger import log
from ..logger import log from cibuildwheel.options import Options
from ..util import resources from cibuildwheel.platforms.macos import install_cpython as install_build_cpython
from ..util.cmd import call, shell, split_command from cibuildwheel.selector import BuildSelector
from ..util.file import ( from cibuildwheel.util import resources
CIBW_CACHE_PATH, from cibuildwheel.util.cmd import call, shell, split_command
copy_test_sources, from cibuildwheel.util.file import CIBW_CACHE_PATH, copy_test_sources, download, move_file
download, from cibuildwheel.util.helpers import prepare_command, unwrap_preserving_paragraphs
move_file, from cibuildwheel.util.packaging import find_compatible_wheel
) from cibuildwheel.venv import constraint_flags, virtualenv
from ..util.helpers import prepare_command, unwrap_preserving_paragraphs
from ..util.packaging import (
find_compatible_wheel,
)
from ..venv import constraint_flags, virtualenv
from .macos import install_cpython as install_build_cpython
if TYPE_CHECKING:
from collections.abc import Sequence, Set
from ..architecture import Architecture
from ..environment import ParsedEnvironment
from ..options import Options
from ..selector import BuildSelector
@dataclasses.dataclass(frozen=True, kw_only=True) @dataclasses.dataclass(frozen=True, kw_only=True)
@@ -284,7 +269,8 @@ def setup_python(
build_frontend: BuildFrontendName, build_frontend: BuildFrontendName,
xbuild_tools: Sequence[str] | None, xbuild_tools: Sequence[str] | None,
) -> tuple[Path, dict[str, str]]: ) -> tuple[Path, dict[str, str]]:
if build_frontend == "build[uv]" or build_frontend == "uv": # Not using set because mypy can't narrow it
if build_frontend == "build[uv]" or build_frontend == "uv": # noqa: PLR1714
msg = "uv doesn't support iOS" msg = "uv doesn't support iOS"
raise errors.FatalError(msg) raise errors.FatalError(msg)
@@ -441,7 +427,8 @@ def build(options: Options, tmp_path: Path) -> None:
build_options = options.build_options(config.identifier) build_options = options.build_options(config.identifier)
build_frontend = build_options.build_frontend build_frontend = build_options.build_frontend
# uv doesn't support iOS # uv doesn't support iOS
if build_frontend.name == "build[uv]" or build_frontend.name == "uv": # Not using set because mypy can't narrow it
if build_frontend.name == "build[uv]" or build_frontend.name == "uv": # noqa: PLR1714
msg = "uv doesn't support iOS" msg = "uv doesn't support iOS"
raise errors.FatalError(msg) raise errors.FatalError(msg)
+12 -12
View File
@@ -8,20 +8,20 @@ from collections.abc import Iterable, Iterator, Sequence, Set
from pathlib import Path, PurePath, PurePosixPath from pathlib import Path, PurePath, PurePosixPath
from typing import TYPE_CHECKING, assert_never from typing import TYPE_CHECKING, assert_never
from .. import errors from cibuildwheel import errors
from ..architecture import Architecture from cibuildwheel.architecture import Architecture
from ..frontend import get_build_frontend_extra_flags from cibuildwheel.frontend import get_build_frontend_extra_flags
from ..logger import log from cibuildwheel.logger import log
from ..oci_container import OCIContainer, OCIContainerEngineConfig, OCIPlatform from cibuildwheel.oci_container import OCIContainer, OCIContainerEngineConfig, OCIPlatform
from ..options import BuildOptions, Options from cibuildwheel.options import BuildOptions, Options
from ..selector import BuildSelector from cibuildwheel.selector import BuildSelector
from ..util import resources from cibuildwheel.util import resources
from ..util.file import copy_test_sources from cibuildwheel.util.file import copy_test_sources
from ..util.helpers import prepare_command, unwrap from cibuildwheel.util.helpers import prepare_command, unwrap
from ..util.packaging import find_compatible_wheel from cibuildwheel.util.packaging import find_compatible_wheel
if TYPE_CHECKING: if TYPE_CHECKING:
from ..typing import PathOrStr from cibuildwheel.typing import PathOrStr
ARCHITECTURE_OCI_PLATFORM_MAP = { ARCHITECTURE_OCI_PLATFORM_MAP = {
Architecture.x86_64: OCIPlatform.AMD64, Architecture.x86_64: OCIPlatform.AMD64,
+22 -19
View File
@@ -15,25 +15,20 @@ from typing import Literal, assert_never
from filelock import FileLock from filelock import FileLock
from packaging.version import Version from packaging.version import Version
from .. import errors from cibuildwheel import errors
from ..architecture import Architecture from cibuildwheel.architecture import Architecture
from ..ci import detect_ci_provider from cibuildwheel.ci import detect_ci_provider
from ..environment import ParsedEnvironment from cibuildwheel.environment import ParsedEnvironment
from ..frontend import BuildFrontendName, get_build_frontend_extra_flags from cibuildwheel.frontend import BuildFrontendName, get_build_frontend_extra_flags
from ..logger import log from cibuildwheel.logger import log
from ..options import Options from cibuildwheel.options import Options
from ..selector import BuildSelector from cibuildwheel.selector import BuildSelector
from ..util import resources from cibuildwheel.util import resources
from ..util.cmd import call, shell from cibuildwheel.util.cmd import call, shell
from ..util.file import ( from cibuildwheel.util.file import CIBW_CACHE_PATH, copy_test_sources, download, move_file
CIBW_CACHE_PATH, from cibuildwheel.util.helpers import prepare_command, unwrap
copy_test_sources, from cibuildwheel.util.packaging import find_compatible_wheel, get_pip_version
download, from cibuildwheel.venv import constraint_flags, find_uv, virtualenv
move_file,
)
from ..util.helpers import prepare_command, unwrap
from ..util.packaging import find_compatible_wheel, get_pip_version
from ..venv import constraint_flags, find_uv, virtualenv
@functools.cache @functools.cache
@@ -258,6 +253,10 @@ def setup_python(
# https://github.com/pypa/virtualenv/issues/620 # https://github.com/pypa/virtualenv/issues/620
# Also see https://github.com/python/cpython/pull/9516 # Also see https://github.com/python/cpython/pull/9516
env.pop("__PYVENV_LAUNCHER__", None) env.pop("__PYVENV_LAUNCHER__", None)
# uv uses this over the current environment's python, so remove it to avoid confusion
env.pop("PYTHON_VERSION", None)
env.pop("PYTHON_ARCH", None)
env.pop("UV_PYTHON", None)
# we version pip ourselves, so we don't care about pip version checking # we version pip ourselves, so we don't care about pip version checking
env["PIP_DISABLE_PIP_VERSION_CHECK"] = "1" env["PIP_DISABLE_PIP_VERSION_CHECK"] = "1"
@@ -375,6 +374,8 @@ def setup_python(
uv_path, uv_path,
"pip", "pip",
"install", "install",
"--python",
which_python,
"--upgrade", "--upgrade",
"delocate", "delocate",
"build[virtualenv, uv]", "build[virtualenv, uv]",
@@ -387,6 +388,8 @@ def setup_python(
uv_path, uv_path,
"pip", "pip",
"install", "install",
"--python",
which_python,
"--upgrade", "--upgrade",
"delocate", "delocate",
*constraint_flags(dependency_constraint), *constraint_flags(dependency_constraint),
+14 -15
View File
@@ -14,16 +14,16 @@ from typing import Final, TypedDict
from filelock import FileLock from filelock import FileLock
from .. import errors from cibuildwheel import errors
from ..architecture import Architecture from cibuildwheel.architecture import Architecture
from ..environment import ParsedEnvironment from cibuildwheel.environment import ParsedEnvironment
from ..frontend import get_build_frontend_extra_flags from cibuildwheel.frontend import get_build_frontend_extra_flags
from ..logger import log from cibuildwheel.logger import log
from ..options import Options from cibuildwheel.options import Options
from ..selector import BuildSelector from cibuildwheel.selector import BuildSelector
from ..util import resources from cibuildwheel.util import resources
from ..util.cmd import call, shell from cibuildwheel.util.cmd import call, shell
from ..util.file import ( from cibuildwheel.util.file import (
CIBW_CACHE_PATH, CIBW_CACHE_PATH,
copy_test_sources, copy_test_sources,
download, download,
@@ -31,13 +31,13 @@ from ..util.file import (
extract_zip, extract_zip,
move_file, move_file,
) )
from ..util.helpers import prepare_command, unwrap, unwrap_preserving_paragraphs from cibuildwheel.util.helpers import prepare_command, unwrap, unwrap_preserving_paragraphs
from ..util.packaging import find_compatible_wheel, get_pip_version from cibuildwheel.util.packaging import find_compatible_wheel, get_pip_version
from ..util.python_build_standalone import ( from cibuildwheel.util.python_build_standalone import (
PythonBuildStandaloneError, PythonBuildStandaloneError,
create_python_build_standalone_environment, create_python_build_standalone_environment,
) )
from ..venv import constraint_flags, virtualenv from cibuildwheel.venv import constraint_flags, virtualenv
IS_WIN: Final[bool] = sys.platform.startswith("win") IS_WIN: Final[bool] = sys.platform.startswith("win")
@@ -285,7 +285,6 @@ def setup_python(
"install", "install",
"--upgrade", "--upgrade",
"pyodide-build", "pyodide-build",
"build[virtualenv]",
*constraint_flags(constraints_path), *constraint_flags(constraints_path),
env=env, env=env,
) )
+24 -14
View File
@@ -12,19 +12,25 @@ from typing import assert_never
from filelock import FileLock from filelock import FileLock
from .. import errors from cibuildwheel import errors
from ..architecture import Architecture from cibuildwheel.architecture import Architecture
from ..environment import ParsedEnvironment from cibuildwheel.environment import ParsedEnvironment
from ..frontend import BuildFrontendName, get_build_frontend_extra_flags from cibuildwheel.frontend import BuildFrontendName, get_build_frontend_extra_flags
from ..logger import log from cibuildwheel.logger import log
from ..options import Options from cibuildwheel.options import Options
from ..selector import BuildSelector from cibuildwheel.selector import BuildSelector
from ..util import resources from cibuildwheel.util import resources
from ..util.cmd import call, shell from cibuildwheel.util.cmd import call, shell
from ..util.file import CIBW_CACHE_PATH, copy_test_sources, download, extract_zip, move_file from cibuildwheel.util.file import (
from ..util.helpers import prepare_command, unwrap CIBW_CACHE_PATH,
from ..util.packaging import find_compatible_wheel, get_pip_version copy_test_sources,
from ..venv import constraint_flags, find_uv, virtualenv download,
extract_zip,
move_file,
)
from cibuildwheel.util.helpers import prepare_command, unwrap
from cibuildwheel.util.packaging import find_compatible_wheel, get_pip_version
from cibuildwheel.venv import constraint_flags, find_uv, virtualenv
def get_nuget_args( def get_nuget_args(
@@ -287,7 +293,9 @@ def setup_python(
# set up environment variables for run_with_env # set up environment variables for run_with_env
env["PYTHON_VERSION"] = python_configuration.version env["PYTHON_VERSION"] = python_configuration.version
env["PYTHON_ARCH"] = python_configuration.arch env["PYTHON_ARCH"] = python_configuration.arch
env["PIP_DISABLE_PIP_VERSION_CHECK"] = "1" env.pop("UV_PYTHON", None)
if not use_uv:
env["PIP_DISABLE_PIP_VERSION_CHECK"] = "1"
# update env with results from CIBW_ENVIRONMENT # update env with results from CIBW_ENVIRONMENT
env = environment.as_dictionary(prev_environment=env) env = environment.as_dictionary(prev_environment=env)
@@ -328,6 +336,8 @@ def setup_python(
uv_path, uv_path,
"pip", "pip",
"install", "install",
"--python",
where_python,
"--upgrade", "--upgrade",
"build[virtualenv]", "build[virtualenv]",
*constraint_flags(dependency_constraint), *constraint_flags(dependency_constraint),
+3 -3
View File
@@ -179,8 +179,8 @@ python_configurations = [
{ identifier = "pp39-macosx_arm64", version = "3.9", url = "https://downloads.python.org/pypy/pypy3.9-v7.3.16-macos_arm64.tar.bz2" }, { identifier = "pp39-macosx_arm64", version = "3.9", url = "https://downloads.python.org/pypy/pypy3.9-v7.3.16-macos_arm64.tar.bz2" },
{ identifier = "pp310-macosx_x86_64", version = "3.10", url = "https://downloads.python.org/pypy/pypy3.10-v7.3.19-macos_x86_64.tar.bz2" }, { identifier = "pp310-macosx_x86_64", version = "3.10", url = "https://downloads.python.org/pypy/pypy3.10-v7.3.19-macos_x86_64.tar.bz2" },
{ identifier = "pp310-macosx_arm64", version = "3.10", url = "https://downloads.python.org/pypy/pypy3.10-v7.3.19-macos_arm64.tar.bz2" }, { identifier = "pp310-macosx_arm64", version = "3.10", url = "https://downloads.python.org/pypy/pypy3.10-v7.3.19-macos_arm64.tar.bz2" },
{ identifier = "pp311-macosx_x86_64", version = "3.11", url = "https://downloads.python.org/pypy/pypy3.11-v7.3.20-macos_x86_64.tar.bz2" }, { identifier = "pp311-macosx_x86_64", version = "3.11", url = "https://downloads.python.org/pypy/pypy3.11-v7.3.21-macos_x86_64.tar.bz2" },
{ identifier = "pp311-macosx_arm64", version = "3.11", url = "https://downloads.python.org/pypy/pypy3.11-v7.3.20-macos_arm64.tar.bz2" }, { identifier = "pp311-macosx_arm64", version = "3.11", url = "https://downloads.python.org/pypy/pypy3.11-v7.3.21-macos_arm64.tar.bz2" },
{ identifier = "gp311_242-macosx_x86_64", version = "3.11", url = "https://github.com/oracle/graalpython/releases/download/graal-24.2.2/graalpy-24.2.2-macos-amd64.tar.gz" }, { identifier = "gp311_242-macosx_x86_64", version = "3.11", url = "https://github.com/oracle/graalpython/releases/download/graal-24.2.2/graalpy-24.2.2-macos-amd64.tar.gz" },
{ identifier = "gp311_242-macosx_arm64", version = "3.11", url = "https://github.com/oracle/graalpython/releases/download/graal-24.2.2/graalpy-24.2.2-macos-aarch64.tar.gz" }, { identifier = "gp311_242-macosx_arm64", version = "3.11", url = "https://github.com/oracle/graalpython/releases/download/graal-24.2.2/graalpy-24.2.2-macos-aarch64.tar.gz" },
{ identifier = "gp312_250-macosx_x86_64", version = "3.12", url = "https://github.com/oracle/graalpython/releases/download/graal-25.0.1/graalpy-25.0.1-macos-amd64.tar.gz" }, { identifier = "gp312_250-macosx_x86_64", version = "3.12", url = "https://github.com/oracle/graalpython/releases/download/graal-25.0.1/graalpy-25.0.1-macos-amd64.tar.gz" },
@@ -218,7 +218,7 @@ python_configurations = [
{ identifier = "pp38-win_amd64", version = "3.8", url = "https://downloads.python.org/pypy/pypy3.8-v7.3.11-win64.zip" }, { identifier = "pp38-win_amd64", version = "3.8", url = "https://downloads.python.org/pypy/pypy3.8-v7.3.11-win64.zip" },
{ identifier = "pp39-win_amd64", version = "3.9", url = "https://downloads.python.org/pypy/pypy3.9-v7.3.16-win64.zip" }, { identifier = "pp39-win_amd64", version = "3.9", url = "https://downloads.python.org/pypy/pypy3.9-v7.3.16-win64.zip" },
{ identifier = "pp310-win_amd64", version = "3.10", url = "https://downloads.python.org/pypy/pypy3.10-v7.3.19-win64.zip" }, { identifier = "pp310-win_amd64", version = "3.10", url = "https://downloads.python.org/pypy/pypy3.10-v7.3.19-win64.zip" },
{ identifier = "pp311-win_amd64", version = "3.11", url = "https://downloads.python.org/pypy/pypy3.11-v7.3.20-win64.zip" }, { identifier = "pp311-win_amd64", version = "3.11", url = "https://downloads.python.org/pypy/pypy3.11-v7.3.21-win64.zip" },
{ identifier = "gp311_242-win_amd64", version = "3.11", url = "https://github.com/oracle/graalpython/releases/download/graal-24.2.2/graalpy-24.2.2-windows-amd64.zip" }, { identifier = "gp311_242-win_amd64", version = "3.11", url = "https://github.com/oracle/graalpython/releases/download/graal-24.2.2/graalpy-24.2.2-windows-amd64.zip" },
{ identifier = "gp312_250-win_amd64", version = "3.12", url = "https://github.com/oracle/graalpython/releases/download/graal-25.0.2/graalpy-25.0.2-windows-amd64.zip" }, { identifier = "gp312_250-win_amd64", version = "3.12", url = "https://github.com/oracle/graalpython/releases/download/graal-25.0.2/graalpy-25.0.2-windows-amd64.zip" },
] ]
@@ -10,7 +10,7 @@ build==1.2.2.post1
# pyodide-build # pyodide-build
certifi==2026.2.25 certifi==2026.2.25
# via requests # via requests
charset-normalizer==3.4.5 charset-normalizer==3.4.6
# via requests # via requests
click==8.1.8 click==8.1.8
# via # via
@@ -19,7 +19,7 @@ click==8.1.8
# pyodide-cli # pyodide-cli
distlib==0.4.0 distlib==0.4.0
# via virtualenv # via virtualenv
filelock==3.25.0 filelock==3.25.2
# via # via
# python-discovery # python-discovery
# virtualenv # virtualenv
@@ -62,7 +62,7 @@ pyodide-lock==0.1.2
# via pyodide-build # via pyodide-build
pyproject-hooks==1.2.0 pyproject-hooks==1.2.0
# via build # via build
python-discovery==1.1.1 python-discovery==1.2.0
# via virtualenv # via virtualenv
requests==2.32.5 requests==2.32.5
# via pyodide-build # via pyodide-build
@@ -81,7 +81,7 @@ typing-inspection==0.4.2
# via pydantic # via pydantic
urllib3==2.6.3 urllib3==2.6.3
# via requests # via requests
virtualenv==21.1.0 virtualenv==21.2.0
# via # via
# build # build
# pyodide-build # pyodide-build
@@ -10,7 +10,7 @@ build==1.2.2.post1
# pyodide-build # pyodide-build
certifi==2026.2.25 certifi==2026.2.25
# via requests # via requests
charset-normalizer==3.4.5 charset-normalizer==3.4.6
# via requests # via requests
click==8.1.8 click==8.1.8
# via # via
@@ -19,7 +19,7 @@ click==8.1.8
# pyodide-cli # pyodide-cli
distlib==0.4.0 distlib==0.4.0
# via virtualenv # via virtualenv
filelock==3.25.0 filelock==3.25.2
# via # via
# python-discovery # python-discovery
# virtualenv # virtualenv
@@ -62,7 +62,7 @@ pyodide-lock==0.1.2
# via pyodide-build # via pyodide-build
pyproject-hooks==1.2.0 pyproject-hooks==1.2.0
# via build # via build
python-discovery==1.1.1 python-discovery==1.2.0
# via virtualenv # via virtualenv
requests==2.32.5 requests==2.32.5
# via pyodide-build # via pyodide-build
@@ -81,7 +81,7 @@ typing-inspection==0.4.2
# via pydantic # via pydantic
urllib3==2.6.3 urllib3==2.6.3
# via requests # via requests
virtualenv==21.1.0 virtualenv==21.2.0
# via # via
# build # build
# pyodide-build # pyodide-build
@@ -8,11 +8,11 @@ delocate==0.13.0
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
distlib==0.4.0 distlib==0.4.0
# via virtualenv # via virtualenv
filelock==3.25.0 filelock==3.25.2
# via # via
# python-discovery # python-discovery
# virtualenv # virtualenv
importlib-metadata==8.7.1 importlib-metadata==9.0.0
# via build # via build
macholib==1.16.4 macholib==1.16.4
# via delocate # via delocate
@@ -28,7 +28,7 @@ platformdirs==4.9.4
# virtualenv # virtualenv
pyproject-hooks==1.2.0 pyproject-hooks==1.2.0
# via build # via build
python-discovery==1.1.1 python-discovery==1.2.0
# via virtualenv # via virtualenv
tomli==2.4.0 tomli==2.4.0
# via build # via build
@@ -36,7 +36,7 @@ typing-extensions==4.15.0
# via # via
# delocate # delocate
# virtualenv # virtualenv
virtualenv==21.1.0 virtualenv==21.2.0
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
zipp==3.23.0 zipp==3.23.0
# via importlib-metadata # via importlib-metadata
@@ -8,7 +8,7 @@ delocate==0.13.0
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
distlib==0.4.0 distlib==0.4.0
# via virtualenv # via virtualenv
filelock==3.25.0 filelock==3.25.2
# via # via
# python-discovery # python-discovery
# virtualenv # virtualenv
@@ -26,9 +26,9 @@ platformdirs==4.9.4
# virtualenv # virtualenv
pyproject-hooks==1.2.0 pyproject-hooks==1.2.0
# via build # via build
python-discovery==1.1.1 python-discovery==1.2.0
# via virtualenv # via virtualenv
typing-extensions==4.15.0 typing-extensions==4.15.0
# via delocate # via delocate
virtualenv==21.1.0 virtualenv==21.2.0
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
@@ -8,7 +8,7 @@ delocate==0.13.0
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
distlib==0.4.0 distlib==0.4.0
# via virtualenv # via virtualenv
filelock==3.25.0 filelock==3.25.2
# via # via
# python-discovery # python-discovery
# virtualenv # virtualenv
@@ -26,9 +26,9 @@ platformdirs==4.9.4
# virtualenv # virtualenv
pyproject-hooks==1.2.0 pyproject-hooks==1.2.0
# via build # via build
python-discovery==1.1.1 python-discovery==1.2.0
# via virtualenv # via virtualenv
typing-extensions==4.15.0 typing-extensions==4.15.0
# via delocate # via delocate
virtualenv==21.1.0 virtualenv==21.2.0
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
@@ -8,7 +8,7 @@ delocate==0.13.0
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
distlib==0.4.0 distlib==0.4.0
# via virtualenv # via virtualenv
filelock==3.25.0 filelock==3.25.2
# via # via
# python-discovery # python-discovery
# virtualenv # virtualenv
@@ -26,9 +26,9 @@ platformdirs==4.9.4
# virtualenv # virtualenv
pyproject-hooks==1.2.0 pyproject-hooks==1.2.0
# via build # via build
python-discovery==1.1.1 python-discovery==1.2.0
# via virtualenv # via virtualenv
typing-extensions==4.15.0 typing-extensions==4.15.0
# via delocate # via delocate
virtualenv==21.1.0 virtualenv==21.2.0
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
@@ -8,7 +8,7 @@ delocate==0.13.0
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
distlib==0.4.0 distlib==0.4.0
# via virtualenv # via virtualenv
filelock==3.25.0 filelock==3.25.2
# via # via
# python-discovery # python-discovery
# virtualenv # virtualenv
@@ -26,9 +26,9 @@ platformdirs==4.9.4
# virtualenv # virtualenv
pyproject-hooks==1.2.0 pyproject-hooks==1.2.0
# via build # via build
python-discovery==1.1.1 python-discovery==1.2.0
# via virtualenv # via virtualenv
typing-extensions==4.15.0 typing-extensions==4.15.0
# via delocate # via delocate
virtualenv==21.1.0 virtualenv==21.2.0
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
@@ -28,7 +28,7 @@ platformdirs==4.3.6
# virtualenv # virtualenv
pyproject-hooks==1.2.0 pyproject-hooks==1.2.0
# via build # via build
python-discovery==1.1.1 python-discovery==1.2.0
# via virtualenv # via virtualenv
tomli==2.4.0 tomli==2.4.0
# via build # via build
@@ -36,7 +36,7 @@ typing-extensions==4.13.2
# via # via
# delocate # delocate
# virtualenv # virtualenv
virtualenv==21.1.0 virtualenv==21.2.0
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
zipp==3.20.2 zipp==3.20.2
# via importlib-metadata # via importlib-metadata
@@ -28,7 +28,7 @@ platformdirs==4.4.0
# virtualenv # virtualenv
pyproject-hooks==1.2.0 pyproject-hooks==1.2.0
# via build # via build
python-discovery==1.1.1 python-discovery==1.2.0
# via virtualenv # via virtualenv
tomli==2.4.0 tomli==2.4.0
# via build # via build
@@ -36,7 +36,7 @@ typing-extensions==4.15.0
# via # via
# delocate # delocate
# virtualenv # virtualenv
virtualenv==21.1.0 virtualenv==21.2.0
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
zipp==3.23.0 zipp==3.23.0
# via importlib-metadata # via importlib-metadata
+3 -3
View File
@@ -8,7 +8,7 @@ delocate==0.13.0
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
distlib==0.4.0 distlib==0.4.0
# via virtualenv # via virtualenv
filelock==3.25.0 filelock==3.25.2
# via # via
# python-discovery # python-discovery
# virtualenv # virtualenv
@@ -26,9 +26,9 @@ platformdirs==4.9.4
# virtualenv # virtualenv
pyproject-hooks==1.2.0 pyproject-hooks==1.2.0
# via build # via build
python-discovery==1.1.1 python-discovery==1.2.0
# via virtualenv # via virtualenv
typing-extensions==4.15.0 typing-extensions==4.15.0
# via delocate # via delocate
virtualenv==21.1.0 virtualenv==21.2.0
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
+34 -34
View File
@@ -1,54 +1,54 @@
[x86_64] [x86_64]
manylinux2014 = quay.io/pypa/manylinux2014_x86_64:2026.03.06-3 manylinux2014 = quay.io/pypa/manylinux2014_x86_64:2026.03.20-1
manylinux_2_28 = quay.io/pypa/manylinux_2_28_x86_64:2026.03.06-3 manylinux_2_28 = quay.io/pypa/manylinux_2_28_x86_64:2026.03.20-1
manylinux_2_34 = quay.io/pypa/manylinux_2_34_x86_64:2026.03.06-3 manylinux_2_34 = quay.io/pypa/manylinux_2_34_x86_64:2026.03.20-1
musllinux_1_2 = quay.io/pypa/musllinux_1_2_x86_64:2026.03.06-3 musllinux_1_2 = quay.io/pypa/musllinux_1_2_x86_64:2026.03.20-1
[i686] [i686]
manylinux2014 = quay.io/pypa/manylinux2014_i686:2026.03.06-3 manylinux2014 = quay.io/pypa/manylinux2014_i686:2026.03.20-1
manylinux_2_28 = quay.io/pypa/manylinux_2_28_i686:2026.03.06-3 manylinux_2_28 = quay.io/pypa/manylinux_2_28_i686:2026.03.20-1
manylinux_2_34 = quay.io/pypa/manylinux_2_34_i686:2026.03.06-3 manylinux_2_34 = quay.io/pypa/manylinux_2_34_i686:2026.03.20-1
musllinux_1_2 = quay.io/pypa/musllinux_1_2_i686:2026.03.06-3 musllinux_1_2 = quay.io/pypa/musllinux_1_2_i686:2026.03.20-1
[aarch64] [aarch64]
manylinux2014 = quay.io/pypa/manylinux2014_aarch64:2026.03.06-3 manylinux2014 = quay.io/pypa/manylinux2014_aarch64:2026.03.20-1
manylinux_2_28 = quay.io/pypa/manylinux_2_28_aarch64:2026.03.06-3 manylinux_2_28 = quay.io/pypa/manylinux_2_28_aarch64:2026.03.20-1
manylinux_2_34 = quay.io/pypa/manylinux_2_34_aarch64:2026.03.06-3 manylinux_2_34 = quay.io/pypa/manylinux_2_34_aarch64:2026.03.20-1
musllinux_1_2 = quay.io/pypa/musllinux_1_2_aarch64:2026.03.06-3 musllinux_1_2 = quay.io/pypa/musllinux_1_2_aarch64:2026.03.20-1
[ppc64le] [ppc64le]
manylinux2014 = quay.io/pypa/manylinux2014_ppc64le:2026.03.06-3 manylinux2014 = quay.io/pypa/manylinux2014_ppc64le:2026.03.20-1
manylinux_2_28 = quay.io/pypa/manylinux_2_28_ppc64le:2026.03.06-3 manylinux_2_28 = quay.io/pypa/manylinux_2_28_ppc64le:2026.03.20-1
manylinux_2_34 = quay.io/pypa/manylinux_2_34_ppc64le:2026.03.06-3 manylinux_2_34 = quay.io/pypa/manylinux_2_34_ppc64le:2026.03.20-1
musllinux_1_2 = quay.io/pypa/musllinux_1_2_ppc64le:2026.03.06-3 musllinux_1_2 = quay.io/pypa/musllinux_1_2_ppc64le:2026.03.20-1
[s390x] [s390x]
manylinux2014 = quay.io/pypa/manylinux2014_s390x:2026.03.06-3 manylinux2014 = quay.io/pypa/manylinux2014_s390x:2026.03.20-1
manylinux_2_28 = quay.io/pypa/manylinux_2_28_s390x:2026.03.06-3 manylinux_2_28 = quay.io/pypa/manylinux_2_28_s390x:2026.03.20-1
manylinux_2_34 = quay.io/pypa/manylinux_2_34_s390x:2026.03.06-3 manylinux_2_34 = quay.io/pypa/manylinux_2_34_s390x:2026.03.20-1
musllinux_1_2 = quay.io/pypa/musllinux_1_2_s390x:2026.03.06-3 musllinux_1_2 = quay.io/pypa/musllinux_1_2_s390x:2026.03.20-1
[pypy_x86_64] [pypy_x86_64]
manylinux2014 = quay.io/pypa/manylinux2014_x86_64:2026.03.06-3 manylinux2014 = quay.io/pypa/manylinux2014_x86_64:2026.03.20-1
manylinux_2_28 = quay.io/pypa/manylinux_2_28_x86_64:2026.03.06-3 manylinux_2_28 = quay.io/pypa/manylinux_2_28_x86_64:2026.03.20-1
manylinux_2_34 = quay.io/pypa/manylinux_2_34_x86_64:2026.03.06-3 manylinux_2_34 = quay.io/pypa/manylinux_2_34_x86_64:2026.03.20-1
[pypy_i686] [pypy_i686]
manylinux2014 = quay.io/pypa/manylinux2014_i686:2026.03.06-3 manylinux2014 = quay.io/pypa/manylinux2014_i686:2026.03.20-1
manylinux_2_28 = quay.io/pypa/manylinux_2_28_i686:2026.03.06-3 manylinux_2_28 = quay.io/pypa/manylinux_2_28_i686:2026.03.20-1
manylinux_2_34 = quay.io/pypa/manylinux_2_34_i686:2026.03.06-3 manylinux_2_34 = quay.io/pypa/manylinux_2_34_i686:2026.03.20-1
[pypy_aarch64] [pypy_aarch64]
manylinux2014 = quay.io/pypa/manylinux2014_aarch64:2026.03.06-3 manylinux2014 = quay.io/pypa/manylinux2014_aarch64:2026.03.20-1
manylinux_2_28 = quay.io/pypa/manylinux_2_28_aarch64:2026.03.06-3 manylinux_2_28 = quay.io/pypa/manylinux_2_28_aarch64:2026.03.20-1
manylinux_2_34 = quay.io/pypa/manylinux_2_34_aarch64:2026.03.06-3 manylinux_2_34 = quay.io/pypa/manylinux_2_34_aarch64:2026.03.20-1
[armv7l] [armv7l]
manylinux_2_31 = quay.io/pypa/manylinux_2_31_armv7l:2026.03.06-3 manylinux_2_31 = quay.io/pypa/manylinux_2_31_armv7l:2026.03.20-1
manylinux_2_35 = quay.io/pypa/manylinux_2_35_armv7l:2026.03.06-3 manylinux_2_35 = quay.io/pypa/manylinux_2_35_armv7l:2026.03.20-1
musllinux_1_2 = quay.io/pypa/musllinux_1_2_armv7l:2026.03.06-3 musllinux_1_2 = quay.io/pypa/musllinux_1_2_armv7l:2026.03.20-1
[riscv64] [riscv64]
manylinux_2_39 = quay.io/pypa/manylinux_2_39_riscv64:2026.03.06-3 manylinux_2_39 = quay.io/pypa/manylinux_2_39_riscv64:2026.03.20-1
musllinux_1_2 = quay.io/pypa/musllinux_1_2_riscv64:2026.03.06-3 musllinux_1_2 = quay.io/pypa/musllinux_1_2_riscv64:2026.03.20-1
@@ -1,483 +1,723 @@
{ {
"releases": [ "releases": [
{ {
"tag": "20260303", "tag": "20260320",
"assets": [ "assets": [
{ {
"name": "cpython-3.10.20+20260303-aarch64-apple-darwin-install_only.tar.gz", "name": "cpython-3.10.20+20260320-aarch64-apple-darwin-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.10.20%2B20260303-aarch64-apple-darwin-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.10.20%2B20260320-aarch64-apple-darwin-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.10.20+20260303-aarch64-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.10.20+20260320-aarch64-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.10.20%2B20260303-aarch64-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.10.20%2B20260320-aarch64-unknown-linux-gnu-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.10.20+20260303-aarch64-unknown-linux-musl-install_only.tar.gz", "name": "cpython-3.10.20+20260320-aarch64-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.10.20%2B20260303-aarch64-unknown-linux-musl-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.10.20%2B20260320-aarch64-unknown-linux-musl-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.10.20+20260303-armv7-unknown-linux-gnueabi-install_only.tar.gz", "name": "cpython-3.10.20+20260320-armv7-unknown-linux-gnueabi-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.10.20%2B20260303-armv7-unknown-linux-gnueabi-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.10.20%2B20260320-armv7-unknown-linux-gnueabi-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.10.20+20260303-armv7-unknown-linux-gnueabihf-install_only.tar.gz", "name": "cpython-3.10.20+20260320-armv7-unknown-linux-gnueabihf-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.10.20%2B20260303-armv7-unknown-linux-gnueabihf-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.10.20%2B20260320-armv7-unknown-linux-gnueabihf-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.10.20+20260303-i686-pc-windows-msvc-install_only.tar.gz", "name": "cpython-3.10.20+20260320-i686-pc-windows-msvc-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.10.20%2B20260303-i686-pc-windows-msvc-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.10.20%2B20260320-i686-pc-windows-msvc-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.10.20+20260303-ppc64le-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.10.20+20260320-ppc64le-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.10.20%2B20260303-ppc64le-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.10.20%2B20260320-ppc64le-unknown-linux-gnu-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.10.20+20260303-riscv64-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.10.20+20260320-riscv64-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.10.20%2B20260303-riscv64-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.10.20%2B20260320-riscv64-unknown-linux-gnu-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.10.20+20260303-s390x-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.10.20+20260320-s390x-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.10.20%2B20260303-s390x-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.10.20%2B20260320-s390x-unknown-linux-gnu-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.10.20+20260303-x86_64-apple-darwin-install_only.tar.gz", "name": "cpython-3.10.20+20260320-x86_64-apple-darwin-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.10.20%2B20260303-x86_64-apple-darwin-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.10.20%2B20260320-x86_64-apple-darwin-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.10.20+20260303-x86_64-pc-windows-msvc-install_only.tar.gz", "name": "cpython-3.10.20+20260320-x86_64-pc-windows-msvc-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.10.20%2B20260303-x86_64-pc-windows-msvc-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.10.20%2B20260320-x86_64-pc-windows-msvc-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.10.20+20260303-x86_64-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.10.20+20260320-x86_64-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.10.20%2B20260303-x86_64-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.10.20%2B20260320-x86_64-unknown-linux-gnu-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.10.20+20260303-x86_64-unknown-linux-musl-install_only.tar.gz", "name": "cpython-3.10.20+20260320-x86_64-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.10.20%2B20260303-x86_64-unknown-linux-musl-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.10.20%2B20260320-x86_64-unknown-linux-musl-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.10.20+20260303-x86_64_v2-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.10.20+20260320-x86_64_v2-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.10.20%2B20260303-x86_64_v2-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.10.20%2B20260320-x86_64_v2-unknown-linux-gnu-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.10.20+20260303-x86_64_v2-unknown-linux-musl-install_only.tar.gz", "name": "cpython-3.10.20+20260320-x86_64_v2-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.10.20%2B20260303-x86_64_v2-unknown-linux-musl-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.10.20%2B20260320-x86_64_v2-unknown-linux-musl-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.10.20+20260303-x86_64_v3-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.10.20+20260320-x86_64_v3-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.10.20%2B20260303-x86_64_v3-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.10.20%2B20260320-x86_64_v3-unknown-linux-gnu-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.10.20+20260303-x86_64_v3-unknown-linux-musl-install_only.tar.gz", "name": "cpython-3.10.20+20260320-x86_64_v3-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.10.20%2B20260303-x86_64_v3-unknown-linux-musl-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.10.20%2B20260320-x86_64_v3-unknown-linux-musl-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.10.20+20260303-x86_64_v4-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.10.20+20260320-x86_64_v4-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.10.20%2B20260303-x86_64_v4-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.10.20%2B20260320-x86_64_v4-unknown-linux-gnu-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.10.20+20260303-x86_64_v4-unknown-linux-musl-install_only.tar.gz", "name": "cpython-3.10.20+20260320-x86_64_v4-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.10.20%2B20260303-x86_64_v4-unknown-linux-musl-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.10.20%2B20260320-x86_64_v4-unknown-linux-musl-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.11.15+20260303-aarch64-apple-darwin-install_only.tar.gz", "name": "cpython-3.11.15+20260320-aarch64-apple-darwin-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.11.15%2B20260303-aarch64-apple-darwin-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.11.15%2B20260320-aarch64-apple-darwin-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.11.15+20260303-aarch64-pc-windows-msvc-install_only.tar.gz", "name": "cpython-3.11.15+20260320-aarch64-pc-windows-msvc-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.11.15%2B20260303-aarch64-pc-windows-msvc-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.11.15%2B20260320-aarch64-pc-windows-msvc-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.11.15+20260303-aarch64-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.11.15+20260320-aarch64-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.11.15%2B20260303-aarch64-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.11.15%2B20260320-aarch64-unknown-linux-gnu-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.11.15+20260303-aarch64-unknown-linux-musl-install_only.tar.gz", "name": "cpython-3.11.15+20260320-aarch64-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.11.15%2B20260303-aarch64-unknown-linux-musl-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.11.15%2B20260320-aarch64-unknown-linux-musl-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.11.15+20260303-armv7-unknown-linux-gnueabi-install_only.tar.gz", "name": "cpython-3.11.15+20260320-armv7-unknown-linux-gnueabi-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.11.15%2B20260303-armv7-unknown-linux-gnueabi-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.11.15%2B20260320-armv7-unknown-linux-gnueabi-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.11.15+20260303-armv7-unknown-linux-gnueabihf-install_only.tar.gz", "name": "cpython-3.11.15+20260320-armv7-unknown-linux-gnueabihf-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.11.15%2B20260303-armv7-unknown-linux-gnueabihf-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.11.15%2B20260320-armv7-unknown-linux-gnueabihf-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.11.15+20260303-i686-pc-windows-msvc-install_only.tar.gz", "name": "cpython-3.11.15+20260320-i686-pc-windows-msvc-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.11.15%2B20260303-i686-pc-windows-msvc-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.11.15%2B20260320-i686-pc-windows-msvc-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.11.15+20260303-ppc64le-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.11.15+20260320-ppc64le-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.11.15%2B20260303-ppc64le-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.11.15%2B20260320-ppc64le-unknown-linux-gnu-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.11.15+20260303-riscv64-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.11.15+20260320-riscv64-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.11.15%2B20260303-riscv64-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.11.15%2B20260320-riscv64-unknown-linux-gnu-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.11.15+20260303-s390x-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.11.15+20260320-s390x-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.11.15%2B20260303-s390x-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.11.15%2B20260320-s390x-unknown-linux-gnu-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.11.15+20260303-x86_64-apple-darwin-install_only.tar.gz", "name": "cpython-3.11.15+20260320-x86_64-apple-darwin-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.11.15%2B20260303-x86_64-apple-darwin-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.11.15%2B20260320-x86_64-apple-darwin-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.11.15+20260303-x86_64-pc-windows-msvc-install_only.tar.gz", "name": "cpython-3.11.15+20260320-x86_64-pc-windows-msvc-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.11.15%2B20260303-x86_64-pc-windows-msvc-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.11.15%2B20260320-x86_64-pc-windows-msvc-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.11.15+20260303-x86_64-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.11.15+20260320-x86_64-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.11.15%2B20260303-x86_64-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.11.15%2B20260320-x86_64-unknown-linux-gnu-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.11.15+20260303-x86_64-unknown-linux-musl-install_only.tar.gz", "name": "cpython-3.11.15+20260320-x86_64-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.11.15%2B20260303-x86_64-unknown-linux-musl-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.11.15%2B20260320-x86_64-unknown-linux-musl-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.11.15+20260303-x86_64_v2-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.11.15+20260320-x86_64_v2-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.11.15%2B20260303-x86_64_v2-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.11.15%2B20260320-x86_64_v2-unknown-linux-gnu-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.11.15+20260303-x86_64_v2-unknown-linux-musl-install_only.tar.gz", "name": "cpython-3.11.15+20260320-x86_64_v2-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.11.15%2B20260303-x86_64_v2-unknown-linux-musl-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.11.15%2B20260320-x86_64_v2-unknown-linux-musl-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.11.15+20260303-x86_64_v3-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.11.15+20260320-x86_64_v3-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.11.15%2B20260303-x86_64_v3-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.11.15%2B20260320-x86_64_v3-unknown-linux-gnu-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.11.15+20260303-x86_64_v3-unknown-linux-musl-install_only.tar.gz", "name": "cpython-3.11.15+20260320-x86_64_v3-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.11.15%2B20260303-x86_64_v3-unknown-linux-musl-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.11.15%2B20260320-x86_64_v3-unknown-linux-musl-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.11.15+20260303-x86_64_v4-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.11.15+20260320-x86_64_v4-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.11.15%2B20260303-x86_64_v4-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.11.15%2B20260320-x86_64_v4-unknown-linux-gnu-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.11.15+20260303-x86_64_v4-unknown-linux-musl-install_only.tar.gz", "name": "cpython-3.11.15+20260320-x86_64_v4-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.11.15%2B20260303-x86_64_v4-unknown-linux-musl-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.11.15%2B20260320-x86_64_v4-unknown-linux-musl-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.12.13+20260303-aarch64-apple-darwin-install_only.tar.gz", "name": "cpython-3.12.13+20260320-aarch64-apple-darwin-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.12.13%2B20260303-aarch64-apple-darwin-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.12.13%2B20260320-aarch64-apple-darwin-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.12.13+20260303-aarch64-pc-windows-msvc-install_only.tar.gz", "name": "cpython-3.12.13+20260320-aarch64-pc-windows-msvc-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.12.13%2B20260303-aarch64-pc-windows-msvc-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.12.13%2B20260320-aarch64-pc-windows-msvc-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.12.13+20260303-aarch64-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.12.13+20260320-aarch64-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.12.13%2B20260303-aarch64-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.12.13%2B20260320-aarch64-unknown-linux-gnu-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.12.13+20260303-aarch64-unknown-linux-musl-install_only.tar.gz", "name": "cpython-3.12.13+20260320-aarch64-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.12.13%2B20260303-aarch64-unknown-linux-musl-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.12.13%2B20260320-aarch64-unknown-linux-musl-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.12.13+20260303-armv7-unknown-linux-gnueabi-install_only.tar.gz", "name": "cpython-3.12.13+20260320-armv7-unknown-linux-gnueabi-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.12.13%2B20260303-armv7-unknown-linux-gnueabi-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.12.13%2B20260320-armv7-unknown-linux-gnueabi-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.12.13+20260303-armv7-unknown-linux-gnueabihf-install_only.tar.gz", "name": "cpython-3.12.13+20260320-armv7-unknown-linux-gnueabihf-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.12.13%2B20260303-armv7-unknown-linux-gnueabihf-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.12.13%2B20260320-armv7-unknown-linux-gnueabihf-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.12.13+20260303-i686-pc-windows-msvc-install_only.tar.gz", "name": "cpython-3.12.13+20260320-i686-pc-windows-msvc-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.12.13%2B20260303-i686-pc-windows-msvc-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.12.13%2B20260320-i686-pc-windows-msvc-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.12.13+20260303-ppc64le-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.12.13+20260320-ppc64le-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.12.13%2B20260303-ppc64le-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.12.13%2B20260320-ppc64le-unknown-linux-gnu-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.12.13+20260303-riscv64-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.12.13+20260320-riscv64-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.12.13%2B20260303-riscv64-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.12.13%2B20260320-riscv64-unknown-linux-gnu-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.12.13+20260303-s390x-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.12.13+20260320-s390x-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.12.13%2B20260303-s390x-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.12.13%2B20260320-s390x-unknown-linux-gnu-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.12.13+20260303-x86_64-apple-darwin-install_only.tar.gz", "name": "cpython-3.12.13+20260320-x86_64-apple-darwin-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.12.13%2B20260303-x86_64-apple-darwin-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.12.13%2B20260320-x86_64-apple-darwin-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.12.13+20260303-x86_64-pc-windows-msvc-install_only.tar.gz", "name": "cpython-3.12.13+20260320-x86_64-pc-windows-msvc-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.12.13%2B20260303-x86_64-pc-windows-msvc-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.12.13%2B20260320-x86_64-pc-windows-msvc-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.12.13+20260303-x86_64-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.12.13+20260320-x86_64-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.12.13%2B20260303-x86_64-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.12.13%2B20260320-x86_64-unknown-linux-gnu-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.12.13+20260303-x86_64-unknown-linux-musl-install_only.tar.gz", "name": "cpython-3.12.13+20260320-x86_64-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.12.13%2B20260303-x86_64-unknown-linux-musl-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.12.13%2B20260320-x86_64-unknown-linux-musl-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.12.13+20260303-x86_64_v2-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.12.13+20260320-x86_64_v2-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.12.13%2B20260303-x86_64_v2-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.12.13%2B20260320-x86_64_v2-unknown-linux-gnu-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.12.13+20260303-x86_64_v2-unknown-linux-musl-install_only.tar.gz", "name": "cpython-3.12.13+20260320-x86_64_v2-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.12.13%2B20260303-x86_64_v2-unknown-linux-musl-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.12.13%2B20260320-x86_64_v2-unknown-linux-musl-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.12.13+20260303-x86_64_v3-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.12.13+20260320-x86_64_v3-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.12.13%2B20260303-x86_64_v3-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.12.13%2B20260320-x86_64_v3-unknown-linux-gnu-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.12.13+20260303-x86_64_v3-unknown-linux-musl-install_only.tar.gz", "name": "cpython-3.12.13+20260320-x86_64_v3-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.12.13%2B20260303-x86_64_v3-unknown-linux-musl-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.12.13%2B20260320-x86_64_v3-unknown-linux-musl-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.12.13+20260303-x86_64_v4-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.12.13+20260320-x86_64_v4-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.12.13%2B20260303-x86_64_v4-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.12.13%2B20260320-x86_64_v4-unknown-linux-gnu-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.12.13+20260303-x86_64_v4-unknown-linux-musl-install_only.tar.gz", "name": "cpython-3.12.13+20260320-x86_64_v4-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.12.13%2B20260303-x86_64_v4-unknown-linux-musl-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.12.13%2B20260320-x86_64_v4-unknown-linux-musl-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.13.12+20260303-aarch64-apple-darwin-install_only.tar.gz", "name": "cpython-3.13.12+20260320-aarch64-apple-darwin-freethreaded-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.13.12%2B20260303-aarch64-apple-darwin-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.13.12%2B20260320-aarch64-apple-darwin-freethreaded-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.13.12+20260303-aarch64-pc-windows-msvc-install_only.tar.gz", "name": "cpython-3.13.12+20260320-aarch64-apple-darwin-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.13.12%2B20260303-aarch64-pc-windows-msvc-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.13.12%2B20260320-aarch64-apple-darwin-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.13.12+20260303-aarch64-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.13.12+20260320-aarch64-pc-windows-msvc-freethreaded-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.13.12%2B20260303-aarch64-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.13.12%2B20260320-aarch64-pc-windows-msvc-freethreaded-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.13.12+20260303-aarch64-unknown-linux-musl-install_only.tar.gz", "name": "cpython-3.13.12+20260320-aarch64-pc-windows-msvc-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.13.12%2B20260303-aarch64-unknown-linux-musl-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.13.12%2B20260320-aarch64-pc-windows-msvc-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.13.12+20260303-armv7-unknown-linux-gnueabi-install_only.tar.gz", "name": "cpython-3.13.12+20260320-aarch64-unknown-linux-gnu-freethreaded-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.13.12%2B20260303-armv7-unknown-linux-gnueabi-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.13.12%2B20260320-aarch64-unknown-linux-gnu-freethreaded-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.13.12+20260303-armv7-unknown-linux-gnueabihf-install_only.tar.gz", "name": "cpython-3.13.12+20260320-aarch64-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.13.12%2B20260303-armv7-unknown-linux-gnueabihf-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.13.12%2B20260320-aarch64-unknown-linux-gnu-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.13.12+20260303-i686-pc-windows-msvc-install_only.tar.gz", "name": "cpython-3.13.12+20260320-aarch64-unknown-linux-musl-freethreaded-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.13.12%2B20260303-i686-pc-windows-msvc-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.13.12%2B20260320-aarch64-unknown-linux-musl-freethreaded-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.13.12+20260303-ppc64le-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.13.12+20260320-aarch64-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.13.12%2B20260303-ppc64le-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.13.12%2B20260320-aarch64-unknown-linux-musl-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.13.12+20260303-riscv64-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.13.12+20260320-armv7-unknown-linux-gnueabi-freethreaded-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.13.12%2B20260303-riscv64-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.13.12%2B20260320-armv7-unknown-linux-gnueabi-freethreaded-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.13.12+20260303-s390x-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.13.12+20260320-armv7-unknown-linux-gnueabi-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.13.12%2B20260303-s390x-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.13.12%2B20260320-armv7-unknown-linux-gnueabi-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.13.12+20260303-x86_64-apple-darwin-install_only.tar.gz", "name": "cpython-3.13.12+20260320-armv7-unknown-linux-gnueabihf-freethreaded-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.13.12%2B20260303-x86_64-apple-darwin-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.13.12%2B20260320-armv7-unknown-linux-gnueabihf-freethreaded-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.13.12+20260303-x86_64-pc-windows-msvc-install_only.tar.gz", "name": "cpython-3.13.12+20260320-armv7-unknown-linux-gnueabihf-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.13.12%2B20260303-x86_64-pc-windows-msvc-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.13.12%2B20260320-armv7-unknown-linux-gnueabihf-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.13.12+20260303-x86_64-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.13.12+20260320-i686-pc-windows-msvc-freethreaded-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.13.12%2B20260303-x86_64-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.13.12%2B20260320-i686-pc-windows-msvc-freethreaded-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.13.12+20260303-x86_64-unknown-linux-musl-install_only.tar.gz", "name": "cpython-3.13.12+20260320-i686-pc-windows-msvc-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.13.12%2B20260303-x86_64-unknown-linux-musl-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.13.12%2B20260320-i686-pc-windows-msvc-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.13.12+20260303-x86_64_v2-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.13.12+20260320-ppc64le-unknown-linux-gnu-freethreaded-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.13.12%2B20260303-x86_64_v2-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.13.12%2B20260320-ppc64le-unknown-linux-gnu-freethreaded-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.13.12+20260303-x86_64_v2-unknown-linux-musl-install_only.tar.gz", "name": "cpython-3.13.12+20260320-ppc64le-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.13.12%2B20260303-x86_64_v2-unknown-linux-musl-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.13.12%2B20260320-ppc64le-unknown-linux-gnu-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.13.12+20260303-x86_64_v3-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.13.12+20260320-riscv64-unknown-linux-gnu-freethreaded-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.13.12%2B20260303-x86_64_v3-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.13.12%2B20260320-riscv64-unknown-linux-gnu-freethreaded-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.13.12+20260303-x86_64_v3-unknown-linux-musl-install_only.tar.gz", "name": "cpython-3.13.12+20260320-riscv64-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.13.12%2B20260303-x86_64_v3-unknown-linux-musl-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.13.12%2B20260320-riscv64-unknown-linux-gnu-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.13.12+20260303-x86_64_v4-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.13.12+20260320-s390x-unknown-linux-gnu-freethreaded-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.13.12%2B20260303-x86_64_v4-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.13.12%2B20260320-s390x-unknown-linux-gnu-freethreaded-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.13.12+20260303-x86_64_v4-unknown-linux-musl-install_only.tar.gz", "name": "cpython-3.13.12+20260320-s390x-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.13.12%2B20260303-x86_64_v4-unknown-linux-musl-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.13.12%2B20260320-s390x-unknown-linux-gnu-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.14.3+20260303-aarch64-apple-darwin-install_only.tar.gz", "name": "cpython-3.13.12+20260320-x86_64-apple-darwin-freethreaded-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.14.3%2B20260303-aarch64-apple-darwin-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.13.12%2B20260320-x86_64-apple-darwin-freethreaded-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.14.3+20260303-aarch64-pc-windows-msvc-install_only.tar.gz", "name": "cpython-3.13.12+20260320-x86_64-apple-darwin-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.14.3%2B20260303-aarch64-pc-windows-msvc-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.13.12%2B20260320-x86_64-apple-darwin-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.14.3+20260303-aarch64-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.13.12+20260320-x86_64-pc-windows-msvc-freethreaded-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.14.3%2B20260303-aarch64-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.13.12%2B20260320-x86_64-pc-windows-msvc-freethreaded-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.14.3+20260303-aarch64-unknown-linux-musl-install_only.tar.gz", "name": "cpython-3.13.12+20260320-x86_64-pc-windows-msvc-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.14.3%2B20260303-aarch64-unknown-linux-musl-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.13.12%2B20260320-x86_64-pc-windows-msvc-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.14.3+20260303-armv7-unknown-linux-gnueabi-install_only.tar.gz", "name": "cpython-3.13.12+20260320-x86_64-unknown-linux-gnu-freethreaded-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.14.3%2B20260303-armv7-unknown-linux-gnueabi-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.13.12%2B20260320-x86_64-unknown-linux-gnu-freethreaded-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.14.3+20260303-armv7-unknown-linux-gnueabihf-install_only.tar.gz", "name": "cpython-3.13.12+20260320-x86_64-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.14.3%2B20260303-armv7-unknown-linux-gnueabihf-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.13.12%2B20260320-x86_64-unknown-linux-gnu-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.14.3+20260303-i686-pc-windows-msvc-install_only.tar.gz", "name": "cpython-3.13.12+20260320-x86_64-unknown-linux-musl-freethreaded-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.14.3%2B20260303-i686-pc-windows-msvc-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.13.12%2B20260320-x86_64-unknown-linux-musl-freethreaded-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.14.3+20260303-ppc64le-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.13.12+20260320-x86_64-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.14.3%2B20260303-ppc64le-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.13.12%2B20260320-x86_64-unknown-linux-musl-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.14.3+20260303-riscv64-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.13.12+20260320-x86_64_v2-unknown-linux-gnu-freethreaded-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.14.3%2B20260303-riscv64-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.13.12%2B20260320-x86_64_v2-unknown-linux-gnu-freethreaded-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.14.3+20260303-s390x-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.13.12+20260320-x86_64_v2-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.14.3%2B20260303-s390x-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.13.12%2B20260320-x86_64_v2-unknown-linux-gnu-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.14.3+20260303-x86_64-apple-darwin-install_only.tar.gz", "name": "cpython-3.13.12+20260320-x86_64_v2-unknown-linux-musl-freethreaded-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.14.3%2B20260303-x86_64-apple-darwin-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.13.12%2B20260320-x86_64_v2-unknown-linux-musl-freethreaded-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.14.3+20260303-x86_64-pc-windows-msvc-install_only.tar.gz", "name": "cpython-3.13.12+20260320-x86_64_v2-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.14.3%2B20260303-x86_64-pc-windows-msvc-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.13.12%2B20260320-x86_64_v2-unknown-linux-musl-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.14.3+20260303-x86_64-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.13.12+20260320-x86_64_v3-unknown-linux-gnu-freethreaded-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.14.3%2B20260303-x86_64-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.13.12%2B20260320-x86_64_v3-unknown-linux-gnu-freethreaded-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.14.3+20260303-x86_64-unknown-linux-musl-install_only.tar.gz", "name": "cpython-3.13.12+20260320-x86_64_v3-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.14.3%2B20260303-x86_64-unknown-linux-musl-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.13.12%2B20260320-x86_64_v3-unknown-linux-gnu-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.14.3+20260303-x86_64_v2-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.13.12+20260320-x86_64_v3-unknown-linux-musl-freethreaded-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.14.3%2B20260303-x86_64_v2-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.13.12%2B20260320-x86_64_v3-unknown-linux-musl-freethreaded-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.14.3+20260303-x86_64_v2-unknown-linux-musl-install_only.tar.gz", "name": "cpython-3.13.12+20260320-x86_64_v3-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.14.3%2B20260303-x86_64_v2-unknown-linux-musl-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.13.12%2B20260320-x86_64_v3-unknown-linux-musl-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.14.3+20260303-x86_64_v3-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.13.12+20260320-x86_64_v4-unknown-linux-gnu-freethreaded-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.14.3%2B20260303-x86_64_v3-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.13.12%2B20260320-x86_64_v4-unknown-linux-gnu-freethreaded-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.14.3+20260303-x86_64_v3-unknown-linux-musl-install_only.tar.gz", "name": "cpython-3.13.12+20260320-x86_64_v4-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.14.3%2B20260303-x86_64_v3-unknown-linux-musl-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.13.12%2B20260320-x86_64_v4-unknown-linux-gnu-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.14.3+20260303-x86_64_v4-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.13.12+20260320-x86_64_v4-unknown-linux-musl-freethreaded-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.14.3%2B20260303-x86_64_v4-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.13.12%2B20260320-x86_64_v4-unknown-linux-musl-freethreaded-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.14.3+20260303-x86_64_v4-unknown-linux-musl-install_only.tar.gz", "name": "cpython-3.13.12+20260320-x86_64_v4-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.14.3%2B20260303-x86_64_v4-unknown-linux-musl-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.13.12%2B20260320-x86_64_v4-unknown-linux-musl-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.15.0a6+20260303-aarch64-apple-darwin-install_only.tar.gz", "name": "cpython-3.14.3+20260320-aarch64-apple-darwin-freethreaded-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.15.0a6%2B20260303-aarch64-apple-darwin-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.14.3%2B20260320-aarch64-apple-darwin-freethreaded-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.15.0a6+20260303-aarch64-pc-windows-msvc-install_only.tar.gz", "name": "cpython-3.14.3+20260320-aarch64-apple-darwin-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.15.0a6%2B20260303-aarch64-pc-windows-msvc-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.14.3%2B20260320-aarch64-apple-darwin-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.15.0a6+20260303-aarch64-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.14.3+20260320-aarch64-pc-windows-msvc-freethreaded-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.15.0a6%2B20260303-aarch64-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.14.3%2B20260320-aarch64-pc-windows-msvc-freethreaded-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.15.0a6+20260303-aarch64-unknown-linux-musl-install_only.tar.gz", "name": "cpython-3.14.3+20260320-aarch64-pc-windows-msvc-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.15.0a6%2B20260303-aarch64-unknown-linux-musl-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.14.3%2B20260320-aarch64-pc-windows-msvc-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.15.0a6+20260303-armv7-unknown-linux-gnueabi-install_only.tar.gz", "name": "cpython-3.14.3+20260320-aarch64-unknown-linux-gnu-freethreaded-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.15.0a6%2B20260303-armv7-unknown-linux-gnueabi-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.14.3%2B20260320-aarch64-unknown-linux-gnu-freethreaded-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.15.0a6+20260303-armv7-unknown-linux-gnueabihf-install_only.tar.gz", "name": "cpython-3.14.3+20260320-aarch64-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.15.0a6%2B20260303-armv7-unknown-linux-gnueabihf-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.14.3%2B20260320-aarch64-unknown-linux-gnu-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.15.0a6+20260303-i686-pc-windows-msvc-install_only.tar.gz", "name": "cpython-3.14.3+20260320-aarch64-unknown-linux-musl-freethreaded-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.15.0a6%2B20260303-i686-pc-windows-msvc-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.14.3%2B20260320-aarch64-unknown-linux-musl-freethreaded-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.15.0a6+20260303-ppc64le-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.14.3+20260320-aarch64-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.15.0a6%2B20260303-ppc64le-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.14.3%2B20260320-aarch64-unknown-linux-musl-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.15.0a6+20260303-riscv64-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.14.3+20260320-armv7-unknown-linux-gnueabi-freethreaded-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.15.0a6%2B20260303-riscv64-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.14.3%2B20260320-armv7-unknown-linux-gnueabi-freethreaded-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.15.0a6+20260303-s390x-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.14.3+20260320-armv7-unknown-linux-gnueabi-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.15.0a6%2B20260303-s390x-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.14.3%2B20260320-armv7-unknown-linux-gnueabi-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.15.0a6+20260303-x86_64-apple-darwin-install_only.tar.gz", "name": "cpython-3.14.3+20260320-armv7-unknown-linux-gnueabihf-freethreaded-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.15.0a6%2B20260303-x86_64-apple-darwin-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.14.3%2B20260320-armv7-unknown-linux-gnueabihf-freethreaded-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.15.0a6+20260303-x86_64-pc-windows-msvc-install_only.tar.gz", "name": "cpython-3.14.3+20260320-armv7-unknown-linux-gnueabihf-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.15.0a6%2B20260303-x86_64-pc-windows-msvc-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.14.3%2B20260320-armv7-unknown-linux-gnueabihf-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.15.0a6+20260303-x86_64-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.14.3+20260320-i686-pc-windows-msvc-freethreaded-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.15.0a6%2B20260303-x86_64-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.14.3%2B20260320-i686-pc-windows-msvc-freethreaded-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.15.0a6+20260303-x86_64-unknown-linux-musl-install_only.tar.gz", "name": "cpython-3.14.3+20260320-i686-pc-windows-msvc-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.15.0a6%2B20260303-x86_64-unknown-linux-musl-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.14.3%2B20260320-i686-pc-windows-msvc-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.15.0a6+20260303-x86_64_v2-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.14.3+20260320-ppc64le-unknown-linux-gnu-freethreaded-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.15.0a6%2B20260303-x86_64_v2-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.14.3%2B20260320-ppc64le-unknown-linux-gnu-freethreaded-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.15.0a6+20260303-x86_64_v2-unknown-linux-musl-install_only.tar.gz", "name": "cpython-3.14.3+20260320-ppc64le-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.15.0a6%2B20260303-x86_64_v2-unknown-linux-musl-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.14.3%2B20260320-ppc64le-unknown-linux-gnu-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.15.0a6+20260303-x86_64_v3-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.14.3+20260320-riscv64-unknown-linux-gnu-freethreaded-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.15.0a6%2B20260303-x86_64_v3-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.14.3%2B20260320-riscv64-unknown-linux-gnu-freethreaded-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.15.0a6+20260303-x86_64_v3-unknown-linux-musl-install_only.tar.gz", "name": "cpython-3.14.3+20260320-riscv64-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.15.0a6%2B20260303-x86_64_v3-unknown-linux-musl-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.14.3%2B20260320-riscv64-unknown-linux-gnu-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.15.0a6+20260303-x86_64_v4-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.14.3+20260320-s390x-unknown-linux-gnu-freethreaded-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.15.0a6%2B20260303-x86_64_v4-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.14.3%2B20260320-s390x-unknown-linux-gnu-freethreaded-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.15.0a6+20260303-x86_64_v4-unknown-linux-musl-install_only.tar.gz", "name": "cpython-3.14.3+20260320-s390x-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260303/cpython-3.15.0a6%2B20260303-x86_64_v4-unknown-linux-musl-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.14.3%2B20260320-s390x-unknown-linux-gnu-install_only.tar.gz"
},
{
"name": "cpython-3.14.3+20260320-x86_64-apple-darwin-freethreaded-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.14.3%2B20260320-x86_64-apple-darwin-freethreaded-install_only.tar.gz"
},
{
"name": "cpython-3.14.3+20260320-x86_64-apple-darwin-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.14.3%2B20260320-x86_64-apple-darwin-install_only.tar.gz"
},
{
"name": "cpython-3.14.3+20260320-x86_64-pc-windows-msvc-freethreaded-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.14.3%2B20260320-x86_64-pc-windows-msvc-freethreaded-install_only.tar.gz"
},
{
"name": "cpython-3.14.3+20260320-x86_64-pc-windows-msvc-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.14.3%2B20260320-x86_64-pc-windows-msvc-install_only.tar.gz"
},
{
"name": "cpython-3.14.3+20260320-x86_64-unknown-linux-gnu-freethreaded-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.14.3%2B20260320-x86_64-unknown-linux-gnu-freethreaded-install_only.tar.gz"
},
{
"name": "cpython-3.14.3+20260320-x86_64-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.14.3%2B20260320-x86_64-unknown-linux-gnu-install_only.tar.gz"
},
{
"name": "cpython-3.14.3+20260320-x86_64-unknown-linux-musl-freethreaded-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.14.3%2B20260320-x86_64-unknown-linux-musl-freethreaded-install_only.tar.gz"
},
{
"name": "cpython-3.14.3+20260320-x86_64-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.14.3%2B20260320-x86_64-unknown-linux-musl-install_only.tar.gz"
},
{
"name": "cpython-3.14.3+20260320-x86_64_v2-unknown-linux-gnu-freethreaded-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.14.3%2B20260320-x86_64_v2-unknown-linux-gnu-freethreaded-install_only.tar.gz"
},
{
"name": "cpython-3.14.3+20260320-x86_64_v2-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.14.3%2B20260320-x86_64_v2-unknown-linux-gnu-install_only.tar.gz"
},
{
"name": "cpython-3.14.3+20260320-x86_64_v2-unknown-linux-musl-freethreaded-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.14.3%2B20260320-x86_64_v2-unknown-linux-musl-freethreaded-install_only.tar.gz"
},
{
"name": "cpython-3.14.3+20260320-x86_64_v2-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.14.3%2B20260320-x86_64_v2-unknown-linux-musl-install_only.tar.gz"
},
{
"name": "cpython-3.14.3+20260320-x86_64_v3-unknown-linux-gnu-freethreaded-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.14.3%2B20260320-x86_64_v3-unknown-linux-gnu-freethreaded-install_only.tar.gz"
},
{
"name": "cpython-3.14.3+20260320-x86_64_v3-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.14.3%2B20260320-x86_64_v3-unknown-linux-gnu-install_only.tar.gz"
},
{
"name": "cpython-3.14.3+20260320-x86_64_v3-unknown-linux-musl-freethreaded-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.14.3%2B20260320-x86_64_v3-unknown-linux-musl-freethreaded-install_only.tar.gz"
},
{
"name": "cpython-3.14.3+20260320-x86_64_v3-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.14.3%2B20260320-x86_64_v3-unknown-linux-musl-install_only.tar.gz"
},
{
"name": "cpython-3.14.3+20260320-x86_64_v4-unknown-linux-gnu-freethreaded-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.14.3%2B20260320-x86_64_v4-unknown-linux-gnu-freethreaded-install_only.tar.gz"
},
{
"name": "cpython-3.14.3+20260320-x86_64_v4-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.14.3%2B20260320-x86_64_v4-unknown-linux-gnu-install_only.tar.gz"
},
{
"name": "cpython-3.14.3+20260320-x86_64_v4-unknown-linux-musl-freethreaded-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.14.3%2B20260320-x86_64_v4-unknown-linux-musl-freethreaded-install_only.tar.gz"
},
{
"name": "cpython-3.14.3+20260320-x86_64_v4-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.14.3%2B20260320-x86_64_v4-unknown-linux-musl-install_only.tar.gz"
},
{
"name": "cpython-3.15.0a7+20260320-aarch64-apple-darwin-freethreaded-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.15.0a7%2B20260320-aarch64-apple-darwin-freethreaded-install_only.tar.gz"
},
{
"name": "cpython-3.15.0a7+20260320-aarch64-apple-darwin-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.15.0a7%2B20260320-aarch64-apple-darwin-install_only.tar.gz"
},
{
"name": "cpython-3.15.0a7+20260320-aarch64-pc-windows-msvc-freethreaded-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.15.0a7%2B20260320-aarch64-pc-windows-msvc-freethreaded-install_only.tar.gz"
},
{
"name": "cpython-3.15.0a7+20260320-aarch64-pc-windows-msvc-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.15.0a7%2B20260320-aarch64-pc-windows-msvc-install_only.tar.gz"
},
{
"name": "cpython-3.15.0a7+20260320-aarch64-unknown-linux-gnu-freethreaded-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.15.0a7%2B20260320-aarch64-unknown-linux-gnu-freethreaded-install_only.tar.gz"
},
{
"name": "cpython-3.15.0a7+20260320-aarch64-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.15.0a7%2B20260320-aarch64-unknown-linux-gnu-install_only.tar.gz"
},
{
"name": "cpython-3.15.0a7+20260320-aarch64-unknown-linux-musl-freethreaded-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.15.0a7%2B20260320-aarch64-unknown-linux-musl-freethreaded-install_only.tar.gz"
},
{
"name": "cpython-3.15.0a7+20260320-aarch64-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.15.0a7%2B20260320-aarch64-unknown-linux-musl-install_only.tar.gz"
},
{
"name": "cpython-3.15.0a7+20260320-armv7-unknown-linux-gnueabi-freethreaded-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.15.0a7%2B20260320-armv7-unknown-linux-gnueabi-freethreaded-install_only.tar.gz"
},
{
"name": "cpython-3.15.0a7+20260320-armv7-unknown-linux-gnueabi-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.15.0a7%2B20260320-armv7-unknown-linux-gnueabi-install_only.tar.gz"
},
{
"name": "cpython-3.15.0a7+20260320-armv7-unknown-linux-gnueabihf-freethreaded-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.15.0a7%2B20260320-armv7-unknown-linux-gnueabihf-freethreaded-install_only.tar.gz"
},
{
"name": "cpython-3.15.0a7+20260320-armv7-unknown-linux-gnueabihf-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.15.0a7%2B20260320-armv7-unknown-linux-gnueabihf-install_only.tar.gz"
},
{
"name": "cpython-3.15.0a7+20260320-i686-pc-windows-msvc-freethreaded-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.15.0a7%2B20260320-i686-pc-windows-msvc-freethreaded-install_only.tar.gz"
},
{
"name": "cpython-3.15.0a7+20260320-i686-pc-windows-msvc-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.15.0a7%2B20260320-i686-pc-windows-msvc-install_only.tar.gz"
},
{
"name": "cpython-3.15.0a7+20260320-ppc64le-unknown-linux-gnu-freethreaded-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.15.0a7%2B20260320-ppc64le-unknown-linux-gnu-freethreaded-install_only.tar.gz"
},
{
"name": "cpython-3.15.0a7+20260320-ppc64le-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.15.0a7%2B20260320-ppc64le-unknown-linux-gnu-install_only.tar.gz"
},
{
"name": "cpython-3.15.0a7+20260320-riscv64-unknown-linux-gnu-freethreaded-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.15.0a7%2B20260320-riscv64-unknown-linux-gnu-freethreaded-install_only.tar.gz"
},
{
"name": "cpython-3.15.0a7+20260320-riscv64-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.15.0a7%2B20260320-riscv64-unknown-linux-gnu-install_only.tar.gz"
},
{
"name": "cpython-3.15.0a7+20260320-s390x-unknown-linux-gnu-freethreaded-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.15.0a7%2B20260320-s390x-unknown-linux-gnu-freethreaded-install_only.tar.gz"
},
{
"name": "cpython-3.15.0a7+20260320-s390x-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.15.0a7%2B20260320-s390x-unknown-linux-gnu-install_only.tar.gz"
},
{
"name": "cpython-3.15.0a7+20260320-x86_64-apple-darwin-freethreaded-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.15.0a7%2B20260320-x86_64-apple-darwin-freethreaded-install_only.tar.gz"
},
{
"name": "cpython-3.15.0a7+20260320-x86_64-apple-darwin-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.15.0a7%2B20260320-x86_64-apple-darwin-install_only.tar.gz"
},
{
"name": "cpython-3.15.0a7+20260320-x86_64-pc-windows-msvc-freethreaded-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.15.0a7%2B20260320-x86_64-pc-windows-msvc-freethreaded-install_only.tar.gz"
},
{
"name": "cpython-3.15.0a7+20260320-x86_64-pc-windows-msvc-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.15.0a7%2B20260320-x86_64-pc-windows-msvc-install_only.tar.gz"
},
{
"name": "cpython-3.15.0a7+20260320-x86_64-unknown-linux-gnu-freethreaded-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.15.0a7%2B20260320-x86_64-unknown-linux-gnu-freethreaded-install_only.tar.gz"
},
{
"name": "cpython-3.15.0a7+20260320-x86_64-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.15.0a7%2B20260320-x86_64-unknown-linux-gnu-install_only.tar.gz"
},
{
"name": "cpython-3.15.0a7+20260320-x86_64-unknown-linux-musl-freethreaded-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.15.0a7%2B20260320-x86_64-unknown-linux-musl-freethreaded-install_only.tar.gz"
},
{
"name": "cpython-3.15.0a7+20260320-x86_64-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.15.0a7%2B20260320-x86_64-unknown-linux-musl-install_only.tar.gz"
},
{
"name": "cpython-3.15.0a7+20260320-x86_64_v2-unknown-linux-gnu-freethreaded-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.15.0a7%2B20260320-x86_64_v2-unknown-linux-gnu-freethreaded-install_only.tar.gz"
},
{
"name": "cpython-3.15.0a7+20260320-x86_64_v2-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.15.0a7%2B20260320-x86_64_v2-unknown-linux-gnu-install_only.tar.gz"
},
{
"name": "cpython-3.15.0a7+20260320-x86_64_v2-unknown-linux-musl-freethreaded-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.15.0a7%2B20260320-x86_64_v2-unknown-linux-musl-freethreaded-install_only.tar.gz"
},
{
"name": "cpython-3.15.0a7+20260320-x86_64_v2-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.15.0a7%2B20260320-x86_64_v2-unknown-linux-musl-install_only.tar.gz"
},
{
"name": "cpython-3.15.0a7+20260320-x86_64_v3-unknown-linux-gnu-freethreaded-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.15.0a7%2B20260320-x86_64_v3-unknown-linux-gnu-freethreaded-install_only.tar.gz"
},
{
"name": "cpython-3.15.0a7+20260320-x86_64_v3-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.15.0a7%2B20260320-x86_64_v3-unknown-linux-gnu-install_only.tar.gz"
},
{
"name": "cpython-3.15.0a7+20260320-x86_64_v3-unknown-linux-musl-freethreaded-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.15.0a7%2B20260320-x86_64_v3-unknown-linux-musl-freethreaded-install_only.tar.gz"
},
{
"name": "cpython-3.15.0a7+20260320-x86_64_v3-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.15.0a7%2B20260320-x86_64_v3-unknown-linux-musl-install_only.tar.gz"
},
{
"name": "cpython-3.15.0a7+20260320-x86_64_v4-unknown-linux-gnu-freethreaded-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.15.0a7%2B20260320-x86_64_v4-unknown-linux-gnu-freethreaded-install_only.tar.gz"
},
{
"name": "cpython-3.15.0a7+20260320-x86_64_v4-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.15.0a7%2B20260320-x86_64_v4-unknown-linux-gnu-install_only.tar.gz"
},
{
"name": "cpython-3.15.0a7+20260320-x86_64_v4-unknown-linux-musl-freethreaded-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.15.0a7%2B20260320-x86_64_v4-unknown-linux-musl-freethreaded-install_only.tar.gz"
},
{
"name": "cpython-3.15.0a7+20260320-x86_64_v4-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260320/cpython-3.15.0a7%2B20260320-x86_64_v4-unknown-linux-musl-install_only.tar.gz"
} }
] ]
} }
+1 -1
View File
@@ -1 +1 @@
default = { version = "21.1.0", url = "https://github.com/pypa/get-virtualenv/releases/download/21.1.0/virtualenv.pyz" } default = { version = "21.2.0", url = "https://github.com/pypa/get-virtualenv/releases/download/21.2.0/virtualenv.pyz" }
+1 -1
View File
@@ -1,7 +1,7 @@
import json import json
from typing import Any from typing import Any
from .util import resources from cibuildwheel.util import resources
def get_schema(tool_name: str = "cibuildwheel") -> dict[str, Any]: def get_schema(tool_name: str = "cibuildwheel") -> dict[str, Any]:
+7 -6
View File
@@ -2,7 +2,7 @@ import dataclasses
import itertools import itertools
from enum import StrEnum from enum import StrEnum
from fnmatch import fnmatch from fnmatch import fnmatch
from typing import Any from typing import Self
import bracex import bracex
from packaging.specifiers import SpecifierSet from packaging.specifiers import SpecifierSet
@@ -37,11 +37,12 @@ class EnableGroup(StrEnum):
PyodidePrerelease = "pyodide-prerelease" PyodidePrerelease = "pyodide-prerelease"
@classmethod @classmethod
def all_groups(cls) -> frozenset["EnableGroup"]: def all_groups(cls) -> frozenset[Self]:
return frozenset(cls) # see https://github.com/python/mypy/issues/20434 for the reason to type: ignore[arg-type]
return frozenset(set(cls) - {cls.CPythonFreeThreading}) # type: ignore[arg-type]
@classmethod @classmethod
def parse_option_value(cls, value: str) -> frozenset["EnableGroup"]: def parse_option_value(cls, value: str) -> frozenset[Self]:
""" """
Parses a string of space-separated values into a set of EnableGroup Parses a string of space-separated values into a set of EnableGroup
members. The string may contain group names or "all". members. The string may contain group names or "all".
@@ -113,7 +114,7 @@ class BuildSelector:
return should_build and not should_skip return should_build and not should_skip
def options_summary(self) -> Any: def options_summary(self) -> dict[str, str | list[str]]:
return { return {
"build_config": self.build_config, "build_config": self.build_config,
"skip_config": self.skip_config, "skip_config": self.skip_config,
@@ -134,5 +135,5 @@ class TestSelector:
should_skip = selector_matches(self.skip_config, build_id) should_skip = selector_matches(self.skip_config, build_id)
return not should_skip return not should_skip
def options_summary(self) -> Any: def options_summary(self) -> dict[str, str]:
return {"skip_config": self.skip_config} return {"skip_config": self.skip_config}
+2 -2
View File
@@ -7,8 +7,8 @@ import typing
from collections.abc import Iterator, Mapping from collections.abc import Iterator, Mapping
from typing import Final, Literal from typing import Final, Literal
from ..errors import FatalError from cibuildwheel.errors import FatalError
from ..typing import PathOrStr from cibuildwheel.typing import PathOrStr
_IS_WIN: Final[bool] = sys.platform.startswith("win") _IS_WIN: Final[bool] = sys.platform.startswith("win")
+1 -1
View File
@@ -12,7 +12,7 @@ from zipfile import ZipFile
import certifi import certifi
from platformdirs import user_cache_path from platformdirs import user_cache_path
from ..errors import FatalError from cibuildwheel.errors import FatalError
DEFAULT_CIBW_CACHE_PATH: Final[Path] = user_cache_path(appname="cibuildwheel", appauthor="pypa") DEFAULT_CIBW_CACHE_PATH: Final[Path] = user_cache_path(appname="cibuildwheel", appauthor="pypa")
CIBW_CACHE_PATH: Final[Path] = Path( CIBW_CACHE_PATH: Final[Path] = Path(
+1 -1
View File
@@ -7,7 +7,7 @@ import textwrap
from collections import defaultdict from collections import defaultdict
from collections.abc import Sequence from collections.abc import Sequence
from ..typing import PathOrStr from cibuildwheel.typing import PathOrStr
def format_safe(template: str, **kwargs: str | os.PathLike[str]) -> str: def format_safe(template: str, **kwargs: str | os.PathLike[str]) -> str:
+8 -9
View File
@@ -2,13 +2,13 @@ import shlex
from collections.abc import Mapping, Sequence from collections.abc import Mapping, Sequence
from dataclasses import dataclass, field from dataclasses import dataclass, field
from pathlib import Path, PurePath from pathlib import Path, PurePath
from typing import Any, Literal, Self, TypeVar from typing import Literal, Self, TypeVar
from packaging.utils import parse_wheel_filename from packaging.utils import parse_wheel_filename
from . import resources from cibuildwheel.util import resources
from .cmd import call from cibuildwheel.util.cmd import call
from .helpers import parse_key_value_string, unwrap from cibuildwheel.util.helpers import parse_key_value_string, unwrap
@dataclass(kw_only=True) @dataclass(kw_only=True)
@@ -102,7 +102,7 @@ class DependencyConstraints:
return None return None
def options_summary(self) -> Any: def options_summary(self) -> str | dict[str, str]:
if self == DependencyConstraints.pinned(): if self == DependencyConstraints.pinned():
return "pinned" return "pinned"
elif self.packages: elif self.packages:
@@ -169,10 +169,9 @@ def find_compatible_wheel(wheels: Sequence[T], identifier: str) -> T | None:
elif platform.startswith("pyodide"): elif platform.startswith("pyodide"):
# each Pyodide version has its own platform tag # each Pyodide version has its own platform tag
continue continue
else: # Windows should exactly match
# Windows should exactly match elif tag.platform != platform:
if tag.platform != platform: continue
continue
# If all the filters above pass, then the wheel is a previously built compatible wheel. # If all the filters above pass, then the wheel is a previously built compatible wheel.
return wheel return wheel
+1 -1
View File
@@ -3,7 +3,7 @@ import tomllib
from pathlib import Path from pathlib import Path
from typing import Final from typing import Final
from ..typing import PlatformName from cibuildwheel.typing import PlatformName
PATH: Final[Path] = Path(__file__).parent.parent / "resources" PATH: Final[Path] = Path(__file__).parent.parent / "resources"
INSTALL_CERTIFI_SCRIPT: Final[Path] = PATH / "install_certifi.py" INSTALL_CERTIFI_SCRIPT: Final[Path] = PATH / "install_certifi.py"
+3 -3
View File
@@ -12,9 +12,9 @@ from filelock import FileLock
from packaging.requirements import InvalidRequirement, Requirement from packaging.requirements import InvalidRequirement, Requirement
from packaging.version import Version from packaging.version import Version
from .util import resources from cibuildwheel.util import resources
from .util.cmd import call from cibuildwheel.util.cmd import call
from .util.file import CIBW_CACHE_PATH, download from cibuildwheel.util.file import CIBW_CACHE_PATH, download
_IS_WIN: Final[bool] = sys.platform.startswith("win") _IS_WIN: Final[bool] = sys.platform.startswith("win")
+16
View File
@@ -4,6 +4,16 @@ title: Changelog
# Changelog # Changelog
### v3.4.1
_2 April 2026_
- ⚠️ Building for the experimental CPython 3.13 free-threading variant is now deprecated. That functionality will be removed in the next minor release. The [`enable`](https://cibuildwheel.pypa.io/en/stable/options/#enable) option `cpython-freethreading` is therefore also deprecated. Builds specifying `enable = "all"` no longer select `cpython-freethreading`. CPython 3.14 free-threading support remains available without the `enable` flag. (#2787)
- 🐛 iOS builds will no longer skip `repair-wheel-command` if it's defined in config (#2761)
- 🐛 Fix bug causing `uv` to fail when environments define PYTHON_VERSION or UV_PYTHON, conflicting with our venvs (#2795)
- ✨ cibuildwheel prints the selected build identifiers at the start of the build. (#2785)
- 🔐 The GitHub Action now references other actions with a full SHA (#2744)
### v3.4.0 ### v3.4.0
_5 March 2026_ _5 March 2026_
@@ -167,6 +177,12 @@ See @henryiii's [release post](https://iscinumpy.dev/post/cibuildwheel-3-0-0/) f
- 📚 Docs now primarily use the pyproject.toml name of options, rather than the environment variable name. (#2389) - 📚 Docs now primarily use the pyproject.toml name of options, rather than the environment variable name. (#2389)
- 📚 README table now matches docs and auto-updates. (#2427, #2428) - 📚 README table now matches docs and auto-updates. (#2427, #2428)
### v2.23.4
_16 March 2026_
- 🐛 Fix HTTP 429 errors while downloading virtualenv from GitHub blob URLs uses a https://bootstrap.pypa.io/ URL instead. (#2775)
### v2.23.3 ### v2.23.3
_26 April 2025_ _26 April 2025_
+6 -3
View File
@@ -125,11 +125,14 @@ There are two suggested methods for keeping cibuildwheel up to date that instead
If you use GitHub Actions for builds, you can use cibuildwheel as an action: If you use GitHub Actions for builds, you can use cibuildwheel as an action:
```yaml ```yaml
uses: pypa/cibuildwheel@v3.4.0 uses: pypa/cibuildwheel@v3.4.1
``` ```
This is a composite step that just runs cibuildwheel using pipx. You can set command-line options as `with:` parameters, and use `env:` as normal. This is a composite step that just runs cibuildwheel using pipx. You can set command-line options as `with:` parameters, and use `env:` as normal.
!!! note "Minor version tags"
Unlike some GitHub Actions, cibuildwheel does **not** provide a floating `@v3` major-version tag, since our minor version change can add/remove wheels. You can, however, pin to a minor version such as `@v3.4` to automatically receive patch releases within that minor version. Dependabot (shown below) is the recommended way to stay up to date.
Then, your `.github/dependabot.yml` file could look like this: Then, your `.github/dependabot.yml` file could look like this:
```yaml ```yaml
@@ -147,7 +150,7 @@ The second option, and the only one that supports other CI systems, is using a `
```bash ```bash
# requirements-cibw.txt # requirements-cibw.txt
cibuildwheel==3.4.0 cibuildwheel==3.4.1
``` ```
Then your install step would have `python -m pip install -r requirements-cibw.txt` in it. Your `.github/dependabot.yml` file could look like this: Then your install step would have `python -m pip install -r requirements-cibw.txt` in it. Your `.github/dependabot.yml` file could look like this:
@@ -312,7 +315,7 @@ Solutions to this vary, but the simplest is to use pipx:
# most runners have pipx preinstalled, but in case you don't # most runners have pipx preinstalled, but in case you don't
python3 -m pip install pipx python3 -m pip install pipx
pipx run cibuildwheel==3.4.0 --output-dir wheelhouse pipx run cibuildwheel==3.4.1 --output-dir wheelhouse
pipx run twine upload wheelhouse/*.whl pipx run twine upload wheelhouse/*.whl
``` ```
+1 -1
View File
@@ -8,7 +8,7 @@ import rich.console
import rich.text import rich.text
def define_env(env: Any) -> None: def define_env(env: Any) -> None: # noqa: ANN401
"Hook function for mkdocs-macros" "Hook function for mkdocs-macros"
@env.macro # type: ignore[untyped-decorator] @env.macro # type: ignore[untyped-decorator]
+6 -6
View File
@@ -92,11 +92,11 @@ title: Working examples
| [keyvi][] | ![github icon][] | ![linux icon][] ![apple icon][] | FST based key value index highly optimized for size and lookup performance, utilizes ccache action for improved runtime | | [keyvi][] | ![github icon][] | ![linux icon][] ![apple icon][] | FST based key value index highly optimized for size and lookup performance, utilizes ccache action for improved runtime |
| [PyGLM][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Fast OpenGL Mathematics (GLM) for Python | | [PyGLM][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Fast OpenGL Mathematics (GLM) for Python |
| [iDynTree][] | ![github icon][] | ![linux icon][] | Uses manylinux_2_24 | | [iDynTree][] | ![github icon][] | ![linux icon][] | Uses manylinux_2_24 |
| [TgCrypto][] | ![travisci icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Includes a Windows Travis build. |
| [power-grid-model][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Python/C++ library for distribution power system analysis | | [power-grid-model][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Python/C++ library for distribution power system analysis |
| [TgCrypto][] | ![travisci icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Includes a Windows Travis build. |
| [streaming-form-data][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Streaming parser for multipart/form-data written in Cython | | [streaming-form-data][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Streaming parser for multipart/form-data written in Cython |
| [Imagecodecs (fork)][] | ![azurepipelines icon][] | ![apple icon][] ![linux icon][] | Over 20 external dependencies in compiled libraries, custom docker image, `libomp`, `openblas` and `install_name_tool` for macOS. |
| [pybase64][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Fast Base64 encoding/decoding in Python | | [pybase64][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Fast Base64 encoding/decoding in Python |
| [Imagecodecs (fork)][] | ![azurepipelines icon][] | ![apple icon][] ![linux icon][] | Over 20 external dependencies in compiled libraries, custom docker image, `libomp`, `openblas` and `install_name_tool` for macOS. |
| [bx-python][] | ![travisci icon][] | ![apple icon][] ![linux icon][] | A library that includes Cython extensions. | | [bx-python][] | ![travisci icon][] | ![apple icon][] ![linux icon][] | A library that includes Cython extensions. |
| [boost-histogram][] | ![github icon][] ![travisci icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Supports full range of wheels, including PyPy and alternate archs. | | [boost-histogram][] | ![github icon][] ![travisci icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Supports full range of wheels, including PyPy and alternate archs. |
| [Python-WebRTC][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | a Python extension that provides bindings to WebRTC M92 | | [Python-WebRTC][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | a Python extension that provides bindings to WebRTC M92 |
@@ -108,8 +108,8 @@ title: Working examples
| [ninja][] | ![github icon][] ![travisci icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Multitagged binary builds for all supported platforms, using cibw 2 config configuration. | | [ninja][] | ![github icon][] ![travisci icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Multitagged binary builds for all supported platforms, using cibw 2 config configuration. |
| [etebase-py][] | ![travisci icon][] | ![linux icon][] | Python bindings to a Rust library using `setuptools-rust`, and `sccache` for improved speed. | | [etebase-py][] | ![travisci icon][] | ![linux icon][] | Python bindings to a Rust library using `setuptools-rust`, and `sccache` for improved speed. |
| [cf-units][] | ![github icon][] | ![apple icon][] ![linux icon][] | Units of measure as required by the Climate and Forecast (CF) Metadata Conventions | | [cf-units][] | ![github icon][] | ![apple icon][] ![linux icon][] | Units of measure as required by the Climate and Forecast (CF) Metadata Conventions |
| [numpythia][] | ![github icon][] | ![apple icon][] ![linux icon][] | The interface between PYTHIA and NumPy |
| [SiPM][] | ![github icon][] | ![apple icon][] ![linux icon][] | High performance library for SiPM detectors simulation using C++17, OpenMP and AVX2 intrinsics. | | [SiPM][] | ![github icon][] | ![apple icon][] ![linux icon][] | High performance library for SiPM detectors simulation using C++17, OpenMP and AVX2 intrinsics. |
| [numpythia][] | ![github icon][] | ![apple icon][] ![linux icon][] | The interface between PYTHIA and NumPy |
| [aalink][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Async Python interface for Ableton Link. | | [aalink][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Async Python interface for Ableton Link. |
| [pyjet][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | The interface between FastJet and NumPy | | [pyjet][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | The interface between FastJet and NumPy |
| [ril][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | A python binding to Rust Imaging library using maturin and Pyo3, utilizes Github Action cache to improve speed. Builds abi3 wheels. | | [ril][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | A python binding to Rust Imaging library using maturin and Pyo3, utilizes Github Action cache to improve speed. Builds abi3 wheels. |
@@ -203,11 +203,11 @@ title: Working examples
[keyvi]: https://github.com/KeyviDev/keyvi [keyvi]: https://github.com/KeyviDev/keyvi
[PyGLM]: https://github.com/Zuzu-Typ/PyGLM [PyGLM]: https://github.com/Zuzu-Typ/PyGLM
[iDynTree]: https://github.com/robotology/idyntree [iDynTree]: https://github.com/robotology/idyntree
[TgCrypto]: https://github.com/pyrogram/tgcrypto
[power-grid-model]: https://github.com/PowerGridModel/power-grid-model [power-grid-model]: https://github.com/PowerGridModel/power-grid-model
[TgCrypto]: https://github.com/pyrogram/tgcrypto
[streaming-form-data]: https://github.com/siddhantgoel/streaming-form-data [streaming-form-data]: https://github.com/siddhantgoel/streaming-form-data
[Imagecodecs (fork)]: https://github.com/czaki/imagecodecs_build
[pybase64]: https://github.com/mayeut/pybase64 [pybase64]: https://github.com/mayeut/pybase64
[Imagecodecs (fork)]: https://github.com/czaki/imagecodecs_build
[bx-python]: https://github.com/bxlab/bx-python [bx-python]: https://github.com/bxlab/bx-python
[boost-histogram]: https://github.com/scikit-hep/boost-histogram [boost-histogram]: https://github.com/scikit-hep/boost-histogram
[Python-WebRTC]: https://github.com/MarshalX/python-webrtc [Python-WebRTC]: https://github.com/MarshalX/python-webrtc
@@ -219,8 +219,8 @@ title: Working examples
[ninja]: https://github.com/scikit-build/ninja-python-distributions [ninja]: https://github.com/scikit-build/ninja-python-distributions
[etebase-py]: https://github.com/etesync/etebase-py [etebase-py]: https://github.com/etesync/etebase-py
[cf-units]: https://github.com/SciTools/cf-units [cf-units]: https://github.com/SciTools/cf-units
[numpythia]: https://github.com/scikit-hep/numpythia
[SiPM]: https://github.com/EdoPro98/SimSiPM [SiPM]: https://github.com/EdoPro98/SimSiPM
[numpythia]: https://github.com/scikit-hep/numpythia
[aalink]: https://github.com/artfwo/aalink [aalink]: https://github.com/artfwo/aalink
[pyjet]: https://github.com/scikit-hep/pyjet [pyjet]: https://github.com/scikit-hep/pyjet
[ril]: https://github.com/Cryptex-github/ril-py [ril]: https://github.com/Cryptex-github/ril-py
+3 -3
View File
@@ -6,7 +6,7 @@ jobs:
- bash: | - bash: |
set -o errexit set -o errexit
python3 -m pip install --upgrade pip python3 -m pip install --upgrade pip
pip3 install cibuildwheel==3.4.0 pip3 install cibuildwheel==3.4.1
displayName: Install dependencies displayName: Install dependencies
- bash: cibuildwheel --output-dir wheelhouse . - bash: cibuildwheel --output-dir wheelhouse .
displayName: Build wheels displayName: Build wheels
@@ -20,7 +20,7 @@ jobs:
- bash: | - bash: |
set -o errexit set -o errexit
python3 -m pip install --upgrade pip python3 -m pip install --upgrade pip
python3 -m pip install cibuildwheel==3.4.0 python3 -m pip install cibuildwheel==3.4.1
displayName: Install dependencies displayName: Install dependencies
- bash: cibuildwheel --output-dir wheelhouse . - bash: cibuildwheel --output-dir wheelhouse .
displayName: Build wheels displayName: Build wheels
@@ -34,7 +34,7 @@ jobs:
- bash: | - bash: |
set -o errexit set -o errexit
python -m pip install --upgrade pip python -m pip install --upgrade pip
pip install cibuildwheel==3.4.0 pip install cibuildwheel==3.4.1
displayName: Install dependencies displayName: Install dependencies
- bash: cibuildwheel --output-dir wheelhouse . - bash: cibuildwheel --output-dir wheelhouse .
displayName: Build wheels displayName: Build wheels
+3 -3
View File
@@ -11,7 +11,7 @@ jobs:
- run: - run:
name: Build the Linux wheels. name: Build the Linux wheels.
command: | command: |
python3 -m pip install --user cibuildwheel==3.4.0 python3 -m pip install --user cibuildwheel==3.4.1
cibuildwheel --output-dir wheelhouse cibuildwheel --output-dir wheelhouse
- store_artifacts: - store_artifacts:
path: wheelhouse/ path: wheelhouse/
@@ -28,7 +28,7 @@ jobs:
- run: - run:
name: Build the Linux aarch64 wheels. name: Build the Linux aarch64 wheels.
command: | command: |
python3 -m pip install --user cibuildwheel==3.4.0 python3 -m pip install --user cibuildwheel==3.4.1
python3 -m cibuildwheel --output-dir wheelhouse python3 -m cibuildwheel --output-dir wheelhouse
- store_artifacts: - store_artifacts:
path: wheelhouse/ path: wheelhouse/
@@ -44,7 +44,7 @@ jobs:
name: Build the OS X wheels. name: Build the OS X wheels.
command: | command: |
sudo softwareupdate --install-rosetta --agree-to-license # for python<=3.8 or x86_64/universal2 tests sudo softwareupdate --install-rosetta --agree-to-license # for python<=3.8 or x86_64/universal2 tests
pip3 install cibuildwheel==3.4.0 pip3 install cibuildwheel==3.4.1
cibuildwheel --output-dir wheelhouse cibuildwheel --output-dir wheelhouse
- store_artifacts: - store_artifacts:
path: wheelhouse/ path: wheelhouse/
+1 -1
View File
@@ -1,6 +1,6 @@
build_and_store_wheels: &BUILD_AND_STORE_WHEELS build_and_store_wheels: &BUILD_AND_STORE_WHEELS
install_cibuildwheel_script: install_cibuildwheel_script:
- python -m pip install cibuildwheel==3.4.0 - python -m pip install cibuildwheel==3.4.1
run_cibuildwheel_script: run_cibuildwheel_script:
- cibuildwheel - cibuildwheel
wheels_artifacts: wheels_artifacts:
+1 -1
View File
@@ -1,6 +1,6 @@
build_and_store_wheels: &BUILD_AND_STORE_WHEELS build_and_store_wheels: &BUILD_AND_STORE_WHEELS
install_cibuildwheel_script: install_cibuildwheel_script:
- python -m pip install cibuildwheel==3.4.0 - python -m pip install cibuildwheel==3.4.1
run_cibuildwheel_script: run_cibuildwheel_script:
- cibuildwheel - cibuildwheel
wheels_artifacts: wheels_artifacts:
+1 -1
View File
@@ -53,7 +53,7 @@ jobs:
persist-credentials: false persist-credentials: false
- name: Build wheels - name: Build wheels
uses: pypa/cibuildwheel@v3.4.0 uses: pypa/cibuildwheel@v3.4.1
env: env:
CIBW_PLATFORM: ${{ matrix.platform || 'auto' }} CIBW_PLATFORM: ${{ matrix.platform || 'auto' }}
CIBW_ARCHS: ${{ matrix.archs || 'auto' }} CIBW_ARCHS: ${{ matrix.archs || 'auto' }}
+1 -1
View File
@@ -17,7 +17,7 @@ jobs:
persist-credentials: false persist-credentials: false
- name: Build wheels - name: Build wheels
uses: pypa/cibuildwheel@v3.4.0 uses: pypa/cibuildwheel@v3.4.1
# env: # env:
# CIBW_SOME_OPTION: value # CIBW_SOME_OPTION: value
# ... # ...
+1 -1
View File
@@ -17,7 +17,7 @@ jobs:
persist-credentials: false persist-credentials: false
- name: Build wheels - name: Build wheels
run: pipx run cibuildwheel==3.4.0 run: pipx run cibuildwheel==3.4.1
- uses: actions/upload-artifact@v4 - uses: actions/upload-artifact@v4
with: with:
+1 -1
View File
@@ -23,7 +23,7 @@ jobs:
platforms: all platforms: all
- name: Build wheels - name: Build wheels
uses: pypa/cibuildwheel@v3.4.0 uses: pypa/cibuildwheel@v3.4.1
env: env:
# configure cibuildwheel on Linux to build native archs ('auto'), # configure cibuildwheel on Linux to build native archs ('auto'),
# and to split the remaining architectures between the x86_64 and # and to split the remaining architectures between the x86_64 and
+3 -3
View File
@@ -12,7 +12,7 @@ linux:
DOCKER_TLS_CERTDIR: "" DOCKER_TLS_CERTDIR: ""
script: script:
- curl -sSL https://get.docker.com/ | sh - curl -sSL https://get.docker.com/ | sh
- python -m pip install cibuildwheel==3.4.0 - python -m pip install cibuildwheel==3.4.1
- cibuildwheel --output-dir wheelhouse - cibuildwheel --output-dir wheelhouse
artifacts: artifacts:
paths: paths:
@@ -23,7 +23,7 @@ windows:
before_script: before_script:
- choco install python -y --allow-downgrade --version 3.12.4 - choco install python -y --allow-downgrade --version 3.12.4
- choco install git.install -y - choco install git.install -y
- py -m pip install cibuildwheel==3.4.0 - py -m pip install cibuildwheel==3.4.1
script: script:
- py -m cibuildwheel --output-dir wheelhouse --platform windows - py -m cibuildwheel --output-dir wheelhouse --platform windows
artifacts: artifacts:
@@ -35,7 +35,7 @@ windows:
macos: macos:
image: macos-14-xcode-15 image: macos-14-xcode-15
before_script: before_script:
- python3 -m pip install cibuildwheel==3.4.0 - python3 -m pip install cibuildwheel==3.4.1
script: script:
- python3 -m cibuildwheel --output-dir wheelhouse - python3 -m cibuildwheel --output-dir wheelhouse
artifacts: artifacts:
+1 -1
View File
@@ -14,7 +14,7 @@ linux:
- curl -sSL https://get.docker.com/ | sh - curl -sSL https://get.docker.com/ | sh
# Warning: This is extremely slow, be careful with how many wheels you build # Warning: This is extremely slow, be careful with how many wheels you build
- docker run --rm --privileged multiarch/qemu-user-static --reset -p yes - docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
- python -m pip install cibuildwheel==3.4.0 - python -m pip install cibuildwheel==3.4.1
# Assuming your CI runner's default architecture is x86_64... # Assuming your CI runner's default architecture is x86_64...
- cibuildwheel --output-dir wheelhouse --platform linux --archs aarch64 - cibuildwheel --output-dir wheelhouse --platform linux --archs aarch64
artifacts: artifacts:
+11 -12
View File
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
[project] [project]
name = "cibuildwheel" name = "cibuildwheel"
version = "3.4.0" version = "3.4.1"
description = "Build Python wheels on CI with minimal configuration." description = "Build Python wheels on CI with minimal configuration."
readme = "README.md" readme = "README.md"
license = "BSD-2-Clause" license = "BSD-2-Clause"
@@ -128,17 +128,10 @@ files = [
"noxfile.py", "noxfile.py",
] ]
warn_unused_configs = true warn_unused_configs = true
strict = true strict = true
disallow_untyped_defs = false
enable_error_code = ["ignore-without-code", "redundant-expr", "truthy-bool"] enable_error_code = ["ignore-without-code", "redundant-expr", "truthy-bool"]
warn_unreachable = false warn_unreachable = false
[[tool.mypy.overrides]]
module = "cibuildwheel.*"
disallow_untyped_defs = true
[[tool.mypy.overrides]] [[tool.mypy.overrides]]
module = [ module = [
"setuptools._distutils", # needed even if only directly import setuptools._distutils.util "setuptools._distutils", # needed even if only directly import setuptools._distutils.util
@@ -190,6 +183,7 @@ messages_control.disable = [
] ]
[tool.ruff] [tool.ruff]
show-fixes = true
line-length = 100 line-length = 100
[tool.ruff.lint] [tool.ruff.lint]
@@ -197,6 +191,7 @@ extend-select = [
"B", # flake8-bugbear "B", # flake8-bugbear
"I", # isort "I", # isort
"ARG", # flake8-unused-arguments "ARG", # flake8-unused-arguments
"ANN", # flake8-annotations
"C4", # flake8-comprehensions "C4", # flake8-comprehensions
"EM", # flake8-errmsg "EM", # flake8-errmsg
"ICN", # flake8-import-conventions "ICN", # flake8-import-conventions
@@ -211,6 +206,7 @@ extend-select = [
"RUF", # Ruff-specific "RUF", # Ruff-specific
"SIM", # flake8-simplify "SIM", # flake8-simplify
"TID251", # flake8-tidy-imports.banned-api "TID251", # flake8-tidy-imports.banned-api
"TID252", # flake8-tidy-imports.relative-imports
"UP", # pyupgrade "UP", # pyupgrade
"YTT", # flake8-2020 "YTT", # flake8-2020
"EXE", # flake8-executable "EXE", # flake8-executable
@@ -227,15 +223,17 @@ extend-select = [
"TC", # flake8-type-checking "TC", # flake8-type-checking
] ]
ignore = [ ignore = [
"PLR", # Design related pylint codes "PLR09", # Design related pylint codes
"PLR2004", # Magic value in comparison
"RET504", "RET505", "RET508", # else after control flow "RET504", "RET505", "RET508", # else after control flow
"PT007", # Lists of tuples in Pytest "PT007", # Lists of tuples in Pytest
"PYI025", # Set as AbstractSet "PYI025", # Set as AbstractSet
"ISC001", # Conflicts with formatter
"EXE003", # Ruff doesn't like uv?
"PTH123", # open -> Path.open "PTH123", # open -> Path.open
] ]
flake8-unused-arguments.ignore-variadic-names = true flake8-unused-arguments.ignore-variadic-names = true
flake8-tidy-imports.ban-relative-imports = "all"
flake8-annotations.allow-star-arg-any = true
flake8-annotations.mypy-init-return = true
[tool.ruff.lint.flake8-tidy-imports.banned-api] [tool.ruff.lint.flake8-tidy-imports.banned-api]
"typing.Mapping".msg = "Use collections.abc.Mapping instead." "typing.Mapping".msg = "Use collections.abc.Mapping instead."
@@ -245,7 +243,8 @@ flake8-unused-arguments.ignore-variadic-names = true
"typing.Set".msg = "Use collections.abc.Set instead." "typing.Set".msg = "Use collections.abc.Set instead."
[tool.ruff.lint.per-file-ignores] [tool.ruff.lint.per-file-ignores]
"unit_test/*" = ["PLC1901"] "unit_test/*" = ["PLC1901", "TID252"]
"test/*" = ["TID252"]
"bin/*" = ["TID251"] "bin/*" = ["TID251"]
"cibuildwheel/resources/install_certifi.py" = ["PTH"] "cibuildwheel/resources/install_certifi.py" = ["PTH"]
+1 -1
View File
@@ -46,7 +46,7 @@ def pytest_addoption(parser: pytest.Parser) -> None:
) )
def pytest_configure(config): def pytest_configure(config: pytest.Config) -> None:
flag_enable = config.getoption("--enable") flag_enable = config.getoption("--enable")
flag_platform = config.getoption("--platform") flag_platform = config.getoption("--platform")
+12 -5
View File
@@ -1,4 +1,5 @@
import textwrap import textwrap
from pathlib import Path
import packaging.utils import packaging.utils
import pytest import pytest
@@ -21,7 +22,7 @@ basic_project = test_projects.new_c_project(
@pytest.mark.serial @pytest.mark.serial
def test_dummy_serial(): def test_dummy_serial() -> None:
"""A no-op test to ensure that at least one serial test is always found. """A no-op test to ensure that at least one serial test is always found.
Without this no-op test, CI fails on CircleCI because no serial tests are Without this no-op test, CI fails on CircleCI because no serial tests are
@@ -29,7 +30,9 @@ def test_dummy_serial():
""" """
def test(tmp_path, build_frontend_env, capfd): def test(
tmp_path: Path, build_frontend_env: dict[str, str], capfd: pytest.CaptureFixture[str]
) -> None:
project_dir = tmp_path / "project" project_dir = tmp_path / "project"
basic_project.generate(project_dir) basic_project.generate(project_dir)
@@ -52,7 +55,7 @@ def test(tmp_path, build_frontend_env, capfd):
@pytest.mark.skip(reason="to keep test output clean") @pytest.mark.skip(reason="to keep test output clean")
def test_sample_build(tmp_path, capfd): def test_sample_build(tmp_path: Path, capfd: pytest.CaptureFixture[str]) -> None:
project_dir = tmp_path / "project" project_dir = tmp_path / "project"
basic_project.generate(project_dir) basic_project.generate(project_dir)
@@ -70,7 +73,9 @@ def test_sample_build(tmp_path, capfd):
@pytest.mark.parametrize( @pytest.mark.parametrize(
"enable_setting", ["", "cpython-prerelease", "pypy", "cpython-freethreading"] "enable_setting", ["", "cpython-prerelease", "pypy", "cpython-freethreading"]
) )
def test_build_identifiers(tmp_path, enable_setting, monkeypatch): def test_build_identifiers(
tmp_path: Path, enable_setting: str, monkeypatch: pytest.MonkeyPatch
) -> None:
project_dir = tmp_path / "project" project_dir = tmp_path / "project"
basic_project.generate(project_dir) basic_project.generate(project_dir)
@@ -93,7 +98,9 @@ def test_build_identifiers(tmp_path, enable_setting, monkeypatch):
(None, {"CIBW_ALLOW_EMPTY": "1"}), (None, {"CIBW_ALLOW_EMPTY": "1"}),
], ],
) )
def test_allow_empty(tmp_path, add_args, env_allow_empty): def test_allow_empty(
tmp_path: Path, add_args: list[str] | None, env_allow_empty: dict[str, str]
) -> None:
project_dir = tmp_path / "project" project_dir = tmp_path / "project"
basic_project.generate(project_dir) basic_project.generate(project_dir)
+8 -5
View File
@@ -1,4 +1,7 @@
import textwrap import textwrap
from pathlib import Path
import pytest
from . import test_projects, utils from . import test_projects, utils
@@ -31,7 +34,7 @@ limited_api_project = test_projects.new_c_project(
limited_api_project.files["pyproject.toml"] = pyproject_toml limited_api_project.files["pyproject.toml"] = pyproject_toml
def test_abi3(tmp_path): def test_abi3(tmp_path: Path) -> None:
project_dir = tmp_path / "project" project_dir = tmp_path / "project"
limited_api_project.generate(project_dir) limited_api_project.generate(project_dir)
@@ -41,7 +44,7 @@ def test_abi3(tmp_path):
add_env={ add_env={
# free_threaded, GraalPy, and PyPy do not have a Py_LIMITED_API equivalent, just build one of those # free_threaded, GraalPy, and PyPy do not have a Py_LIMITED_API equivalent, just build one of those
# also limit the number of builds for test performance reasons # also limit the number of builds for test performance reasons
"CIBW_BUILD": "cp39-* cp310-* pp310-* gp312_250-* cp312-* cp313t-*", "CIBW_BUILD": "cp39-* cp310-* pp310-* gp312_250-* cp312-* cp314t-*",
"CIBW_ENABLE": "all", "CIBW_ENABLE": "all",
}, },
) )
@@ -62,7 +65,7 @@ def test_abi3(tmp_path):
python_abi_tags=[ python_abi_tags=[
"cp39-cp39", "cp39-cp39",
"cp310-abi3", # <-- ABI3, works with 3.10 and 3.12 "cp310-abi3", # <-- ABI3, works with 3.10 and 3.12
"cp313-cp313t", "cp314-cp314t",
"pp310-pypy310_pp73", "pp310-pypy310_pp73",
"graalpy312-graalpy250_312_native", "graalpy312-graalpy250_312_native",
], ],
@@ -178,7 +181,7 @@ ctypes_project.files["test/add_test.py"] = textwrap.dedent(
ctypes_project.files["pyproject.toml"] = pyproject_toml ctypes_project.files["pyproject.toml"] = pyproject_toml
def test_abi_none(tmp_path, capfd): def test_abi_none(tmp_path: Path, capfd: pytest.CaptureFixture[str]) -> None:
project_dir = tmp_path / "project" project_dir = tmp_path / "project"
ctypes_project.generate(project_dir) ctypes_project.generate(project_dir)
@@ -189,7 +192,7 @@ def test_abi_none(tmp_path, capfd):
"CIBW_TEST_REQUIRES": "pytest", "CIBW_TEST_REQUIRES": "pytest",
"CIBW_TEST_COMMAND": f"{utils.invoke_pytest()} {{project}}/test", "CIBW_TEST_COMMAND": f"{utils.invoke_pytest()} {{project}}/test",
# limit the number of builds for test performance reasons # limit the number of builds for test performance reasons
"CIBW_BUILD": "cp38-* cp{}{}-* cp313t-* pp310-*".format(*utils.SINGLE_PYTHON_VERSION), "CIBW_BUILD": "cp38-* cp{}{}-* cp314t-* pp310-*".format(*utils.SINGLE_PYTHON_VERSION),
"CIBW_ENABLE": "all", "CIBW_ENABLE": "all",
}, },
) )
+43 -23
View File
@@ -2,6 +2,8 @@ import os
import platform import platform
import re import re
import sys import sys
import typing
from collections.abc import Callable
from dataclasses import dataclass from dataclasses import dataclass
from pathlib import Path from pathlib import Path
from shutil import rmtree, which from shutil import rmtree, which
@@ -52,8 +54,10 @@ if "ANDROID_HOME" not in os.environ:
# Many CI services don't support running the Android emulator: see platforms.md. # Many CI services don't support running the Android emulator: see platforms.md.
supports_emulator = (not ci) or ("GITHUB_ACTIONS" in os.environ and platform.system() == "Linux") supports_emulator = (not ci) or ("GITHUB_ACTIONS" in os.environ and platform.system() == "Linux")
T = typing.TypeVar("T", bound=Callable[..., typing.Any])
def needs_emulator(test):
def needs_emulator(test: T) -> T:
# All copies of the testbed app run on the same emulator with the same # All copies of the testbed app run on the same emulator with the same
# application ID, so these tests must be run serially. # application ID, so these tests must be run serially.
test = pytest.mark.serial(test) test = pytest.mark.serial(test)
@@ -85,7 +89,7 @@ cp313_env = {
} }
def test_android_home(tmp_path, capfd): def test_android_home(tmp_path: Path, capfd: pytest.CaptureFixture[str]) -> None:
new_c_project().generate(tmp_path) new_c_project().generate(tmp_path)
env = os.environ.copy() env = os.environ.copy()
del env["ANDROID_HOME"] del env["ANDROID_HOME"]
@@ -100,7 +104,7 @@ def test_android_home(tmp_path, capfd):
# a build, which is marked as serial so it will run before the parallel tests, but isn't # a build, which is marked as serial so it will run before the parallel tests, but isn't
# marked as needs_emulator so it will run on all CI platforms. # marked as needs_emulator so it will run on all CI platforms.
@pytest.mark.serial @pytest.mark.serial
def test_expected_wheels(tmp_path, spam_env): def test_expected_wheels(tmp_path: Path, spam_env: dict[str, str]) -> None:
# Since this test covers all Python versions, check the cross venv. # Since this test covers all Python versions, check the cross venv.
test_module = "_cross_venv_test_android" test_module = "_cross_venv_test_android"
project = new_c_project(setup_py_add=f"import {test_module}") project = new_c_project(setup_py_add=f"import {test_module}")
@@ -119,7 +123,7 @@ def test_expected_wheels(tmp_path, spam_env):
@needs_emulator @needs_emulator
def test_frontend_good(tmp_path, build_frontend_env): def test_frontend_good(tmp_path: Path, build_frontend_env: dict[str, str]) -> None:
new_c_project().generate(tmp_path) new_c_project().generate(tmp_path)
wheels = cibuildwheel_run( wheels = cibuildwheel_run(
tmp_path, tmp_path,
@@ -129,7 +133,7 @@ def test_frontend_good(tmp_path, build_frontend_env):
@pytest.mark.parametrize("frontend", ["pip"]) @pytest.mark.parametrize("frontend", ["pip"])
def test_frontend_bad(frontend, tmp_path, capfd): def test_frontend_bad(frontend: str, tmp_path: Path, capfd: pytest.CaptureFixture[str]) -> None:
new_c_project().generate(tmp_path) new_c_project().generate(tmp_path)
with pytest.raises(CalledProcessError): with pytest.raises(CalledProcessError):
cibuildwheel_run( cibuildwheel_run(
@@ -140,7 +144,7 @@ def test_frontend_bad(frontend, tmp_path, capfd):
@needs_emulator @needs_emulator
def test_archs(tmp_path, capfd): def test_archs(tmp_path: Path, capfd: pytest.CaptureFixture[str]) -> None:
new_c_project().generate(tmp_path) new_c_project().generate(tmp_path)
# Build all architectures while checking the handling of the `before` commands. # Build all architectures while checking the handling of the `before` commands.
@@ -189,7 +193,7 @@ def test_archs(tmp_path, capfd):
pytest.fail(f"Unexpected line: {line!r}") pytest.fail(f"Unexpected line: {line!r}")
def test_build_requires(tmp_path, capfd): def test_build_requires(tmp_path: Path, capfd: pytest.CaptureFixture[str]) -> None:
# Build-time requirements should be installed for the build platform, not for Android. Prove # Build-time requirements should be installed for the build platform, not for Android. Prove
# this by installing some non-pure-Python requirements and using them in setup.py. # this by installing some non-pure-Python requirements and using them in setup.py.
# #
@@ -226,13 +230,13 @@ def test_build_requires(tmp_path, capfd):
@pytest.fixture @pytest.fixture
def spam_env(tmp_path): def spam_env(tmp_path: Path) -> dict[str, str]:
project = new_c_project() project = new_c_project()
project.files["test_spam.py"] = dedent( project.files["test_spam.py"] = dedent(
"""\ """\
import spam import spam
def test_spam(): def test_spam() -> None:
assert spam.filter("ham") assert spam.filter("ham")
assert not spam.filter("spam") assert not spam.filter("spam")
print("Spam test passed") print("Spam test passed")
@@ -240,7 +244,7 @@ def spam_env(tmp_path):
) )
project.files["test_empty.py"] = dedent( project.files["test_empty.py"] = dedent(
"""\ """\
def test_empty(): def test_empty() -> None:
pass pass
""" """
) )
@@ -265,7 +269,13 @@ def spam_env(tmp_path):
("pytest test_spam.py", "=== 1 passed in "), ("pytest test_spam.py", "=== 1 passed in "),
], ],
) )
def test_test_command_good(command, expected_output, tmp_path, spam_env, capfd): def test_test_command_good(
command: str,
expected_output: str,
tmp_path: Path,
spam_env: dict[str, str],
capfd: pytest.CaptureFixture[str],
) -> None:
cibuildwheel_run(tmp_path, add_env={**spam_env, "CIBW_TEST_COMMAND": command}) cibuildwheel_run(tmp_path, add_env={**spam_env, "CIBW_TEST_COMMAND": command})
stdout, stderr = capfd.readouterr() stdout, stderr = capfd.readouterr()
assert expected_output in stdout assert expected_output in stdout
@@ -300,7 +310,13 @@ BAD_PLACEHOLDER_ERROR = (
("pytest test_ham.py", "not found: test_ham.py"), ("pytest test_ham.py", "not found: test_ham.py"),
], ],
) )
def test_test_command_bad(command, expected_output, tmp_path, spam_env, capfd): def test_test_command_bad(
command: str,
expected_output: str,
tmp_path: Path,
spam_env: dict[str, str],
capfd: pytest.CaptureFixture[str],
) -> None:
with pytest.raises(CalledProcessError): with pytest.raises(CalledProcessError):
cibuildwheel_run(tmp_path, add_env={**spam_env, "CIBW_TEST_COMMAND": command}) cibuildwheel_run(tmp_path, add_env={**spam_env, "CIBW_TEST_COMMAND": command})
assert expected_output in capfd.readouterr().err assert expected_output in capfd.readouterr().err
@@ -314,7 +330,9 @@ def test_test_command_bad(command, expected_output, tmp_path, spam_env, capfd):
("-E", 1), ("-E", 1),
], ],
) )
def test_test_command_python_options(options, expected, tmp_path, capfd): def test_test_command_python_options(
options: str, expected: int, tmp_path: Path, capfd: pytest.CaptureFixture[str]
) -> None:
project = new_c_project() project = new_c_project()
project.generate(tmp_path) project.generate(tmp_path)
@@ -330,7 +348,9 @@ def test_test_command_python_options(options, expected, tmp_path, capfd):
@needs_emulator @needs_emulator
def test_package_subdir(tmp_path, spam_env, capfd): def test_package_subdir(
tmp_path: Path, spam_env: dict[str, str], capfd: pytest.CaptureFixture[str]
) -> None:
spam_paths = list(tmp_path.iterdir()) spam_paths = list(tmp_path.iterdir())
package_dir = tmp_path / "package" package_dir = tmp_path / "package"
package_dir.mkdir() package_dir.mkdir()
@@ -345,7 +365,7 @@ def test_package_subdir(tmp_path, spam_env, capfd):
@needs_emulator @needs_emulator
def test_no_test_sources(tmp_path, capfd): def test_no_test_sources(tmp_path: Path, capfd: pytest.CaptureFixture[str]) -> None:
new_c_project().generate(tmp_path) new_c_project().generate(tmp_path)
with pytest.raises(CalledProcessError): with pytest.raises(CalledProcessError):
cibuildwheel_run( cibuildwheel_run(
@@ -359,17 +379,17 @@ def test_no_test_sources(tmp_path, capfd):
@needs_emulator @needs_emulator
def test_environment_markers(tmp_path): def test_environment_markers(tmp_path: Path) -> None:
project = new_c_project() project = new_c_project()
test_filename = "test_environment_markers.py" test_filename = "test_environment_markers.py"
project.files[test_filename] = dedent( project.files[test_filename] = dedent(
"""\ """\
import pytest import pytest
def test_android(): def test_android() -> None:
import certifi import certifi
def test_not_android(): def test_not_android() -> None:
try: try:
import platformdirs import platformdirs
except ImportError: except ImportError:
@@ -392,7 +412,7 @@ def test_environment_markers(tmp_path):
@needs_emulator @needs_emulator
def test_verbosity(tmp_path, capfd): def test_verbosity(tmp_path: Path, capfd: pytest.CaptureFixture[str]) -> None:
new_c_project().generate(tmp_path) new_c_project().generate(tmp_path)
test_env = { test_env = {
**cp313_env, **cp313_env,
@@ -418,7 +438,7 @@ def test_verbosity(tmp_path, capfd):
@needs_emulator @needs_emulator
def test_api_level(tmp_path, capfd): def test_api_level(tmp_path: Path, capfd: pytest.CaptureFixture[str]) -> None:
project = new_c_project() project = new_c_project()
project.files["pyproject.toml"] = dedent( project.files["pyproject.toml"] = dedent(
"""\ """\
@@ -450,7 +470,7 @@ def test_api_level(tmp_path, capfd):
@needs_emulator @needs_emulator
def test_libcxx(tmp_path, capfd): def test_libcxx(tmp_path: Path, capfd: pytest.CaptureFixture[str]) -> None:
project_dir = tmp_path / "project" project_dir = tmp_path / "project"
output_dir = tmp_path / "output" output_dir = tmp_path / "output"
@@ -499,7 +519,7 @@ def test_libcxx(tmp_path, capfd):
@needs_emulator @needs_emulator
def test_setuptools_rust(tmp_path, capfd): def test_setuptools_rust(tmp_path: Path, capfd: pytest.CaptureFixture[str]) -> None:
""" """
Test Android cross-compilation using the setuptools-rust toolchain. Test Android cross-compilation using the setuptools-rust toolchain.
""" """
@@ -584,7 +604,7 @@ def test_setuptools_rust(tmp_path, capfd):
@needs_emulator @needs_emulator
def test_maturin(tmp_path, capfd): def test_maturin(tmp_path: Path, capfd: pytest.CaptureFixture[str]) -> None:
""" """
Test Android cross-compilation using the maturin backend. Test Android cross-compilation using the maturin backend.
""" """
+4 -3
View File
@@ -1,5 +1,6 @@
import subprocess import subprocess
import textwrap import textwrap
from pathlib import Path
import pytest import pytest
@@ -29,7 +30,7 @@ project_with_before_build_asserts = test_projects.new_c_project(
) )
def test(tmp_path): def test(tmp_path: Path) -> None:
project_dir = tmp_path / "project" project_dir = tmp_path / "project"
project_with_before_build_asserts.generate(project_dir) project_with_before_build_asserts.generate(project_dir)
@@ -61,7 +62,7 @@ def test(tmp_path):
assert set(actual_wheels) == set(expected_wheels) assert set(actual_wheels) == set(expected_wheels)
def test_failing_command(tmp_path): def test_failing_command(tmp_path: Path) -> None:
project_dir = tmp_path / "project" project_dir = tmp_path / "project"
test_projects.new_c_project().generate(project_dir) test_projects.new_c_project().generate(project_dir)
@@ -75,7 +76,7 @@ def test_failing_command(tmp_path):
) )
def test_cwd(tmp_path): def test_cwd(tmp_path: Path) -> None:
project_dir = tmp_path / "project" project_dir = tmp_path / "project"
test_projects.new_c_project().generate(project_dir) test_projects.new_c_project().generate(project_dir)
+4 -3
View File
@@ -1,5 +1,6 @@
import subprocess import subprocess
import textwrap import textwrap
from pathlib import Path
import pytest import pytest
@@ -36,7 +37,7 @@ project_with_before_build_asserts = test_projects.new_c_project(
) )
def test(tmp_path): def test(tmp_path: Path) -> None:
project_dir = tmp_path / "project" project_dir = tmp_path / "project"
project_with_before_build_asserts.generate(project_dir) project_with_before_build_asserts.generate(project_dir)
@@ -65,7 +66,7 @@ def test(tmp_path):
assert set(actual_wheels) == set(expected_wheels) assert set(actual_wheels) == set(expected_wheels)
def test_failing_command(tmp_path): def test_failing_command(tmp_path: Path) -> None:
project_dir = tmp_path / "project" project_dir = tmp_path / "project"
test_projects.new_c_project().generate(project_dir) test_projects.new_c_project().generate(project_dir)
@@ -79,7 +80,7 @@ def test_failing_command(tmp_path):
) )
def test_cwd(tmp_path): def test_cwd(tmp_path: Path) -> None:
project_dir = tmp_path / "project" project_dir = tmp_path / "project"
test_projects.new_c_project().generate(project_dir) test_projects.new_c_project().generate(project_dir)
+5 -3
View File
@@ -1,3 +1,5 @@
from pathlib import Path
from . import test_projects, utils from . import test_projects, utils
before_test_project = test_projects.new_c_project() before_test_project = test_projects.new_c_project()
@@ -11,7 +13,7 @@ PROJECT_DIR = Path(__file__).parent.parent.resolve()
class TestBeforeTest(TestCase): class TestBeforeTest(TestCase):
def test_version(self): def test_version(self) -> None:
# assert that the Python version as written to pythonversion_bt.txt in the CIBW_BEFORE_TEST step # assert that the Python version as written to pythonversion_bt.txt in the CIBW_BEFORE_TEST step
# is the same one as is currently running. # is the same one as is currently running.
# because of use symlinks in MacOS run this test is also need # because of use symlinks in MacOS run this test is also need
@@ -20,7 +22,7 @@ class TestBeforeTest(TestCase):
print('sys.version', sys.version) print('sys.version', sys.version)
assert stored_version == sys.version assert stored_version == sys.version
def test_prefix(self): def test_prefix(self) -> None:
# check that the prefix also was written # check that the prefix also was written
stored_prefix = PROJECT_DIR.joinpath('pythonprefix_bt.txt').read_text() stored_prefix = PROJECT_DIR.joinpath('pythonprefix_bt.txt').read_text()
print('stored_prefix', stored_prefix) print('stored_prefix', stored_prefix)
@@ -32,7 +34,7 @@ class TestBeforeTest(TestCase):
""" """
def test(tmp_path, build_frontend_env): def test(tmp_path: Path, build_frontend_env: dict[str, str]) -> None:
project_dir = tmp_path / "project" project_dir = tmp_path / "project"
before_test_project.generate(project_dir) before_test_project.generate(project_dir)
test_project_dir = project_dir / "dependency" test_project_dir = project_dir / "dependency"
+4 -1
View File
@@ -1,4 +1,5 @@
import subprocess import subprocess
from pathlib import Path
import pytest import pytest
@@ -12,7 +13,9 @@ from . import test_projects, utils
"build", "build",
], ],
) )
def test_build_frontend_args(tmp_path, capfd, frontend_name): def test_build_frontend_args(
tmp_path: Path, capfd: pytest.CaptureFixture[str], frontend_name: str
) -> None:
project = test_projects.new_c_project() project = test_projects.new_c_project()
project_dir = tmp_path / "project" project_dir = tmp_path / "project"
project.generate(project_dir) project.generate(project_dir)
+2 -1
View File
@@ -1,4 +1,5 @@
import textwrap import textwrap
from pathlib import Path
from . import test_projects, utils from . import test_projects, utils
@@ -15,7 +16,7 @@ project_with_skip_asserts = test_projects.new_c_project(
) )
def test(tmp_path): def test(tmp_path: Path) -> None:
project_dir = tmp_path / "project" project_dir = tmp_path / "project"
project_with_skip_asserts.generate(project_dir) project_with_skip_asserts.generate(project_dir)
+6 -2
View File
@@ -1,3 +1,5 @@
from pathlib import Path
import pytest import pytest
from . import test_projects, utils from . import test_projects, utils
@@ -5,7 +7,9 @@ from . import test_projects, utils
basic_project = test_projects.new_c_project() basic_project = test_projects.new_c_project()
def test_podman(tmp_path, capfd, request): def test_podman(
tmp_path: Path, capfd: pytest.CaptureFixture[str], request: pytest.FixtureRequest
) -> None:
if utils.get_platform() != "linux": if utils.get_platform() != "linux":
pytest.skip("the test is only relevant to the linux build") pytest.skip("the test is only relevant to the linux build")
@@ -35,7 +39,7 @@ def test_podman(tmp_path, capfd, request):
assert "test log statement from before-all" in captured.out assert "test log statement from before-all" in captured.out
def test_create_args(tmp_path, capfd): def test_create_args(tmp_path: Path, capfd: pytest.CaptureFixture[str]) -> None:
if utils.get_platform() != "linux": if utils.get_platform() != "linux":
pytest.skip("the test is only relevant to the linux build") pytest.skip("the test is only relevant to the linux build")
+2 -1
View File
@@ -1,5 +1,6 @@
import platform import platform
import textwrap import textwrap
from pathlib import Path
import pytest import pytest
@@ -22,7 +23,7 @@ dockcross_only_project = test_projects.new_c_project(
@pytest.mark.usefixtures("docker_cleanup") @pytest.mark.usefixtures("docker_cleanup")
def test(tmp_path): def test(tmp_path: Path) -> None:
if utils.get_platform() != "linux": if utils.get_platform() != "linux":
pytest.skip("the test is only relevant to the linux build") pytest.skip("the test is only relevant to the linux build")
if platform.machine() not in ["x86_64", "i686"]: if platform.machine() not in ["x86_64", "i686"]:
+5 -3
View File
@@ -1,3 +1,5 @@
from pathlib import Path
import jinja2 import jinja2
from . import utils from . import utils
@@ -52,7 +54,7 @@ cpp_test_project.files["setup.py"] = jinja2.Template(setup_py_template)
cpp_test_project.files["spam.cpp"] = jinja2.Template(spam_cpp_template) cpp_test_project.files["spam.cpp"] = jinja2.Template(spam_cpp_template)
def test_cpp11(tmp_path): def test_cpp11(tmp_path: Path) -> None:
# This test checks that the C++11 standard is supported # This test checks that the C++11 standard is supported
project_dir = tmp_path / "project" project_dir = tmp_path / "project"
cpp11_project = cpp_test_project.copy() cpp11_project = cpp_test_project.copy()
@@ -68,7 +70,7 @@ def test_cpp11(tmp_path):
assert set(actual_wheels) == set(expected_wheels) assert set(actual_wheels) == set(expected_wheels)
def test_cpp14(tmp_path): def test_cpp14(tmp_path: Path) -> None:
# This test checks that the C++14 standard is supported # This test checks that the C++14 standard is supported
project_dir = tmp_path / "project" project_dir = tmp_path / "project"
cpp14_project = cpp_test_project.copy() cpp14_project = cpp_test_project.copy()
@@ -84,7 +86,7 @@ def test_cpp14(tmp_path):
assert set(actual_wheels) == set(expected_wheels) assert set(actual_wheels) == set(expected_wheels)
def test_cpp17(tmp_path): def test_cpp17(tmp_path: Path) -> None:
# This test checks that the C++17 standard is supported # This test checks that the C++17 standard is supported
project_dir = tmp_path / "project" project_dir = tmp_path / "project"
cpp17_project = cpp_test_project.copy() cpp17_project = cpp_test_project.copy()
+3 -2
View File
@@ -1,6 +1,7 @@
import subprocess import subprocess
import textwrap import textwrap
from contextlib import nullcontext as does_not_raise from contextlib import nullcontext as does_not_raise
from pathlib import Path
import pytest import pytest
@@ -30,7 +31,7 @@ shutil.copy(wheel, dest)
""" """
def test(tmp_path, capfd): def test(tmp_path: Path, capfd: pytest.CaptureFixture[str]) -> None:
# this test checks that a generated wheel name shall be unique in a given cibuildwheel run # this test checks that a generated wheel name shall be unique in a given cibuildwheel run
project_dir = tmp_path / "project" project_dir = tmp_path / "project"
basic_project.generate(project_dir) basic_project.generate(project_dir)
@@ -68,7 +69,7 @@ def test(tmp_path, capfd):
], ],
ids=["no-placeholder", "package-placeholder", "project-placeholder"], ids=["no-placeholder", "package-placeholder", "project-placeholder"],
) )
def test_repair_wheel_command_structure(tmp_path, repair_command): def test_repair_wheel_command_structure(tmp_path: Path, repair_command: str) -> None:
project_dir = tmp_path / "project" project_dir = tmp_path / "project"
project = test_projects.new_c_project() project = test_projects.new_c_project()
project.files["repair.py"] = textwrap.dedent(""" project.files["repair.py"] = textwrap.dedent("""
+9 -3
View File
@@ -36,7 +36,9 @@ for name, expected_version in expected_versions.items():
""" """
def test_check_versions_script(tmp_path, build_frontend_env_nouv, capfd): def test_check_versions_script(
tmp_path: Path, build_frontend_env_nouv: dict[str, str], capfd: pytest.CaptureFixture[str]
) -> None:
if utils.get_platform() == "linux": if utils.get_platform() == "linux":
pytest.skip("we don't test dependency versions on linux, refer to other tests") pytest.skip("we don't test dependency versions on linux, refer to other tests")
@@ -76,7 +78,9 @@ def get_versions_from_constraint_file(constraint_file: Path) -> dict[str, str]:
@pytest.mark.parametrize("python_version", ["3.8", "3.12"]) @pytest.mark.parametrize("python_version", ["3.8", "3.12"])
def test_pinned_versions(tmp_path, python_version, build_frontend_env_nouv): def test_pinned_versions(
tmp_path: Path, python_version: str, build_frontend_env_nouv: dict[str, str]
) -> None:
if utils.get_platform() == "linux": if utils.get_platform() == "linux":
pytest.skip("linux doesn't pin individual tool versions, it pins manylinux images instead") pytest.skip("linux doesn't pin individual tool versions, it pins manylinux images instead")
if python_version != "3.12" and utils.get_platform() == "pyodide": if python_version != "3.12" and utils.get_platform() == "pyodide":
@@ -127,7 +131,9 @@ def test_pinned_versions(tmp_path, python_version, build_frontend_env_nouv):
@pytest.mark.parametrize("method", ["inline", "file"]) @pytest.mark.parametrize("method", ["inline", "file"])
def test_dependency_constraints(method, tmp_path, build_frontend_env_nouv): def test_dependency_constraints(
method: str, tmp_path: Path, build_frontend_env_nouv: dict[str, str]
) -> None:
if utils.get_platform() == "linux": if utils.get_platform() == "linux":
pytest.skip("linux doesn't pin individual tool versions, it pins manylinux images instead") pytest.skip("linux doesn't pin individual tool versions, it pins manylinux images instead")
+4 -3
View File
@@ -1,5 +1,6 @@
import itertools import itertools
import subprocess import subprocess
from pathlib import Path
import pytest import pytest
@@ -10,13 +11,13 @@ project_with_a_test = test_projects.new_c_project()
project_with_a_test.files["test/spam_test.py"] = r""" project_with_a_test.files["test/spam_test.py"] = r"""
import spam import spam
def test_spam(): def test_spam() -> None:
assert spam.filter("spam") == 0 assert spam.filter("spam") == 0
assert spam.filter("ham") != 0 assert spam.filter("ham") != 0
""" """
def test(tmp_path, request): def test(tmp_path: Path, request: pytest.FixtureRequest) -> None:
archs = request.config.getoption("--run-emulation") archs = request.config.getoption("--run-emulation")
if archs is None: if archs is None:
pytest.skip("needs --run-emulation option to run") pytest.skip("needs --run-emulation option to run")
@@ -45,7 +46,7 @@ def test(tmp_path, request):
assert set(actual_wheels) == set(expected_wheels) assert set(actual_wheels) == set(expected_wheels)
def test_setting_arch_on_other_platforms(tmp_path, capfd): def test_setting_arch_on_other_platforms(tmp_path: Path, capfd: pytest.CaptureFixture[str]) -> None:
if utils.get_platform() == "linux": if utils.get_platform() == "linux":
pytest.skip("this test checks the behaviour on platforms other than linux") pytest.skip("this test checks the behaviour on platforms other than linux")
+4 -3
View File
@@ -2,6 +2,7 @@ import os
import subprocess import subprocess
import sys import sys
import textwrap import textwrap
from pathlib import Path
import pytest import pytest
@@ -33,7 +34,7 @@ project_with_environment_asserts = test_projects.new_c_project(
) )
def test(tmp_path): def test(tmp_path: Path) -> None:
python_echo = f"'{sys.executable}' -c \"import sys; print(*sys.argv[1:])\"" python_echo = f"'{sys.executable}' -c \"import sys; print(*sys.argv[1:])\""
project_dir = tmp_path / "project" project_dir = tmp_path / "project"
project_with_environment_asserts.generate(project_dir) project_with_environment_asserts.generate(project_dir)
@@ -55,7 +56,7 @@ def test(tmp_path):
assert set(actual_wheels) == set(expected_wheels) assert set(actual_wheels) == set(expected_wheels)
def test_overridden_path(tmp_path, capfd): def test_overridden_path(tmp_path: Path, capfd: pytest.CaptureFixture[str]) -> None:
project_dir = tmp_path / "project" project_dir = tmp_path / "project"
output_dir = tmp_path / "output" output_dir = tmp_path / "output"
@@ -108,7 +109,7 @@ def test_overridden_path(tmp_path, capfd):
), ),
], ],
) )
def test_overridden_pip_constraint(tmp_path, build_frontend): def test_overridden_pip_constraint(tmp_path: Path, build_frontend: str) -> None:
""" """
Verify that users can use PIP_CONSTRAINT to specify a specific version of Verify that users can use PIP_CONSTRAINT to specify a specific version of
a build-system.requires dependency, by asserting the version of pytz in the a build-system.requires dependency, by asserting the version of pytz in the
+6 -4
View File
@@ -6,6 +6,8 @@ from collections.abc import Mapping
from pathlib import Path from pathlib import Path
from tempfile import TemporaryDirectory from tempfile import TemporaryDirectory
import pytest
from test.test_projects.base import TestProject from test.test_projects.base import TestProject
from . import test_projects, utils from . import test_projects, utils
@@ -59,7 +61,7 @@ def cibuildwheel_from_sdist_run(
# tests # tests
def test_simple(tmp_path): def test_simple(tmp_path: Path) -> None:
basic_project = test_projects.new_c_project() basic_project = test_projects.new_c_project()
# make an sdist of the project # make an sdist of the project
@@ -87,7 +89,7 @@ def test_simple(tmp_path):
assert set(actual_wheels) == set(expected_wheels) assert set(actual_wheels) == set(expected_wheels)
def test_external_config_file_argument(tmp_path, capfd): def test_external_config_file_argument(tmp_path: Path, capfd: pytest.CaptureFixture[str]) -> None:
basic_project = test_projects.new_c_project() basic_project = test_projects.new_c_project()
# make an sdist of the project # make an sdist of the project
@@ -118,7 +120,7 @@ def test_external_config_file_argument(tmp_path, capfd):
assert "test log statement from before-all" in captured.out assert "test log statement from before-all" in captured.out
def test_config_in_pyproject_toml(tmp_path, capfd): def test_config_in_pyproject_toml(tmp_path: Path, capfd: pytest.CaptureFixture[str]) -> None:
# make a project with a pyproject.toml # make a project with a pyproject.toml
project = test_projects.new_c_project() project = test_projects.new_c_project()
project.files["pyproject.toml"] = textwrap.dedent( project.files["pyproject.toml"] = textwrap.dedent(
@@ -145,7 +147,7 @@ def test_config_in_pyproject_toml(tmp_path, capfd):
assert "test log statement from before-build 8419" in captured.out assert "test log statement from before-build 8419" in captured.out
def test_internal_config_file_argument(tmp_path, capfd): def test_internal_config_file_argument(tmp_path: Path, capfd: pytest.CaptureFixture[str]) -> None:
# make a project with a config file inside # make a project with a config file inside
project = test_projects.new_c_project( project = test_projects.new_c_project(
setup_cfg_add="include_package_data = True", setup_cfg_add="include_package_data = True",
+23 -15
View File
@@ -1,10 +1,9 @@
from __future__ import annotations
import os import os
import platform import platform
import shutil import shutil
import subprocess import subprocess
import textwrap import textwrap
from pathlib import Path
import pytest import pytest
@@ -24,7 +23,7 @@ import platform
from unittest import TestCase from unittest import TestCase
class TestPlatform(TestCase): class TestPlatform(TestCase):
def test_platform(self): def test_platform(self) -> None:
self.assertEqual(platform.machine(), "{platform.machine()}") self.assertEqual(platform.machine(), "{platform.machine()}")
""" """
@@ -61,7 +60,12 @@ def skip_if_ios_testing_not_supported() -> None:
{"CIBW_PLATFORM": "ios", "CIBW_BUILD_FRONTEND": "build"}, {"CIBW_PLATFORM": "ios", "CIBW_BUILD_FRONTEND": "build"},
], ],
) )
def test_ios_platforms(tmp_path, build_config, monkeypatch, capfd): def test_ios_platforms(
tmp_path: Path,
build_config: dict[str, str],
monkeypatch: pytest.MonkeyPatch,
capfd: pytest.CaptureFixture[str],
) -> None:
skip_if_ios_testing_not_supported() skip_if_ios_testing_not_supported()
# Create a temporary "bin" directory, symlink a tool that we know eixsts # Create a temporary "bin" directory, symlink a tool that we know eixsts
@@ -69,7 +73,9 @@ def test_ios_platforms(tmp_path, build_config, monkeypatch, capfd):
# and add the temp bin directory to the PATH. # and add the temp bin directory to the PATH.
tools_dir = tmp_path / "bin" tools_dir = tmp_path / "bin"
tools_dir.mkdir() tools_dir.mkdir()
tools_dir.joinpath("does-exist").symlink_to(shutil.which("true")) true_app = shutil.which("true")
assert true_app is not None
tools_dir.joinpath("does-exist").symlink_to(true_app)
monkeypatch.setenv("PATH", str(tools_dir), prepend=os.pathsep) monkeypatch.setenv("PATH", str(tools_dir), prepend=os.pathsep)
@@ -112,7 +118,7 @@ def test_ios_platforms(tmp_path, build_config, monkeypatch, capfd):
@pytest.mark.serial @pytest.mark.serial
def test_no_test_sources(tmp_path, capfd): def test_no_test_sources(tmp_path: Path, capfd: pytest.CaptureFixture[str]) -> None:
"""Build will provide a helpful error if pytest is run and test-sources is not defined.""" """Build will provide a helpful error if pytest is run and test-sources is not defined."""
skip_if_ios_testing_not_supported() skip_if_ios_testing_not_supported()
@@ -140,7 +146,7 @@ def test_no_test_sources(tmp_path, capfd):
) )
def test_ios_testing_with_placeholder(tmp_path, capfd): def test_ios_testing_with_placeholder(tmp_path: Path, capfd: pytest.CaptureFixture[str]) -> None:
""" """
Tests with the {project} placeholder are not supported on iOS, because the test command Tests with the {project} placeholder are not supported on iOS, because the test command
is run in the simulator. is run in the simulator.
@@ -170,7 +176,7 @@ def test_ios_testing_with_placeholder(tmp_path, capfd):
@pytest.mark.serial @pytest.mark.serial
@pytest.mark.flaky(reruns=2) @pytest.mark.flaky(reruns=2)
def test_ios_test_command_short_circuit(tmp_path, capfd): def test_ios_test_command_short_circuit(tmp_path: Path, capfd: pytest.CaptureFixture[str]) -> None:
skip_if_ios_testing_not_supported() skip_if_ios_testing_not_supported()
project_dir = tmp_path / "project" project_dir = tmp_path / "project"
@@ -198,7 +204,7 @@ def test_ios_test_command_short_circuit(tmp_path, capfd):
assert "Zen of Python" not in captured.out + captured.err assert "Zen of Python" not in captured.out + captured.err
def test_missing_xbuild_tool(tmp_path, capfd): def test_missing_xbuild_tool(tmp_path: Path, capfd: pytest.CaptureFixture[str]) -> None:
"""Build will fail if xbuild-tools references a non-existent tool.""" """Build will fail if xbuild-tools references a non-existent tool."""
skip_if_ios_testing_not_supported() skip_if_ios_testing_not_supported()
@@ -222,7 +228,7 @@ def test_missing_xbuild_tool(tmp_path, capfd):
assert "Could not find a 'does-not-exist' executable on the path." in captured.err assert "Could not find a 'does-not-exist' executable on the path." in captured.err
def test_no_xbuild_tool_definition(tmp_path, capfd): def test_no_xbuild_tool_definition(tmp_path: Path, capfd: pytest.CaptureFixture[str]) -> None:
"""Build will succeed with a warning if there is no xbuild-tools definition.""" """Build will succeed with a warning if there is no xbuild-tools definition."""
skip_if_ios_testing_not_supported() skip_if_ios_testing_not_supported()
@@ -256,7 +262,7 @@ def test_no_xbuild_tool_definition(tmp_path, capfd):
assert "Your project configuration does not define any cross-build tools." in captured.err assert "Your project configuration does not define any cross-build tools." in captured.err
def test_empty_xbuild_tool_definition(tmp_path, capfd): def test_empty_xbuild_tool_definition(tmp_path: Path, capfd: pytest.CaptureFixture[str]) -> None:
"""Build will succeed with no warning if there is an empty xbuild-tools definition.""" """Build will succeed with no warning if there is an empty xbuild-tools definition."""
skip_if_ios_testing_not_supported() skip_if_ios_testing_not_supported()
@@ -288,7 +294,9 @@ def test_empty_xbuild_tool_definition(tmp_path, capfd):
@pytest.mark.serial @pytest.mark.serial
def test_ios_test_command_without_python_dash_m(tmp_path, capfd): def test_ios_test_command_without_python_dash_m(
tmp_path: Path, capfd: pytest.CaptureFixture[str]
) -> None:
"""pytest should be able to run without python -m, but it should warn.""" """pytest should be able to run without python -m, but it should warn."""
skip_if_ios_testing_not_supported() skip_if_ios_testing_not_supported()
@@ -298,7 +306,7 @@ def test_ios_test_command_without_python_dash_m(tmp_path, capfd):
project.files["tests/__init__.py"] = "" project.files["tests/__init__.py"] = ""
project.files["tests/test_spam.py"] = textwrap.dedent(""" project.files["tests/test_spam.py"] = textwrap.dedent("""
import spam import spam
def test_spam(): def test_spam() -> None:
assert spam.filter("spam") == 0 assert spam.filter("spam") == 0
assert spam.filter("ham") != 0 assert spam.filter("ham") != 0
""") """)
@@ -326,7 +334,7 @@ def test_ios_test_command_without_python_dash_m(tmp_path, capfd):
assert "iOS tests configured with a test command which doesn't start with 'python -m'" in err assert "iOS tests configured with a test command which doesn't start with 'python -m'" in err
def test_ios_test_command_invalid(tmp_path, capfd): def test_ios_test_command_invalid(tmp_path: Path, capfd: pytest.CaptureFixture[str]) -> None:
"""Test command should raise an error if it's clearly invalid.""" """Test command should raise an error if it's clearly invalid."""
skip_if_ios_testing_not_supported() skip_if_ios_testing_not_supported()
@@ -349,7 +357,7 @@ def test_ios_test_command_invalid(tmp_path, capfd):
assert "iOS tests configured with a test command which doesn't start with 'python -m'" in err assert "iOS tests configured with a test command which doesn't start with 'python -m'" in err
def test_repair_step(tmp_path): def test_repair_step(tmp_path: Path) -> None:
"""Build will succeed & the custom repair step is called.""" """Build will succeed & the custom repair step is called."""
skip_if_ios_testing_not_supported() skip_if_ios_testing_not_supported()
+2 -1
View File
@@ -1,12 +1,13 @@
import platform import platform
import subprocess import subprocess
from pathlib import Path
import pytest import pytest
from . import test_projects, utils from . import test_projects, utils
def test_python_exist(tmp_path, capfd): def test_python_exist(tmp_path: Path, capfd: pytest.CaptureFixture[str]) -> None:
if utils.get_platform() != "linux": if utils.get_platform() != "linux":
pytest.skip("the test is only relevant to the linux build") pytest.skip("the test is only relevant to the linux build")
machine = platform.machine() machine = platform.machine()
+23 -7
View File
@@ -1,4 +1,5 @@
import platform import platform
from pathlib import Path
import pytest import pytest
@@ -19,7 +20,7 @@ ALL_MACOS_WHEELS = {
DEPLOYMENT_TARGET_TOO_LOW_WARNING = "Bumping MACOSX_DEPLOYMENT_TARGET" DEPLOYMENT_TARGET_TOO_LOW_WARNING = "Bumping MACOSX_DEPLOYMENT_TARGET"
def test_cross_compiled_build(tmp_path): def test_cross_compiled_build(tmp_path: Path) -> None:
if utils.get_platform() != "macos": if utils.get_platform() != "macos":
pytest.skip("this test is only relevant to macos") pytest.skip("this test is only relevant to macos")
if utils.get_xcode_version() < (12, 2): if utils.get_xcode_version() < (12, 2):
@@ -51,7 +52,12 @@ def test_cross_compiled_build(tmp_path):
}, },
], ],
) )
def test_cross_compiled_test(tmp_path, capfd, build_universal2, test_config): def test_cross_compiled_test(
tmp_path: Path,
capfd: pytest.CaptureFixture[str],
build_universal2: bool,
test_config: dict[str, str],
) -> None:
if utils.get_platform() != "macos": if utils.get_platform() != "macos":
pytest.skip("this test is only relevant to macos") pytest.skip("this test is only relevant to macos")
if utils.get_xcode_version() < (12, 2): if utils.get_xcode_version() < (12, 2):
@@ -110,7 +116,9 @@ def test_cross_compiled_test(tmp_path, capfd, build_universal2, test_config):
assert set(actual_wheels) == set(expected_wheels) assert set(actual_wheels) == set(expected_wheels)
def test_deployment_target_warning_is_firing(tmp_path, capfd): def test_deployment_target_warning_is_firing(
tmp_path: Path, capfd: pytest.CaptureFixture[str]
) -> None:
# force the warning to check that we can detect it if it happens # force the warning to check that we can detect it if it happens
if utils.get_platform() != "macos": if utils.get_platform() != "macos":
pytest.skip("this test is only relevant to macos") pytest.skip("this test is only relevant to macos")
@@ -133,7 +141,9 @@ def test_deployment_target_warning_is_firing(tmp_path, capfd):
@pytest.mark.parametrize("skip_arm64_test", [False, True]) @pytest.mark.parametrize("skip_arm64_test", [False, True])
def test_universal2_testing_on_x86_64(tmp_path, capfd, skip_arm64_test): def test_universal2_testing_on_x86_64(
tmp_path: Path, capfd: pytest.CaptureFixture[str], skip_arm64_test: bool
) -> None:
if utils.get_platform() != "macos": if utils.get_platform() != "macos":
pytest.skip("this test is only relevant to macos") pytest.skip("this test is only relevant to macos")
if utils.get_xcode_version() < (12, 2): if utils.get_xcode_version() < (12, 2):
@@ -172,7 +182,9 @@ def test_universal2_testing_on_x86_64(tmp_path, capfd, skip_arm64_test):
assert set(actual_wheels) == set(expected_wheels) assert set(actual_wheels) == set(expected_wheels)
def test_universal2_testing_on_arm64(build_frontend_env, tmp_path, capfd): def test_universal2_testing_on_arm64(
build_frontend_env: dict[str, str], tmp_path: Path, capfd: pytest.CaptureFixture[str]
) -> None:
# cibuildwheel should test the universal2 wheel on both x86_64 and arm64, when run on arm64 # cibuildwheel should test the universal2 wheel on both x86_64 and arm64, when run on arm64
if utils.get_platform() != "macos": if utils.get_platform() != "macos":
pytest.skip("this test is only relevant to macos") pytest.skip("this test is only relevant to macos")
@@ -203,7 +215,9 @@ def test_universal2_testing_on_arm64(build_frontend_env, tmp_path, capfd):
assert set(actual_wheels) == set(expected_wheels) assert set(actual_wheels) == set(expected_wheels)
def test_cp38_arm64_testing(tmp_path, capfd, request): def test_cp38_arm64_testing(
tmp_path: Path, capfd: pytest.CaptureFixture[str], request: pytest.FixtureRequest
) -> None:
if utils.get_platform() != "macos": if utils.get_platform() != "macos":
pytest.skip("this test is only relevant to macos") pytest.skip("this test is only relevant to macos")
if utils.get_xcode_version() < (12, 2): if utils.get_xcode_version() < (12, 2):
@@ -238,7 +252,9 @@ def test_cp38_arm64_testing(tmp_path, capfd, request):
assert set(actual_wheels) == set(expected_wheels) assert set(actual_wheels) == set(expected_wheels)
def test_cp38_arm64_testing_universal2_installer(tmp_path, capfd, request): def test_cp38_arm64_testing_universal2_installer(
tmp_path: Path, capfd: pytest.CaptureFixture[str], request: pytest.FixtureRequest
) -> None:
if not request.config.getoption("--run-cp38-universal2"): if not request.config.getoption("--run-cp38-universal2"):
pytest.skip("needs --run-cp38-universal2 option to run") pytest.skip("needs --run-cp38-universal2 option to run")
+2 -1
View File
@@ -1,5 +1,6 @@
import platform import platform
import textwrap import textwrap
from pathlib import Path
import pytest import pytest
@@ -61,7 +62,7 @@ project_with_manylinux_symbols = test_projects.new_c_project(
], ],
) )
@pytest.mark.usefixtures("docker_cleanup") @pytest.mark.usefixtures("docker_cleanup")
def test(manylinux_image, tmp_path): def test(manylinux_image: str, tmp_path: Path) -> None:
if utils.get_platform() != "linux": if utils.get_platform() != "linux":
pytest.skip("the container image test is only relevant to the linux build") pytest.skip("the container image test is only relevant to the linux build")
+3 -1
View File
@@ -1,3 +1,5 @@
from pathlib import Path
import packaging.utils import packaging.utils
from . import test_projects, utils from . import test_projects, utils
@@ -5,7 +7,7 @@ from . import test_projects, utils
meson_project = test_projects.new_meson_project() meson_project = test_projects.new_meson_project()
def test_meson_python_basic(tmp_path, build_frontend_env): def test_meson_python_basic(tmp_path: Path, build_frontend_env: dict[str, str]) -> None:
"""Test that cibuildwheel can build a project with meson-python backend.""" """Test that cibuildwheel can build a project with meson-python backend."""
project_dir = tmp_path / "project" project_dir = tmp_path / "project"
+2 -1
View File
@@ -1,4 +1,5 @@
import textwrap import textwrap
from pathlib import Path
import pytest import pytest
@@ -27,7 +28,7 @@ project_with_manylinux_symbols = test_projects.new_c_project(
["musllinux_1_2"], ["musllinux_1_2"],
) )
@pytest.mark.usefixtures("docker_cleanup") @pytest.mark.usefixtures("docker_cleanup")
def test(musllinux_image, tmp_path): def test(musllinux_image: str, tmp_path: Path) -> None:
if utils.get_platform() != "linux": if utils.get_platform() != "linux":
pytest.skip("the container image test is only relevant to the linux build") pytest.skip("the container image test is only relevant to the linux build")
+2 -1
View File
@@ -1,4 +1,5 @@
import textwrap import textwrap
from pathlib import Path
from . import test_projects, utils from . import test_projects, utils
@@ -29,7 +30,7 @@ build-backend = "setuptools.build_meta"
""" """
def test_pep518(tmp_path, build_frontend_env): def test_pep518(tmp_path: Path, build_frontend_env: dict[str, str]) -> None:
project_dir = tmp_path / "project" project_dir = tmp_path / "project"
basic_project.generate(project_dir) basic_project.generate(project_dir)
+2 -1
View File
@@ -1,4 +1,5 @@
import subprocess import subprocess
from pathlib import Path
import pytest import pytest
@@ -23,7 +24,7 @@ def a_function():
""" """
def test(tmp_path, capfd): def test(tmp_path: Path, capfd: pytest.CaptureFixture[str]) -> None:
# this test checks that if a pure wheel is generated, the build should # this test checks that if a pure wheel is generated, the build should
# fail. # fail.
project_dir = tmp_path / "project" project_dir = tmp_path / "project"
+7 -6
View File
@@ -3,6 +3,7 @@ import os
import subprocess import subprocess
import sys import sys
import textwrap import textwrap
from pathlib import Path
import pytest import pytest
@@ -48,7 +49,7 @@ if __name__ == "__main__":
@pytest.mark.parametrize("use_pyproject_toml", [True, False]) @pytest.mark.parametrize("use_pyproject_toml", [True, False])
def test_pyodide_build(tmp_path, use_pyproject_toml): def test_pyodide_build(tmp_path: Path, use_pyproject_toml: bool) -> None:
if sys.platform == "win32": if sys.platform == "win32":
pytest.skip("pyodide-build doesn't work correctly on Windows") pytest.skip("pyodide-build doesn't work correctly on Windows")
@@ -88,7 +89,7 @@ def test_pyodide_build(tmp_path, use_pyproject_toml):
assert set(actual_wheels) == set(expected_wheels) assert set(actual_wheels) == set(expected_wheels)
def test_pyodide_version_incompatible(tmp_path, capfd): def test_pyodide_version_incompatible(tmp_path: Path, capfd: pytest.CaptureFixture[str]) -> None:
if sys.platform == "win32": if sys.platform == "win32":
pytest.skip("pyodide-build doesn't work correctly on Windows") pytest.skip("pyodide-build doesn't work correctly on Windows")
@@ -110,19 +111,19 @@ def test_pyodide_version_incompatible(tmp_path, capfd):
@pytest.mark.parametrize("expect_failure", [True, False]) @pytest.mark.parametrize("expect_failure", [True, False])
def test_pyodide_build_and_test(tmp_path, expect_failure): def test_pyodide_build_and_test(tmp_path: Path, expect_failure: bool) -> None:
if sys.platform == "win32": if sys.platform == "win32":
pytest.skip("pyodide-build doesn't work correctly on Windows") pytest.skip("pyodide-build doesn't work correctly on Windows")
if expect_failure: if expect_failure:
basic_project.files["test/spam_test.py"] = textwrap.dedent(r""" basic_project.files["test/spam_test.py"] = textwrap.dedent(r"""
def test_filter(): def test_filter() -> None:
assert 0 == 1 assert 0 == 1
""") """)
else: else:
basic_project.files["test/spam_test.py"] = textwrap.dedent(r""" basic_project.files["test/spam_test.py"] = textwrap.dedent(r"""
import spam import spam
def test_filter(): def test_filter() -> None:
assert spam.filter("spam") == 0 assert spam.filter("spam") == 0
""") """)
basic_project.generate(tmp_path) basic_project.generate(tmp_path)
@@ -149,7 +150,7 @@ def test_pyodide_build_and_test(tmp_path, expect_failure):
assert set(actual_wheels) == set(expected_wheels) assert set(actual_wheels) == set(expected_wheels)
def test_pyodide_repair_wheel(tmp_path): def test_pyodide_repair_wheel(tmp_path: Path) -> None:
if sys.platform == "win32": if sys.platform == "win32":
pytest.skip("pyodide-build doesn't work correctly on Windows") pytest.skip("pyodide-build doesn't work correctly on Windows")
+2 -1
View File
@@ -1,4 +1,5 @@
import textwrap import textwrap
from pathlib import Path
import pytest import pytest
@@ -32,7 +33,7 @@ project_with_ssl_tests = test_projects.new_c_project(
@pytest.mark.flaky(reruns=2) @pytest.mark.flaky(reruns=2)
def test(tmp_path): def test(tmp_path: Path) -> None:
# this test checks that SSL is working in the build environment using # this test checks that SSL is working in the build environment using
# some checks in setup.py. # some checks in setup.py.
project_dir = tmp_path / "project" project_dir = tmp_path / "project"
+2 -1
View File
@@ -1,6 +1,7 @@
from pathlib import Path from pathlib import Path
import jinja2 import jinja2
import pytest
from . import utils from . import utils
from .test_projects import TestProject from .test_projects import TestProject
@@ -31,7 +32,7 @@ print('before_build.py executed!')
""" """
def test(capfd, tmp_path): def test(capfd: pytest.CaptureFixture[str], tmp_path: Path) -> None:
project_dir = tmp_path / "project" project_dir = tmp_path / "project"
subdir_package_project.generate(project_dir) subdir_package_project.generate(project_dir)
+10 -10
View File
@@ -43,11 +43,11 @@ def path_contains(parent, child):
class TestSpam(TestCase): class TestSpam(TestCase):
def test_filter(self): def test_filter(self) -> None:
self.assertEqual(0, spam.filter("spam")) self.assertEqual(0, spam.filter("spam"))
self.assertNotEqual(0, spam.filter("ham")) self.assertNotEqual(0, spam.filter("ham"))
def test_virtualenv(self): def test_virtualenv(self) -> None:
# sys.prefix is different from sys.base_prefix when running a virtualenv # sys.prefix is different from sys.base_prefix when running a virtualenv
# See https://docs.python.org/3/library/venv.html, which virtualenv seems # See https://docs.python.org/3/library/venv.html, which virtualenv seems
# to honor in recent releases # to honor in recent releases
@@ -58,7 +58,7 @@ class TestSpam(TestCase):
self.assertTrue(path_contains(sys.prefix, spam.__file__)) self.assertTrue(path_contains(sys.prefix, spam.__file__))
self.assertIn("VIRTUAL_ENV", os.environ) self.assertIn("VIRTUAL_ENV", os.environ)
def test_uname(self): def test_uname(self) -> None:
if platform.system() == "Windows": if platform.system() == "Windows":
return return
# if we're running in 32-bit Python, check that the machine is i686. # if we're running in 32-bit Python, check that the machine is i686.
@@ -69,7 +69,7 @@ class TestSpam(TestCase):
''' '''
def test(tmp_path): def test(tmp_path: Path) -> None:
project_dir = tmp_path / "project" project_dir = tmp_path / "project"
project_with_a_test.generate(project_dir) project_with_a_test.generate(project_dir)
@@ -90,7 +90,7 @@ def test(tmp_path):
assert set(actual_wheels) == set(expected_wheels) assert set(actual_wheels) == set(expected_wheels)
def test_extras_require(tmp_path): def test_extras_require(tmp_path: Path) -> None:
project_dir = tmp_path / "project" project_dir = tmp_path / "project"
project_with_a_test.generate(project_dir) project_with_a_test.generate(project_dir)
@@ -112,7 +112,7 @@ def test_extras_require(tmp_path):
assert set(actual_wheels) == set(expected_wheels) assert set(actual_wheels) == set(expected_wheels)
def test_dependency_groups(tmp_path): def test_dependency_groups(tmp_path: Path) -> None:
group_project = project_with_a_test.copy() group_project = project_with_a_test.copy()
group_project.files["pyproject.toml"] = inspect.cleandoc(""" group_project.files["pyproject.toml"] = inspect.cleandoc("""
[build-system] [build-system]
@@ -149,12 +149,12 @@ project_with_a_failing_test.files["test/spam_test.py"] = r"""
from unittest import TestCase from unittest import TestCase
class TestSpam(TestCase): class TestSpam(TestCase):
def test_something(self): def test_something(self) -> None:
self.fail('this test is supposed to fail') self.fail('this test is supposed to fail')
""" """
def test_failing_test(tmp_path): def test_failing_test(tmp_path: Path) -> None:
"""Ensure a failing test causes cibuildwheel to error out and exit""" """Ensure a failing test causes cibuildwheel to error out and exit"""
project_dir = tmp_path / "project" project_dir = tmp_path / "project"
output_dir = tmp_path / "output" output_dir = tmp_path / "output"
@@ -215,7 +215,7 @@ def test_bare_pytest_invocation(
) )
def test_test_sources(tmp_path): def test_test_sources(tmp_path: Path) -> None:
project_dir = tmp_path / "project" project_dir = tmp_path / "project"
project_with_a_test.generate(project_dir) project_with_a_test.generate(project_dir)
@@ -235,7 +235,7 @@ def test_test_sources(tmp_path):
assert set(actual_wheels) == set(expected_wheels) assert set(actual_wheels) == set(expected_wheels)
def test_test_environment(tmp_path): def test_test_environment(tmp_path: Path) -> None:
project_dir = tmp_path / "project" project_dir = tmp_path / "project"
test_projects.new_c_project().generate(project_dir) test_projects.new_c_project().generate(project_dir)
+12 -2
View File
@@ -1,4 +1,5 @@
import subprocess import subprocess
from pathlib import Path
import pytest import pytest
@@ -9,7 +10,12 @@ SO_FILE_WARNING = "NOTE: Shared object (.so) files found in this project."
@pytest.mark.parametrize("project_contains_so_files", [False, True]) @pytest.mark.parametrize("project_contains_so_files", [False, True])
def test_failed_build_with_so_files(tmp_path, capfd, build_frontend_env, project_contains_so_files): def test_failed_build_with_so_files(
tmp_path: Path,
capfd: pytest.CaptureFixture[str],
build_frontend_env: dict[str, str],
project_contains_so_files: bool,
) -> None:
project = TestProject() project = TestProject()
project.files["setup.py"] = "raise Exception('this build will fail')\n" project.files["setup.py"] = "raise Exception('this build will fail')\n"
if project_contains_so_files: if project_contains_so_files:
@@ -35,7 +41,11 @@ def test_failed_build_with_so_files(tmp_path, capfd, build_frontend_env, project
@pytest.mark.parametrize("project_contains_so_files", [False, True]) @pytest.mark.parametrize("project_contains_so_files", [False, True])
def test_failed_repair_with_so_files(tmp_path, capfd, project_contains_so_files): def test_failed_repair_with_so_files(
tmp_path: Path,
capfd: pytest.CaptureFixture[str],
project_contains_so_files: bool,
) -> None:
if utils.get_platform() != "linux": if utils.get_platform() != "linux":
pytest.skip("this test is only relevant to the linux build") pytest.skip("this test is only relevant to the linux build")
+3 -1
View File
@@ -1,3 +1,5 @@
from pathlib import Path
import pytest import pytest
from . import test_projects, utils from . import test_projects, utils
@@ -5,7 +7,7 @@ from . import test_projects, utils
basic_project = test_projects.new_c_project() basic_project = test_projects.new_c_project()
def test_wheel_tag_is_correct_when_using_macosx_deployment_target(tmp_path): def test_wheel_tag_is_correct_when_using_macosx_deployment_target(tmp_path: Path) -> None:
if utils.get_platform() != "macos": if utils.get_platform() != "macos":
pytest.skip("This test is only relevant to MACOSX_DEPLOYMENT_TARGET") pytest.skip("This test is only relevant to MACOSX_DEPLOYMENT_TARGET")
+3 -1
View File
@@ -38,7 +38,9 @@ def skip_if_no_msvc(arm64: bool = False) -> None:
@pytest.mark.parametrize("use_pyproject_toml", [True, False]) @pytest.mark.parametrize("use_pyproject_toml", [True, False])
def test_wheel_tag_is_correct_when_using_windows_cross_compile(tmp_path, use_pyproject_toml): def test_wheel_tag_is_correct_when_using_windows_cross_compile(
tmp_path: Path, use_pyproject_toml: bool
) -> None:
if utils.get_platform() != "windows": if utils.get_platform() != "windows":
pytest.skip("This test is only relevant to Windows") pytest.skip("This test is only relevant to Windows")
+2 -2
View File
@@ -11,7 +11,7 @@ import sys
from collections.abc import Generator, Mapping, Sequence from collections.abc import Generator, Mapping, Sequence
from pathlib import Path from pathlib import Path
from tempfile import TemporaryDirectory from tempfile import TemporaryDirectory
from typing import Any, Final from typing import Final
import pytest import pytest
@@ -458,7 +458,7 @@ def get_xcode_version() -> tuple[int, int]:
return (int(version_parts[0]), int(version_parts[1])) return (int(version_parts[0]), int(version_parts[1]))
def skip_if_pyodide(reason: str) -> Any: def skip_if_pyodide(reason: str) -> pytest.MarkDecorator:
return pytest.mark.skipif(get_platform() == "pyodide", reason=reason) return pytest.mark.skipif(get_platform() == "pyodide", reason=reason)
+13 -8
View File
@@ -6,6 +6,7 @@ import pytest
import cibuildwheel.architecture import cibuildwheel.architecture
from cibuildwheel.architecture import Architecture, arch_synonym from cibuildwheel.architecture import Architecture, arch_synonym
from cibuildwheel.typing import PlatformName
@pytest.fixture( @pytest.fixture(
@@ -20,7 +21,9 @@ from cibuildwheel.architecture import Architecture, arch_synonym
pytest.param(("windows", "win32", "ARM64", "arm"), id="windows-arm"), pytest.param(("windows", "win32", "ARM64", "arm"), id="windows-arm"),
] ]
) )
def platform_machine(request, monkeypatch): def platform_machine(
request: pytest.FixtureRequest, monkeypatch: pytest.MonkeyPatch
) -> tuple[str, str]:
platform_name, platform_value, machine_value, machine_name = request.param platform_name, platform_value, machine_value, machine_name = request.param
monkeypatch.setattr(sys, "platform", platform_value) monkeypatch.setattr(sys, "platform", platform_value)
monkeypatch.setattr(platform_module, "machine", lambda: machine_value) monkeypatch.setattr(platform_module, "machine", lambda: machine_value)
@@ -28,7 +31,7 @@ def platform_machine(request, monkeypatch):
return platform_name, machine_name return platform_name, machine_name
def test_arch_auto(platform_machine): def test_arch_auto(platform_machine: tuple[str, str]) -> None:
_, machine_name = platform_machine _, machine_name = platform_machine
arch_set = Architecture.auto_archs("linux") arch_set = Architecture.auto_archs("linux")
@@ -52,7 +55,7 @@ def test_arch_auto(platform_machine):
assert arch_set == expected[machine_name] assert arch_set == expected[machine_name]
def test_arch_auto64(platform_machine): def test_arch_auto64(platform_machine: tuple[str, str]) -> None:
_, machine_name = platform_machine _, machine_name = platform_machine
arch_set = Architecture.parse_config("auto64", "linux") arch_set = Architecture.parse_config("auto64", "linux")
@@ -68,7 +71,7 @@ def test_arch_auto64(platform_machine):
assert arch_set == expected[machine_name] assert arch_set == expected[machine_name]
def test_arch_auto32(platform_machine): def test_arch_auto32(platform_machine: tuple[str, str]) -> None:
_, machine_name = platform_machine _, machine_name = platform_machine
arch_set = Architecture.parse_config("auto32", "linux") arch_set = Architecture.parse_config("auto32", "linux")
@@ -83,7 +86,7 @@ def test_arch_auto32(platform_machine):
assert arch_set == expected[machine_name] assert arch_set == expected[machine_name]
def test_arch_auto_no_aarch32(monkeypatch): def test_arch_auto_no_aarch32(monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setattr(sys, "platform", "linux") monkeypatch.setattr(sys, "platform", "linux")
monkeypatch.setattr(platform_module, "machine", lambda: "aarch64") monkeypatch.setattr(platform_module, "machine", lambda: "aarch64")
monkeypatch.setattr(shutil, "which", lambda *args, **kwargs: None) monkeypatch.setattr(shutil, "which", lambda *args, **kwargs: None)
@@ -103,14 +106,14 @@ def test_arch_auto_no_aarch32(monkeypatch):
assert arch_set == set() assert arch_set == set()
def test_arch_native_on_ios(monkeypatch): def test_arch_native_on_ios(monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setattr(sys, "platform", "darwin") monkeypatch.setattr(sys, "platform", "darwin")
monkeypatch.setattr(platform_module, "machine", lambda: "arm64") monkeypatch.setattr(platform_module, "machine", lambda: "arm64")
arch_set = Architecture.parse_config("native", platform="ios") arch_set = Architecture.parse_config("native", platform="ios")
assert arch_set == {Architecture.arm64_iphonesimulator} assert arch_set == {Architecture.arm64_iphonesimulator}
def test_arch_auto_on_ios(monkeypatch): def test_arch_auto_on_ios(monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setattr(sys, "platform", "darwin") monkeypatch.setattr(sys, "platform", "darwin")
monkeypatch.setattr(platform_module, "machine", lambda: "arm64") monkeypatch.setattr(platform_module, "machine", lambda: "arm64")
arch_set = Architecture.parse_config("auto", platform="ios") arch_set = Architecture.parse_config("auto", platform="ios")
@@ -130,5 +133,7 @@ def test_arch_auto_on_ios(monkeypatch):
("x86", "windows", "macos", None), ("x86", "windows", "macos", None),
], ],
) )
def test_arch_synonym(arch, from_platform, to_platform, expected): def test_arch_synonym(
arch: str, from_platform: PlatformName, to_platform: PlatformName, expected: str | None
) -> None:
assert arch_synonym(arch, from_platform, to_platform) == expected assert arch_synonym(arch, from_platform, to_platform) == expected
+2 -2
View File
@@ -6,7 +6,7 @@ from cibuildwheel.extra import Printable, dump_python_configurations
from cibuildwheel.util import resources from cibuildwheel.util import resources
def test_compare_configs(): def test_compare_configs() -> None:
txt = resources.BUILD_PLATFORMS.read_text() txt = resources.BUILD_PLATFORMS.read_text()
with resources.BUILD_PLATFORMS.open("rb") as f2: with resources.BUILD_PLATFORMS.open("rb") as f2:
@@ -18,7 +18,7 @@ def test_compare_configs():
assert new_txt == txt assert new_txt == txt
def test_dump_with_Version(): def test_dump_with_Version() -> None:
# MyPy doesn't understand deeply nested dicts correctly # MyPy doesn't understand deeply nested dicts correctly
example: dict[str, dict[str, list[dict[str, Printable]]]] = { example: dict[str, dict[str, list[dict[str, Printable]]]] = {
"windows": { "windows": {
+15 -15
View File
@@ -4,7 +4,7 @@ import cibuildwheel.selector
from cibuildwheel.selector import BuildSelector, EnableGroup from cibuildwheel.selector import BuildSelector, EnableGroup
def test_build(): def test_build() -> None:
build_selector = BuildSelector( build_selector = BuildSelector(
build_config="cp3*-* *-manylinux*", skip_config="", enable=frozenset([EnableGroup.PyPy]) build_config="cp3*-* *-manylinux*", skip_config="", enable=frozenset([EnableGroup.PyPy])
) )
@@ -41,7 +41,7 @@ def test_build():
assert not build_selector("pp311-win_amd64") assert not build_selector("pp311-win_amd64")
def test_build_filter_pre(): def test_build_filter_pre() -> None:
build_selector = BuildSelector( build_selector = BuildSelector(
build_config="cp3*-* *-manylinux*", build_config="cp3*-* *-manylinux*",
skip_config="", skip_config="",
@@ -55,7 +55,7 @@ def test_build_filter_pre():
assert not build_selector("cp313t-manylinux_x86_64") assert not build_selector("cp313t-manylinux_x86_64")
def test_build_filter_pypy(): def test_build_filter_pypy() -> None:
build_selector = BuildSelector( build_selector = BuildSelector(
build_config="*", build_config="*",
skip_config="", skip_config="",
@@ -67,7 +67,7 @@ def test_build_filter_pypy():
assert not build_selector("pp39-manylinux_x86_64") assert not build_selector("pp39-manylinux_x86_64")
def test_build_filter_pypy_eol(): def test_build_filter_pypy_eol() -> None:
build_selector = BuildSelector( build_selector = BuildSelector(
build_config="*", build_config="*",
skip_config="", skip_config="",
@@ -79,7 +79,7 @@ def test_build_filter_pypy_eol():
assert build_selector("pp39-manylinux_x86_64") assert build_selector("pp39-manylinux_x86_64")
def test_build_filter_pypy_all(): def test_build_filter_pypy_all() -> None:
build_selector = BuildSelector( build_selector = BuildSelector(
build_config="*", build_config="*",
skip_config="", skip_config="",
@@ -91,7 +91,7 @@ def test_build_filter_pypy_all():
assert build_selector("pp39-manylinux_x86_64") assert build_selector("pp39-manylinux_x86_64")
def test_build_filter_pyodide_prerelease(): def test_build_filter_pyodide_prerelease() -> None:
build_selector = BuildSelector( build_selector = BuildSelector(
build_config="*", build_config="*",
skip_config="", skip_config="",
@@ -101,7 +101,7 @@ def test_build_filter_pyodide_prerelease():
assert build_selector("cp313-pyodide_wasm32") assert build_selector("cp313-pyodide_wasm32")
def test_build_filter_pyodide(): def test_build_filter_pyodide() -> None:
build_selector = BuildSelector( build_selector = BuildSelector(
build_config="*", build_config="*",
skip_config="", skip_config="",
@@ -111,7 +111,7 @@ def test_build_filter_pyodide():
assert build_selector("cp313-pyodide_wasm32") assert build_selector("cp313-pyodide_wasm32")
def test_skip(): def test_skip() -> None:
build_selector = BuildSelector( build_selector = BuildSelector(
build_config="*", build_config="*",
skip_config="pp310-* cp3?-manylinux_i686 cp36-win* *-win32", skip_config="pp310-* cp3?-manylinux_i686 cp36-win* *-win32",
@@ -136,7 +136,7 @@ def test_skip():
assert build_selector("cp37-win_amd64") assert build_selector("cp37-win_amd64")
def test_build_and_skip(): def test_build_and_skip() -> None:
build_selector = BuildSelector( build_selector = BuildSelector(
build_config="cp36-* cp37-macosx* *-manylinux*", build_config="cp36-* cp37-macosx* *-manylinux*",
skip_config="pp37-* cp37-manylinux_i686", skip_config="pp37-* cp37-manylinux_i686",
@@ -160,7 +160,7 @@ def test_build_and_skip():
assert not build_selector("cp37-win_amd64") assert not build_selector("cp37-win_amd64")
def test_build_braces(): def test_build_braces() -> None:
build_selector = BuildSelector(build_config="cp{36,37}*", skip_config="") build_selector = BuildSelector(build_config="cp{36,37}*", skip_config="")
assert build_selector("cp36-manylinux_x86_64") assert build_selector("cp36-manylinux_x86_64")
@@ -169,7 +169,7 @@ def test_build_braces():
assert not build_selector("cp39-manylinux_x86_64") assert not build_selector("cp39-manylinux_x86_64")
def test_build_limited_python(): def test_build_limited_python() -> None:
build_selector = BuildSelector( build_selector = BuildSelector(
build_config="*", build_config="*",
skip_config="", skip_config="",
@@ -190,7 +190,7 @@ def test_build_limited_python():
assert build_selector("gp311_242-win_amd64") assert build_selector("gp311_242-win_amd64")
def test_build_limited_python_partial(): def test_build_limited_python_partial() -> None:
build_selector = BuildSelector( build_selector = BuildSelector(
build_config="*", skip_config="", requires_python=SpecifierSet(">=3.6, !=3.7.*") build_config="*", skip_config="", requires_python=SpecifierSet(">=3.6, !=3.7.*")
) )
@@ -201,7 +201,7 @@ def test_build_limited_python_partial():
assert build_selector("cp39-manylinux_x86_64") assert build_selector("cp39-manylinux_x86_64")
def test_build_limited_python_patch(): def test_build_limited_python_patch() -> None:
build_selector = BuildSelector( build_selector = BuildSelector(
build_config="*", skip_config="", requires_python=SpecifierSet(">=3.6.8") build_config="*", skip_config="", requires_python=SpecifierSet(">=3.6.8")
) )
@@ -210,13 +210,13 @@ def test_build_limited_python_patch():
assert build_selector("cp37-manylinux_x86_64") assert build_selector("cp37-manylinux_x86_64")
def test_build_free_threaded_python(): def test_build_free_threaded_python() -> None:
build_selector = BuildSelector(build_config="*", skip_config="", enable=frozenset(EnableGroup)) build_selector = BuildSelector(build_config="*", skip_config="", enable=frozenset(EnableGroup))
assert build_selector("cp313t-manylinux_x86_64") assert build_selector("cp313t-manylinux_x86_64")
def test_testing_selector(): def test_testing_selector() -> None:
# This is not a global import to keep pytest from collecting it as a test # This is not a global import to keep pytest from collecting it as a test
test_selector = cibuildwheel.selector.TestSelector(skip_config="cp36-*") test_selector = cibuildwheel.selector.TestSelector(skip_config="cp36-*")
+3 -3
View File
@@ -6,7 +6,7 @@ import pytest
MOCK_PACKAGE_DIR = Path("some_package_dir") MOCK_PACKAGE_DIR = Path("some_package_dir")
def pytest_addoption(parser): def pytest_addoption(parser: pytest.Parser) -> None:
parser.addoption("--run-docker", action="store_true", default=False, help="run docker tests") parser.addoption("--run-docker", action="store_true", default=False, help="run docker tests")
parser.addoption("--run-podman", action="store_true", default=False, help="run podman tests") parser.addoption("--run-podman", action="store_true", default=False, help="run podman tests")
parser.addoption( parser.addoption(
@@ -18,13 +18,13 @@ def pytest_addoption(parser):
@pytest.fixture @pytest.fixture
def fake_package_dir(tmp_path, monkeypatch): def fake_package_dir(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> list[str]:
""" """
Monkey-patch enough for the main() function to run Monkey-patch enough for the main() function to run
""" """
real_path_exists = Path.exists real_path_exists = Path.exists
def mock_path_exists(path): def mock_path_exists(path: Path) -> bool:
if str(path).endswith(str(MOCK_PACKAGE_DIR / "setup.py")): if str(path).endswith(str(MOCK_PACKAGE_DIR / "setup.py")):
return True return True
else: else:

Some files were not shown because too many files have changed in this diff Show More