Compare commits

...
29 Commits
Author SHA1 Message Date
Joe Rickerby 298ed2fb2c Bump version: v3.3.1 2026-01-05 19:57:01 +00:00
Joe Rickerbyandmayeut f0ff944318 [3.3.x] Update dependencies (#2708)
* Update deps

nox --force-color -s update_constraints && nox --force-color -s update_pins

* update deps

nox -s update_pins

---------

Co-authored-by: mayeut <mayeut@users.noreply.github.com>
2026-01-05 19:51:01 +00:00
Joe Rickerby 63fd63b352 Bump version: v3.3.0 2025-11-12 19:27:31 +00:00
Henry Schreiner f4fe311fc9 fix: support Docker 29 (#2660)
* fix: support Docker 29

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

* refactor: closer to actual case, lambda

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

---------

Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>
2025-11-12 14:15:10 -05:00
Alexander CondelloandJoe Rickerby f6c810852d feat: make the {project} placeholder available to repair-wheel-command (#2589)
* Make the {project} placeholder available to repair-wheel-command

* Add separate test for {project} placeholder in repair-wheel-command

* Make the {project} placeholder available to repair-wheel-command

* reduce duplicated work in tests

* Use a valid wheel filename for the post-repair name

---------

Co-authored-by: Joe Rickerby <joerick@mac.com>
2025-11-10 20:59:32 -05:00
Henry Schreiner ccbae30b53 feat: support uv with Android (#2587) 2025-11-10 19:43:52 -05:00
Henry Schreiner 1337e50f74 chore: pytest log_level is better than log_cli_level (#2657)
Committed via https://github.com/asottile/all-repos
2025-11-10 22:47:32 +01:00
Matthieu Darbois 720f8e266f feat: add manylinux_2_35 (#2656)
pypa/manylinux now has a manylinux_2_35_armv7l image allowing for better C++20 support.
piwheels is still building for Debian Bullseye so keeping manylinux_2_31 as the default image.
2025-11-10 15:54:53 -05:00
pre-commit-ci[bot]andpre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> 4c7f3696b1 [pre-commit.ci] pre-commit autoupdate (#2658)
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.14.3 → v0.14.4](https://github.com/astral-sh/ruff-pre-commit/compare/v0.14.3...v0.14.4)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2025-11-10 15:53:57 -05:00
Henry Schreiner e1baa60eb0 chore: enable more Ruff checks (#2654)
Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>
2025-11-07 18:48:20 -05:00
Joe RickerbyandHenry Schreiner 1f2f8b28d5 fix: don't constrain build-system.requires with our dependency-versions (#2583)
* Don't constrain build-system.requires with dependency-versions

* Remove setting of VIRTUALENV_PIP (it doesn't appear to have any effect)

* Alter tests to assert the versions in before_build, not setup.py

* Skip the util-test on linux

---------

Co-authored-by: Henry Schreiner <HenrySchreinerIII@gmail.com>
2025-11-06 17:03:00 -05:00
pre-commit-ci[bot]andpre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> 8c5b02f42c [pre-commit.ci] pre-commit autoupdate (#2648)
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.14.2 → v0.14.3](https://github.com/astral-sh/ruff-pre-commit/compare/v0.14.2...v0.14.3)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2025-11-06 16:49:12 -05:00
cibuildwheel-bot[bot]andcibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com> 997a6e1931 [Bot] Update dependencies (#2646)
Update dependencies

Co-authored-by: cibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com>
2025-11-06 14:43:00 -05:00
4fe7630d9c feat: add configuration option for test executor arguments (#2636)
* Add test-execution-args option.

* Add usage of test-execution-args.

* Add CI configuration to use test-execution-args.

* Document the test-execution-args setting.

* Simplify code using or syntax instead of inline if.

Co-authored-by: Malcolm Smith <smith@chaquo.com>

* Clarified some Android-specific terminology, and added details about the default args to the test runner.

* Switch to a dict-based test-execution configuration

* Add tests for test-execution parsing.

* Add all the files before pushing...

* Add note about default Android version for testbed.

* Improve description of test-execution setting.

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

* Switch to using test-runtime.

---------

Co-authored-by: Malcolm Smith <smith@chaquo.com>
Co-authored-by: Joe Rickerby <joerick@mac.com>
2025-11-05 16:19:41 -05:00
cibuildwheel-bot[bot]andcibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com> c53e541c2d [Bot] Update dependencies (#2642)
Update dependencies

Co-authored-by: cibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com>
2025-10-29 12:44:46 +00:00
pre-commit-ci[bot]andpre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> 58d113ad2b [pre-commit.ci] pre-commit autoupdate (#2644)
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.14.1 → v0.14.2](https://github.com/astral-sh/ruff-pre-commit/compare/v0.14.1...v0.14.2)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2025-10-29 12:44:28 +00:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> de0262ea87 chore(deps): bump the actions group with 2 updates (#2643)
Bumps the actions group with 2 updates: [actions/download-artifact](https://github.com/actions/download-artifact) and [actions/upload-artifact](https://github.com/actions/upload-artifact).


Updates `actions/download-artifact` from 5 to 6
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](https://github.com/actions/download-artifact/compare/v5...v6)

Updates `actions/upload-artifact` from 4 to 5
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/download-artifact
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: actions
- dependency-name: actions/upload-artifact
  dependency-version: '5'
  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>
2025-10-27 17:56:46 +00:00
cibuildwheel-bot[bot]cibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com>Joe Rickerby
41f3304a86 [Bot] Update dependencies (#2633)
Update dependencies

Co-authored-by: cibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com>
Co-authored-by: Joe Rickerby <joerick@mac.com>
2025-10-26 17:02:37 +00:00
Ofek Lev a3af13a337 Allow installation of extras in GitHub action (#2630) 2025-10-26 13:29:26 +00:00
pre-commit-ci[bot]andpre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> 168717b5c5 [pre-commit.ci] pre-commit autoupdate (#2635)
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.14.0 → v0.14.1](https://github.com/astral-sh/ruff-pre-commit/compare/v0.14.0...v0.14.1)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2025-10-25 16:25:41 +01:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> a592c06add chore(deps): bump wntrblm/nox from 2025.05.01 to 2025.10.16 in the actions group (#2634)
chore(deps): bump wntrblm/nox in the actions group

Bumps the actions group with 1 update: [wntrblm/nox](https://github.com/wntrblm/nox).


Updates `wntrblm/nox` from 2025.05.01 to 2025.10.16
- [Release notes](https://github.com/wntrblm/nox/releases)
- [Changelog](https://github.com/wntrblm/nox/blob/main/CHANGELOG.md)
- [Commits](https://github.com/wntrblm/nox/compare/2025.05.01...2025.10.16)

---
updated-dependencies:
- dependency-name: wntrblm/nox
  dependency-version: 2025.10.16
  dependency-type: direct:production
  dependency-group: actions
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-10-25 16:25:00 +01:00
Henry Schreiner bbe00a21e3 chore: fix warning on pylint 4 (#2624)
Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>
2025-10-25 15:35:48 +01:00
Malcolm Smithandpre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> 362020b1c7 Update Android test-command handling (#2590)
* Update Android test-command handling

* Update to Python 3.13.8

* Update documentation and tests

* Deal with `sysconfig.get_config_var("exec_prefix")` changing in Python 3.14, and add cross venv tests

* Allow test commands starting with `python3`

* test-command cleanups

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

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

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2025-10-25 15:29:52 +01:00
Joe Rickerby 8165422c41 chrome: remove dependency workaround for mkdocs-macro-plugin (#2639)
chrome: remove version pin for mkdocs-macro-plugin
2025-10-25 14:40:07 +01:00
Alex WillmerandJoe Rickerby a6acd2a2d5 docs: Note the evalution order of environment variables (#2618)
* docs: Note the evalution order of environment variables

* Remove example that doesn't reinforce good practice

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

---------

Co-authored-by: Joe Rickerby <joerick@mac.com>
2025-10-15 15:44:15 -04:00
Michael R. Crusoe 372dd68cf6 docs: working examples: pyzmq no longer uses CircleCI (#2620)
pyzmq no longer uses CircleCI

https://github.com/zeromq/pyzmq/commit/014bc3eefc8bb1f883bacc9392966022de62be30
2025-10-15 15:43:39 -04:00
cibuildwheel-bot[bot]andcibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com> cb5496943f [Bot] Update dependencies (#2621)
Update dependencies

Co-authored-by: cibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com>
2025-10-15 15:42:54 -04:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> ad74d64a16 chore(deps): bump astral-sh/setup-uv from 6 to 7 in the actions group (#2622)
Bumps the actions group with 1 update: [astral-sh/setup-uv](https://github.com/astral-sh/setup-uv).


Updates `astral-sh/setup-uv` from 6 to 7
- [Release notes](https://github.com/astral-sh/setup-uv/releases)
- [Commits](https://github.com/astral-sh/setup-uv/compare/v6...v7)

---
updated-dependencies:
- dependency-name: astral-sh/setup-uv
  dependency-version: '7'
  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>
2025-10-15 15:42:31 -04:00
pre-commit-ci[bot]andpre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> be214efadb [pre-commit.ci] pre-commit autoupdate (#2623)
updates:
- [github.com/python-jsonschema/check-jsonschema: 0.34.0 → 0.34.1](https://github.com/python-jsonschema/check-jsonschema/compare/0.34.0...0.34.1)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2025-10-15 15:41:27 -04:00
75 changed files with 1175 additions and 746 deletions
+1 -1
View File
@@ -27,7 +27,7 @@ jobs:
attestations: write attestations: write
steps: steps:
- uses: actions/download-artifact@v5 - uses: actions/download-artifact@v6
with: with:
name: Packages name: Packages
path: dist path: dist
+13 -5
View File
@@ -79,9 +79,13 @@ jobs:
- os: macos-15 - os: macos-15
python_version: '3.13' python_version: '3.13'
test_select: ios test_select: ios
# Exercise iOS on a non-default simulator.
test_runtime: 'args: --simulator "iPhone 16e,OS=18.5"'
- os: macos-15-intel - os: macos-15-intel
python_version: '3.13' python_version: '3.13'
test_select: android test_select: android
# Exercise Android on a non-default simulator
test_runtime: 'args: --managed minVersion'
- os: macos-15 - os: macos-15
python_version: '3.13' python_version: '3.13'
test_select: android test_select: android
@@ -94,7 +98,7 @@ jobs:
python-version: ${{ matrix.python_version }} python-version: ${{ matrix.python_version }}
allow-prereleases: true allow-prereleases: true
- uses: astral-sh/setup-uv@v6 - uses: astral-sh/setup-uv@v7
- name: Free up disk space - name: Free up disk space
if: runner.os == 'Linux' if: runner.os == 'Linux'
@@ -154,6 +158,7 @@ jobs:
CIBW_ARCHS_MACOS: x86_64 universal2 arm64 CIBW_ARCHS_MACOS: x86_64 universal2 arm64
CIBW_BUILD_FRONTEND: ${{ matrix.test_select && 'build' || 'build[uv]' }} CIBW_BUILD_FRONTEND: ${{ matrix.test_select && 'build' || 'build[uv]' }}
CIBW_PLATFORM: ${{ matrix.test_select }} CIBW_PLATFORM: ${{ matrix.test_select }}
CIBW_TEST_RUNTIME: ${{ matrix.test_runtime }}
- name: Run a sample build (GitHub Action, only) - name: Run a sample build (GitHub Action, only)
uses: ./ uses: ./
@@ -179,6 +184,7 @@ jobs:
uses: ./ uses: ./
env: env:
CIBW_PLATFORM: ${{ matrix.test_select }} CIBW_PLATFORM: ${{ matrix.test_select }}
CIBW_TEST_RUNTIME: ${{ matrix.test_runtime }}
with: with:
package-dir: sample_proj package-dir: sample_proj
output-dir: wheelhouse_config_file output-dir: wheelhouse_config_file
@@ -196,12 +202,14 @@ 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@v4 - uses: actions/upload-artifact@v5
with: with:
name: cibw-wheels-${{ matrix.os }}-${{ strategy.job-index }} name: cibw-wheels-${{ matrix.os }}-${{ strategy.job-index }}
path: wheelhouse/*.whl path: wheelhouse/*.whl
- name: Test cibuildwheel - name: Test cibuildwheel
env:
CIBW_TEST_RUNTIME: ${{ matrix.test_runtime }}
run: | run: |
uv run --no-sync bin/run_tests.py --test-select=${{ matrix.test_select || 'native' }} ${{ (runner.os == 'Linux' && runner.arch == 'X64') && '--run-podman' || '' }} uv run --no-sync bin/run_tests.py --test-select=${{ matrix.test_select || 'native' }} ${{ (runner.os == 'Linux' && runner.arch == 'X64') && '--run-podman' || '' }}
@@ -216,7 +224,7 @@ jobs:
- uses: actions/setup-python@v6 - uses: actions/setup-python@v6
with: with:
python-version: "3.x" python-version: "3.x"
- uses: astral-sh/setup-uv@v6 - uses: astral-sh/setup-uv@v7
- 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
@@ -239,7 +247,7 @@ jobs:
- uses: actions/setup-python@v6 - uses: actions/setup-python@v6
with: with:
python-version: "3.x" python-version: "3.x"
- uses: astral-sh/setup-uv@v6 - uses: astral-sh/setup-uv@v7
- name: Install dependencies - name: Install dependencies
run: uv sync --no-dev --group test run: uv sync --no-dev --group test
@@ -260,7 +268,7 @@ jobs:
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@v6 - uses: astral-sh/setup-uv@v7
- name: Install dependencies - name: Install dependencies
run: uv sync --no-dev --group test run: uv sync --no-dev --group test
+1 -1
View File
@@ -32,7 +32,7 @@ jobs:
- uses: actions/checkout@v5 - uses: actions/checkout@v5
- uses: wntrblm/nox@2025.05.01 - uses: wntrblm/nox@2025.10.16
- name: "Run update: dependencies" - name: "Run update: dependencies"
run: nox --force-color -s update_constraints run: nox --force-color -s update_constraints
+2 -2
View File
@@ -14,7 +14,7 @@ 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.14.0 rev: v0.14.4
hooks: hooks:
- id: ruff-check - id: ruff-check
args: ["--fix", "--show-fixes"] args: ["--fix", "--show-fixes"]
@@ -83,7 +83,7 @@ repos:
- repo: https://github.com/python-jsonschema/check-jsonschema - repo: https://github.com/python-jsonschema/check-jsonschema
rev: 0.34.0 rev: 0.34.1
hooks: hooks:
- id: check-dependabot - id: check-dependabot
- id: check-github-actions - id: check-github-actions
+26 -29
View File
@@ -59,8 +59,8 @@ Usage
| | Linux | macOS | Windows | Linux ARM | macOS ARM | Windows ARM | Android | iOS | | | Linux | macOS | Windows | Linux ARM | macOS ARM | Windows ARM | Android | iOS |
|-----------------|-------|-------|---------|-----------|-----------|-------------|---------|-----| |-----------------|-------|-------|---------|-----------|-----------|-------------|---------|-----|
| GitHub Actions | ✅ | ✅ | ✅ | ✅ | ✅ | ✅² | ✅⁴ | ✅³ | | GitHub Actions | ✅ | ✅ | ✅ | ✅ | ✅ | ✅² | ✅⁴ | ✅³ |
| Azure Pipelines | ✅ | ✅ | ✅ | | ✅ | ✅² | ✅⁴ | ✅³ | | Azure Pipelines | ✅ | ✅ | ✅ | | ✅ | ✅² | ✅⁴ | ✅³ |
| Travis CI | ✅ | | ✅ | ✅ | | | ✅⁴ | | | Travis CI | ✅ | | ✅ | ✅ | | | ✅⁴ | |
| CircleCI | ✅ | ✅ | | ✅ | ✅ | | ✅⁴ | ✅³ | | CircleCI | ✅ | ✅ | | ✅ | ✅ | | ✅⁴ | ✅³ |
| Gitlab CI | ✅ | ✅ | ✅ | ✅¹ | ✅ | | ✅⁴ | ✅³ | | Gitlab CI | ✅ | ✅ | ✅ | ✅¹ | ✅ | | ✅⁴ | ✅³ |
@@ -70,7 +70,6 @@ Usage
<sup>² [Uses cross-compilation](https://cibuildwheel.pypa.io/en/stable/faq/#windows-arm64). It is not possible to test `arm64` on this CI platform.</sup><br> <sup>² [Uses cross-compilation](https://cibuildwheel.pypa.io/en/stable/faq/#windows-arm64). It is not possible to test `arm64` on this CI platform.</sup><br>
<sup>³ Requires a macOS runner; runs tests on the simulator for the runner's architecture. </sup><br> <sup>³ Requires a macOS runner; runs tests on the simulator for the runner's architecture. </sup><br>
<sup>⁴ Building for Android requires the runner to be Linux x86_64, macOS ARM64 or macOS x86_64. Testing has [additional requirements](https://cibuildwheel.pypa.io/en/stable/platforms/#android).</sup><br> <sup>⁴ Building for Android requires the runner to be Linux x86_64, macOS ARM64 or macOS x86_64. Testing has [additional requirements](https://cibuildwheel.pypa.io/en/stable/platforms/#android).</sup><br>
<sup>⁵ The `macos-15` and `macos-latest` images are [incompatible with cibuildwheel at this time](platforms/#ios-system-requirements)</sup><br> when building iOS wheels.
<!--intro-end--> <!--intro-end-->
@@ -100,7 +99,7 @@ jobs:
- uses: actions/setup-python@v5 - uses: actions/setup-python@v5
- name: Install cibuildwheel - name: Install cibuildwheel
run: python -m pip install cibuildwheel==3.2.1 run: python -m pip install cibuildwheel==3.3.1
- name: Build wheels - name: Build wheels
run: python -m cibuildwheel --output-dir wheelhouse run: python -m cibuildwheel --output-dir wheelhouse
@@ -160,12 +159,13 @@ The following diagram summarises the steps that cibuildwheel takes on each platf
| | [`test-groups`](https://cibuildwheel.pypa.io/en/stable/options/#test-groups) | Specify test dependencies from your project's `dependency-groups` | | | [`test-groups`](https://cibuildwheel.pypa.io/en/stable/options/#test-groups) | Specify test dependencies from your project's `dependency-groups` |
| | [`test-skip`](https://cibuildwheel.pypa.io/en/stable/options/#test-skip) | Skip running tests on some builds | | | [`test-skip`](https://cibuildwheel.pypa.io/en/stable/options/#test-skip) | Skip running tests on some builds |
| | [`test-environment`](https://cibuildwheel.pypa.io/en/stable/options/#test-environment) | Set environment variables for the test environment | | | [`test-environment`](https://cibuildwheel.pypa.io/en/stable/options/#test-environment) | Set environment variables for the test environment |
| | [`test-runtime`](https://cibuildwheel.pypa.io/en/stable/options/#test-runtime) | Controls how the tests will be executed. |
| **Debugging** | [`debug-keep-container`](https://cibuildwheel.pypa.io/en/stable/options/#debug-keep-container) | Keep the container after running for debugging. | | **Debugging** | [`debug-keep-container`](https://cibuildwheel.pypa.io/en/stable/options/#debug-keep-container) | Keep the container after running for debugging. |
| | [`debug-traceback`](https://cibuildwheel.pypa.io/en/stable/options/#debug-traceback) | Print full traceback when errors occur. | | | [`debug-traceback`](https://cibuildwheel.pypa.io/en/stable/options/#debug-traceback) | Print full traceback when errors occur. |
| | [`build-verbosity`](https://cibuildwheel.pypa.io/en/stable/options/#build-verbosity) | Increase/decrease the output of the build | | | [`build-verbosity`](https://cibuildwheel.pypa.io/en/stable/options/#build-verbosity) | Increase/decrease the output of the build |
<!--[[[end]]] (sum: FxE3nIgFiY) --> <!--[[[end]]] (sum: dbfwOkj/k/) -->
These options can be specified in a pyproject.toml file, or as environment variables, see [configuration docs](https://cibuildwheel.pypa.io/en/latest/configuration/). These options can be specified in a pyproject.toml file, or as environment variables, see [configuration docs](https://cibuildwheel.pypa.io/en/latest/configuration/).
@@ -230,6 +230,26 @@ Changelog
<!-- [[[cog from readme_changelog import mini_changelog; print(mini_changelog()) ]]] --> <!-- [[[cog from readme_changelog import mini_changelog; print(mini_changelog()) ]]] -->
### v3.3.1
_5 January 2026_
- 🛠 Update dependencies and container pins, including updating to CPython 3.14.2. (#2708)
### v3.3.0
_12 November 2025_
- 🐛 Fix an incompatibility with Docker v29 (#2660)
- ✨ Adds `test-runtime` option, to customise how tests on simulated/emulated environments are run (#2636)
- ✨ Adds support for new `manylinux_2_35` images on 32-bit ARM `armv7l`, offering better C++20 compatibility (#2656)
- ✨ `build[uv]` is now supported on Android (#2587)
- ✨ You can now install extras (such as `uv`) with a simple option on the GitHub Action (#2630)
- ✨ `{project}` and `{package}` placeholders are now supported in `repair-wheel-command` (#2589)
- 🛠 The versions set with `dependency-versions` no longer constrain packages specified by your `build-system.requires`. Previously, on platforms other than Linux, the constraints in this option would remain in the environment during the build. This has been tidied up make behaviour more consistent between platforms, and to prevent version conflicts. (#2583)
- 🛠 Improve the handling of `test-command` on Android, enabling more options to be passed (#2590)
- 📚 Docs improvements (#2618)
### v3.2.1 ### v3.2.1
_12 October 2025_ _12 October 2025_
@@ -267,30 +287,7 @@ _19 August 2025_
- 🧪 Fix and enable doctests (#2546) - 🧪 Fix and enable doctests (#2546)
- 📚 Improve our docs on free-threading (#2549) - 📚 Improve our docs on free-threading (#2549)
<!-- [[[end]]] (sum: PDe+dJWkRl) -->
### v3.1.3
_1 August 2025_
- 🐛 Fix bug where "latest" dependencies couldn't update to pip 25.2 on Windows (#2537)
- 🧪 Use pytest-rerunfailures to improve some of our iOS/Android tests (#2527, #2539)
- 🧪 Remove some GraalPy Windows workarounds in our tests (#2501)
### v3.1.2
_29 July 2025_
- ⚠️ Add an error if `CIBW_FREE_THREADING_SUPPORT` is set; you are likely missing 3.13t wheels, please use the `enable`/`CIBW_ENABLE` (#2520)
- 🛠 `riscv64` now enabled if you target that architecture, it's now supported on PyPI (#2509)
- 🛠 Add warning when using `cpython-experimental-riscv64` (no longer needed) (#2526, #2528)
- 🛠 iOS versions bumped, fixing issues with 3.14 (now RC 1) (#2530)
- 🐛 Fix bug in Android running wheel from our GitHub Action (#2517)
- 🐛 Fix warning when using `test-skip` of `"*-macosx_universal2:arm64"` (#2522)
- 🐛 Fix incorrect number of wheels reported in logs, again (#2517)
- 📚 We welcome our Android platform maintainer (#2516)
<!-- [[[end]]] (sum: ZUsMYXdVXu) -->
--- ---
+33 -5
View File
@@ -17,6 +17,10 @@ inputs:
description: 'Build a specific wheel only. No need for arch/platform if this is set' description: 'Build a specific wheel only. No need for arch/platform if this is set'
required: false required: false
default: '' default: ''
extras:
description: 'Comma-separated list of extras to install'
required: false
default: ''
branding: branding:
icon: package icon: package
color: yellow color: yellow
@@ -42,6 +46,10 @@ 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())
if sys.platform == "linux":
EXTRAS.discard("uv")
class EnvBuilder(venv.EnvBuilder): class EnvBuilder(venv.EnvBuilder):
def __init__(self): def __init__(self):
@@ -53,7 +61,10 @@ 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
run([sys.executable, "-m", "pip", "--python", context.env_exe, "install", r"${{ github.action_path }}"], check=True) install_spec = r"${{ github.action_path }}"
if EXTRAS:
install_spec += f"[{','.join(sorted(EXTRAS))}]"
run([sys.executable, "-m", "pip", "--python", context.env_exe, "install", install_spec], check=True)
print("::group::Install cibuildwheel") print("::group::Install cibuildwheel")
@@ -62,30 +73,47 @@ runs:
shutil.rmtree(venv_path) shutil.rmtree(venv_path)
builder = EnvBuilder() builder = EnvBuilder()
builder.create(venv_path) builder.create(venv_path)
cibw_path = [path for path in builder.bin_path.glob("cibuildwheel*") if path.stem == "cibuildwheel"][0] exposed_binaries = {"cibuildwheel"}
if "uv" in EXTRAS:
exposed_binaries.add("uv")
clean_bin_path = builder.bin_path.parent / f"{builder.bin_path.name}.clean"
clean_bin_path.mkdir()
for path in list(builder.bin_path.iterdir()):
if path.stem in exposed_binaries:
try:
os.symlink(path, clean_bin_path / path.name)
except OSError:
import shutil
shutil.copy2(path, clean_bin_path / path.name)
full_path = f"{clean_bin_path}{os.pathsep}{os.environ['PATH']}"
with open(os.environ["GITHUB_OUTPUT"], "at") as f: with open(os.environ["GITHUB_OUTPUT"], "at") as f:
f.write(f"cibw-path={cibw_path}\n") f.write(f"updated-path={full_path}\n")
print("::endgroup::") print("::endgroup::")
EOF EOF
shell: bash shell: bash
# Redirecting stderr to stdout to fix interleaving issue in Actions. # Redirecting stderr to stdout to fix interleaving issue in Actions.
- run: > - run: >
"${{ steps.cibw.outputs.cibw-path }}" cibuildwheel
"${{ inputs.package-dir }}" "${{ inputs.package-dir }}"
${{ inputs.output-dir != '' && format('--output-dir "{0}"', inputs.output-dir) || ''}} ${{ inputs.output-dir != '' && format('--output-dir "{0}"', inputs.output-dir) || ''}}
${{ inputs.config-file != '' && format('--config-file "{0}"', inputs.config-file) || ''}} ${{ inputs.config-file != '' && format('--config-file "{0}"', inputs.config-file) || ''}}
${{ inputs.only != '' && format('--only "{0}"', inputs.only) || ''}} ${{ inputs.only != '' && format('--only "{0}"', inputs.only) || ''}}
2>&1 2>&1
env:
PATH: "${{ steps.cibw.outputs.updated-path }}"
shell: bash shell: bash
if: runner.os != 'Windows' if: runner.os != 'Windows'
# Windows needs powershell to interact nicely with Meson # Windows needs powershell to interact nicely with Meson
- run: > - run: >
& "${{ steps.cibw.outputs.cibw-path }}" cibuildwheel
"${{ inputs.package-dir }}" "${{ inputs.package-dir }}"
${{ inputs.output-dir != '' && format('--output-dir "{0}"', inputs.output-dir) || ''}} ${{ inputs.output-dir != '' && format('--output-dir "{0}"', inputs.output-dir) || ''}}
${{ inputs.config-file != '' && format('--config-file "{0}"', inputs.config-file) || ''}} ${{ inputs.config-file != '' && format('--config-file "{0}"', inputs.config-file) || ''}}
${{ inputs.only != '' && format('--only "{0}"', inputs.only) || ''}} ${{ inputs.only != '' && format('--only "{0}"', inputs.only) || ''}}
env:
PATH: "${{ steps.cibw.outputs.updated-path }}"
shell: pwsh shell: pwsh
if: runner.os == 'Windows' if: runner.os == 'Windows'
+2 -2
View File
@@ -68,8 +68,8 @@ def bump_version() -> None:
sys.exit(1) sys.exit(1)
# fmt: off # fmt: off
print( 'Current version:', current_version) print( "Current version:", current_version)
new_version = input(' New version: ').strip() new_version = input(" New version: ").strip()
# fmt: on # fmt: on
try: try:
+19
View File
@@ -224,6 +224,24 @@ properties:
test-environment: test-environment:
description: Set environment variables for the test environment description: Set environment variables for the test environment
type: string_table type: string_table
test-runtime:
description: Additional configuration for the test runner
oneOf:
- type: string
pattern: '^$'
- type: object
additionalProperties: false
- type: string
pattern: 'args:'
- type: object
additionalProperties: false
required: [args]
properties:
args:
type: array
items:
type: string
""" """
schema = yaml.safe_load(starter) schema = yaml.safe_load(starter)
@@ -304,6 +322,7 @@ items:
test-sources: {"$ref": "#/$defs/inherit"} test-sources: {"$ref": "#/$defs/inherit"}
test-requires: {"$ref": "#/$defs/inherit"} test-requires: {"$ref": "#/$defs/inherit"}
test-environment: {"$ref": "#/$defs/inherit"} test-environment: {"$ref": "#/$defs/inherit"}
test-runtime: {"$ref": "#/$defs/inherit"}
""" """
) )
+2
View File
@@ -71,6 +71,8 @@ images = [
"pypy_aarch64", "pypy_aarch64",
], ],
), ),
# manylinux_2_35 images
PyPAImage("manylinux_2_35", ["armv7l"]),
# manylinux_2_39 images # manylinux_2_39 images
PyPAImage("manylinux_2_39", ["riscv64"]), PyPAImage("manylinux_2_39", ["riscv64"]),
# musllinux_1_2 images # musllinux_1_2 images
+1 -1
View File
@@ -1 +1 @@
__version__ = "3.2.1" __version__ = "3.3.1"
+1 -1
View File
@@ -314,7 +314,7 @@ def _compute_platform(args: CommandLineArguments) -> PlatformName:
if args.only: if args.only:
return _compute_platform_only(args.only) return _compute_platform_only(args.only)
elif platform_option_value != "auto": elif platform_option_value != "auto":
return typing.cast(PlatformName, platform_option_value) return typing.cast("PlatformName", platform_option_value)
return native_platform() return native_platform()
+2 -2
View File
@@ -41,7 +41,7 @@ def dump_python_configurations(
def _json_request(request: urllib.request.Request, timeout: int = 30) -> dict[str, Any]: def _json_request(request: urllib.request.Request, timeout: int = 30) -> dict[str, Any]:
with urllib.request.urlopen(request, timeout=timeout) as response: with urllib.request.urlopen(request, timeout=timeout) as response:
return typing.cast(dict[str, Any], json.load(response)) return typing.cast("dict[str, Any]", json.load(response))
def github_api_request(path: str, *, max_retries: int = 3) -> dict[str, Any]: def github_api_request(path: str, *, max_retries: int = 3) -> dict[str, Any]:
@@ -98,4 +98,4 @@ def get_pyodide_xbuildenv_info() -> PyodideXBuildEnvInfo:
"https://pyodide.github.io/pyodide/api/pyodide-cross-build-environments.json" "https://pyodide.github.io/pyodide/api/pyodide-cross-build-environments.json"
) )
with urllib.request.urlopen(xbuildenv_info_url) as response: with urllib.request.urlopen(xbuildenv_info_url) as response:
return typing.cast(PyodideXBuildEnvInfo, json.loads(response.read().decode("utf-8"))) return typing.cast("PyodideXBuildEnvInfo", json.loads(response.read().decode("utf-8")))
+1 -1
View File
@@ -24,7 +24,7 @@ class BuildFrontendConfig:
msg = f"Unrecognised build frontend {name!r}, must be one of {names}" msg = f"Unrecognised build frontend {name!r}, must be one of {names}"
raise ValueError(msg) raise ValueError(msg)
name = typing.cast(BuildFrontendName, name) name = typing.cast("BuildFrontendName", name)
args = config_dict.get("args") or [] args = config_dict.get("args") or []
return cls(name=name, args=args) return cls(name=name, args=args)
+11 -8
View File
@@ -78,7 +78,7 @@ class OCIContainerEngineConfig:
msg = f"unknown container engine {name}" msg = f"unknown container engine {name}"
raise ValueError(msg) raise ValueError(msg)
name = typing.cast(ContainerEngineName, name) name = typing.cast("ContainerEngineName", name)
# some flexibility in the option names to cope with TOML conventions # some flexibility in the option names to cope with TOML conventions
create_args = config_dict.get("create_args") or config_dict.get("create-args") or [] create_args = config_dict.get("create_args") or config_dict.get("create-args") or []
disable_host_mount_options = ( disable_host_mount_options = (
@@ -116,11 +116,14 @@ DEFAULT_ENGINE = OCIContainerEngineConfig("docker")
def _check_engine_version(engine: OCIContainerEngineConfig) -> None: def _check_engine_version(engine: OCIContainerEngineConfig) -> None:
try: try:
version_string = call(engine.name, "version", "-f", "{{json .}}", capture_stdout=True) version_string = call(engine.name, "version", "-f", "{{json .}}", capture_stdout=True)
version_info = json.loads(version_string.strip()) # We are using lowercase keys for all dicts so we are not affected by casing of keys
version_info = json.loads(
version_string.strip(), object_pairs_hook=lambda inp: {k.lower(): v for k, v in inp}
)
match engine.name: match engine.name:
case "docker": case "docker":
client_api_version = FlexibleVersion(version_info["Client"]["ApiVersion"]) client_api_version = FlexibleVersion(version_info["client"]["apiversion"])
server_api_version = FlexibleVersion(version_info["Server"]["ApiVersion"]) server_api_version = FlexibleVersion(version_info["server"]["apiversion"])
# --platform support was introduced in 1.32 as experimental, 1.41 removed the experimental flag # --platform support was introduced in 1.32 as experimental, 1.41 removed the experimental flag
version = min(client_api_version, server_api_version) version = min(client_api_version, server_api_version)
minimum_version = FlexibleVersion("1.41") minimum_version = FlexibleVersion("1.41")
@@ -135,9 +138,9 @@ def _check_engine_version(engine: OCIContainerEngineConfig) -> None:
) )
case "podman": case "podman":
# podman uses the same version string for "Version" & "ApiVersion" # podman uses the same version string for "Version" & "ApiVersion"
client_version = FlexibleVersion(version_info["Client"]["Version"]) client_version = FlexibleVersion(version_info["client"]["version"])
if "Server" in version_info: if "server" in version_info:
server_version = FlexibleVersion(version_info["Server"]["Version"]) server_version = FlexibleVersion(version_info["server"]["version"])
else: else:
server_version = client_version server_version = client_version
# --platform support was introduced in v3 # --platform support was introduced in v3
@@ -515,7 +518,7 @@ class OCIContainer:
capture_output=True, capture_output=True,
) )
) )
return typing.cast(dict[str, str], env) return typing.cast("dict[str, str]", env)
def environment_executor(self, command: Sequence[str], environment: dict[str, str]) -> str: def environment_executor(self, command: Sequence[str], environment: dict[str, str]) -> str:
# used as an EnvironmentExecutor to evaluate commands and capture output # used as an EnvironmentExecutor to evaluate commands and capture output
+31 -1
View File
@@ -24,7 +24,7 @@ from .projectfiles import get_requires_python_str, resolve_dependency_groups
from .selector import BuildSelector, EnableGroup, TestSelector, selector_matches from .selector import BuildSelector, EnableGroup, TestSelector, selector_matches
from .typing import PLATFORMS, PlatformName from .typing import PLATFORMS, PlatformName
from .util import resources from .util import resources
from .util.helpers import format_safe, strtobool, unwrap from .util.helpers import format_safe, parse_key_value_string, strtobool, unwrap
from .util.packaging import DependencyConstraints from .util.packaging import DependencyConstraints
MANYLINUX_ARCHS: Final[tuple[str, ...]] = ( MANYLINUX_ARCHS: Final[tuple[str, ...]] = (
@@ -92,6 +92,20 @@ class GlobalOptions:
allow_empty: bool allow_empty: bool
@dataclasses.dataclass(frozen=True)
class TestRuntimeConfig:
args: Sequence[str] = ()
@classmethod
def from_config_string(cls, config_string: str) -> Self:
config_dict = parse_key_value_string(config_string, [], ["args"])
args = config_dict.get("args") or []
return cls(args=args)
def options_summary(self) -> str | dict[str, str]:
return {"args": repr(self.args)}
@dataclasses.dataclass(frozen=True, kw_only=True) @dataclasses.dataclass(frozen=True, kw_only=True)
class BuildOptions: class BuildOptions:
globals: GlobalOptions globals: GlobalOptions
@@ -110,6 +124,7 @@ class BuildOptions:
test_extras: str test_extras: str
test_groups: list[str] test_groups: list[str]
test_environment: ParsedEnvironment test_environment: ParsedEnvironment
test_runtime: TestRuntimeConfig
build_verbosity: int build_verbosity: int
build_frontend: BuildFrontendConfig build_frontend: BuildFrontendConfig
config_settings: str config_settings: str
@@ -761,6 +776,20 @@ class Options:
msg = f"Malformed environment option {test_environment_config!r}" msg = f"Malformed environment option {test_environment_config!r}"
raise errors.ConfigurationError(msg) from e raise errors.ConfigurationError(msg) from e
test_runtime_str = self.reader.get(
"test-runtime",
env_plat=False,
option_format=ShlexTableFormat(sep="; ", pair_sep=":", allow_merge=False),
)
if not test_runtime_str:
test_runtime = TestRuntimeConfig()
else:
try:
test_runtime = TestRuntimeConfig.from_config_string(test_runtime_str)
except ValueError as e:
msg = f"Failed to parse test runtime config. {e}"
raise errors.ConfigurationError(msg) from e
test_requires = self.reader.get( test_requires = self.reader.get(
"test-requires", option_format=ListFormat(sep=" ") "test-requires", option_format=ListFormat(sep=" ")
).split() ).split()
@@ -868,6 +897,7 @@ class Options:
test_command=test_command, test_command=test_command,
test_sources=test_sources, test_sources=test_sources,
test_environment=test_environment, test_environment=test_environment,
test_runtime=test_runtime,
test_requires=[*test_requires, *test_requirements_from_groups], test_requires=[*test_requires, *test_requirements_from_groups],
test_extras=test_extras, test_extras=test_extras,
test_groups=test_groups, test_groups=test_groups,
+10 -7
View File
@@ -1,16 +1,19 @@
from __future__ import annotations from __future__ import annotations
import sys import sys
from collections.abc import Sequence from typing import TYPE_CHECKING, Final, Protocol
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
from cibuildwheel.typing import GenericPythonConfiguration, PlatformName if TYPE_CHECKING:
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):
+67 -26
View File
@@ -34,14 +34,12 @@ from ..util.file import CIBW_CACHE_PATH, copy_test_sources, download, move_file
from ..util.helpers import prepare_command from ..util.helpers import prepare_command
from ..util.packaging import find_compatible_wheel from ..util.packaging import find_compatible_wheel
from ..util.python_build_standalone import create_python_build_standalone_environment from ..util.python_build_standalone import create_python_build_standalone_environment
from ..venv import constraint_flags, virtualenv from ..venv import constraint_flags, find_uv, virtualenv
ANDROID_TRIPLET = {
def android_triplet(identifier: str) -> str: "arm64_v8a": "aarch64-linux-android",
return { "x86_64": "x86_64-linux-android",
"arm64_v8a": "aarch64-linux-android", }
"x86_64": "x86_64-linux-android",
}[parse_identifier(identifier)[1]]
def parse_identifier(identifier: str) -> tuple[str, str]: def parse_identifier(identifier: str) -> tuple[str, str]:
@@ -53,6 +51,10 @@ def parse_identifier(identifier: str) -> tuple[str, str]:
return (f"{major}.{minor}", arch) return (f"{major}.{minor}", arch)
def android_triplet(identifier: str) -> str:
return ANDROID_TRIPLET[parse_identifier(identifier)[1]]
@dataclass(frozen=True) @dataclass(frozen=True)
class PythonConfiguration: class PythonConfiguration:
version: str version: str
@@ -147,7 +149,7 @@ def build(options: Options, tmp_path: Path) -> None:
built_wheel = build_wheel(state) built_wheel = build_wheel(state)
repaired_wheel = repair_wheel(state, built_wheel) repaired_wheel = repair_wheel(state, built_wheel)
test_wheel(state, repaired_wheel) test_wheel(state, repaired_wheel, build_frontend=build_options.build_frontend.name)
output_wheel: Path | None = None output_wheel: Path | None = None
if compatible_wheel is None: if compatible_wheel is None:
@@ -187,6 +189,13 @@ def setup_env(
* android_env, which uses the environment while simulating running on Android. * android_env, which uses the environment while simulating running on Android.
""" """
log.step("Setting up build environment...") log.step("Setting up build environment...")
build_frontend = build_options.build_frontend.name
use_uv = build_frontend == "build[uv]"
uv_path = find_uv()
if use_uv and uv_path is None:
msg = "uv not found"
raise AssertionError(msg)
pip = ["pip"] if not use_uv else [str(uv_path), "pip"]
# Create virtual environment # Create virtual environment
python_exe = create_python_build_standalone_environment( python_exe = create_python_build_standalone_environment(
@@ -197,14 +206,14 @@ def setup_env(
version=config.version, tmp_dir=build_path version=config.version, tmp_dir=build_path
) )
build_env = virtualenv( build_env = virtualenv(
config.version, python_exe, venv_dir, dependency_constraint, use_uv=False config.version, python_exe, venv_dir, dependency_constraint, use_uv=use_uv
) )
create_cmake_toolchain(config, build_path, python_dir, build_env) create_cmake_toolchain(config, build_path, python_dir, build_env)
# Apply custom environment variables, and check environment is still valid # Apply custom environment variables, and check environment is still valid
build_env = build_options.environment.as_dictionary(build_env) build_env = build_options.environment.as_dictionary(build_env)
build_env["PIP_DISABLE_PIP_VERSION_CHECK"] = "1" build_env["PIP_DISABLE_PIP_VERSION_CHECK"] = "1"
for command in ["python", "pip"]: for command in ["python"] if use_uv else ["python", "pip"]:
command_path = call("which", command, env=build_env, capture_stdout=True).strip() command_path = call("which", command, env=build_env, capture_stdout=True).strip()
if command_path != f"{venv_dir}/bin/{command}": if command_path != f"{venv_dir}/bin/{command}":
msg = ( msg = (
@@ -219,11 +228,10 @@ def setup_env(
android_env = setup_android_env(config, python_dir, venv_dir, build_env) android_env = setup_android_env(config, python_dir, venv_dir, build_env)
# Install build tools # Install build tools
build_frontend = build_options.build_frontend if build_frontend not in {"build", "build[uv]"}:
if build_frontend.name != "build":
msg = "Android requires the build frontend to be 'build'" msg = "Android requires the build frontend to be 'build'"
raise errors.FatalError(msg) raise errors.FatalError(msg)
call("pip", "install", "build", *constraint_flags(dependency_constraint), env=build_env) call(*pip, "install", "build", *constraint_flags(dependency_constraint), env=build_env)
# Build-time requirements must be queried within android_env, because # Build-time requirements must be queried within android_env, because
# `get_requires_for_build` can run arbitrary code in setup.py scripts, which may be # `get_requires_for_build` can run arbitrary code in setup.py scripts, which may be
@@ -243,13 +251,13 @@ def setup_env(
pb = ProjectBuilder.from_isolated_env(AndroidEnv(), build_options.package_dir) pb = ProjectBuilder.from_isolated_env(AndroidEnv(), build_options.package_dir)
if pb.build_system_requires: if pb.build_system_requires:
call("pip", "install", *pb.build_system_requires, env=build_env) call(*pip, "install", *pb.build_system_requires, env=build_env)
requires_for_build = pb.get_requires_for_build( requires_for_build = pb.get_requires_for_build(
"wheel", parse_config_settings(build_options.config_settings) "wheel", parse_config_settings(build_options.config_settings)
) )
if requires_for_build: if requires_for_build:
call("pip", "install", *requires_for_build, env=build_env) call(*pip, "install", *requires_for_build, env=build_env)
return build_env, android_env return build_env, android_env
@@ -439,7 +447,11 @@ def repair_wheel(state: BuildState, built_wheel: Path) -> Path:
if state.options.repair_command: if state.options.repair_command:
shell( shell(
prepare_command( prepare_command(
state.options.repair_command, wheel=built_wheel, dest_dir=repaired_wheel_dir state.options.repair_command,
wheel=built_wheel,
dest_dir=repaired_wheel_dir,
package=state.options.package_dir,
project=".",
), ),
env=state.build_env, env=state.build_env,
) )
@@ -559,12 +571,19 @@ def soname_with_hash(src_path: Path) -> str:
return src_name return src_name
def test_wheel(state: BuildState, wheel: Path) -> None: def test_wheel(state: BuildState, wheel: Path, *, build_frontend: str) -> None:
test_command = state.options.test_command test_command = state.options.test_command
if not (test_command and state.options.test_selector(state.config.identifier)): if not (test_command and state.options.test_selector(state.config.identifier)):
return return
log.step("Testing wheel...") log.step("Testing wheel...")
use_uv = build_frontend == "build[uv]"
uv_path = find_uv()
if use_uv and uv_path is None:
msg = "uv not found"
raise AssertionError(msg)
pip = ["pip"] if not use_uv else [str(uv_path), "pip"]
native_arch = arch_synonym(platform.machine(), platforms.native_platform(), "android") native_arch = arch_synonym(platform.machine(), platforms.native_platform(), "android")
if state.config.arch != native_arch: if state.config.arch != native_arch:
log.warning( log.warning(
@@ -580,15 +599,23 @@ def test_wheel(state: BuildState, wheel: Path) -> None:
env=state.build_env, env=state.build_env,
) )
platform_args = (
["--python-platform", android_triplet(state.config.identifier)]
if use_uv
else [
"--platform",
sysconfig_print("get_platform()", state.android_env).replace("-", "_"),
]
)
# Install the wheel and test-requires. # Install the wheel and test-requires.
site_packages_dir = state.build_path / "site-packages" site_packages_dir = state.build_path / "site-packages"
site_packages_dir.mkdir() site_packages_dir.mkdir()
call( call(
"pip", *pip,
"install", "install",
"--only-binary=:all:", "--only-binary=:all:",
"--platform", *platform_args,
sysconfig_print("get_platform()", state.android_env).replace("-", "_"),
"--target", "--target",
site_packages_dir, site_packages_dir,
f"{wheel}{state.options.test_extras}", f"{wheel}{state.options.test_extras}",
@@ -617,8 +644,11 @@ def test_wheel(state: BuildState, wheel: Path) -> None:
# Parse test-command. # Parse test-command.
test_args = shlex.split(test_command) test_args = shlex.split(test_command)
if test_args[:2] in [["python", "-c"], ["python", "-m"]]: if test_args[0] in ["python", "python3"] and any(arg in test_args for arg in ["-c", "-m"]):
test_args[:3] = [test_args[1], test_args[2], "--"] # Forward the args to the CPython testbed script. We require '-c' or '-m'
# to be in the command, because without those flags, the testbed script
# will prepend '-m test', which will run Python's own test suite.
del test_args[0]
elif test_args[0] in ["pytest"]: elif test_args[0] in ["pytest"]:
# We transform some commands into the `python -m` form, but this is deprecated. # We transform some commands into the `python -m` form, but this is deprecated.
msg = ( msg = (
@@ -627,25 +657,36 @@ def test_wheel(state: BuildState, wheel: Path) -> None:
"If this works, all you need to do is add that to your test command." "If this works, all you need to do is add that to your test command."
) )
log.warning(msg) log.warning(msg)
test_args[:1] = ["-m", test_args[0], "--"] test_args.insert(0, "-m")
else: else:
msg = ( msg = (
f"Test command {test_command!r} is not supported on Android. " f"Test command {test_command!r} is not supported on Android. "
f"Supported commands are 'python -m' and 'python -c'." f"Command must begin with 'python' or 'python3', and contain '-m' or '-c'."
) )
raise errors.FatalError(msg) raise errors.FatalError(msg)
# By default, run on a testbed managed emulator running the newest supported
# Android version. However, if the user specifies a --managed or --connected
# test execution argument, that argument takes precedence.
test_runtime_args = state.options.test_runtime.args
if any(arg.startswith(("--managed", "--connected")) for arg in test_runtime_args):
emulator_args = []
else:
emulator_args = ["--managed", "maxVersion"]
# Run the test app. # Run the test app.
call( call(
state.python_dir / "android.py", state.python_dir / "android.py",
"test", "test",
"--managed",
"maxVersion",
"--site-packages", "--site-packages",
site_packages_dir, site_packages_dir,
"--cwd", "--cwd",
cwd_dir, cwd_dir,
*emulator_args,
*(["-v"] if state.options.build_verbosity > 0 else []), *(["-v"] if state.options.build_verbosity > 0 else []),
*test_runtime_args,
"--",
*test_args, *test_args,
env=state.build_env, env=state.build_env,
) )
+37 -19
View File
@@ -2,27 +2,23 @@ from __future__ import annotations
import dataclasses import dataclasses
import os import os
import platform
import shlex import shlex
import shutil 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 assert_never from typing import TYPE_CHECKING, assert_never
from filelock import FileLock from filelock import FileLock
from .. import errors from .. import errors
from ..architecture import Architecture
from ..environment import ParsedEnvironment
from ..frontend import ( from ..frontend import (
BuildFrontendName, BuildFrontendName,
get_build_frontend_extra_flags, get_build_frontend_extra_flags,
) )
from ..logger import log from ..logger import log
from ..options import Options
from ..selector import BuildSelector
from ..util import resources from ..util import resources
from ..util.cmd import call, shell, split_command from ..util.cmd import call, shell, split_command
from ..util.file import ( from ..util.file import (
@@ -33,13 +29,19 @@ from ..util.file import (
) )
from ..util.helpers import prepare_command, unwrap_preserving_paragraphs from ..util.helpers import prepare_command, unwrap_preserving_paragraphs
from ..util.packaging import ( from ..util.packaging import (
combine_constraints,
find_compatible_wheel, find_compatible_wheel,
get_pip_version,
) )
from ..venv import constraint_flags, virtualenv from ..venv import constraint_flags, virtualenv
from .macos import install_cpython as install_build_cpython 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)
class PythonConfiguration: class PythonConfiguration:
@@ -461,7 +463,6 @@ def build(options: Options, tmp_path: Path) -> None:
build_frontend=build_frontend.name, build_frontend=build_frontend.name,
xbuild_tools=build_options.xbuild_tools, xbuild_tools=build_options.xbuild_tools,
) )
pip_version = get_pip_version(env)
compatible_wheel = find_compatible_wheel(built_wheels, config.identifier) compatible_wheel = find_compatible_wheel(built_wheels, config.identifier)
if compatible_wheel: if compatible_wheel:
@@ -489,11 +490,6 @@ def build(options: Options, tmp_path: Path) -> None:
build_frontend, build_options.build_verbosity, build_options.config_settings build_frontend, build_options.build_verbosity, build_options.config_settings
) )
build_env = env.copy()
build_env["VIRTUALENV_PIP"] = pip_version
if constraints_path:
combine_constraints(build_env, constraints_path, None)
match build_frontend.name: match build_frontend.name:
case "pip": case "pip":
# Path.resolve() is needed. Without it pip wheel may try to # Path.resolve() is needed. Without it pip wheel may try to
@@ -508,7 +504,7 @@ def build(options: Options, tmp_path: Path) -> None:
f"--wheel-dir={built_wheel_dir}", f"--wheel-dir={built_wheel_dir}",
"--no-deps", "--no-deps",
*extra_flags, *extra_flags,
env=build_env, env=env,
) )
case "build": case "build":
call( call(
@@ -519,7 +515,7 @@ def build(options: Options, tmp_path: Path) -> None:
"--wheel", "--wheel",
f"--outdir={built_wheel_dir}", f"--outdir={built_wheel_dir}",
*extra_flags, *extra_flags,
env=build_env, env=env,
) )
case _: case _:
assert_never(build_frontend) assert_never(build_frontend)
@@ -537,9 +533,7 @@ def build(options: Options, tmp_path: Path) -> None:
elif config.arch != os.uname().machine: elif config.arch != os.uname().machine:
log.step("Skipping tests on non-native simulator architecture") log.step("Skipping tests on non-native simulator architecture")
else: else:
test_env = build_options.test_environment.as_dictionary( test_env = build_options.test_environment.as_dictionary(prev_environment=env)
prev_environment=build_env
)
if build_options.before_test: if build_options.before_test:
before_test_prepared = prepare_command( before_test_prepared = prepare_command(
@@ -653,11 +647,35 @@ def build(options: Options, tmp_path: Path) -> None:
) )
raise errors.FatalError(msg) raise errors.FatalError(msg)
test_runtime_args = build_options.test_runtime.args
# 2025-10: The GitHub Actions macos-15 runner has a known issue where
# the default simulator won't start due to a disk performance issue;
# see https://github.com/actions/runner-images/issues/12777 for details.
# In the meantime, if it looks like we're running on a GitHub Actions
# macos-15 runner, use a simulator that is known to work, unless the
# user explicitly specifies a simulator.
os_version, _, arch = platform.mac_ver()
if (
"GITHUB_ACTIONS" in os.environ
and os_version.startswith("15.")
and arch == "arm64"
and not any(
arg.startswith("--simulator") for arg in test_runtime_args
)
):
test_runtime_args = [
"--simulator",
"iPhone 16e,OS=18.5",
*test_runtime_args,
]
call( call(
"python", "python",
testbed_path, testbed_path,
"run", "run",
*(["--verbose"] if build_options.build_verbosity > 0 else []), *(["--verbose"] if build_options.build_verbosity > 0 else []),
*test_runtime_args,
"--", "--",
*final_command, *final_command,
env=test_env, env=test_env,
+9 -3
View File
@@ -6,7 +6,7 @@ import textwrap
from collections import OrderedDict from collections import OrderedDict
from collections.abc import Iterable, Iterator, Sequence, Set from collections.abc import Iterable, Iterator, Sequence, Set
from pathlib import Path, PurePath, PurePosixPath from pathlib import Path, PurePath, PurePosixPath
from typing import assert_never from typing import TYPE_CHECKING, assert_never
from .. import errors from .. import errors
from ..architecture import Architecture from ..architecture import Architecture
@@ -15,12 +15,14 @@ from ..logger import log
from ..oci_container import OCIContainer, OCIContainerEngineConfig, OCIPlatform from ..oci_container import OCIContainer, OCIContainerEngineConfig, OCIPlatform
from ..options import BuildOptions, Options from ..options import BuildOptions, Options
from ..selector import BuildSelector from ..selector import BuildSelector
from ..typing import PathOrStr
from ..util import resources from ..util import resources
from ..util.file import copy_test_sources from ..util.file import copy_test_sources
from ..util.helpers import prepare_command, unwrap from ..util.helpers import prepare_command, unwrap
from ..util.packaging import find_compatible_wheel from ..util.packaging import find_compatible_wheel
if TYPE_CHECKING:
from ..typing import PathOrStr
ARCHITECTURE_OCI_PLATFORM_MAP = { ARCHITECTURE_OCI_PLATFORM_MAP = {
Architecture.x86_64: OCIPlatform.AMD64, Architecture.x86_64: OCIPlatform.AMD64,
Architecture.i686: OCIPlatform.i386, Architecture.i686: OCIPlatform.i386,
@@ -320,7 +322,11 @@ def build_in_container(
if build_options.repair_command: if build_options.repair_command:
log.step("Repairing wheel...") log.step("Repairing wheel...")
repair_command_prepared = prepare_command( repair_command_prepared = prepare_command(
build_options.repair_command, wheel=built_wheel, dest_dir=repaired_wheel_dir build_options.repair_command,
wheel=built_wheel,
dest_dir=repaired_wheel_dir,
package=container_package_dir,
project=container_project_path,
) )
container.call(["sh", "-c", repair_command_prepared], env=env) container.call(["sh", "-c", repair_command_prepared], env=env)
else: else:
+4 -8
View File
@@ -32,7 +32,7 @@ from ..util.file import (
move_file, move_file,
) )
from ..util.helpers import prepare_command, unwrap from ..util.helpers import prepare_command, unwrap
from ..util.packaging import combine_constraints, find_compatible_wheel, get_pip_version from ..util.packaging import find_compatible_wheel, get_pip_version
from ..venv import constraint_flags, find_uv, virtualenv from ..venv import constraint_flags, find_uv, virtualenv
@@ -60,7 +60,7 @@ def get_macos_version() -> tuple[int, int]:
capture_stdout=True, capture_stdout=True,
) )
version = tuple(map(int, version_str.split(".")[:2])) version = tuple(map(int, version_str.split(".")[:2]))
return typing.cast(tuple[int, int], version) return typing.cast("tuple[int, int]", version)
@functools.cache @functools.cache
@@ -464,12 +464,6 @@ def build(options: Options, tmp_path: Path) -> None:
) )
build_env = env.copy() build_env = env.copy()
if pip_version is not None:
build_env["VIRTUALENV_PIP"] = pip_version
if constraints_path:
combine_constraints(
build_env, constraints_path, identifier_tmp_dir if use_uv else None
)
match build_frontend.name: match build_frontend.name:
case "pip": case "pip":
@@ -528,6 +522,8 @@ def build(options: Options, tmp_path: Path) -> None:
wheel=built_wheel, wheel=built_wheel,
dest_dir=repaired_wheel_dir, dest_dir=repaired_wheel_dir,
delocate_archs=delocate_archs, delocate_archs=delocate_archs,
package=build_options.package_dir,
project=".",
) )
shell(repair_command_prepared, env=env) shell(repair_command_prepared, env=env)
else: else:
+5 -7
View File
@@ -32,7 +32,7 @@ from ..util.file import (
move_file, move_file,
) )
from ..util.helpers import prepare_command, unwrap, unwrap_preserving_paragraphs from ..util.helpers import prepare_command, unwrap, unwrap_preserving_paragraphs
from ..util.packaging import combine_constraints, find_compatible_wheel, get_pip_version from ..util.packaging import find_compatible_wheel, get_pip_version
from ..util.python_build_standalone import ( from ..util.python_build_standalone import (
PythonBuildStandaloneError, PythonBuildStandaloneError,
create_python_build_standalone_environment, create_python_build_standalone_environment,
@@ -130,7 +130,7 @@ def get_all_xbuildenv_version_info(env: dict[str, str]) -> list[PyodideXBuildEnv
msg = f"Invalid xbuildenvs info, got {xbuildenvs_info}" msg = f"Invalid xbuildenvs info, got {xbuildenvs_info}"
raise ValueError(msg) raise ValueError(msg)
return typing.cast(list[PyodideXBuildEnvInfo], xbuildenvs_info["environments"]) return typing.cast("list[PyodideXBuildEnvInfo]", xbuildenvs_info["environments"])
def get_xbuildenv_version_info( def get_xbuildenv_version_info(
@@ -419,17 +419,13 @@ def build(options: Options, tmp_path: Path) -> None:
build_frontend, build_options.build_verbosity, build_options.config_settings build_frontend, build_options.build_verbosity, build_options.config_settings
) )
build_env = env.copy()
if constraints_path:
combine_constraints(build_env, constraints_path, identifier_tmp_dir)
build_env["VIRTUALENV_PIP"] = pip_version
call( call(
"pyodide", "pyodide",
"build", "build",
build_options.package_dir, build_options.package_dir,
f"--outdir={built_wheel_dir}", f"--outdir={built_wheel_dir}",
*extra_flags, *extra_flags,
env=build_env, env=env,
) )
built_wheel = next(built_wheel_dir.glob("*.whl")) built_wheel = next(built_wheel_dir.glob("*.whl"))
@@ -443,6 +439,8 @@ def build(options: Options, tmp_path: Path) -> None:
build_options.repair_command, build_options.repair_command,
wheel=built_wheel, wheel=built_wheel,
dest_dir=repaired_wheel_dir, dest_dir=repaired_wheel_dir,
package=build_options.package_dir,
project=".",
) )
shell(repair_command_prepared, env=env) shell(repair_command_prepared, env=env)
log.step_end() log.step_end()
+5 -10
View File
@@ -23,7 +23,7 @@ from ..util import resources
from ..util.cmd import call, shell from ..util.cmd import call, shell
from ..util.file import CIBW_CACHE_PATH, copy_test_sources, download, extract_zip, move_file from ..util.file import CIBW_CACHE_PATH, copy_test_sources, download, extract_zip, move_file
from ..util.helpers import prepare_command, unwrap from ..util.helpers import prepare_command, unwrap
from ..util.packaging import combine_constraints, find_compatible_wheel, get_pip_version from ..util.packaging import find_compatible_wheel, get_pip_version
from ..venv import constraint_flags, find_uv, virtualenv from ..venv import constraint_flags, find_uv, virtualenv
@@ -468,13 +468,6 @@ def build(options: Options, tmp_path: Path) -> None:
shell("graalpy -m pip install setuptools wheel", env=env) shell("graalpy -m pip install setuptools wheel", env=env)
extra_flags = [*extra_flags, "-n"] extra_flags = [*extra_flags, "-n"]
build_env = env.copy()
if pip_version is not None:
build_env["VIRTUALENV_PIP"] = pip_version
if constraints_path:
combine_constraints(build_env, constraints_path, identifier_tmp_dir)
match build_frontend.name: match build_frontend.name:
case "pip": case "pip":
# Path.resolve() is needed. Without it pip wheel may try to fetch package from pypi.org # Path.resolve() is needed. Without it pip wheel may try to fetch package from pypi.org
@@ -488,7 +481,7 @@ def build(options: Options, tmp_path: Path) -> None:
f"--wheel-dir={built_wheel_dir}", f"--wheel-dir={built_wheel_dir}",
"--no-deps", "--no-deps",
*extra_flags, *extra_flags,
env=build_env, env=env,
) )
case "build" | "build[uv]": case "build" | "build[uv]":
if ( if (
@@ -506,7 +499,7 @@ def build(options: Options, tmp_path: Path) -> None:
"--wheel", "--wheel",
f"--outdir={built_wheel_dir}", f"--outdir={built_wheel_dir}",
*extra_flags, *extra_flags,
env=build_env, env=env,
) )
case _: case _:
assert_never(build_frontend) assert_never(build_frontend)
@@ -525,6 +518,8 @@ def build(options: Options, tmp_path: Path) -> None:
build_options.repair_command, build_options.repair_command,
wheel=built_wheel, wheel=built_wheel,
dest_dir=repaired_wheel_dir, dest_dir=repaired_wheel_dir,
package=build_options.package_dir,
project=".",
) )
shell(repair_command_prepared, env=env) shell(repair_command_prepared, env=env)
else: else:
+1 -1
View File
@@ -50,7 +50,7 @@ class Analyzer(ast.NodeVisitor):
) )
match node: match node:
case ast.keyword(arg="python_requires", value=ast.Constant(value=str(version))): case ast.keyword(arg="python_requires", value=ast.Constant(value=str() as version)):
if unnested or name_main_unnested: if unnested or name_main_unnested:
self.requires_python = version self.requires_python = version
+11 -7
View File
@@ -68,16 +68,20 @@ def initialize() -> None:
# sysconfig ############################################################### # sysconfig ###############################################################
# #
# We don't change the actual sys.base_prefix and base_exec_prefix, because that # Load the sysconfigdata file, generating its name from sys.abiflags,
# could have unpredictable effects. Instead, we change the internal variables
# used to generate sysconfig.get_path("include").
exec_prefix = sysconfig.get_config_var("exec_prefix")
sysconfig._BASE_PREFIX = sysconfig._BASE_EXEC_PREFIX = exec_prefix # type: ignore[attr-defined]
# Reload the sysconfigdata file, generating its name from sys.abiflags,
# sys.platform, and sys.implementation._multiarch. # sys.platform, and sys.implementation._multiarch.
sysconfig._init_config_vars() # type: ignore[attr-defined] sysconfig._init_config_vars() # type: ignore[attr-defined]
# We don't change the actual sys.base_prefix and base_exec_prefix, because that
# could have unpredictable effects. Instead, we change the sysconfig variables
# used by sysconfig.get_paths().
vars = sysconfig.get_config_vars()
try:
host_prefix = vars["host_prefix"] # This variable was added in Python 3.14.
except KeyError:
host_prefix = vars["exec_prefix"]
vars["installed_base"] = vars["installed_platbase"] = host_prefix
# sysconfig.get_platform, which determines the wheel tag, is implemented in terms of # sysconfig.get_platform, which determines the wheel tag, is implemented in terms of
# sys.platform, sysconfig.get_config_var("ANDROID_API_LEVEL") (see localized_vars in # sys.platform, sysconfig.get_config_var("ANDROID_API_LEVEL") (see localized_vars in
# android.py), and os.uname. # android.py), and os.uname.
+32 -32
View File
@@ -161,18 +161,18 @@ python_configurations = [
{ identifier = "cp312-macosx_x86_64", version = "3.12", url = "https://www.python.org/ftp/python/3.12.10/python-3.12.10-macos11.pkg" }, { identifier = "cp312-macosx_x86_64", version = "3.12", url = "https://www.python.org/ftp/python/3.12.10/python-3.12.10-macos11.pkg" },
{ identifier = "cp312-macosx_arm64", version = "3.12", url = "https://www.python.org/ftp/python/3.12.10/python-3.12.10-macos11.pkg" }, { identifier = "cp312-macosx_arm64", version = "3.12", url = "https://www.python.org/ftp/python/3.12.10/python-3.12.10-macos11.pkg" },
{ identifier = "cp312-macosx_universal2", version = "3.12", url = "https://www.python.org/ftp/python/3.12.10/python-3.12.10-macos11.pkg" }, { identifier = "cp312-macosx_universal2", version = "3.12", url = "https://www.python.org/ftp/python/3.12.10/python-3.12.10-macos11.pkg" },
{ identifier = "cp313-macosx_x86_64", version = "3.13", url = "https://www.python.org/ftp/python/3.13.8/python-3.13.8-macos11.pkg" }, { identifier = "cp313-macosx_x86_64", version = "3.13", url = "https://www.python.org/ftp/python/3.13.11/python-3.13.11-macos11.pkg" },
{ identifier = "cp313-macosx_arm64", version = "3.13", url = "https://www.python.org/ftp/python/3.13.8/python-3.13.8-macos11.pkg" }, { identifier = "cp313-macosx_arm64", version = "3.13", url = "https://www.python.org/ftp/python/3.13.11/python-3.13.11-macos11.pkg" },
{ identifier = "cp313-macosx_universal2", version = "3.13", url = "https://www.python.org/ftp/python/3.13.8/python-3.13.8-macos11.pkg" }, { identifier = "cp313-macosx_universal2", version = "3.13", url = "https://www.python.org/ftp/python/3.13.11/python-3.13.11-macos11.pkg" },
{ identifier = "cp313t-macosx_x86_64", version = "3.13", url = "https://www.python.org/ftp/python/3.13.8/python-3.13.8-macos11.pkg" }, { identifier = "cp313t-macosx_x86_64", version = "3.13", url = "https://www.python.org/ftp/python/3.13.11/python-3.13.11-macos11.pkg" },
{ identifier = "cp313t-macosx_arm64", version = "3.13", url = "https://www.python.org/ftp/python/3.13.8/python-3.13.8-macos11.pkg" }, { identifier = "cp313t-macosx_arm64", version = "3.13", url = "https://www.python.org/ftp/python/3.13.11/python-3.13.11-macos11.pkg" },
{ identifier = "cp313t-macosx_universal2", version = "3.13", url = "https://www.python.org/ftp/python/3.13.8/python-3.13.8-macos11.pkg" }, { identifier = "cp313t-macosx_universal2", version = "3.13", url = "https://www.python.org/ftp/python/3.13.11/python-3.13.11-macos11.pkg" },
{ identifier = "cp314-macosx_x86_64", version = "3.14", url = "https://www.python.org/ftp/python/3.14.0/python-3.14.0-macos11.pkg" }, { identifier = "cp314-macosx_x86_64", version = "3.14", url = "https://www.python.org/ftp/python/3.14.2/python-3.14.2-macos11.pkg" },
{ identifier = "cp314-macosx_arm64", version = "3.14", url = "https://www.python.org/ftp/python/3.14.0/python-3.14.0-macos11.pkg" }, { identifier = "cp314-macosx_arm64", version = "3.14", url = "https://www.python.org/ftp/python/3.14.2/python-3.14.2-macos11.pkg" },
{ identifier = "cp314-macosx_universal2", version = "3.14", url = "https://www.python.org/ftp/python/3.14.0/python-3.14.0-macos11.pkg" }, { identifier = "cp314-macosx_universal2", version = "3.14", url = "https://www.python.org/ftp/python/3.14.2/python-3.14.2-macos11.pkg" },
{ identifier = "cp314t-macosx_x86_64", version = "3.14", url = "https://www.python.org/ftp/python/3.14.0/python-3.14.0-macos11.pkg" }, { identifier = "cp314t-macosx_x86_64", version = "3.14", url = "https://www.python.org/ftp/python/3.14.2/python-3.14.2-macos11.pkg" },
{ identifier = "cp314t-macosx_arm64", version = "3.14", url = "https://www.python.org/ftp/python/3.14.0/python-3.14.0-macos11.pkg" }, { identifier = "cp314t-macosx_arm64", version = "3.14", url = "https://www.python.org/ftp/python/3.14.2/python-3.14.2-macos11.pkg" },
{ identifier = "cp314t-macosx_universal2", version = "3.14", url = "https://www.python.org/ftp/python/3.14.0/python-3.14.0-macos11.pkg" }, { identifier = "cp314t-macosx_universal2", version = "3.14", url = "https://www.python.org/ftp/python/3.14.2/python-3.14.2-macos11.pkg" },
{ identifier = "pp38-macosx_x86_64", version = "3.8", url = "https://downloads.python.org/pypy/pypy3.8-v7.3.11-macos_x86_64.tar.bz2" }, { identifier = "pp38-macosx_x86_64", version = "3.8", url = "https://downloads.python.org/pypy/pypy3.8-v7.3.11-macos_x86_64.tar.bz2" },
{ identifier = "pp38-macosx_arm64", version = "3.8", url = "https://downloads.python.org/pypy/pypy3.8-v7.3.11-macos_arm64.tar.bz2" }, { identifier = "pp38-macosx_arm64", version = "3.8", url = "https://downloads.python.org/pypy/pypy3.8-v7.3.11-macos_arm64.tar.bz2" },
{ identifier = "pp39-macosx_x86_64", version = "3.9", url = "https://downloads.python.org/pypy/pypy3.9-v7.3.16-macos_x86_64.tar.bz2" }, { identifier = "pp39-macosx_x86_64", version = "3.9", url = "https://downloads.python.org/pypy/pypy3.9-v7.3.16-macos_x86_64.tar.bz2" },
@@ -183,8 +183,8 @@ python_configurations = [
{ 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.20-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.0/graalpy-25.0.0-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" },
{ identifier = "gp312_250-macosx_arm64", version = "3.12", url = "https://github.com/oracle/graalpython/releases/download/graal-25.0.0/graalpy-25.0.0-macos-aarch64.tar.gz" }, { identifier = "gp312_250-macosx_arm64", version = "3.12", url = "https://github.com/oracle/graalpython/releases/download/graal-25.0.1/graalpy-25.0.1-macos-aarch64.tar.gz" },
] ]
[windows] [windows]
@@ -199,42 +199,42 @@ python_configurations = [
{ identifier = "cp311-win_amd64", version = "3.11.9" }, { identifier = "cp311-win_amd64", version = "3.11.9" },
{ identifier = "cp312-win32", version = "3.12.10" }, { identifier = "cp312-win32", version = "3.12.10" },
{ identifier = "cp312-win_amd64", version = "3.12.10" }, { identifier = "cp312-win_amd64", version = "3.12.10" },
{ identifier = "cp313-win32", version = "3.13.8" }, { identifier = "cp313-win32", version = "3.13.11" },
{ identifier = "cp313t-win32", version = "3.13.8" }, { identifier = "cp313t-win32", version = "3.13.11" },
{ identifier = "cp313-win_amd64", version = "3.13.8" }, { identifier = "cp313-win_amd64", version = "3.13.11" },
{ identifier = "cp313t-win_amd64", version = "3.13.8" }, { identifier = "cp313t-win_amd64", version = "3.13.11" },
{ identifier = "cp314-win32", version = "3.14.0" }, { identifier = "cp314-win32", version = "3.14.2" },
{ identifier = "cp314t-win32", version = "3.14.0" }, { identifier = "cp314t-win32", version = "3.14.2" },
{ identifier = "cp314-win_amd64", version = "3.14.0" }, { identifier = "cp314-win_amd64", version = "3.14.2" },
{ identifier = "cp314t-win_amd64", version = "3.14.0" }, { identifier = "cp314t-win_amd64", version = "3.14.2" },
{ identifier = "cp39-win_arm64", version = "3.9.10" }, { identifier = "cp39-win_arm64", version = "3.9.10" },
{ identifier = "cp310-win_arm64", version = "3.10.11" }, { identifier = "cp310-win_arm64", version = "3.10.11" },
{ identifier = "cp311-win_arm64", version = "3.11.9" }, { identifier = "cp311-win_arm64", version = "3.11.9" },
{ identifier = "cp312-win_arm64", version = "3.12.10" }, { identifier = "cp312-win_arm64", version = "3.12.10" },
{ identifier = "cp313-win_arm64", version = "3.13.8" }, { identifier = "cp313-win_arm64", version = "3.13.11" },
{ identifier = "cp313t-win_arm64", version = "3.13.8" }, { identifier = "cp313t-win_arm64", version = "3.13.11" },
{ identifier = "cp314-win_arm64", version = "3.14.0" }, { identifier = "cp314-win_arm64", version = "3.14.2" },
{ identifier = "cp314t-win_arm64", version = "3.14.0" }, { identifier = "cp314t-win_arm64", version = "3.14.2" },
{ 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.20-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.0/graalpy-25.0.0-windows-amd64.zip" }, { identifier = "gp312_250-win_amd64", version = "3.12", url = "https://github.com/oracle/graalpython/releases/download/graal-25.0.1/graalpy-25.0.1-windows-amd64.zip" },
] ]
[pyodide] [pyodide]
python_configurations = [ python_configurations = [
{ identifier = "cp312-pyodide_wasm32", version = "3.12", default_pyodide_version = "0.27.7", node_version = "v22" }, { identifier = "cp312-pyodide_wasm32", version = "3.12", default_pyodide_version = "0.27.7", node_version = "v22" },
{ identifier = "cp313-pyodide_wasm32", version = "3.13", default_pyodide_version = "0.28.3", node_version = "v22" }, { identifier = "cp313-pyodide_wasm32", version = "3.13", default_pyodide_version = "0.29.0", node_version = "v22" },
] ]
[android] [android]
python_configurations = [ python_configurations = [
{ identifier = "cp313-android_arm64_v8a", version = "3.13", url = "https://repo.maven.apache.org/maven2/com/chaquo/python/python/3.13.7/python-3.13.7-aarch64-linux-android.tar.gz" }, { identifier = "cp313-android_arm64_v8a", version = "3.13", url = "https://repo.maven.apache.org/maven2/com/chaquo/python/python/3.13.11/python-3.13.11-aarch64-linux-android.tar.gz" },
{ identifier = "cp313-android_x86_64", version = "3.13", url = "https://repo.maven.apache.org/maven2/com/chaquo/python/python/3.13.7/python-3.13.7-x86_64-linux-android.tar.gz" }, { identifier = "cp313-android_x86_64", version = "3.13", url = "https://repo.maven.apache.org/maven2/com/chaquo/python/python/3.13.11/python-3.13.11-x86_64-linux-android.tar.gz" },
{ identifier = "cp314-android_arm64_v8a", version = "3.14", url = "https://www.python.org/ftp/python/3.14.0/python-3.14.0-aarch64-linux-android.tar.gz" }, { identifier = "cp314-android_arm64_v8a", version = "3.14", url = "https://www.python.org/ftp/python/3.14.2/python-3.14.2-aarch64-linux-android.tar.gz" },
{ identifier = "cp314-android_x86_64", version = "3.14", url = "https://www.python.org/ftp/python/3.14.0/python-3.14.0-x86_64-linux-android.tar.gz" }, { identifier = "cp314-android_x86_64", version = "3.14", url = "https://www.python.org/ftp/python/3.14.2/python-3.14.2-x86_64-linux-android.tar.gz" },
] ]
[ios] [ios]
@@ -569,6 +569,39 @@
], ],
"title": "CIBW_TEST_ENVIRONMENT" "title": "CIBW_TEST_ENVIRONMENT"
}, },
"test-runtime": {
"description": "Additional configuration for the test runner",
"oneOf": [
{
"type": "string",
"pattern": "^$"
},
{
"type": "object",
"additionalProperties": false
},
{
"type": "string",
"pattern": "args:"
},
{
"type": "object",
"additionalProperties": false,
"required": [
"args"
],
"properties": {
"args": {
"type": "array",
"items": {
"type": "string"
}
}
}
}
],
"title": "CIBW_TEST_RUNTIME"
},
"overrides": { "overrides": {
"type": "array", "type": "array",
"description": "An overrides array", "description": "An overrides array",
@@ -638,6 +671,9 @@
}, },
"test-environment": { "test-environment": {
"$ref": "#/$defs/inherit" "$ref": "#/$defs/inherit"
},
"test-runtime": {
"$ref": "#/$defs/inherit"
} }
} }
}, },
@@ -748,6 +784,9 @@
}, },
"test-environment": { "test-environment": {
"$ref": "#/properties/test-environment" "$ref": "#/properties/test-environment"
},
"test-runtime": {
"$ref": "#/properties/test-runtime"
} }
} }
} }
@@ -876,6 +915,9 @@
}, },
"test-environment": { "test-environment": {
"$ref": "#/properties/test-environment" "$ref": "#/properties/test-environment"
},
"test-runtime": {
"$ref": "#/properties/test-runtime"
} }
} }
}, },
@@ -936,6 +978,9 @@
}, },
"test-environment": { "test-environment": {
"$ref": "#/properties/test-environment" "$ref": "#/properties/test-environment"
},
"test-runtime": {
"$ref": "#/properties/test-runtime"
} }
} }
}, },
@@ -1009,6 +1054,9 @@
}, },
"test-environment": { "test-environment": {
"$ref": "#/properties/test-environment" "$ref": "#/properties/test-environment"
},
"test-runtime": {
"$ref": "#/properties/test-runtime"
} }
} }
}, },
@@ -1069,6 +1117,9 @@
}, },
"test-environment": { "test-environment": {
"$ref": "#/properties/test-environment" "$ref": "#/properties/test-environment"
},
"test-runtime": {
"$ref": "#/properties/test-runtime"
} }
} }
}, },
@@ -1129,6 +1180,9 @@
}, },
"test-environment": { "test-environment": {
"$ref": "#/properties/test-environment" "$ref": "#/properties/test-environment"
},
"test-runtime": {
"$ref": "#/properties/test-runtime"
} }
} }
}, },
@@ -1189,6 +1243,9 @@
}, },
"test-environment": { "test-environment": {
"$ref": "#/properties/test-environment" "$ref": "#/properties/test-environment"
},
"test-runtime": {
"$ref": "#/properties/test-runtime"
} }
} }
} }
@@ -2,7 +2,7 @@
# nox -s update_constraints # nox -s update_constraints
annotated-types==0.7.0 annotated-types==0.7.0
# via pydantic # via pydantic
anyio==4.11.0 anyio==4.12.0
# via httpx # via httpx
auditwheel-emscripten==0.2.0 auditwheel-emscripten==0.2.0
# via pyodide-build # via pyodide-build
@@ -10,12 +10,12 @@ build==1.2.2.post1
# via # via
# -r .nox/update_constraints/tmp/constraints-pyodide.in # -r .nox/update_constraints/tmp/constraints-pyodide.in
# pyodide-build # pyodide-build
certifi==2025.10.5 certifi==2026.1.4
# via # via
# httpcore # httpcore
# httpx # httpx
# requests # requests
charset-normalizer==3.4.3 charset-normalizer==3.4.4
# via requests # via requests
click==8.1.8 click==8.1.8
# via # via
@@ -23,7 +23,7 @@ click==8.1.8
# typer # typer
distlib==0.4.0 distlib==0.4.0
# via virtualenv # via virtualenv
filelock==3.20.0 filelock==3.20.2
# via virtualenv # via virtualenv
h11==0.16.0 h11==0.16.0
# via httpcore # via httpcore
@@ -31,7 +31,7 @@ httpcore==1.0.9
# via httpx # via httpx
httpx==0.28.1 httpx==0.28.1
# via unearth # via unearth
idna==3.10 idna==3.11
# via # via
# anyio # anyio
# httpx # httpx
@@ -48,48 +48,44 @@ packaging==25.0
# build # build
# pyodide-build # pyodide-build
# unearth # unearth
pip==25.2 pip==25.3
# via -r .nox/update_constraints/tmp/constraints-pyodide.in # via -r .nox/update_constraints/tmp/constraints-pyodide.in
platformdirs==4.5.0 platformdirs==4.5.1
# via # via
# pyodide-build # pyodide-build
# virtualenv # virtualenv
pydantic==2.12.0 pydantic==2.12.5
# via # via
# pyodide-build # pyodide-build
# pyodide-lock # pyodide-lock
pydantic-core==2.41.1 pydantic-core==2.41.5
# via pydantic # via pydantic
pygments==2.19.2 pygments==2.19.2
# via rich # via rich
pyodide-build==0.30.7 pyodide-build==0.30.9
# via -r .nox/update_constraints/tmp/constraints-pyodide.in # via -r .nox/update_constraints/tmp/constraints-pyodide.in
pyodide-cli==0.4.0 pyodide-cli==0.4.0
# via # via
# auditwheel-emscripten # auditwheel-emscripten
# pyodide-build # pyodide-build
pyodide-lock==0.1.0 pyodide-lock==0.1.1
# via pyodide-build # via pyodide-build
pyproject-hooks==1.2.0 pyproject-hooks==1.2.0
# via build # via build
requests==2.32.5 requests==2.32.5
# via pyodide-build # via pyodide-build
resolvelib==1.2.0 resolvelib==1.2.1
# via pyodide-build # via pyodide-build
rich==14.2.0 rich==14.2.0
# via # via
# pyodide-build # pyodide-build
# pyodide-cli # pyodide-cli
# typer # typer
ruamel-yaml==0.18.15 ruamel-yaml==0.19.1
# via pyodide-build # via pyodide-build
ruamel-yaml-clib==0.2.14
# via ruamel-yaml
shellingham==1.5.4 shellingham==1.5.4
# via typer # via typer
sniffio==1.3.1 typer==0.21.0
# via anyio
typer==0.19.2
# via # via
# auditwheel-emscripten # auditwheel-emscripten
# pyodide-build # pyodide-build
@@ -103,11 +99,11 @@ typing-extensions==4.15.0
# typing-inspection # typing-inspection
typing-inspection==0.4.2 typing-inspection==0.4.2
# via pydantic # via pydantic
unearth==0.17.5 unearth==0.18.2
# via pyodide-build # via pyodide-build
urllib3==2.5.0 urllib3==2.6.2
# via requests # via requests
virtualenv==20.35.2 virtualenv==20.35.4
# via # via
# build # build
# pyodide-build # pyodide-build
@@ -2,7 +2,7 @@
# nox -s update_constraints # nox -s update_constraints
annotated-types==0.7.0 annotated-types==0.7.0
# via pydantic # via pydantic
anyio==4.11.0 anyio==4.12.0
# via httpx # via httpx
auditwheel-emscripten==0.2.0 auditwheel-emscripten==0.2.0
# via pyodide-build # via pyodide-build
@@ -10,12 +10,12 @@ build==1.2.2.post1
# via # via
# -r .nox/update_constraints/tmp/constraints-pyodide.in # -r .nox/update_constraints/tmp/constraints-pyodide.in
# pyodide-build # pyodide-build
certifi==2025.10.5 certifi==2026.1.4
# via # via
# httpcore # httpcore
# httpx # httpx
# requests # requests
charset-normalizer==3.4.3 charset-normalizer==3.4.4
# via requests # via requests
click==8.1.8 click==8.1.8
# via # via
@@ -23,7 +23,7 @@ click==8.1.8
# typer # typer
distlib==0.4.0 distlib==0.4.0
# via virtualenv # via virtualenv
filelock==3.20.0 filelock==3.20.2
# via virtualenv # via virtualenv
h11==0.16.0 h11==0.16.0
# via httpcore # via httpcore
@@ -31,7 +31,7 @@ httpcore==1.0.9
# via httpx # via httpx
httpx==0.28.1 httpx==0.28.1
# via unearth # via unearth
idna==3.10 idna==3.11
# via # via
# anyio # anyio
# httpx # httpx
@@ -48,48 +48,44 @@ packaging==25.0
# build # build
# pyodide-build # pyodide-build
# unearth # unearth
pip==25.2 pip==25.3
# via -r .nox/update_constraints/tmp/constraints-pyodide.in # via -r .nox/update_constraints/tmp/constraints-pyodide.in
platformdirs==4.5.0 platformdirs==4.5.1
# via # via
# pyodide-build # pyodide-build
# virtualenv # virtualenv
pydantic==2.12.0 pydantic==2.12.5
# via # via
# pyodide-build # pyodide-build
# pyodide-lock # pyodide-lock
pydantic-core==2.41.1 pydantic-core==2.41.5
# via pydantic # via pydantic
pygments==2.19.2 pygments==2.19.2
# via rich # via rich
pyodide-build==0.30.7 pyodide-build==0.30.9
# via -r .nox/update_constraints/tmp/constraints-pyodide.in # via -r .nox/update_constraints/tmp/constraints-pyodide.in
pyodide-cli==0.4.0 pyodide-cli==0.4.0
# via # via
# auditwheel-emscripten # auditwheel-emscripten
# pyodide-build # pyodide-build
pyodide-lock==0.1.0 pyodide-lock==0.1.1
# via pyodide-build # via pyodide-build
pyproject-hooks==1.2.0 pyproject-hooks==1.2.0
# via build # via build
requests==2.32.5 requests==2.32.5
# via pyodide-build # via pyodide-build
resolvelib==1.2.0 resolvelib==1.2.1
# via pyodide-build # via pyodide-build
rich==14.2.0 rich==14.2.0
# via # via
# pyodide-build # pyodide-build
# pyodide-cli # pyodide-cli
# typer # typer
ruamel-yaml==0.18.15 ruamel-yaml==0.19.1
# via pyodide-build # via pyodide-build
ruamel-yaml-clib==0.2.14
# via ruamel-yaml
shellingham==1.5.4 shellingham==1.5.4
# via typer # via typer
sniffio==1.3.1 typer==0.21.0
# via anyio
typer==0.19.2
# via # via
# auditwheel-emscripten # auditwheel-emscripten
# pyodide-build # pyodide-build
@@ -102,11 +98,11 @@ typing-extensions==4.15.0
# typing-inspection # typing-inspection
typing-inspection==0.4.2 typing-inspection==0.4.2
# via pydantic # via pydantic
unearth==0.17.5 unearth==0.18.2
# via pyodide-build # via pyodide-build
urllib3==2.5.0 urllib3==2.6.2
# via requests # via requests
virtualenv==20.35.2 virtualenv==20.35.4
# via # via
# build # build
# pyodide-build # pyodide-build
@@ -1,6 +1,6 @@
# This file was autogenerated by uv via the following command: # This file was autogenerated by uv via the following command:
# nox -s update_constraints # nox -s update_constraints
altgraph==0.17.4 altgraph==0.17.5
# via macholib # via macholib
build==1.3.0 build==1.3.0
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
@@ -8,19 +8,19 @@ 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.20.0 filelock==3.20.2
# via virtualenv # via virtualenv
importlib-metadata==8.7.0 importlib-metadata==8.7.1
# via build # via build
macholib==1.16.3 macholib==1.16.4
# via delocate # via delocate
packaging==25.0 packaging==25.0
# via # via
# build # build
# delocate # delocate
pip==25.2 pip==25.3
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
platformdirs==4.5.0 platformdirs==4.5.1
# via virtualenv # via virtualenv
pyproject-hooks==1.2.0 pyproject-hooks==1.2.0
# via build # via build
@@ -30,7 +30,7 @@ typing-extensions==4.15.0
# via # via
# delocate # delocate
# virtualenv # virtualenv
virtualenv==20.35.2 virtualenv==20.35.4
# 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
@@ -1,6 +1,6 @@
# This file was autogenerated by uv via the following command: # This file was autogenerated by uv via the following command:
# nox -s update_constraints # nox -s update_constraints
altgraph==0.17.4 altgraph==0.17.5
# via macholib # via macholib
build==1.3.0 build==1.3.0
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
@@ -8,21 +8,21 @@ 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.20.0 filelock==3.20.2
# via virtualenv # via virtualenv
macholib==1.16.3 macholib==1.16.4
# via delocate # via delocate
packaging==25.0 packaging==25.0
# via # via
# build # build
# delocate # delocate
pip==25.2 pip==25.3
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
platformdirs==4.5.0 platformdirs==4.5.1
# via virtualenv # via virtualenv
pyproject-hooks==1.2.0 pyproject-hooks==1.2.0
# via build # via build
typing-extensions==4.15.0 typing-extensions==4.15.0
# via delocate # via delocate
virtualenv==20.35.2 virtualenv==20.35.4
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
@@ -1,6 +1,6 @@
# This file was autogenerated by uv via the following command: # This file was autogenerated by uv via the following command:
# nox -s update_constraints # nox -s update_constraints
altgraph==0.17.4 altgraph==0.17.5
# via macholib # via macholib
build==1.3.0 build==1.3.0
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
@@ -8,21 +8,21 @@ 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.20.0 filelock==3.20.2
# via virtualenv # via virtualenv
macholib==1.16.3 macholib==1.16.4
# via delocate # via delocate
packaging==25.0 packaging==25.0
# via # via
# build # build
# delocate # delocate
pip==25.2 pip==25.3
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
platformdirs==4.5.0 platformdirs==4.5.1
# via virtualenv # via virtualenv
pyproject-hooks==1.2.0 pyproject-hooks==1.2.0
# via build # via build
typing-extensions==4.15.0 typing-extensions==4.15.0
# via delocate # via delocate
virtualenv==20.35.2 virtualenv==20.35.4
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
@@ -1,6 +1,6 @@
# This file was autogenerated by uv via the following command: # This file was autogenerated by uv via the following command:
# nox -s update_constraints # nox -s update_constraints
altgraph==0.17.4 altgraph==0.17.5
# via macholib # via macholib
build==1.3.0 build==1.3.0
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
@@ -8,21 +8,21 @@ 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.20.0 filelock==3.20.2
# via virtualenv # via virtualenv
macholib==1.16.3 macholib==1.16.4
# via delocate # via delocate
packaging==25.0 packaging==25.0
# via # via
# build # build
# delocate # delocate
pip==25.2 pip==25.3
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
platformdirs==4.5.0 platformdirs==4.5.1
# via virtualenv # via virtualenv
pyproject-hooks==1.2.0 pyproject-hooks==1.2.0
# via build # via build
typing-extensions==4.15.0 typing-extensions==4.15.0
# via delocate # via delocate
virtualenv==20.35.2 virtualenv==20.35.4
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
@@ -1,6 +1,6 @@
# This file was autogenerated by uv via the following command: # This file was autogenerated by uv via the following command:
# nox -s update_constraints # nox -s update_constraints
altgraph==0.17.4 altgraph==0.17.5
# via macholib # via macholib
build==1.3.0 build==1.3.0
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
@@ -8,21 +8,21 @@ 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.20.0 filelock==3.20.2
# via virtualenv # via virtualenv
macholib==1.16.3 macholib==1.16.4
# via delocate # via delocate
packaging==25.0 packaging==25.0
# via # via
# build # build
# delocate # delocate
pip==25.2 pip==25.3
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
platformdirs==4.5.0 platformdirs==4.5.1
# via virtualenv # via virtualenv
pyproject-hooks==1.2.0 pyproject-hooks==1.2.0
# via build # via build
typing-extensions==4.15.0 typing-extensions==4.15.0
# via delocate # via delocate
virtualenv==20.35.2 virtualenv==20.35.4
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
@@ -1,6 +1,6 @@
# This file was autogenerated by uv via the following command: # This file was autogenerated by uv via the following command:
# nox -s update_constraints # nox -s update_constraints
altgraph==0.17.4 altgraph==0.17.5
# via macholib # via macholib
build==1.2.2.post1 build==1.2.2.post1
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
@@ -12,7 +12,7 @@ filelock==3.16.1
# via virtualenv # via virtualenv
importlib-metadata==8.5.0 importlib-metadata==8.5.0
# via build # via build
macholib==1.16.3 macholib==1.16.4
# via delocate # via delocate
packaging==25.0 packaging==25.0
# via # via
@@ -30,7 +30,7 @@ typing-extensions==4.13.2
# via # via
# delocate # delocate
# virtualenv # virtualenv
virtualenv==20.35.2 virtualenv==20.35.4
# 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
@@ -1,6 +1,6 @@
# This file was autogenerated by uv via the following command: # This file was autogenerated by uv via the following command:
# nox -s update_constraints # nox -s update_constraints
altgraph==0.17.4 altgraph==0.17.5
# via macholib # via macholib
build==1.3.0 build==1.3.0
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
@@ -10,15 +10,15 @@ distlib==0.4.0
# via virtualenv # via virtualenv
filelock==3.19.1 filelock==3.19.1
# via virtualenv # via virtualenv
importlib-metadata==8.7.0 importlib-metadata==8.7.1
# via build # via build
macholib==1.16.3 macholib==1.16.4
# via delocate # via delocate
packaging==25.0 packaging==25.0
# via # via
# build # build
# delocate # delocate
pip==25.2 pip==25.3
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
platformdirs==4.4.0 platformdirs==4.4.0
# via virtualenv # via virtualenv
@@ -30,7 +30,7 @@ typing-extensions==4.15.0
# via # via
# delocate # delocate
# virtualenv # virtualenv
virtualenv==20.35.2 virtualenv==20.35.4
# 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
+6 -6
View File
@@ -1,6 +1,6 @@
# This file was autogenerated by uv via the following command: # This file was autogenerated by uv via the following command:
# nox -s update_constraints # nox -s update_constraints
altgraph==0.17.4 altgraph==0.17.5
# via macholib # via macholib
build==1.3.0 build==1.3.0
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
@@ -8,21 +8,21 @@ 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.20.0 filelock==3.20.2
# via virtualenv # via virtualenv
macholib==1.16.3 macholib==1.16.4
# via delocate # via delocate
packaging==25.0 packaging==25.0
# via # via
# build # build
# delocate # delocate
pip==25.2 pip==25.3
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
platformdirs==4.5.0 platformdirs==4.5.1
# via virtualenv # via virtualenv
pyproject-hooks==1.2.0 pyproject-hooks==1.2.0
# via build # via build
typing-extensions==4.15.0 typing-extensions==4.15.0
# via delocate # via delocate
virtualenv==20.35.2 virtualenv==20.35.4
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
+1
View File
@@ -25,6 +25,7 @@ test-requires = []
test-extras = [] test-extras = []
test-groups = [] test-groups = []
test-environment = {} test-environment = {}
test-runtime = {}
container-engine = "docker" container-engine = "docker"
+3 -2
View File
@@ -1,3 +1,4 @@
url = "https://nodejs.org/dist/" url = "https://nodejs.org/dist/"
v22 = "v22.20.0" v24 = "v24.12.0"
v20 = "v20.19.5" v22 = "v22.21.1"
v20 = "v20.19.6"
+34 -33
View File
@@ -1,53 +1,54 @@
[x86_64] [x86_64]
manylinux2014 = quay.io/pypa/manylinux2014_x86_64:2025.10.10-1 manylinux2014 = quay.io/pypa/manylinux2014_x86_64:2026.01.04-1
manylinux_2_28 = quay.io/pypa/manylinux_2_28_x86_64:2025.10.10-1 manylinux_2_28 = quay.io/pypa/manylinux_2_28_x86_64:2026.01.04-1
manylinux_2_34 = quay.io/pypa/manylinux_2_34_x86_64:2025.10.10-1 manylinux_2_34 = quay.io/pypa/manylinux_2_34_x86_64:2026.01.04-1
musllinux_1_2 = quay.io/pypa/musllinux_1_2_x86_64:2025.10.10-1 musllinux_1_2 = quay.io/pypa/musllinux_1_2_x86_64:2026.01.04-1
[i686] [i686]
manylinux2014 = quay.io/pypa/manylinux2014_i686:2025.10.10-1 manylinux2014 = quay.io/pypa/manylinux2014_i686:2026.01.04-1
manylinux_2_28 = quay.io/pypa/manylinux_2_28_i686:2025.10.10-1 manylinux_2_28 = quay.io/pypa/manylinux_2_28_i686:2026.01.04-1
manylinux_2_34 = quay.io/pypa/manylinux_2_34_i686:2025.10.10-1 manylinux_2_34 = quay.io/pypa/manylinux_2_34_i686:2026.01.04-1
musllinux_1_2 = quay.io/pypa/musllinux_1_2_i686:2025.10.10-1 musllinux_1_2 = quay.io/pypa/musllinux_1_2_i686:2026.01.04-1
[aarch64] [aarch64]
manylinux2014 = quay.io/pypa/manylinux2014_aarch64:2025.10.10-1 manylinux2014 = quay.io/pypa/manylinux2014_aarch64:2026.01.04-1
manylinux_2_28 = quay.io/pypa/manylinux_2_28_aarch64:2025.10.10-1 manylinux_2_28 = quay.io/pypa/manylinux_2_28_aarch64:2026.01.04-1
manylinux_2_34 = quay.io/pypa/manylinux_2_34_aarch64:2025.10.10-1 manylinux_2_34 = quay.io/pypa/manylinux_2_34_aarch64:2026.01.04-1
musllinux_1_2 = quay.io/pypa/musllinux_1_2_aarch64:2025.10.10-1 musllinux_1_2 = quay.io/pypa/musllinux_1_2_aarch64:2026.01.04-1
[ppc64le] [ppc64le]
manylinux2014 = quay.io/pypa/manylinux2014_ppc64le:2025.10.10-1 manylinux2014 = quay.io/pypa/manylinux2014_ppc64le:2026.01.04-1
manylinux_2_28 = quay.io/pypa/manylinux_2_28_ppc64le:2025.10.10-1 manylinux_2_28 = quay.io/pypa/manylinux_2_28_ppc64le:2026.01.04-1
manylinux_2_34 = quay.io/pypa/manylinux_2_34_ppc64le:2025.10.10-1 manylinux_2_34 = quay.io/pypa/manylinux_2_34_ppc64le:2026.01.04-1
musllinux_1_2 = quay.io/pypa/musllinux_1_2_ppc64le:2025.10.10-1 musllinux_1_2 = quay.io/pypa/musllinux_1_2_ppc64le:2026.01.04-1
[s390x] [s390x]
manylinux2014 = quay.io/pypa/manylinux2014_s390x:2025.10.10-1 manylinux2014 = quay.io/pypa/manylinux2014_s390x:2026.01.04-1
manylinux_2_28 = quay.io/pypa/manylinux_2_28_s390x:2025.10.10-1 manylinux_2_28 = quay.io/pypa/manylinux_2_28_s390x:2026.01.04-1
manylinux_2_34 = quay.io/pypa/manylinux_2_34_s390x:2025.10.10-1 manylinux_2_34 = quay.io/pypa/manylinux_2_34_s390x:2026.01.04-1
musllinux_1_2 = quay.io/pypa/musllinux_1_2_s390x:2025.10.10-1 musllinux_1_2 = quay.io/pypa/musllinux_1_2_s390x:2026.01.04-1
[pypy_x86_64] [pypy_x86_64]
manylinux2014 = quay.io/pypa/manylinux2014_x86_64:2025.10.10-1 manylinux2014 = quay.io/pypa/manylinux2014_x86_64:2026.01.04-1
manylinux_2_28 = quay.io/pypa/manylinux_2_28_x86_64:2025.10.10-1 manylinux_2_28 = quay.io/pypa/manylinux_2_28_x86_64:2026.01.04-1
manylinux_2_34 = quay.io/pypa/manylinux_2_34_x86_64:2025.10.10-1 manylinux_2_34 = quay.io/pypa/manylinux_2_34_x86_64:2026.01.04-1
[pypy_i686] [pypy_i686]
manylinux2014 = quay.io/pypa/manylinux2014_i686:2025.10.10-1 manylinux2014 = quay.io/pypa/manylinux2014_i686:2026.01.04-1
manylinux_2_28 = quay.io/pypa/manylinux_2_28_i686:2025.10.10-1 manylinux_2_28 = quay.io/pypa/manylinux_2_28_i686:2026.01.04-1
manylinux_2_34 = quay.io/pypa/manylinux_2_34_i686:2025.10.10-1 manylinux_2_34 = quay.io/pypa/manylinux_2_34_i686:2026.01.04-1
[pypy_aarch64] [pypy_aarch64]
manylinux2014 = quay.io/pypa/manylinux2014_aarch64:2025.10.10-1 manylinux2014 = quay.io/pypa/manylinux2014_aarch64:2026.01.04-1
manylinux_2_28 = quay.io/pypa/manylinux_2_28_aarch64:2025.10.10-1 manylinux_2_28 = quay.io/pypa/manylinux_2_28_aarch64:2026.01.04-1
manylinux_2_34 = quay.io/pypa/manylinux_2_34_aarch64:2025.10.10-1 manylinux_2_34 = quay.io/pypa/manylinux_2_34_aarch64:2026.01.04-1
[armv7l] [armv7l]
manylinux_2_31 = quay.io/pypa/manylinux_2_31_armv7l:2025.10.10-1 manylinux_2_31 = quay.io/pypa/manylinux_2_31_armv7l:2026.01.04-1
musllinux_1_2 = quay.io/pypa/musllinux_1_2_armv7l:2025.10.10-1 manylinux_2_35 = quay.io/pypa/manylinux_2_35_armv7l:2026.01.04-1
musllinux_1_2 = quay.io/pypa/musllinux_1_2_armv7l:2026.01.04-1
[riscv64] [riscv64]
manylinux_2_39 = quay.io/pypa/manylinux_2_39_riscv64:2025.10.10-1 manylinux_2_39 = quay.io/pypa/manylinux_2_39_riscv64:2026.01.04-1
musllinux_1_2 = quay.io/pypa/musllinux_1_2_riscv64:2025.10.10-1 musllinux_1_2 = quay.io/pypa/musllinux_1_2_riscv64:2026.01.04-1
@@ -1,479 +1,483 @@
{ {
"releases": [ "releases": [
{ {
"tag": "20251010", "tag": "20251217",
"assets": [ "assets": [
{ {
"name": "cpython-3.10.19+20251010-aarch64-apple-darwin-install_only.tar.gz", "name": "cpython-3.10.19+20251217-aarch64-apple-darwin-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.10.19%2B20251010-aarch64-apple-darwin-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.10.19%2B20251217-aarch64-apple-darwin-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.10.19+20251010-aarch64-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.10.19+20251217-aarch64-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.10.19%2B20251010-aarch64-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.10.19%2B20251217-aarch64-unknown-linux-gnu-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.10.19+20251010-aarch64-unknown-linux-musl-install_only.tar.gz", "name": "cpython-3.10.19+20251217-aarch64-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.10.19%2B20251010-aarch64-unknown-linux-musl-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.10.19%2B20251217-aarch64-unknown-linux-musl-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.10.19+20251010-armv7-unknown-linux-gnueabi-install_only.tar.gz", "name": "cpython-3.10.19+20251217-armv7-unknown-linux-gnueabi-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.10.19%2B20251010-armv7-unknown-linux-gnueabi-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.10.19%2B20251217-armv7-unknown-linux-gnueabi-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.10.19+20251010-armv7-unknown-linux-gnueabihf-install_only.tar.gz", "name": "cpython-3.10.19+20251217-armv7-unknown-linux-gnueabihf-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.10.19%2B20251010-armv7-unknown-linux-gnueabihf-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.10.19%2B20251217-armv7-unknown-linux-gnueabihf-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.10.19+20251010-i686-pc-windows-msvc-install_only.tar.gz", "name": "cpython-3.10.19+20251217-i686-pc-windows-msvc-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.10.19%2B20251010-i686-pc-windows-msvc-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.10.19%2B20251217-i686-pc-windows-msvc-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.10.19+20251010-ppc64le-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.10.19+20251217-ppc64le-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.10.19%2B20251010-ppc64le-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.10.19%2B20251217-ppc64le-unknown-linux-gnu-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.10.19+20251010-riscv64-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.10.19+20251217-riscv64-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.10.19%2B20251010-riscv64-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.10.19%2B20251217-riscv64-unknown-linux-gnu-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.10.19+20251010-s390x-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.10.19+20251217-s390x-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.10.19%2B20251010-s390x-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.10.19%2B20251217-s390x-unknown-linux-gnu-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.10.19+20251010-x86_64-apple-darwin-install_only.tar.gz", "name": "cpython-3.10.19+20251217-x86_64-apple-darwin-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.10.19%2B20251010-x86_64-apple-darwin-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.10.19%2B20251217-x86_64-apple-darwin-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.10.19+20251010-x86_64-pc-windows-msvc-install_only.tar.gz", "name": "cpython-3.10.19+20251217-x86_64-pc-windows-msvc-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.10.19%2B20251010-x86_64-pc-windows-msvc-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.10.19%2B20251217-x86_64-pc-windows-msvc-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.10.19+20251010-x86_64-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.10.19+20251217-x86_64-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.10.19%2B20251010-x86_64-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.10.19%2B20251217-x86_64-unknown-linux-gnu-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.10.19+20251010-x86_64-unknown-linux-musl-install_only.tar.gz", "name": "cpython-3.10.19+20251217-x86_64-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.10.19%2B20251010-x86_64-unknown-linux-musl-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.10.19%2B20251217-x86_64-unknown-linux-musl-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.10.19+20251010-x86_64_v2-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.10.19+20251217-x86_64_v2-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.10.19%2B20251010-x86_64_v2-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.10.19%2B20251217-x86_64_v2-unknown-linux-gnu-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.10.19+20251010-x86_64_v2-unknown-linux-musl-install_only.tar.gz", "name": "cpython-3.10.19+20251217-x86_64_v2-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.10.19%2B20251010-x86_64_v2-unknown-linux-musl-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.10.19%2B20251217-x86_64_v2-unknown-linux-musl-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.10.19+20251010-x86_64_v3-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.10.19+20251217-x86_64_v3-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.10.19%2B20251010-x86_64_v3-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.10.19%2B20251217-x86_64_v3-unknown-linux-gnu-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.10.19+20251010-x86_64_v3-unknown-linux-musl-install_only.tar.gz", "name": "cpython-3.10.19+20251217-x86_64_v3-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.10.19%2B20251010-x86_64_v3-unknown-linux-musl-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.10.19%2B20251217-x86_64_v3-unknown-linux-musl-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.10.19+20251010-x86_64_v4-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.10.19+20251217-x86_64_v4-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.10.19%2B20251010-x86_64_v4-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.10.19%2B20251217-x86_64_v4-unknown-linux-gnu-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.10.19+20251010-x86_64_v4-unknown-linux-musl-install_only.tar.gz", "name": "cpython-3.10.19+20251217-x86_64_v4-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.10.19%2B20251010-x86_64_v4-unknown-linux-musl-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.10.19%2B20251217-x86_64_v4-unknown-linux-musl-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.11.14+20251010-aarch64-apple-darwin-install_only.tar.gz", "name": "cpython-3.11.14+20251217-aarch64-apple-darwin-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.11.14%2B20251010-aarch64-apple-darwin-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.11.14%2B20251217-aarch64-apple-darwin-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.11.14+20251010-aarch64-pc-windows-msvc-install_only.tar.gz", "name": "cpython-3.11.14+20251217-aarch64-pc-windows-msvc-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.11.14%2B20251010-aarch64-pc-windows-msvc-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.11.14%2B20251217-aarch64-pc-windows-msvc-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.11.14+20251010-aarch64-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.11.14+20251217-aarch64-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.11.14%2B20251010-aarch64-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.11.14%2B20251217-aarch64-unknown-linux-gnu-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.11.14+20251010-aarch64-unknown-linux-musl-install_only.tar.gz", "name": "cpython-3.11.14+20251217-aarch64-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.11.14%2B20251010-aarch64-unknown-linux-musl-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.11.14%2B20251217-aarch64-unknown-linux-musl-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.11.14+20251010-armv7-unknown-linux-gnueabi-install_only.tar.gz", "name": "cpython-3.11.14+20251217-armv7-unknown-linux-gnueabi-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.11.14%2B20251010-armv7-unknown-linux-gnueabi-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.11.14%2B20251217-armv7-unknown-linux-gnueabi-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.11.14+20251010-armv7-unknown-linux-gnueabihf-install_only.tar.gz", "name": "cpython-3.11.14+20251217-armv7-unknown-linux-gnueabihf-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.11.14%2B20251010-armv7-unknown-linux-gnueabihf-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.11.14%2B20251217-armv7-unknown-linux-gnueabihf-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.11.14+20251010-i686-pc-windows-msvc-install_only.tar.gz", "name": "cpython-3.11.14+20251217-i686-pc-windows-msvc-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.11.14%2B20251010-i686-pc-windows-msvc-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.11.14%2B20251217-i686-pc-windows-msvc-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.11.14+20251010-ppc64le-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.11.14+20251217-ppc64le-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.11.14%2B20251010-ppc64le-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.11.14%2B20251217-ppc64le-unknown-linux-gnu-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.11.14+20251010-riscv64-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.11.14+20251217-riscv64-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.11.14%2B20251010-riscv64-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.11.14%2B20251217-riscv64-unknown-linux-gnu-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.11.14+20251010-s390x-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.11.14+20251217-s390x-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.11.14%2B20251010-s390x-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.11.14%2B20251217-s390x-unknown-linux-gnu-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.11.14+20251010-x86_64-apple-darwin-install_only.tar.gz", "name": "cpython-3.11.14+20251217-x86_64-apple-darwin-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.11.14%2B20251010-x86_64-apple-darwin-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.11.14%2B20251217-x86_64-apple-darwin-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.11.14+20251010-x86_64-pc-windows-msvc-install_only.tar.gz", "name": "cpython-3.11.14+20251217-x86_64-pc-windows-msvc-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.11.14%2B20251010-x86_64-pc-windows-msvc-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.11.14%2B20251217-x86_64-pc-windows-msvc-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.11.14+20251010-x86_64-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.11.14+20251217-x86_64-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.11.14%2B20251010-x86_64-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.11.14%2B20251217-x86_64-unknown-linux-gnu-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.11.14+20251010-x86_64-unknown-linux-musl-install_only.tar.gz", "name": "cpython-3.11.14+20251217-x86_64-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.11.14%2B20251010-x86_64-unknown-linux-musl-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.11.14%2B20251217-x86_64-unknown-linux-musl-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.11.14+20251010-x86_64_v2-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.11.14+20251217-x86_64_v2-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.11.14%2B20251010-x86_64_v2-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.11.14%2B20251217-x86_64_v2-unknown-linux-gnu-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.11.14+20251010-x86_64_v2-unknown-linux-musl-install_only.tar.gz", "name": "cpython-3.11.14+20251217-x86_64_v2-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.11.14%2B20251010-x86_64_v2-unknown-linux-musl-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.11.14%2B20251217-x86_64_v2-unknown-linux-musl-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.11.14+20251010-x86_64_v3-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.11.14+20251217-x86_64_v3-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.11.14%2B20251010-x86_64_v3-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.11.14%2B20251217-x86_64_v3-unknown-linux-gnu-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.11.14+20251010-x86_64_v3-unknown-linux-musl-install_only.tar.gz", "name": "cpython-3.11.14+20251217-x86_64_v3-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.11.14%2B20251010-x86_64_v3-unknown-linux-musl-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.11.14%2B20251217-x86_64_v3-unknown-linux-musl-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.11.14+20251010-x86_64_v4-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.11.14+20251217-x86_64_v4-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.11.14%2B20251010-x86_64_v4-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.11.14%2B20251217-x86_64_v4-unknown-linux-gnu-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.11.14+20251010-x86_64_v4-unknown-linux-musl-install_only.tar.gz", "name": "cpython-3.11.14+20251217-x86_64_v4-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.11.14%2B20251010-x86_64_v4-unknown-linux-musl-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.11.14%2B20251217-x86_64_v4-unknown-linux-musl-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.12.12+20251010-aarch64-apple-darwin-install_only.tar.gz", "name": "cpython-3.12.12+20251217-aarch64-apple-darwin-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.12.12%2B20251010-aarch64-apple-darwin-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.12.12%2B20251217-aarch64-apple-darwin-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.12.12+20251010-aarch64-pc-windows-msvc-install_only.tar.gz", "name": "cpython-3.12.12+20251217-aarch64-pc-windows-msvc-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.12.12%2B20251010-aarch64-pc-windows-msvc-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.12.12%2B20251217-aarch64-pc-windows-msvc-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.12.12+20251010-aarch64-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.12.12+20251217-aarch64-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.12.12%2B20251010-aarch64-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.12.12%2B20251217-aarch64-unknown-linux-gnu-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.12.12+20251010-aarch64-unknown-linux-musl-install_only.tar.gz", "name": "cpython-3.12.12+20251217-aarch64-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.12.12%2B20251010-aarch64-unknown-linux-musl-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.12.12%2B20251217-aarch64-unknown-linux-musl-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.12.12+20251010-armv7-unknown-linux-gnueabi-install_only.tar.gz", "name": "cpython-3.12.12+20251217-armv7-unknown-linux-gnueabi-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.12.12%2B20251010-armv7-unknown-linux-gnueabi-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.12.12%2B20251217-armv7-unknown-linux-gnueabi-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.12.12+20251010-armv7-unknown-linux-gnueabihf-install_only.tar.gz", "name": "cpython-3.12.12+20251217-armv7-unknown-linux-gnueabihf-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.12.12%2B20251010-armv7-unknown-linux-gnueabihf-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.12.12%2B20251217-armv7-unknown-linux-gnueabihf-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.12.12+20251010-i686-pc-windows-msvc-install_only.tar.gz", "name": "cpython-3.12.12+20251217-i686-pc-windows-msvc-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.12.12%2B20251010-i686-pc-windows-msvc-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.12.12%2B20251217-i686-pc-windows-msvc-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.12.12+20251010-ppc64le-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.12.12+20251217-ppc64le-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.12.12%2B20251010-ppc64le-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.12.12%2B20251217-ppc64le-unknown-linux-gnu-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.12.12+20251010-riscv64-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.12.12+20251217-riscv64-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.12.12%2B20251010-riscv64-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.12.12%2B20251217-riscv64-unknown-linux-gnu-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.12.12+20251010-s390x-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.12.12+20251217-s390x-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.12.12%2B20251010-s390x-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.12.12%2B20251217-s390x-unknown-linux-gnu-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.12.12+20251010-x86_64-apple-darwin-install_only.tar.gz", "name": "cpython-3.12.12+20251217-x86_64-apple-darwin-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.12.12%2B20251010-x86_64-apple-darwin-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.12.12%2B20251217-x86_64-apple-darwin-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.12.12+20251010-x86_64-pc-windows-msvc-install_only.tar.gz", "name": "cpython-3.12.12+20251217-x86_64-pc-windows-msvc-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.12.12%2B20251010-x86_64-pc-windows-msvc-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.12.12%2B20251217-x86_64-pc-windows-msvc-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.12.12+20251010-x86_64-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.12.12+20251217-x86_64-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.12.12%2B20251010-x86_64-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.12.12%2B20251217-x86_64-unknown-linux-gnu-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.12.12+20251010-x86_64-unknown-linux-musl-install_only.tar.gz", "name": "cpython-3.12.12+20251217-x86_64-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.12.12%2B20251010-x86_64-unknown-linux-musl-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.12.12%2B20251217-x86_64-unknown-linux-musl-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.12.12+20251010-x86_64_v2-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.12.12+20251217-x86_64_v2-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.12.12%2B20251010-x86_64_v2-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.12.12%2B20251217-x86_64_v2-unknown-linux-gnu-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.12.12+20251010-x86_64_v2-unknown-linux-musl-install_only.tar.gz", "name": "cpython-3.12.12+20251217-x86_64_v2-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.12.12%2B20251010-x86_64_v2-unknown-linux-musl-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.12.12%2B20251217-x86_64_v2-unknown-linux-musl-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.12.12+20251010-x86_64_v3-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.12.12+20251217-x86_64_v3-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.12.12%2B20251010-x86_64_v3-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.12.12%2B20251217-x86_64_v3-unknown-linux-gnu-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.12.12+20251010-x86_64_v3-unknown-linux-musl-install_only.tar.gz", "name": "cpython-3.12.12+20251217-x86_64_v3-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.12.12%2B20251010-x86_64_v3-unknown-linux-musl-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.12.12%2B20251217-x86_64_v3-unknown-linux-musl-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.12.12+20251010-x86_64_v4-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.12.12+20251217-x86_64_v4-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.12.12%2B20251010-x86_64_v4-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.12.12%2B20251217-x86_64_v4-unknown-linux-gnu-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.12.12+20251010-x86_64_v4-unknown-linux-musl-install_only.tar.gz", "name": "cpython-3.12.12+20251217-x86_64_v4-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.12.12%2B20251010-x86_64_v4-unknown-linux-musl-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.12.12%2B20251217-x86_64_v4-unknown-linux-musl-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.13.8+20251010-aarch64-apple-darwin-install_only.tar.gz", "name": "cpython-3.13.11+20251217-aarch64-apple-darwin-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.13.8%2B20251010-aarch64-apple-darwin-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.13.11%2B20251217-aarch64-apple-darwin-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.13.8+20251010-aarch64-pc-windows-msvc-install_only.tar.gz", "name": "cpython-3.13.11+20251217-aarch64-pc-windows-msvc-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.13.8%2B20251010-aarch64-pc-windows-msvc-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.13.11%2B20251217-aarch64-pc-windows-msvc-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.13.8+20251010-aarch64-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.13.11+20251217-aarch64-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.13.8%2B20251010-aarch64-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.13.11%2B20251217-aarch64-unknown-linux-gnu-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.13.8+20251010-aarch64-unknown-linux-musl-install_only.tar.gz", "name": "cpython-3.13.11+20251217-aarch64-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.13.8%2B20251010-aarch64-unknown-linux-musl-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.13.11%2B20251217-aarch64-unknown-linux-musl-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.13.8+20251010-armv7-unknown-linux-gnueabi-install_only.tar.gz", "name": "cpython-3.13.11+20251217-armv7-unknown-linux-gnueabi-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.13.8%2B20251010-armv7-unknown-linux-gnueabi-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.13.11%2B20251217-armv7-unknown-linux-gnueabi-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.13.8+20251010-armv7-unknown-linux-gnueabihf-install_only.tar.gz", "name": "cpython-3.13.11+20251217-armv7-unknown-linux-gnueabihf-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.13.8%2B20251010-armv7-unknown-linux-gnueabihf-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.13.11%2B20251217-armv7-unknown-linux-gnueabihf-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.13.8+20251010-i686-pc-windows-msvc-install_only.tar.gz", "name": "cpython-3.13.11+20251217-i686-pc-windows-msvc-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.13.8%2B20251010-i686-pc-windows-msvc-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.13.11%2B20251217-i686-pc-windows-msvc-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.13.8+20251010-ppc64le-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.13.11+20251217-ppc64le-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.13.8%2B20251010-ppc64le-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.13.11%2B20251217-ppc64le-unknown-linux-gnu-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.13.8+20251010-riscv64-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.13.11+20251217-riscv64-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.13.8%2B20251010-riscv64-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.13.11%2B20251217-riscv64-unknown-linux-gnu-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.13.8+20251010-s390x-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.13.11+20251217-s390x-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.13.8%2B20251010-s390x-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.13.11%2B20251217-s390x-unknown-linux-gnu-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.13.8+20251010-x86_64-apple-darwin-install_only.tar.gz", "name": "cpython-3.13.11+20251217-x86_64-apple-darwin-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.13.8%2B20251010-x86_64-apple-darwin-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.13.11%2B20251217-x86_64-apple-darwin-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.13.8+20251010-x86_64-pc-windows-msvc-install_only.tar.gz", "name": "cpython-3.13.11+20251217-x86_64-pc-windows-msvc-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.13.8%2B20251010-x86_64-pc-windows-msvc-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.13.11%2B20251217-x86_64-pc-windows-msvc-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.13.8+20251010-x86_64-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.13.11+20251217-x86_64-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.13.8%2B20251010-x86_64-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.13.11%2B20251217-x86_64-unknown-linux-gnu-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.13.8+20251010-x86_64-unknown-linux-musl-install_only.tar.gz", "name": "cpython-3.13.11+20251217-x86_64-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.13.8%2B20251010-x86_64-unknown-linux-musl-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.13.11%2B20251217-x86_64-unknown-linux-musl-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.13.8+20251010-x86_64_v2-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.13.11+20251217-x86_64_v2-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.13.8%2B20251010-x86_64_v2-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.13.11%2B20251217-x86_64_v2-unknown-linux-gnu-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.13.8+20251010-x86_64_v2-unknown-linux-musl-install_only.tar.gz", "name": "cpython-3.13.11+20251217-x86_64_v2-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.13.8%2B20251010-x86_64_v2-unknown-linux-musl-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.13.11%2B20251217-x86_64_v2-unknown-linux-musl-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.13.8+20251010-x86_64_v3-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.13.11+20251217-x86_64_v3-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.13.8%2B20251010-x86_64_v3-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.13.11%2B20251217-x86_64_v3-unknown-linux-gnu-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.13.8+20251010-x86_64_v3-unknown-linux-musl-install_only.tar.gz", "name": "cpython-3.13.11+20251217-x86_64_v3-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.13.8%2B20251010-x86_64_v3-unknown-linux-musl-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.13.11%2B20251217-x86_64_v3-unknown-linux-musl-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.13.8+20251010-x86_64_v4-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.13.11+20251217-x86_64_v4-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.13.8%2B20251010-x86_64_v4-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.13.11%2B20251217-x86_64_v4-unknown-linux-gnu-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.13.8+20251010-x86_64_v4-unknown-linux-musl-install_only.tar.gz", "name": "cpython-3.13.11+20251217-x86_64_v4-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.13.8%2B20251010-x86_64_v4-unknown-linux-musl-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.13.11%2B20251217-x86_64_v4-unknown-linux-musl-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.14.0+20251010-aarch64-apple-darwin-install_only.tar.gz", "name": "cpython-3.14.2+20251217-aarch64-apple-darwin-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.14.0%2B20251010-aarch64-apple-darwin-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.14.2%2B20251217-aarch64-apple-darwin-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.14.0+20251010-aarch64-pc-windows-msvc-install_only.tar.gz", "name": "cpython-3.14.2+20251217-aarch64-pc-windows-msvc-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.14.0%2B20251010-aarch64-pc-windows-msvc-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.14.2%2B20251217-aarch64-pc-windows-msvc-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.14.0+20251010-aarch64-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.14.2+20251217-aarch64-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.14.0%2B20251010-aarch64-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.14.2%2B20251217-aarch64-unknown-linux-gnu-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.14.0+20251010-aarch64-unknown-linux-musl-install_only.tar.gz", "name": "cpython-3.14.2+20251217-aarch64-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.14.0%2B20251010-aarch64-unknown-linux-musl-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.14.2%2B20251217-aarch64-unknown-linux-musl-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.14.0+20251010-armv7-unknown-linux-gnueabi-install_only.tar.gz", "name": "cpython-3.14.2+20251217-armv7-unknown-linux-gnueabi-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.14.0%2B20251010-armv7-unknown-linux-gnueabi-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.14.2%2B20251217-armv7-unknown-linux-gnueabi-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.14.0+20251010-armv7-unknown-linux-gnueabihf-install_only.tar.gz", "name": "cpython-3.14.2+20251217-armv7-unknown-linux-gnueabihf-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.14.0%2B20251010-armv7-unknown-linux-gnueabihf-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.14.2%2B20251217-armv7-unknown-linux-gnueabihf-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.14.0+20251010-i686-pc-windows-msvc-install_only.tar.gz", "name": "cpython-3.14.2+20251217-i686-pc-windows-msvc-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.14.0%2B20251010-i686-pc-windows-msvc-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.14.2%2B20251217-i686-pc-windows-msvc-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.14.0+20251010-ppc64le-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.14.2+20251217-ppc64le-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.14.0%2B20251010-ppc64le-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.14.2%2B20251217-ppc64le-unknown-linux-gnu-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.14.0+20251010-riscv64-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.14.2+20251217-riscv64-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.14.0%2B20251010-riscv64-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.14.2%2B20251217-riscv64-unknown-linux-gnu-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.14.0+20251010-s390x-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.14.2+20251217-s390x-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.14.0%2B20251010-s390x-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.14.2%2B20251217-s390x-unknown-linux-gnu-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.14.0+20251010-x86_64-apple-darwin-install_only.tar.gz", "name": "cpython-3.14.2+20251217-x86_64-apple-darwin-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.14.0%2B20251010-x86_64-apple-darwin-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.14.2%2B20251217-x86_64-apple-darwin-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.14.0+20251010-x86_64-pc-windows-msvc-install_only.tar.gz", "name": "cpython-3.14.2+20251217-x86_64-pc-windows-msvc-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.14.0%2B20251010-x86_64-pc-windows-msvc-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.14.2%2B20251217-x86_64-pc-windows-msvc-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.14.0+20251010-x86_64-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.14.2+20251217-x86_64-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.14.0%2B20251010-x86_64-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.14.2%2B20251217-x86_64-unknown-linux-gnu-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.14.0+20251010-x86_64-unknown-linux-musl-install_only.tar.gz", "name": "cpython-3.14.2+20251217-x86_64-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.14.0%2B20251010-x86_64-unknown-linux-musl-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.14.2%2B20251217-x86_64-unknown-linux-musl-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.14.0+20251010-x86_64_v2-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.14.2+20251217-x86_64_v2-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.14.0%2B20251010-x86_64_v2-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.14.2%2B20251217-x86_64_v2-unknown-linux-gnu-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.14.0+20251010-x86_64_v2-unknown-linux-musl-install_only.tar.gz", "name": "cpython-3.14.2+20251217-x86_64_v2-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.14.0%2B20251010-x86_64_v2-unknown-linux-musl-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.14.2%2B20251217-x86_64_v2-unknown-linux-musl-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.14.0+20251010-x86_64_v3-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.14.2+20251217-x86_64_v3-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.14.0%2B20251010-x86_64_v3-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.14.2%2B20251217-x86_64_v3-unknown-linux-gnu-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.14.0+20251010-x86_64_v3-unknown-linux-musl-install_only.tar.gz", "name": "cpython-3.14.2+20251217-x86_64_v3-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.14.0%2B20251010-x86_64_v3-unknown-linux-musl-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.14.2%2B20251217-x86_64_v3-unknown-linux-musl-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.14.0+20251010-x86_64_v4-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.14.2+20251217-x86_64_v4-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.14.0%2B20251010-x86_64_v4-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.14.2%2B20251217-x86_64_v4-unknown-linux-gnu-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.14.0+20251010-x86_64_v4-unknown-linux-musl-install_only.tar.gz", "name": "cpython-3.14.2+20251217-x86_64_v4-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.14.0%2B20251010-x86_64_v4-unknown-linux-musl-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.14.2%2B20251217-x86_64_v4-unknown-linux-musl-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.9.24+20251010-aarch64-apple-darwin-install_only.tar.gz", "name": "cpython-3.15.0a3+20251217-aarch64-apple-darwin-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.9.24%2B20251010-aarch64-apple-darwin-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.15.0a3%2B20251217-aarch64-apple-darwin-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.9.24+20251010-aarch64-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.15.0a3+20251217-aarch64-pc-windows-msvc-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.9.24%2B20251010-aarch64-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.15.0a3%2B20251217-aarch64-pc-windows-msvc-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.9.24+20251010-aarch64-unknown-linux-musl-install_only.tar.gz", "name": "cpython-3.15.0a3+20251217-aarch64-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.9.24%2B20251010-aarch64-unknown-linux-musl-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.15.0a3%2B20251217-aarch64-unknown-linux-gnu-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.9.24+20251010-armv7-unknown-linux-gnueabi-install_only.tar.gz", "name": "cpython-3.15.0a3+20251217-aarch64-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.9.24%2B20251010-armv7-unknown-linux-gnueabi-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.15.0a3%2B20251217-aarch64-unknown-linux-musl-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.9.24+20251010-armv7-unknown-linux-gnueabihf-install_only.tar.gz", "name": "cpython-3.15.0a3+20251217-armv7-unknown-linux-gnueabi-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.9.24%2B20251010-armv7-unknown-linux-gnueabihf-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.15.0a3%2B20251217-armv7-unknown-linux-gnueabi-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.9.24+20251010-i686-pc-windows-msvc-install_only.tar.gz", "name": "cpython-3.15.0a3+20251217-armv7-unknown-linux-gnueabihf-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.9.24%2B20251010-i686-pc-windows-msvc-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.15.0a3%2B20251217-armv7-unknown-linux-gnueabihf-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.9.24+20251010-ppc64le-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.15.0a3+20251217-i686-pc-windows-msvc-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.9.24%2B20251010-ppc64le-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.15.0a3%2B20251217-i686-pc-windows-msvc-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.9.24+20251010-riscv64-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.15.0a3+20251217-ppc64le-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.9.24%2B20251010-riscv64-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.15.0a3%2B20251217-ppc64le-unknown-linux-gnu-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.9.24+20251010-s390x-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.15.0a3+20251217-riscv64-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.9.24%2B20251010-s390x-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.15.0a3%2B20251217-riscv64-unknown-linux-gnu-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.9.24+20251010-x86_64-apple-darwin-install_only.tar.gz", "name": "cpython-3.15.0a3+20251217-s390x-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.9.24%2B20251010-x86_64-apple-darwin-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.15.0a3%2B20251217-s390x-unknown-linux-gnu-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.9.24+20251010-x86_64-pc-windows-msvc-install_only.tar.gz", "name": "cpython-3.15.0a3+20251217-x86_64-apple-darwin-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.9.24%2B20251010-x86_64-pc-windows-msvc-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.15.0a3%2B20251217-x86_64-apple-darwin-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.9.24+20251010-x86_64-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.15.0a3+20251217-x86_64-pc-windows-msvc-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.9.24%2B20251010-x86_64-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.15.0a3%2B20251217-x86_64-pc-windows-msvc-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.9.24+20251010-x86_64-unknown-linux-musl-install_only.tar.gz", "name": "cpython-3.15.0a3+20251217-x86_64-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.9.24%2B20251010-x86_64-unknown-linux-musl-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.15.0a3%2B20251217-x86_64-unknown-linux-gnu-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.9.24+20251010-x86_64_v2-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.15.0a3+20251217-x86_64-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.9.24%2B20251010-x86_64_v2-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.15.0a3%2B20251217-x86_64-unknown-linux-musl-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.9.24+20251010-x86_64_v2-unknown-linux-musl-install_only.tar.gz", "name": "cpython-3.15.0a3+20251217-x86_64_v2-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.9.24%2B20251010-x86_64_v2-unknown-linux-musl-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.15.0a3%2B20251217-x86_64_v2-unknown-linux-gnu-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.9.24+20251010-x86_64_v3-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.15.0a3+20251217-x86_64_v2-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.9.24%2B20251010-x86_64_v3-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.15.0a3%2B20251217-x86_64_v2-unknown-linux-musl-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.9.24+20251010-x86_64_v3-unknown-linux-musl-install_only.tar.gz", "name": "cpython-3.15.0a3+20251217-x86_64_v3-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.9.24%2B20251010-x86_64_v3-unknown-linux-musl-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.15.0a3%2B20251217-x86_64_v3-unknown-linux-gnu-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.9.24+20251010-x86_64_v4-unknown-linux-gnu-install_only.tar.gz", "name": "cpython-3.15.0a3+20251217-x86_64_v3-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.9.24%2B20251010-x86_64_v4-unknown-linux-gnu-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.15.0a3%2B20251217-x86_64_v3-unknown-linux-musl-install_only.tar.gz"
}, },
{ {
"name": "cpython-3.9.24+20251010-x86_64_v4-unknown-linux-musl-install_only.tar.gz", "name": "cpython-3.15.0a3+20251217-x86_64_v4-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251010/cpython-3.9.24%2B20251010-x86_64_v4-unknown-linux-musl-install_only.tar.gz" "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.15.0a3%2B20251217-x86_64_v4-unknown-linux-gnu-install_only.tar.gz"
},
{
"name": "cpython-3.15.0a3+20251217-x86_64_v4-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-3.15.0a3%2B20251217-x86_64_v4-unknown-linux-musl-install_only.tar.gz"
} }
] ]
} }
+1 -1
View File
@@ -1 +1 @@
default = { version = "20.35.2", url = "https://github.com/pypa/get-virtualenv/releases/download/20.35.2/virtualenv.pyz" } default = { version = "20.35.4", url = "https://github.com/pypa/get-virtualenv/releases/download/20.35.4/virtualenv.pyz" }
+1 -1
View File
@@ -72,7 +72,7 @@ def call(
if not capture_stdout: if not capture_stdout:
return None return None
sys.stderr.write(result.stderr) sys.stderr.write(result.stderr)
return typing.cast(str, result.stdout) return typing.cast("str", result.stdout)
def shell( def shell(
+1 -28
View File
@@ -1,5 +1,5 @@
import shlex import shlex
from collections.abc import Mapping, MutableMapping, 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 Any, Literal, Self, TypeVar
@@ -178,30 +178,3 @@ def find_compatible_wheel(wheels: Sequence[T], identifier: str) -> T | None:
return wheel return wheel
return None return None
def combine_constraints(
env: MutableMapping[str, str], /, constraints_path: Path, tmp_dir: Path | None
) -> None:
"""
This will workaround a bug in pip<=21.1.1 or uv<=0.2.0 if a tmp_dir is given.
If set to None, this will use the modern URI method.
"""
if tmp_dir:
if " " in str(constraints_path):
assert " " not in str(tmp_dir)
tmp_file = tmp_dir / "constraints.txt"
tmp_file.write_bytes(constraints_path.read_bytes())
constraints_path = tmp_file
our_constraints = str(constraints_path)
else:
our_constraints = (
constraints_path.as_uri() if " " in str(constraints_path) else str(constraints_path)
)
user_constraints = env.get("PIP_CONSTRAINT")
env["UV_CONSTRAINT"] = env["PIP_CONSTRAINT"] = " ".join(
c for c in [our_constraints, user_constraints] if c
)
+1 -1
View File
@@ -28,7 +28,7 @@ class PythonBuildStandaloneReleaseData(typing.TypedDict):
@functools.cache @functools.cache
def get_python_build_standalone_release_data() -> PythonBuildStandaloneReleaseData: def get_python_build_standalone_release_data() -> PythonBuildStandaloneReleaseData:
with open(PYTHON_BUILD_STANDALONE_RELEASES, "rb") as f: with open(PYTHON_BUILD_STANDALONE_RELEASES, "rb") as f:
return typing.cast(PythonBuildStandaloneReleaseData, json.load(f)) return typing.cast("PythonBuildStandaloneReleaseData", json.load(f))
class PythonBuildStandaloneError(Exception): class PythonBuildStandaloneError(Exception):
+20
View File
@@ -4,6 +4,26 @@ title: Changelog
# Changelog # Changelog
### v3.3.1
_5 January 2026_
- 🛠 Update dependencies and container pins, including updating to CPython 3.14.2. (#2708)
### v3.3.0
_12 November 2025_
- 🐛 Fix an incompatibility with Docker v29 (#2660)
- ✨ Adds `test-runtime` option, to customise how tests on simulated/emulated environments are run (#2636)
- ✨ Adds support for new `manylinux_2_35` images on 32-bit ARM `armv7l`, offering better C++20 compatibility (#2656)
- ✨ `build[uv]` is now supported on Android (#2587)
- ✨ You can now install extras (such as `uv`) with a simple option on the GitHub Action (#2630)
- ✨ `{project}` and `{package}` placeholders are now supported in `repair-wheel-command` (#2589)
- 🛠 The versions set with `dependency-versions` no longer constrain packages specified by your `build-system.requires`. Previously, on platforms other than Linux, the constraints in this option would remain in the environment during the build. This has been tidied up make behaviour more consistent between platforms, and to prevent version conflicts. (#2583)
- 🛠 Improve the handling of `test-command` on Android, enabling more options to be passed (#2590)
- 📚 Docs improvements (#2618)
### v3.2.1 ### v3.2.1
_12 October 2025_ _12 October 2025_
+3 -1
View File
@@ -23,7 +23,9 @@ To build Linux, macOS, and Windows wheels using GitHub Actions, create a `.githu
Use `env:` to pass [build options](options.md) and `with:` to set Use `env:` to pass [build options](options.md) and `with:` to set
`package-dir: .`, `output-dir: wheelhouse` and `config-file: ''` `package-dir: .`, `output-dir: wheelhouse` and `config-file: ''`
locations (those values are the defaults). locations (those values are the defaults). You can also pass a
comma-separated list of extras to install additional packages.
For example, `extras: "uv"` to install UV into the virtual environment.
!!! tab "pipx" !!! tab "pipx"
The GitHub Actions runners have pipx installed, so you can easily build in The GitHub Actions runners have pipx installed, so you can easily build in
+2 -2
View File
@@ -172,13 +172,13 @@
- name: pyzmq - name: pyzmq
gh: zeromq/pyzmq gh: zeromq/pyzmq
ci: [github, circleci] ci: [github]
os: [windows, apple, linux] os: [windows, apple, linux]
ci_config: .github/workflows/wheels.yml ci_config: .github/workflows/wheels.yml
notes: | notes: |
Python bindings for zeromq, the networking library. Python bindings for zeromq, the networking library.
Uses Cython on CPython and CFFI on PyPy. Uses Cython on CPython and CFFI on PyPy.
ARM wheels for linux are built natively on CircleCI. ARM wheels for linux are built natively on GitHub Actions.
- name: python-rapidjson - name: python-rapidjson
gh: python-rapidjson/python-rapidjson gh: python-rapidjson/python-rapidjson
+3 -3
View File
@@ -110,7 +110,7 @@ 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.2.1 uses: pypa/cibuildwheel@v3.3.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.
@@ -132,7 +132,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.2.1 cibuildwheel==3.3.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:
@@ -297,7 +297,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.2.1 --output-dir wheelhouse pipx run cibuildwheel==3.3.1 --output-dir wheelhouse
pipx run twine upload wheelhouse/*.whl pipx run twine upload wheelhouse/*.whl
``` ```
+53 -13
View File
@@ -474,12 +474,13 @@ You can use "build\[uv\]", which will use an external [uv][] everywhere
possible, both through `--installer=uv` passed to build, as well as when making possible, both through `--installer=uv` passed to build, as well as when making
all build and test environments. This will generally speed up cibuildwheel. all build and test environments. This will generally speed up cibuildwheel.
Make sure you have an external uv on Windows and macOS, either by Make sure you have an external uv on Windows and macOS, either by
pre-installing it, or installing cibuildwheel with the uv extra, pre-installing it, or installing cibuildwheel with the `uv` extra, which is
`cibuildwheel[uv]`. uv currently does not support Windows on ARM, possible by manually passing `cibuildwheel[uv]` to installers or by using the
musllinux on s390x, Android, or iOS. Legacy dependencies like `extras` option in the [cibuildwheel action](ci-services.md#github-actions).
setuptools on Python < 3.12 and pip are not installed if using uv. uv currently does not support iOS or musllinux on s390x. Legacy dependencies
like setuptools on Python < 3.12 and pip are not installed if using uv.
On Android and Pyodide, only "build" is supported. On Android and Pyodide, the "pip" frontend is not supported.
You can specify extra arguments to pass to the build frontend using the You can specify extra arguments to pass to the build frontend using the
optional `args` option. optional `args` option.
@@ -572,6 +573,7 @@ A list of environment variables to set during the build and test phases. Bash sy
You must use this variable to pass variables to Linux builds, since they execute in a container. It also works for the other platforms. You must use this variable to pass variables to Linux builds, since they execute in a container. It also works for the other platforms.
You can use `$PATH` syntax to insert other variables, or the `$(pwd)` syntax to insert the output of other shell commands. You can use `$PATH` syntax to insert other variables, or the `$(pwd)` syntax to insert the output of other shell commands.
Variables are evaluated in the order they appear. Any variable referenced before it is set will evaluate to an empty string.
To specify more than one environment variable, separate the assignments by spaces. To specify more than one environment variable, separate the assignments by spaces.
@@ -757,9 +759,9 @@ Platform-specific environment variables also available:<br/>
here.](https://yaml-multiline.info). here.](https://yaml-multiline.info).
Note that `manylinux_2_31` builds occur inside a Debian derivative docker Note that `manylinux_2_31`/`manylinux_2_35` builds occur inside a Debian derivative docker
container, where `manylinux2014` builds occur inside a CentOS one. So for container, where `manylinux2014` builds occur inside a CentOS one. So for
`manylinux_2_31` the `before-all` command must use `apt-get -y` `manylinux_2_31`/`manylinux_2_35` the `before-all` command must use `apt-get -y`
instead. instead.
### `before-build` {: #before-build env-var toml} ### `before-build` {: #before-build env-var toml}
@@ -905,6 +907,8 @@ The following placeholders must be used inside the command and will be replaced
- `{dest_dir}` for the absolute path of the directory where to create the repaired wheel - `{dest_dir}` for the absolute path of the directory where to create the repaired wheel
- `{delocate_archs}` (macOS only) comma-separated list of architectures in the wheel. - `{delocate_archs}` (macOS only) comma-separated list of architectures in the wheel.
You can use the `{package}` or `{project}` placeholders in your `repair-wheel-command` to refer to the package being built or the project root, respectively.
The command is run in a shell, so you can run multiple commands like `cmd1 && cmd2`. The command is run in a shell, so you can run multiple commands like `cmd1 && cmd2`.
Platform-specific environment variables are also available:<br/> Platform-specific environment variables are also available:<br/>
@@ -1034,7 +1038,7 @@ Set the Docker image to be used for building [manylinux / musllinux](https://git
For `manylinux-*-image`, except `manylinux-armv7l-image` and `manylinux-riscv64-image`, the value of this option can either be set to `manylinux2014`, `manylinux_2_28` or `manylinux_2_34` to use a pinned version of the [official manylinux images](https://github.com/pypa/manylinux). Alternatively, set these options to any other valid Docker image name. For `manylinux-*-image`, except `manylinux-armv7l-image` and `manylinux-riscv64-image`, the value of this option can either be set to `manylinux2014`, `manylinux_2_28` or `manylinux_2_34` to use a pinned version of the [official manylinux images](https://github.com/pypa/manylinux). Alternatively, set these options to any other valid Docker image name.
For `manylinux-armv7l-image`, the value of this option can either be set to `manylinux_2_31` or a custom image. Support is experimental for now. The `manylinux_2_31` value is only available for `armv7`. For `manylinux-armv7l-image`, the value of this option can either be set to `manylinux_2_31`, `manylinux_2_35` or a custom image. Support is experimental for now. The `manylinux_2_31` and `manylinux_2_35` values are only available for `armv7`.
For `manylinux-riscv64-image`, the value of this option can either be set to `manylinux_2_39` or a custom image. Support is experimental for now. The `manylinux_2_39` value is only available for `riscv64`. For `manylinux-riscv64-image`, the value of this option can either be set to `manylinux_2_39` or a custom image. Support is experimental for now. The `manylinux_2_39` value is only available for `riscv64`.
@@ -1317,7 +1321,7 @@ The available Pyodide versions are determined by the version of `pyodide-build`
### `test-command` {: #test-command env-var toml} ### `test-command` {: #test-command env-var toml}
> The command to test each built wheel > The command to test each built wheel
Shell command to run tests after the build. The wheel will be installed Command to run tests after the build. The wheel will be installed
automatically and available for import from the tests. If this variable is not automatically and available for import from the tests. If this variable is not
set, your wheel will not be installed after building. set, your wheel will not be installed after building.
@@ -1345,11 +1349,12 @@ tree. To access your test code, you have a couple of options:
On all platforms other than Android and iOS, the command is run in a shell, so you can write things like `cmd1 && cmd2`. On all platforms other than Android and iOS, the command is run in a shell, so you can write things like `cmd1 && cmd2`.
On Android and iOS, the command is parsed by `shlex.split`, and is required to On Android and iOS, the command is parsed by `shlex.split`, and must be a Python
be in one of the following forms: command:
* `python -c command ...` (Android only) * On Android, the command must must begin with `python` or `python3`, and contain `-m`
* `python -m module-name ...` or `-c`.
* On iOS, the command must begin with `python -m`.
Platform-specific environment variables are also available:<br/> Platform-specific environment variables are also available:<br/>
`CIBW_TEST_COMMAND_MACOS` | `CIBW_TEST_COMMAND_WINDOWS` | `CIBW_TEST_COMMAND_LINUX` | `CIBW_TEST_COMMAND_ANDROID` | `CIBW_TEST_COMMAND_IOS` | `CIBW_TEST_COMMAND_PYODIDE` `CIBW_TEST_COMMAND_MACOS` | `CIBW_TEST_COMMAND_WINDOWS` | `CIBW_TEST_COMMAND_LINUX` | `CIBW_TEST_COMMAND_ANDROID` | `CIBW_TEST_COMMAND_IOS` | `CIBW_TEST_COMMAND_PYODIDE`
@@ -1668,6 +1673,41 @@ Platform-specific environment variables are also available:<br/>
CIBW_TEST_ENVIRONMENT: PYTHONSAFEPATH=1 CIBW_TEST_ENVIRONMENT: PYTHONSAFEPATH=1
``` ```
### `test-runtime` {: #test-runtime toml env-var }
> Controls how the tests will be executed.
On desktop environments, the tests are executed on the same machine/container as the wheel was built. However on Android and iOS, the tests are run inside a virtual machine a simulator or emulator representing the target.
For these embedded platforms, a testbed project is used to run the tests. The `test-runtime` setting can define an `args` key that defines additional arguments that will be used when starting the testbed project.
Platform-specific environment variables are also available:<br/>
`CIBW_TEST_RUNTIME_ANDROID` |`CIBW_TEST_RUNTIME_IOS`
#### Examples
!!! tab examples "pyproject.toml"
```toml
[tool.cibuildwheel.ios]
# Run the tests on an iPhone 16e simulator running iOS 18.5.
test-runtime = { args = ["--simulator='iPhone 16e,OS=18.5'"] }
[tool.cibuildwheel.android]
# Run the Android tests on the minimum supported Android version.
test-runtime = { args = ["--managed", "minVersion"] }
```
!!! tab examples "Environment variables"
```yaml
# Run the tests on an iPhone 16e simulator running iOS 18.5.
CIBW_TEST_RUNTIME_IOS: "args: --simulator='iPhone 16e,OS=18.5'"
# Run the Android tests on the minimum supported Android version.
CIBW_TEST_RUNTIME_ANDROID: "args: --managed minVersion"
```
## Debugging ## Debugging
+6 -2
View File
@@ -23,7 +23,7 @@ The only side effect to your system will be docker images being pulled.
Linux wheels are built in [`manylinux`/`musllinux` containers](https://github.com/pypa/manylinux) to provide binary compatible wheels on Linux, according to [PEP 600](https://www.python.org/dev/peps/pep-0600/) / [PEP 656](https://www.python.org/dev/peps/pep-0656/). Because of this, when building with `cibuildwheel` on Linux, a few things should be taken into account: Linux wheels are built in [`manylinux`/`musllinux` containers](https://github.com/pypa/manylinux) to provide binary compatible wheels on Linux, according to [PEP 600](https://www.python.org/dev/peps/pep-0600/) / [PEP 656](https://www.python.org/dev/peps/pep-0656/). Because of this, when building with `cibuildwheel` on Linux, a few things should be taken into account:
- Programs and libraries are not installed on the CI runner host, but rather should be installed inside the container - using `yum` for `manylinux2014`, `apt-get` for `manylinux_2_31`, `dnf` for `manylinux_2_28` and `apk` for `musllinux_1_1` or `musllinux_1_2`, or manually. The same goes for environment variables that are potentially needed to customize the wheel building. - Programs and libraries are not installed on the CI runner host, but rather should be installed inside the container - using `yum` for `manylinux2014`, `apt-get` for `manylinux_2_31` or `manylinux_2_35`, `dnf` for `manylinux_2_28` and `apk` for `musllinux_1_1` or `musllinux_1_2`, or manually. The same goes for environment variables that are potentially needed to customize the wheel building.
`cibuildwheel` supports this by providing the [`environment`](options.md#environment) and [`before-all`](options.md#before-all) options to setup the build environment inside the running container. `cibuildwheel` supports this by providing the [`environment`](options.md#environment) and [`before-all`](options.md#before-all) options to setup the build environment inside the running container.
@@ -233,6 +233,8 @@ machine for example, if you're building on an ARM64 machine, then you can te
ARM64 wheel. Wheels of other architectures can still be built, but testing will ARM64 wheel. Wheels of other architectures can still be built, but testing will
automatically be skipped. automatically be skipped.
Any arguments specified using [`test-runtime`](options.md#test-runtime) will be passed as arguments to the Python script that starts the [testbed project](https://github.com/python/cpython/blob/main/Android/README.md#testing). cibuildwheel will automatically start the testbed project with `--site-packages` and `--cwd` arguments matching your test environment, as well as enabling verbose output with `-v` if [`build-verbosity`](options.md#build-verbosity) is enabled. The most common additional arguments to use will be `--managed minVersion` or `--managed maxVersion`, specifying the use of a managed Android emulator with the minimum or maximum supported Android version; or `--connected <serial>`, specifying the use of an existing booted Android emulator or device. By default, the testbed project will run with `--managed maxVersion`.
Running an emulator requires the build machine to either be bare-metal or support Running an emulator requires the build machine to either be bare-metal or support
nested virtualization. CI platforms known to meet this requirement are: nested virtualization. CI platforms known to meet this requirement are:
@@ -320,4 +322,6 @@ If tests have been configured, the test suite will be executed on the simulator
The iOS test environment can't support running shell scripts, so the [`test-command`](options.md#test-command) value must be specified as if it were a command line being passed to `python -m ...`. The iOS test environment can't support running shell scripts, so the [`test-command`](options.md#test-command) value must be specified as if it were a command line being passed to `python -m ...`.
The test process uses the same testbed used by CPython itself to run the CPython test suite. It is an Xcode project that has been configured to have a single Xcode "XCUnit" test - the result of which reports the success or failure of running `python -m <test-command>`. The test process uses the [same testbed used by CPython itself](https://github.com/python/cpython/tree/main/Apple/iOS#testing-python-on-ios) to run the CPython test suite. It is an Xcode project that has been configured to have a single Xcode "XCUnit" test - the result of which reports the success or failure of running `python -m <test-command>`.
Any arguments specified using [`test-runtime`](options.md#test-runtime) will be passed as arguments to the Python script that starts the testbed project. The testbed project will be started with `-v` enabling verbose output if [`build-verbosity`](options.md#build-verbosity) is enabled; the most common additional argument to use will be `--simulator`, which allows the specification of a specific device or iOS version for the test simulator. By default, the testbed project will attempt to find an "SE class" simulator (i.e., an iPhone SE, iPhone 16e, or similar), running the newest iOS version available.
+11 -11
View File
@@ -31,8 +31,8 @@ title: Working examples
| [cmake][] | ![github icon][] ![travisci icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Multitagged binary builds for all supported platforms, using cibw 2 config configuration. | | [cmake][] | ![github icon][] ![travisci icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Multitagged binary builds for all supported platforms, using cibw 2 config configuration. |
| [pyinstrument][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Python profiler with a C extension. No external dependencies. | | [pyinstrument][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Python profiler with a C extension. No external dependencies. |
| [scikit-image][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Image processing library. Uses cibuildwheel to build and test a project that uses Cython with platform-native code. | | [scikit-image][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Image processing library. Uses cibuildwheel to build and test a project that uses Cython with platform-native code. |
| [PyOxidizer][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | A modern Python application packaging and distribution tool |
| [cvxpy][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | A Python-embedded modeling language for convex optimization problems. | | [cvxpy][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | A Python-embedded modeling language for convex optimization problems. |
| [PyOxidizer][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | A modern Python application packaging and distribution tool |
| [twisted-iocpsupport][] | ![github icon][] | ![windows icon][] | A submodule of Twisted that hooks into native C APIs using Cython. | | [twisted-iocpsupport][] | ![github icon][] | ![windows icon][] | A submodule of Twisted that hooks into native C APIs using Cython. |
| [pedalboard][] | ![github icon][] | ![windows icon][] ![linux icon][] ![apple icon][] | A Python library for working with audio data and audio plugins by wrapping the [JUCE](https://github.com/juce-framework/JUCE/) C++ framework. Uses cibuildwheel to deploy on as many operating systems and Python versions as possible with only one dependency (any NumPy). | | [pedalboard][] | ![github icon][] | ![windows icon][] ![linux icon][] ![apple icon][] | A Python library for working with audio data and audio plugins by wrapping the [JUCE](https://github.com/juce-framework/JUCE/) C++ framework. Uses cibuildwheel to deploy on as many operating systems and Python versions as possible with only one dependency (any NumPy). |
| [River][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | 🌊 Online machine learning in Python | | [River][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | 🌊 Online machine learning in Python |
@@ -42,7 +42,7 @@ title: Working examples
| [Dependency Injector][] | ![travisci icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Dependency injection framework for Python, uses Windows TravisCI | | [Dependency Injector][] | ![travisci icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Dependency injection framework for Python, uses Windows TravisCI |
| [UltraJSON][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Ultra fast JSON decoder and encoder written in C with Python bindings | | [UltraJSON][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Ultra fast JSON decoder and encoder written in C with Python bindings |
| [CTranslate2][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Includes libraries from the [Intel oneAPI toolkit](https://www.intel.com/content/www/us/en/developer/tools/oneapi/base-toolkit.html) and CUDA kernels compiled for multiple GPU architectures. | | [CTranslate2][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Includes libraries from the [Intel oneAPI toolkit](https://www.intel.com/content/www/us/en/developer/tools/oneapi/base-toolkit.html) and CUDA kernels compiled for multiple GPU architectures. |
| [pyzmq][] | ![github icon][] ![circleci icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Python bindings for zeromq, the networking library. Uses Cython on CPython and CFFI on PyPy. ARM wheels for linux are built natively on CircleCI. | | [pyzmq][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Python bindings for zeromq, the networking library. Uses Cython on CPython and CFFI on PyPy. ARM wheels for linux are built natively on GitHub Actions. |
| [Implicit][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Includes GPU support for linux wheels | | [Implicit][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Includes GPU support for linux wheels |
| [tinyobjloader][] | ![azurepipelines icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Tiny but powerful single file wavefront obj loader | | [tinyobjloader][] | ![azurepipelines icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Tiny but powerful single file wavefront obj loader |
| [vispy][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Main repository for Vispy | | [vispy][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Main repository for Vispy |
@@ -55,13 +55,13 @@ title: Working examples
| [numexpr][] | ![github icon][] ![travisci icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Fast numerical array expression evaluator for Python, NumPy, Pandas, PyTables and more | | [numexpr][] | ![github icon][] ![travisci icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Fast numerical array expression evaluator for Python, NumPy, Pandas, PyTables and more |
| [Wrapt][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | A Python module for decorators, wrappers and monkey patching. | | [Wrapt][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | A Python module for decorators, wrappers and monkey patching. |
| [h5py][] | ![azurepipelines icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | HDF5 for Python -- The h5py package is a Pythonic interface to the HDF5 binary data format. | | [h5py][] | ![azurepipelines icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | HDF5 for Python -- The h5py package is a Pythonic interface to the HDF5 binary data format. |
| [envd][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | A machine learning development environment build tool |
| [Psycopg 3][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | A modern implementation of a PostgreSQL adapter for Python | | [Psycopg 3][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | A modern implementation of a PostgreSQL adapter for Python |
| [envd][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | A machine learning development environment build tool |
| [OpenColorIO][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | A color management framework for visual effects and animation. | | [OpenColorIO][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | A color management framework for visual effects and animation. |
| [ruptures][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Extensive Cython + NumPy [pyproject.toml](https://github.com/deepcharles/ruptures/blob/master/pyproject.toml) example. | | [ruptures][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Extensive Cython + NumPy [pyproject.toml](https://github.com/deepcharles/ruptures/blob/master/pyproject.toml) example. |
| [aioquic][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | QUIC and HTTP/3 implementation in Python | | [aioquic][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | QUIC and HTTP/3 implementation in Python |
| [SimpleJSON][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | simplejson is a simple, fast, extensible JSON encoder/decoder for Python |
| [OpenTimelineIO][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Open Source API and interchange format for editorial timeline information. | | [OpenTimelineIO][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Open Source API and interchange format for editorial timeline information. |
| [SimpleJSON][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | simplejson is a simple, fast, extensible JSON encoder/decoder for Python |
| [PyTables][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | A Python package to manage extremely large amounts of data | | [PyTables][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | A Python package to manage extremely large amounts of data |
| [google neuroglancer][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | WebGL-based viewer for volumetric data | | [google neuroglancer][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | WebGL-based viewer for volumetric data |
| [Parselmouth][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | A Python interface to the Praat software package, using pybind11, C++17 and CMake, with the core Praat static library built only once and shared between wheels. | | [Parselmouth][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | A Python interface to the Praat software package, using pybind11, C++17 and CMake, with the core Praat static library built only once and shared between wheels. |
@@ -77,8 +77,8 @@ title: Working examples
| [KDEpy][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Kernel Density Estimation in Python | | [KDEpy][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Kernel Density Estimation in Python |
| [dd-trace-py][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Uses custom alternate arch emulation on GitHub | | [dd-trace-py][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Uses custom alternate arch emulation on GitHub |
| [tgcalls][] | ![github icon][] | ![apple icon][] ![windows icon][] | Python `pybind11` binding to Telegram's WebRTC library with third party dependencies like `OpenSSL`, `MozJPEG`, `FFmpeg`, etc. | | [tgcalls][] | ![github icon][] | ![apple icon][] ![windows icon][] | Python `pybind11` binding to Telegram's WebRTC library with third party dependencies like `OpenSSL`, `MozJPEG`, `FFmpeg`, etc. |
| [pybind11 python_example][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Example pybind11 module built with a Python-based build system |
| [sourmash][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Quickly search, compare, and analyze genomic and metagenomic data sets. | | [sourmash][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Quickly search, compare, and analyze genomic and metagenomic data sets. |
| [pybind11 python_example][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Example pybind11 module built with a Python-based build system |
| [python-rapidjson][] | ![travisci icon][] ![gitlab icon][] | ![windows icon][] ![linux icon][] | Python wrapper around rapidjson | | [python-rapidjson][] | ![travisci icon][] ![gitlab icon][] | ![windows icon][] ![linux icon][] | Python wrapper around rapidjson |
| [abess][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | A fast best-subset selection library. It uses cibuildwheel to build a large project with C++ extensions. | | [abess][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | A fast best-subset selection library. It uses cibuildwheel to build a large project with C++ extensions. |
| [python-snappy][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Python bindings for the snappy google library | | [python-snappy][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Python bindings for the snappy google library |
@@ -97,8 +97,8 @@ title: Working examples
| [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 |
| [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 |
| [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. |
| [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. | | [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. |
| [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 |
| [pybind11 scikit_build_example][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | An example combining scikit-build and pybind11 | | [pybind11 scikit_build_example][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | An example combining scikit-build and pybind11 |
| [fathon][] | ![travisci icon][] | ![apple icon][] ![linux icon][] | python package for DFA (Detrended Fluctuation Analysis) and related algorithms | | [fathon][] | ![travisci icon][] | ![apple icon][] ![linux icon][] | python package for DFA (Detrended Fluctuation Analysis) and related algorithms |
@@ -142,8 +142,8 @@ title: Working examples
[cmake]: https://github.com/scikit-build/cmake-python-distributions [cmake]: https://github.com/scikit-build/cmake-python-distributions
[pyinstrument]: https://github.com/joerick/pyinstrument [pyinstrument]: https://github.com/joerick/pyinstrument
[scikit-image]: https://github.com/scikit-image/scikit-image [scikit-image]: https://github.com/scikit-image/scikit-image
[PyOxidizer]: https://github.com/indygreg/PyOxidizer
[cvxpy]: https://github.com/cvxpy/cvxpy [cvxpy]: https://github.com/cvxpy/cvxpy
[PyOxidizer]: https://github.com/indygreg/PyOxidizer
[twisted-iocpsupport]: https://github.com/twisted/twisted-iocpsupport [twisted-iocpsupport]: https://github.com/twisted/twisted-iocpsupport
[pedalboard]: https://github.com/spotify/pedalboard [pedalboard]: https://github.com/spotify/pedalboard
[River]: https://github.com/online-ml/river [River]: https://github.com/online-ml/river
@@ -166,13 +166,13 @@ title: Working examples
[numexpr]: https://github.com/pydata/numexpr [numexpr]: https://github.com/pydata/numexpr
[Wrapt]: https://github.com/GrahamDumpleton/wrapt [Wrapt]: https://github.com/GrahamDumpleton/wrapt
[h5py]: https://github.com/h5py/h5py [h5py]: https://github.com/h5py/h5py
[envd]: https://github.com/tensorchord/envd
[Psycopg 3]: https://github.com/psycopg/psycopg [Psycopg 3]: https://github.com/psycopg/psycopg
[envd]: https://github.com/tensorchord/envd
[OpenColorIO]: https://github.com/AcademySoftwareFoundation/OpenColorIO [OpenColorIO]: https://github.com/AcademySoftwareFoundation/OpenColorIO
[ruptures]: https://github.com/deepcharles/ruptures [ruptures]: https://github.com/deepcharles/ruptures
[aioquic]: https://github.com/aiortc/aioquic [aioquic]: https://github.com/aiortc/aioquic
[SimpleJSON]: https://github.com/simplejson/simplejson
[OpenTimelineIO]: https://github.com/AcademySoftwareFoundation/OpenTimelineIO [OpenTimelineIO]: https://github.com/AcademySoftwareFoundation/OpenTimelineIO
[SimpleJSON]: https://github.com/simplejson/simplejson
[PyTables]: https://github.com/PyTables/PyTables [PyTables]: https://github.com/PyTables/PyTables
[google neuroglancer]: https://github.com/google/neuroglancer [google neuroglancer]: https://github.com/google/neuroglancer
[Parselmouth]: https://github.com/YannickJadoul/Parselmouth [Parselmouth]: https://github.com/YannickJadoul/Parselmouth
@@ -188,8 +188,8 @@ title: Working examples
[KDEpy]: https://github.com/tommyod/KDEpy [KDEpy]: https://github.com/tommyod/KDEpy
[dd-trace-py]: https://github.com/DataDog/dd-trace-py [dd-trace-py]: https://github.com/DataDog/dd-trace-py
[tgcalls]: https://github.com/MarshalX/tgcalls [tgcalls]: https://github.com/MarshalX/tgcalls
[pybind11 python_example]: https://github.com/pybind/python_example
[sourmash]: https://github.com/sourmash-bio/sourmash [sourmash]: https://github.com/sourmash-bio/sourmash
[pybind11 python_example]: https://github.com/pybind/python_example
[python-rapidjson]: https://github.com/python-rapidjson/python-rapidjson [python-rapidjson]: https://github.com/python-rapidjson/python-rapidjson
[abess]: https://github.com/abess-team/abess [abess]: https://github.com/abess-team/abess
[python-snappy]: https://github.com/intake/python-snappy [python-snappy]: https://github.com/intake/python-snappy
@@ -208,8 +208,8 @@ title: Working examples
[streaming-form-data]: https://github.com/siddhantgoel/streaming-form-data [streaming-form-data]: https://github.com/siddhantgoel/streaming-form-data
[pybase64]: https://github.com/mayeut/pybase64 [pybase64]: https://github.com/mayeut/pybase64
[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
[Imagecodecs (fork)]: https://github.com/czaki/imagecodecs_build [Imagecodecs (fork)]: https://github.com/czaki/imagecodecs_build
[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
[pybind11 scikit_build_example]: https://github.com/pybind/scikit_build_example [pybind11 scikit_build_example]: https://github.com/pybind/scikit_build_example
[fathon]: https://github.com/stfbnc/fathon [fathon]: https://github.com/stfbnc/fathon
+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.2.1 pip3 install cibuildwheel==3.3.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.2.1 python3 -m pip install cibuildwheel==3.3.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.2.1 pip install cibuildwheel==3.3.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.2.1 python3 -m pip install --user cibuildwheel==3.3.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.2.1 python3 -m pip install --user cibuildwheel==3.3.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.2.1 pip3 install cibuildwheel==3.3.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.2.1 - python -m pip install cibuildwheel==3.3.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.2.1 - python -m pip install cibuildwheel==3.3.1
run_cibuildwheel_script: run_cibuildwheel_script:
- cibuildwheel - cibuildwheel
wheels_artifacts: wheels_artifacts:
+1 -1
View File
@@ -51,7 +51,7 @@ jobs:
- uses: actions/checkout@v5 - uses: actions/checkout@v5
- name: Build wheels - name: Build wheels
uses: pypa/cibuildwheel@v3.2.1 uses: pypa/cibuildwheel@v3.3.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
@@ -15,7 +15,7 @@ jobs:
- uses: actions/checkout@v5 - uses: actions/checkout@v5
- name: Build wheels - name: Build wheels
uses: pypa/cibuildwheel@v3.2.1 uses: pypa/cibuildwheel@v3.3.1
# env: # env:
# CIBW_SOME_OPTION: value # CIBW_SOME_OPTION: value
# ... # ...
+1 -1
View File
@@ -15,7 +15,7 @@ jobs:
- uses: actions/checkout@v5 - uses: actions/checkout@v5
- name: Build wheels - name: Build wheels
run: pipx run cibuildwheel==3.2.1 run: pipx run cibuildwheel==3.3.1
- uses: actions/upload-artifact@v4 - uses: actions/upload-artifact@v4
with: with:
+1 -1
View File
@@ -21,7 +21,7 @@ jobs:
platforms: all platforms: all
- name: Build wheels - name: Build wheels
uses: pypa/cibuildwheel@v3.2.1 uses: pypa/cibuildwheel@v3.3.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.2.1 - python -m pip install cibuildwheel==3.3.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.2.1 - py -m pip install cibuildwheel==3.3.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.2.1 - python3 -m pip install cibuildwheel==3.3.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.2.1 - python -m pip install cibuildwheel==3.3.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:
+1 -1
View File
@@ -20,7 +20,7 @@ jobs:
- ln -s /c/Python312/python.exe /c/Python312/python3.exe - ln -s /c/Python312/python.exe /c/Python312/python3.exe
install: install:
- python3 -m pip install cibuildwheel==3.2.1 - python3 -m pip install cibuildwheel==3.3.1
script: script:
# build the wheels, put them into './dist' # build the wheels, put them into './dist'
+1 -1
View File
@@ -26,7 +26,7 @@ jobs:
- ln -s /c/Python312/python.exe /c/Python312/python3.exe - ln -s /c/Python312/python.exe /c/Python312/python3.exe
install: install:
- python3 -m pip install cibuildwheel==3.2.1 - python3 -m pip install cibuildwheel==3.3.1
script: script:
# build the wheels, put them into './wheelhouse' # build the wheels, put them into './wheelhouse'
+2 -2
View File
@@ -52,7 +52,7 @@ jobs:
- stage: deploy - stage: deploy
name: Build and deploy Linux wheels name: Build and deploy Linux wheels
services: docker services: docker
install: python3 -m pip install cibuildwheel==3.2.1 twine install: python3 -m pip install cibuildwheel==3.3.1 twine
script: python3 -m cibuildwheel --output-dir wheelhouse script: python3 -m cibuildwheel --output-dir wheelhouse
after_success: python3 -m twine upload --skip-existing wheelhouse/*.whl after_success: python3 -m twine upload --skip-existing wheelhouse/*.whl
# Deploy on windows # Deploy on windows
@@ -60,7 +60,7 @@ jobs:
name: Build and deploy Windows wheels name: Build and deploy Windows wheels
os: windows os: windows
language: shell language: shell
install: python3 -m pip install cibuildwheel==3.2.1 twine install: python3 -m pip install cibuildwheel==3.3.1 twine
script: python3 -m cibuildwheel --output-dir wheelhouse script: python3 -m cibuildwheel --output-dir wheelhouse
after_success: python3 -m twine upload --skip-existing wheelhouse/*.whl after_success: python3 -m twine upload --skip-existing wheelhouse/*.whl
+12 -6
View File
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
[project] [project]
name = "cibuildwheel" name = "cibuildwheel"
version = "3.2.1" version = "3.3.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"
@@ -79,13 +79,10 @@ bin = [
docs = [ docs = [
"jinja2>=3.1.2", "jinja2>=3.1.2",
"mkdocs-include-markdown-plugin==6.2.2", "mkdocs-include-markdown-plugin==6.2.2",
"mkdocs-macros-plugin", "mkdocs-macros-plugin>=1.4.1",
"mkdocs==1.6.1", "mkdocs==1.6.1",
"pymdown-extensions", "pymdown-extensions",
"rich", "rich",
# transitive dep of mkdocs-macros-plugin
# https://github.com/fralau/mkdocs-macros-plugin/issues/269
"requests",
] ]
test = [ test = [
"build", "build",
@@ -113,7 +110,7 @@ addopts = ["-ra", "--showlocals", "--strict-markers", "--strict-config", "--xdoc
junit_family = "xunit2" junit_family = "xunit2"
xfail_strict = true xfail_strict = true
filterwarnings = ["error"] filterwarnings = ["error"]
log_cli_level = "INFO" log_level = "INFO"
markers = [ markers = [
"serial: tests that must *not* be run in parallel (deselect with '-m \"not serial\"')", "serial: tests that must *not* be run in parallel (deselect with '-m \"not serial\"')",
"ios: tests that run on iOS", "ios: tests that run on iOS",
@@ -219,6 +216,15 @@ extend-select = [
"EXE", # flake8-executable "EXE", # flake8-executable
"PYI", # flake8-pyi "PYI", # flake8-pyi
"PERF101", "PERF102", "PERF401", "PERF402", "PERF403", # A selection of perflint codes "PERF101", "PERF102", "PERF401", "PERF402", "PERF403", # A selection of perflint codes
"DTZ", # flake8-datetimez
"FA", # flake8-future-annotations
"FLY", # flynt
"FURB", # refurb
"LOG", # flake8-logging
"Q", # flake8-quotes
"SLOT", # flake8-slots
"T10", # flake8-debugger
"TC", # flake8-type-checking
] ]
ignore = [ ignore = [
"PLR", # Design related pylint codes "PLR", # Design related pylint codes
+20
View File
@@ -0,0 +1,20 @@
import sys
import sysconfig
from pathlib import Path
assert sys.platform == "android"
assert sysconfig.get_platform().startswith("android-")
android_prefix = Path(f"{sys.prefix}/../python/prefix").resolve()
assert android_prefix.is_dir()
vars = sysconfig.get_config_vars()
assert vars["INCLUDEDIR"] == f"{android_prefix}/include"
assert vars["LDVERSION"] == f"{sys.version_info[0]}.{sys.version_info[1]}{sys.abiflags}"
assert vars["INCLUDEPY"] == f"{vars['INCLUDEDIR']}/python{vars['LDVERSION']}"
assert vars["LIBDIR"] == f"{android_prefix}/lib"
assert vars["Py_ENABLE_SHARED"] == 1
paths = sysconfig.get_paths()
assert paths["include"] == vars["INCLUDEPY"]
assert paths["platinclude"] == vars["INCLUDEPY"]
+27 -7
View File
@@ -154,19 +154,39 @@ def docker_warmup_fixture(
@pytest.fixture(params=["pip", "build"]) @pytest.fixture(params=["pip", "build"])
def build_frontend_env_nouv(request: pytest.FixtureRequest) -> dict[str, str]: def build_frontend_env_nouv(request: pytest.FixtureRequest) -> dict[str, str]:
frontend = request.param frontend = request.param
if get_platform() == "pyodide" and frontend == "pip": marks = {m.name for m in request.node.iter_markers()}
platform = "pyodide" if "pyodide" in marks else get_platform()
if platform == "pyodide" and frontend == "pip":
pytest.skip("Can't use pip as build frontend for pyodide platform") pytest.skip("Can't use pip as build frontend for pyodide platform")
return {"CIBW_BUILD_FRONTEND": frontend} return {"CIBW_BUILD_FRONTEND": frontend}
@pytest.fixture @pytest.fixture(params=["pip", "build", "build[uv]"])
def build_frontend_env(build_frontend_env_nouv: dict[str, str]) -> dict[str, str]: def build_frontend_env(request: pytest.FixtureRequest) -> dict[str, str]:
frontend = build_frontend_env_nouv["CIBW_BUILD_FRONTEND"] frontend = request.param
if frontend != "build" or get_platform() == "pyodide" or find_uv() is None: marks = {m.name for m in request.node.iter_markers()}
return build_frontend_env_nouv if "android" in marks:
platform = "android"
elif "ios" in marks:
platform = "ios"
elif "pyodide" in marks:
platform = "pyodide"
else:
platform = get_platform()
return {"CIBW_BUILD_FRONTEND": "build[uv]"} if platform in {"pyodide", "ios", "android"} and frontend == "pip":
pytest.skip(f"Can't use pip as build frontend for {platform}")
if platform == "pyodide" and frontend == "build[uv]":
pytest.skip("Can't use uv with pyodide yet")
uv_path = find_uv()
if uv_path is None and frontend == "build[uv]":
pytest.skip("Can't find uv, so skipping uv tests")
if uv_path is not None and frontend == "build" and platform not in {"android", "ios"}:
pytest.skip("No need to check build when uv is present")
return {"CIBW_BUILD_FRONTEND": frontend}
@pytest.fixture @pytest.fixture
+87 -53
View File
@@ -32,22 +32,25 @@ if (platform.system(), platform.machine()) not in [
allow_module_level=True, allow_module_level=True,
) )
# Detect CI services which have the Android SDK pre-installed. # Azure Pipelines does not set the CI variable.
ci_supports_build = ( ci = any(key in os.environ for key in ["CI", "TF_BUILD"])
("CIRRUS_CI" in os.environ and platform.system() == "Darwin")
or "GITHUB_ACTIONS" in os.environ
or "TF_BUILD" in os.environ # Azure Pipelines
)
if "ANDROID_HOME" not in os.environ: if "ANDROID_HOME" not in os.environ:
msg = "ANDROID_HOME environment variable is not set" msg = "ANDROID_HOME environment variable is not set"
if ci_supports_build:
# Fail if we're on a CI service which is supposed to have the Android SDK
# pre-installed; otherwise skip the module.
if (
("CIRRUS_CI" in os.environ and platform.system() == "Darwin")
or "GITHUB_ACTIONS" in os.environ
or "TF_BUILD" in os.environ
):
pytest.fail(msg) pytest.fail(msg)
else: else:
pytest.skip(msg, allow_module_level=True) pytest.skip(msg, allow_module_level=True)
# 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.
ci_supports_emulator = "GITHUB_ACTIONS" in os.environ and platform.system() == "Linux" supports_emulator = (not ci) or ("GITHUB_ACTIONS" in os.environ and platform.system() == "Linux")
def needs_emulator(test): def needs_emulator(test):
@@ -55,7 +58,7 @@ def needs_emulator(test):
# 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)
if ci_supports_build and not ci_supports_emulator: if not supports_emulator:
test = pytest.mark.skip("This CI platform doesn't support the emulator")(test) test = pytest.mark.skip("This CI platform doesn't support the emulator")(test)
return test return test
@@ -92,27 +95,40 @@ def test_android_home(tmp_path, capfd):
assert "ANDROID_HOME environment variable is not set" in capfd.readouterr().err assert "ANDROID_HOME environment variable is not set" in capfd.readouterr().err
# the first build can fail to setup - mark as flaky, and serial to make sure it runs first # android-env.sh may need to install the NDK, and it isn't safe to do that multiple
# times in parallel. So make sure there's at least one test which gets as far as doing
# 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.
@pytest.mark.serial @pytest.mark.serial
@pytest.mark.flaky(reruns=2) def test_expected_wheels(tmp_path, spam_env):
def test_expected_wheels(tmp_path): # Since this test covers all Python versions, check the cross venv.
new_c_project().generate(tmp_path) test_module = "_cross_venv_test_android"
wheels = cibuildwheel_run(tmp_path, add_env={"CIBW_PLATFORM": "android"}) project = new_c_project(setup_py_add=f"import {test_module}")
project.files[f"{test_module}.py"] = (Path(__file__).parent / f"{test_module}.py").read_text()
project.generate(tmp_path)
# Build wheels for all Python versions on the current architecture.
del spam_env["CIBW_BUILD"]
if not supports_emulator:
del spam_env["CIBW_TEST_COMMAND"]
wheels = cibuildwheel_run(tmp_path, add_env=spam_env)
assert wheels == expected_wheels( assert wheels == expected_wheels(
"spam", "0.1.0", platform="android", machine_arch=native_arch.android_abi "spam", "0.1.0", platform="android", machine_arch=native_arch.android_abi
) )
def test_frontend_good(tmp_path): @needs_emulator
def test_frontend_good(tmp_path, build_frontend_env):
new_c_project().generate(tmp_path) new_c_project().generate(tmp_path)
wheels = cibuildwheel_run( wheels = cibuildwheel_run(
tmp_path, tmp_path,
add_env={**cp313_env, "CIBW_BUILD_FRONTEND": "build"}, add_env={**cp313_env, **build_frontend_env, "CIBW_TEST_COMMAND": "python -m site"},
) )
assert wheels == [f"spam-0.1.0-cp313-cp313-android_21_{native_arch.android_abi}.whl"] assert wheels == [f"spam-0.1.0-cp313-cp313-android_21_{native_arch.android_abi}.whl"]
@pytest.mark.parametrize("frontend", ["build[uv]", "pip"]) @pytest.mark.parametrize("frontend", ["pip"])
def test_frontend_bad(frontend, tmp_path, capfd): def test_frontend_bad(frontend, tmp_path, capfd):
new_c_project().generate(tmp_path) new_c_project().generate(tmp_path)
with pytest.raises(CalledProcessError): with pytest.raises(CalledProcessError):
@@ -222,12 +238,20 @@ def spam_env(tmp_path):
print("Spam test passed") print("Spam test passed")
""" """
) )
project.files["test_empty.py"] = dedent(
"""\
def test_empty():
pass
"""
)
project.generate(tmp_path) project.generate(tmp_path)
return { return {
**cp313_env, **cp313_env,
"CIBW_TEST_SOURCES": "test_spam.py", "CIBW_TEST_SOURCES": "test_spam.py test_empty.py",
"CIBW_TEST_REQUIRES": "pytest==8.3.5", "CIBW_TEST_REQUIRES": "pytest==8.3.5",
"CIBW_TEST_COMMAND": "python -m pytest",
} }
@@ -235,7 +259,8 @@ def spam_env(tmp_path):
@pytest.mark.parametrize( @pytest.mark.parametrize(
("command", "expected_output"), ("command", "expected_output"),
[ [
("python -c 'import test_spam; test_spam.test_spam()'", "Spam test passed"), ("python3 -c 'import test_spam; test_spam.test_spam()'", "Spam test passed"),
("python -m pytest", "=== 2 passed in "),
("python -m pytest test_spam.py", "=== 1 passed in "), ("python -m pytest test_spam.py", "=== 1 passed in "),
("pytest test_spam.py", "=== 1 passed in "), ("pytest test_spam.py", "=== 1 passed in "),
], ],
@@ -252,27 +277,25 @@ def test_test_command_good(command, expected_output, tmp_path, spam_env, capfd):
) in stderr ) in stderr
BAD_FORMAT_ERROR = (
"Test command '{}' is not supported on Android. "
"Command must begin with 'python' or 'python3', and contain '-m' or '-c'."
)
BAD_PLACEHOLDER_ERROR = (
"Test command '{}' with a '{{project}}' or '{{package}}' placeholder "
"is not supported on Android"
)
@needs_emulator @needs_emulator
@pytest.mark.parametrize( @pytest.mark.parametrize(
("command", "expected_output"), ("command", "expected_output"),
[ [
# Build-time failure: unrecognized command # Build-time failure
( ("./test_spam.py", BAD_FORMAT_ERROR.format("./test_spam.py")),
"./test_spam.py", ("python test_spam.py", BAD_FORMAT_ERROR.format("python test_spam.py")),
"Test command './test_spam.py' is not supported on Android. " ("pytest {project}", BAD_PLACEHOLDER_ERROR.format("pytest {project}")),
"Supported commands are 'python -m' and 'python -c'.", ("pytest {package}", BAD_PLACEHOLDER_ERROR.format("pytest {package}")),
),
# Build-time failure: unrecognized placeholder
(
"pytest {project}",
"Test command 'pytest {project}' with a '{project}' or '{package}' "
"placeholder is not supported on Android",
),
(
"pytest {package}",
"Test command 'pytest {package}' with a '{project}' or '{package}' "
"placeholder is not supported on Android",
),
# Runtime failure # Runtime failure
("pytest test_ham.py", "not found: test_ham.py"), ("pytest test_ham.py", "not found: test_ham.py"),
], ],
@@ -283,6 +306,29 @@ def test_test_command_bad(command, expected_output, tmp_path, spam_env, capfd):
assert expected_output in capfd.readouterr().err assert expected_output in capfd.readouterr().err
@needs_emulator
@pytest.mark.parametrize(
("options", "expected"),
[
("", 0),
("-E", 1),
],
)
def test_test_command_python_options(options, expected, tmp_path, capfd):
project = new_c_project()
project.generate(tmp_path)
command = 'import sys; print(f"{sys.flags.ignore_environment=}")'
cibuildwheel_run(
tmp_path,
add_env={
**cp313_env,
"CIBW_TEST_COMMAND": f"python {options} -c '{command}'",
},
)
assert f"sys.flags.ignore_environment={expected}" in capfd.readouterr().out
@needs_emulator @needs_emulator
def test_package_subdir(tmp_path, spam_env, capfd): def test_package_subdir(tmp_path, spam_env, capfd):
spam_paths = list(tmp_path.iterdir()) spam_paths = list(tmp_path.iterdir())
@@ -291,17 +337,11 @@ def test_package_subdir(tmp_path, spam_env, capfd):
for path in spam_paths: for path in spam_paths:
path.rename(package_dir / path.name) path.rename(package_dir / path.name)
test_filename = "package/" + spam_env["CIBW_TEST_SOURCES"] spam_env["CIBW_TEST_SOURCES"] = " ".join(
cibuildwheel_run( f"package/{path}" for path in spam_env["CIBW_TEST_SOURCES"].split()
tmp_path,
package_dir,
add_env={
**spam_env,
"CIBW_TEST_SOURCES": test_filename,
"CIBW_TEST_COMMAND": f"python -m pytest {test_filename}",
},
) )
assert "=== 1 passed in " in capfd.readouterr().out cibuildwheel_run(tmp_path, package_dir, add_env=spam_env)
assert "=== 2 passed in " in capfd.readouterr().out
@needs_emulator @needs_emulator
@@ -346,13 +386,7 @@ def test_environment_markers(tmp_path):
**cp313_env, **cp313_env,
"CIBW_TEST_COMMAND": f"python -m pytest {test_filename}", "CIBW_TEST_COMMAND": f"python -m pytest {test_filename}",
"CIBW_TEST_SOURCES": test_filename, "CIBW_TEST_SOURCES": test_filename,
"CIBW_TEST_REQUIRES": " ".join( "CIBW_TEST_REQUIRES": "pytest certifi;sys_platform=='android' platformdirs;sys_platform!='android'",
[
"pytest",
"certifi;sys_platform=='android'",
"platformdirs;sys_platform!='android'",
]
),
}, },
) )
+40
View File
@@ -1,4 +1,5 @@
import subprocess import subprocess
import textwrap
from contextlib import nullcontext as does_not_raise from contextlib import nullcontext as does_not_raise
import pytest import pytest
@@ -56,3 +57,42 @@ def test(tmp_path, capfd):
# We only produced one wheel (perhaps Pyodide) # We only produced one wheel (perhaps Pyodide)
# check that it has the right name # check that it has the right name
assert result[0].startswith("spam-0.1.0-py2-none-") assert result[0].startswith("spam-0.1.0-py2-none-")
@pytest.mark.parametrize(
"repair_command",
[
"python repair.py {wheel} {dest_dir}",
"python {package}/repair.py {wheel} {dest_dir}",
"python {project}/repair.py {wheel} {dest_dir}",
],
ids=["no-placeholder", "package-placeholder", "project-placeholder"],
)
def test_repair_wheel_command_structure(tmp_path, repair_command):
project_dir = tmp_path / "project"
project = test_projects.new_c_project()
project.files["repair.py"] = textwrap.dedent("""
import shutil
import sys
from pathlib import Path
wheel = Path(sys.argv[1])
dest_dir = Path(sys.argv[2])
dest_dir.mkdir(parents=True, exist_ok=True)
shutil.copy(wheel, dest_dir / "spamrepaired-0.0.1-py-none-any.whl")
""")
# Combined test for repair wheel command formats (plain, {package}, {project})
project.generate(project_dir)
result = utils.cibuildwheel_run(
project_dir,
add_env={
"CIBW_REPAIR_WHEEL_COMMAND": repair_command,
"CIBW_ARCHS": "native",
},
single_python=True,
)
assert result == ["spamrepaired-0.0.1-py-none-any.whl"]
+78 -54
View File
@@ -1,5 +1,7 @@
import json
import platform import platform
import re import re
import subprocess
import textwrap import textwrap
from pathlib import Path from pathlib import Path
@@ -9,40 +11,62 @@ from cibuildwheel.util import resources
from . import test_projects, utils from . import test_projects, utils
project_with_expected_version_checks = test_projects.new_c_project( VERSION_REGEX = r"([\w-]+)==([^\s]+)"
setup_py_add=textwrap.dedent(
r"""
import subprocess
import os
import sys
versions_output_text = subprocess.check_output( CHECK_VERSIONS_SCRIPT = """\
[sys.executable, '-m', 'pip', 'freeze', '--all', '-qq'], '''
universal_newlines=True, Checks that the versions in the env var EXPECTED_VERSIONS match those
) installed in the active venv.
versions = versions_output_text.strip().splitlines() '''
import os, subprocess, sys, json
# `versions` now looks like: versions_raw = json.loads(
# ['pip==x.x.x', 'setuptools==x.x.x', 'wheel==x.x.x'] subprocess.check_output([
sys.executable, '-m', 'pip', 'list', '--format=json',
print('Gathered versions', versions) ], text=True)
expected_version = os.environ['EXPECTED_PIP_VERSION']
assert f'pip=={expected_version}' in versions, (
f'error: pip version should equal {expected_version}'
)
"""
)
) )
versions = {item['name']: item['version'] for item in versions_raw}
expected_versions = json.loads(os.environ['EXPECTED_VERSIONS'])
project_with_expected_version_checks.files["pyproject.toml"] = r""" for name, expected_version in expected_versions.items():
[build-system] if name not in versions:
requires = ["setuptools", "pip"] continue
build-backend = "setuptools.build_meta" if versions[name] != expected_version:
raise SystemExit(f'error: {name} version should equal {expected_version}. Versions: {versions}')
""" """
VERSION_REGEX = r"([\w-]+)==([^\s]+)"
def test_check_versions_script(tmp_path, build_frontend_env_nouv, capfd):
if utils.get_platform() == "linux":
pytest.skip("we don't test dependency versions on linux, refer to other tests")
# sanity check that the CHECK_VERSIONS_SCRIPT fails when it should
project_dir = tmp_path / "project"
test_projects.new_c_project().generate(project_dir)
expected_versions = {
"pip": "0.0.1",
"build": "0.0.2",
}
script = project_dir / "check_versions.py"
script.write_text(CHECK_VERSIONS_SCRIPT)
with pytest.raises(subprocess.CalledProcessError):
utils.cibuildwheel_run(
project_dir,
add_env={
"CIBW_BEFORE_BUILD": f"python {script.name}",
"EXPECTED_VERSIONS": json.dumps(expected_versions),
**build_frontend_env_nouv,
},
)
captured = capfd.readouterr()
assert (
"error: pip version should equal 0.0.1" in captured.err
or "error: build version should equal 0.0.2" in captured.err
)
def get_versions_from_constraint_file(constraint_file: Path) -> dict[str, str]: def get_versions_from_constraint_file(constraint_file: Path) -> dict[str, str]:
@@ -65,11 +89,15 @@ def test_pinned_versions(tmp_path, python_version, build_frontend_env_nouv):
pytest.skip(f"Windows ARM64 does not support Python {python_version}") pytest.skip(f"Windows ARM64 does not support Python {python_version}")
project_dir = tmp_path / "project" project_dir = tmp_path / "project"
project_with_expected_version_checks.generate(project_dir) test_projects.new_c_project().generate(project_dir)
# read the expected versions from the appropriate constraint file
version_no_dot = python_version.replace(".", "") version_no_dot = python_version.replace(".", "")
build_environment = {}
build_pattern = f"[cp]p{version_no_dot}-*" # create cross-platform Python before-build script to verify versions pre-build
before_build_script = project_dir / "check_versions.py"
before_build_script.write_text(CHECK_VERSIONS_SCRIPT)
if utils.get_platform() == "pyodide": if utils.get_platform() == "pyodide":
constraint_filename = f"constraints-pyodide{version_no_dot}.txt" constraint_filename = f"constraints-pyodide{version_no_dot}.txt"
else: else:
@@ -77,16 +105,13 @@ def test_pinned_versions(tmp_path, python_version, build_frontend_env_nouv):
constraint_file = resources.PATH / constraint_filename constraint_file = resources.PATH / constraint_filename
constraint_versions = get_versions_from_constraint_file(constraint_file) constraint_versions = get_versions_from_constraint_file(constraint_file)
build_environment["EXPECTED_PIP_VERSION"] = constraint_versions["pip"] # build and test the wheels (dependency version check occurs before-build)
cibw_environment_option = " ".join(f"{k}={v}" for k, v in build_environment.items())
# build and test the wheels
actual_wheels = utils.cibuildwheel_run( actual_wheels = utils.cibuildwheel_run(
project_dir, project_dir,
add_env={ add_env={
"CIBW_BUILD": build_pattern, "CIBW_BUILD": f"[cp]p{version_no_dot}-*",
"CIBW_ENVIRONMENT": cibw_environment_option, "CIBW_BEFORE_BUILD": f"python {before_build_script.name}",
"EXPECTED_VERSIONS": json.dumps(constraint_versions),
**build_frontend_env_nouv, **build_frontend_env_nouv,
}, },
) )
@@ -107,10 +132,11 @@ def test_dependency_constraints(method, tmp_path, build_frontend_env_nouv):
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")
project_dir = tmp_path / "project" project_dir = tmp_path / "project"
project_with_expected_version_checks.generate(project_dir) test_projects.new_c_project().generate(project_dir)
tool_versions = { tool_versions = {
"pip": "23.1.2", "pip": "23.1.2",
"build": "1.2.2",
"delocate": "0.10.3", "delocate": "0.10.3",
} }
@@ -120,6 +146,7 @@ def test_dependency_constraints(method, tmp_path, build_frontend_env_nouv):
textwrap.dedent( textwrap.dedent(
""" """
pip=={pip} pip=={pip}
build=={build}
delocate=={delocate} delocate=={delocate}
""".format(**tool_versions) """.format(**tool_versions)
) )
@@ -133,7 +160,7 @@ def test_dependency_constraints(method, tmp_path, build_frontend_env_nouv):
msg = f"Unknown method: {method}" msg = f"Unknown method: {method}"
raise ValueError(msg) raise ValueError(msg)
build_environment = {} skip = ""
if ( if (
utils.get_platform() == "windows" utils.get_platform() == "windows"
@@ -144,32 +171,29 @@ def test_dependency_constraints(method, tmp_path, build_frontend_env_nouv):
# from a virtualenv seeded executable. See # from a virtualenv seeded executable. See
# https://github.com/oracle/graalpython/issues/491 and remove this once # https://github.com/oracle/graalpython/issues/491 and remove this once
# GraalPy 24 is dropped # GraalPy 24 is dropped
build_frontend_env_nouv["CIBW_SKIP"] = "gp311*" skip = "gp311*"
for package_name, version in tool_versions.items(): # cross-platform Python script for dependency constraint checks
env_name = f"EXPECTED_{package_name.upper()}_VERSION" before_build_script = project_dir / "check_versions.py"
build_environment[env_name] = version before_build_script.write_text(CHECK_VERSIONS_SCRIPT)
cibw_environment_option = " ".join(f"{k}={v}" for k, v in build_environment.items()) # build and test the wheels (dependency version check occurs pre-build)
# build and test the wheels
actual_wheels = utils.cibuildwheel_run( actual_wheels = utils.cibuildwheel_run(
project_dir, project_dir,
add_env={ add_env={
"CIBW_ENVIRONMENT": cibw_environment_option, "CIBW_SKIP": skip,
"CIBW_DEPENDENCY_VERSIONS": dependency_version_option, "CIBW_DEPENDENCY_VERSIONS": dependency_version_option,
"CIBW_BEFORE_BUILD": f"python {before_build_script.name}",
"EXPECTED_VERSIONS": json.dumps(tool_versions),
**build_frontend_env_nouv, **build_frontend_env_nouv,
}, },
single_python=True,
) )
# also check that we got the right wheels # also check that we got the right wheels
expected_wheels = utils.expected_wheels("spam", "0.1.0") expected_wheels = utils.expected_wheels("spam", "0.1.0", single_python=True)
if ( if skip == "gp*":
utils.get_platform() == "windows"
and method == "file"
and build_frontend_env_nouv["CIBW_BUILD_FRONTEND"] == "build"
):
# See reference to https://github.com/oracle/graalpython/issues/491 # See reference to https://github.com/oracle/graalpython/issues/491
# above # above
expected_wheels = [w for w in expected_wheels if "graalpy311" not in w] expected_wheels = [w for w in expected_wheels if "graalpy311" not in w]
+2 -2
View File
@@ -84,7 +84,7 @@ def test(manylinux_image, tmp_path):
"CIBW_MANYLINUX_PYPY_I686_IMAGE": manylinux_image, "CIBW_MANYLINUX_PYPY_I686_IMAGE": manylinux_image,
} }
if platform.machine() == "aarch64": if platform.machine() == "aarch64":
# We just have a manylinux_2_31 image for armv7l # We just have a manylinux_2_31/manylinux_2_35 image for armv7l
add_env["CIBW_ARCHS"] = "aarch64" add_env["CIBW_ARCHS"] = "aarch64"
actual_wheels = utils.cibuildwheel_run(project_dir, add_env=add_env) actual_wheels = utils.cibuildwheel_run(project_dir, add_env=add_env)
@@ -100,7 +100,7 @@ def test(manylinux_image, tmp_path):
) )
if platform.machine() == "aarch64": if platform.machine() == "aarch64":
# We just have a manylinux_2_31 image for armv7l # We just have a manylinux_2_31/manylinux_2_35 image for armv7l
expected_wheels = [w for w in expected_wheels if "armv7l" not in w] expected_wheels = [w for w in expected_wheels if "armv7l" not in w]
assert set(actual_wheels) == set(expected_wheels) assert set(actual_wheels) == set(expected_wheels)
+5
View File
@@ -628,6 +628,11 @@ def test_multiarch_image(container_engine, platform):
'{"Client":{"Version":"24.0.0","ApiVersion":"1.43"},"Server":{"ApiVersion":"1.43"}}', '{"Client":{"Version":"24.0.0","ApiVersion":"1.43"},"Server":{"ApiVersion":"1.43"}}',
nullcontext(), nullcontext(),
), ),
(
"docker",
'{"Client":{"Version":"29.0.0","ApiVersion":"1.52"},"Server":{"APIVersion":"1.52"}}',
nullcontext(),
),
( (
"docker", "docker",
'{"Client":{"ApiVersion":"1.43"},"Server":{"ApiVersion":"1.30"}}', '{"Client":{"ApiVersion":"1.43"},"Server":{"ApiVersion":"1.30"}}',
+2 -2
View File
@@ -56,7 +56,7 @@ def test_build_default_launches(monkeypatch):
main() main()
build_in_container = typing.cast(mock.Mock, platforms.linux.build_in_container) build_in_container = typing.cast("mock.Mock", platforms.linux.build_in_container)
assert build_in_container.call_count == 4 assert build_in_container.call_count == 4
@@ -126,7 +126,7 @@ before-all = "true"
main() main()
build_in_container = typing.cast(mock.Mock, platforms.linux.build_in_container) build_in_container = typing.cast("mock.Mock", platforms.linux.build_in_container)
assert build_in_container.call_count == 7 assert build_in_container.call_count == 7
+34
View File
@@ -2,6 +2,7 @@ import os
import platform as platform_module import platform as platform_module
import textwrap import textwrap
import unittest.mock import unittest.mock
from collections.abc import Sequence
from pathlib import Path from pathlib import Path
from typing import Literal from typing import Literal
@@ -626,6 +627,39 @@ def test_get_build_frontend_extra_flags_warning(
mock_warning.assert_called_once() mock_warning.assert_called_once()
@pytest.mark.parametrize(
("definition", "expected_args"),
[
("", ()),
('test-runtime = ""', ()),
("test-runtime = {}", ()),
('test-runtime = {args = ""}', []),
('test-runtime = "args: --simulator foo"', ["--simulator", "foo"]),
('test-runtime = {args = ["--simulator", "foo"]}', ["--simulator", "foo"]),
],
)
def test_test_runtime_handling(
tmp_path: Path, definition: str, expected_args: Sequence[str] | None
) -> None:
args = CommandLineArguments.defaults()
args.package_dir = tmp_path
pyproject_toml: Path = tmp_path / "pyproject.toml"
pyproject_toml.write_text(
textwrap.dedent(
f"""\
[tool.cibuildwheel]
{definition}
"""
)
)
options = Options(platform="ios", command_line_arguments=args, env={})
local = options.build_options("cp313-ios_13_0_arm64_iphoneos")
assert local.test_runtime.args == expected_args
@pytest.mark.parametrize( @pytest.mark.parametrize(
("definition", "expected"), ("definition", "expected"),
[ [
+4 -1
View File
@@ -1,5 +1,5 @@
import shlex import shlex
from pathlib import Path from typing import TYPE_CHECKING
import pytest import pytest
@@ -13,6 +13,9 @@ from cibuildwheel.options import (
_resolve_cascade, _resolve_cascade,
) )
if TYPE_CHECKING:
from pathlib import Path
PYPROJECT_1 = """ PYPROJECT_1 = """
[tool.cibuildwheel] [tool.cibuildwheel]
build = "cp39*" build = "cp39*"