Compare commits

...
121 Commits
Author SHA1 Message Date
Joe Rickerby 355c5a46b2 Fix PATH manipulation in action.yml 2025-12-21 16:05:43 +00:00
Joe Rickerby bc79c16a71 Another approach to the uv installation question
Don't get clever about it at all, instead make uv on PATH a hard
requirement.
2025-12-19 17:20:39 +00:00
cibuildwheel-bot[bot]andcibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com> 90422f1824 [Bot] Update dependencies (#2692)
Update dependencies

Co-authored-by: cibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com>
2025-12-15 23:38:01 -05:00
pre-commit-ci[bot]andpre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> 986d80b3d7 [pre-commit.ci] pre-commit autoupdate (#2694)
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.14.8 → v0.14.9](https://github.com/astral-sh/ruff-pre-commit/compare/v0.14.8...v0.14.9)
- [github.com/pre-commit/mirrors-mypy: v1.19.0 → v1.19.1](https://github.com/pre-commit/mirrors-mypy/compare/v1.19.0...v1.19.1)
- [github.com/python-jsonschema/check-jsonschema: 0.35.0 → 0.36.0](https://github.com/python-jsonschema/check-jsonschema/compare/0.35.0...0.36.0)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2025-12-15 23:37:41 -05:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> 5acadc2dfc chore(deps): bump the actions group with 3 updates (#2693)
Bumps the actions group with 3 updates: [actions/download-artifact](https://github.com/actions/download-artifact), [actions/upload-artifact](https://github.com/actions/upload-artifact) and [peter-evans/create-pull-request](https://github.com/peter-evans/create-pull-request).


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

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

Updates `peter-evans/create-pull-request` from 7 to 8
- [Release notes](https://github.com/peter-evans/create-pull-request/releases)
- [Commits](https://github.com/peter-evans/create-pull-request/compare/v7...v8)

---
updated-dependencies:
- dependency-name: actions/download-artifact
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: actions
- dependency-name: actions/upload-artifact
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: actions
- dependency-name: peter-evans/create-pull-request
  dependency-version: '8'
  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-12-15 20:31:18 +01:00
cibuildwheel-bot[bot]andcibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com> 6878a1baeb [Bot] Update dependencies (#2688)
Update dependencies

Co-authored-by: cibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com>
2025-12-09 00:11:05 -05:00
Malcolm Smith 7288bbed76 Update Android Python versions (#2687)
* Update Android Python versions

* Restore "free up disk space" step for non-Android jobs only
2025-12-09 00:10:36 -05:00
pre-commit-ci[bot]andpre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> 0cb04c05db [pre-commit.ci] pre-commit autoupdate (#2689)
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.14.7 → v0.14.8](https://github.com/astral-sh/ruff-pre-commit/compare/v0.14.7...v0.14.8)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2025-12-09 00:09:16 -05:00
Marco Sulla 3c2d5961de Added more infos about muslinux support of uv in options.md (#2675)
uv doesn't support also ppc64le and riscv64 for muslinux
2025-12-06 12:15:11 +01:00
pre-commit-ci[bot]pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>Henry Schreiner
6c7e3ee860 [pre-commit.ci] pre-commit autoupdate (#2680)
* [pre-commit.ci] pre-commit autoupdate

updates:
- [github.com/astral-sh/ruff-pre-commit: v0.14.6 → v0.14.7](https://github.com/astral-sh/ruff-pre-commit/compare/v0.14.6...v0.14.7)
- [github.com/pre-commit/mirrors-mypy: v1.18.2 → v1.19.0](https://github.com/pre-commit/mirrors-mypy/compare/v1.18.2...v1.19.0)

* chore: update for newer mypy

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

---------

Signed-off-by: Henry Schreiner <henryfs@princeton.edu>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Henry Schreiner <henryfs@princeton.edu>
2025-12-02 18:06:04 -05:00
cibuildwheel-bot[bot]andcibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com> df2ce29908 [Bot] Update dependencies (#2677)
Update dependencies

Co-authored-by: cibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com>
2025-12-02 12:22:25 -05:00
pre-commit-ci[bot]andpre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> 74a3c45b74 [pre-commit.ci] pre-commit autoupdate (#2674)
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.14.5 → v0.14.6](https://github.com/astral-sh/ruff-pre-commit/compare/v0.14.5...v0.14.6)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2025-11-28 15:52:36 +00:00
Eric Larson 9f991f2330 DOC: Document location in error message (#2669) 2025-11-28 15:48:44 +00:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> ea4b3eb6a5 chore(deps): bump actions/checkout from 5 to 6 in the actions group (#2672)
Bumps the actions group with 1 update: [actions/checkout](https://github.com/actions/checkout).


Updates `actions/checkout` from 5 to 6
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '6'
  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-11-24 11:28:39 -05:00
cibuildwheel-bot[bot]andcibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com> 6bc6700ab3 [Bot] Update dependencies (#2671)
Update dependencies

Co-authored-by: cibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com>
2025-11-24 10:56:53 -05:00
cibuildwheel-bot[bot]andcibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com> c314f9f07b [Bot] Update dependencies (#2665)
Update dependencies

Co-authored-by: cibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com>
2025-11-18 09:48:55 -05:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> dd81fa002c chore(deps): bump wntrblm/nox from 2025.10.16 to 2025.11.12 in the actions group (#2666)
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.10.16 to 2025.11.12
- [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.10.16...2025.11.12)

---
updated-dependencies:
- dependency-name: wntrblm/nox
  dependency-version: 2025.11.12
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: actions
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-18 09:48:43 -05:00
pre-commit-ci[bot]andpre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> 3658bf2f84 [pre-commit.ci] pre-commit autoupdate (#2667)
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.14.4 → v0.14.5](https://github.com/astral-sh/ruff-pre-commit/compare/v0.14.4...v0.14.5)
- [github.com/python-jsonschema/check-jsonschema: 0.34.1 → 0.35.0](https://github.com/python-jsonschema/check-jsonschema/compare/0.34.1...0.35.0)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2025-11-17 17:51:47 -05: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
Joe Rickerby 9c00cb4f6b Bump version: v3.2.1 2025-10-12 09:23:50 +01:00
cibuildwheel-bot[bot]andcibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com> ae65c7d85b [Bot] Update dependencies (#2614)
Update dependencies

Co-authored-by: cibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com>
2025-10-12 09:15:54 +01:00
pre-commit-ci[bot]pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>Henry Schreiner
86c3857999 [pre-commit.ci] pre-commit autoupdate (#2615)
* [pre-commit.ci] pre-commit autoupdate

updates:
- [github.com/astral-sh/ruff-pre-commit: v0.13.2 → v0.13.3](https://github.com/astral-sh/ruff-pre-commit/compare/v0.13.2...v0.13.3)

* Update .pre-commit-config.yaml

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Henry Schreiner <HenrySchreinerIII@gmail.com>
2025-10-08 10:51:31 -04:00
Marc Mueller 68b1a81bb2 docs: include free-threading builds in identifier list (#2617)
* doc: include free-threading builds in identifier list

* doc: update Python 3.13 as well
2025-10-08 10:51:13 -04:00
Marcelo DuarteandJoe Rickerby f131cd7935 fix: Python 3.14 on macOS requires MACOSX_DEPLOYMENT_TARGET set to 10.15 (#2613)
* Python 3.14 on macOS requires MACOSX_DEPLOYMENT_TARGET set to 10.15

* Update README.md

---------

Co-authored-by: Joe Rickerby <joerick@mac.com>
2025-10-08 10:50:57 -04:00
cibuildwheel-bot[bot]andcibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com> 8602e864d4 [Bot] Update dependencies (#2606)
Update dependencies

Co-authored-by: cibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com>
2025-10-02 14:41:35 -04:00
Russell Keith-Magee 8ccc2650de fix: resolve issues with macOS-15 runners (#2607)
* Update iOS support packages to use new-style Xcode runner.

* Explicitly set the Xcode version for macOS runners.

* Correct a download URL.

* Minor tweak to re-trigger CI.
2025-10-02 14:41:07 -04:00
pre-commit-ci[bot] c0c1dea51f [pre-commit.ci] pre-commit autoupdate (#2608) 2025-09-29 21:22:34 +02:00
Joe Rickerby 7c619efba9 Bump version: v3.2.0 2025-09-22 21:44:26 +01:00
cibuildwheel-bot[bot]andcibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com> bbebb68339 [Bot] Update dependencies (#2603)
Update dependencies

Co-authored-by: cibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com>
2025-09-22 21:25:51 +01:00
pre-commit-ci[bot]pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>Joe Rickerby
5bbeaf830f [pre-commit.ci] pre-commit autoupdate (#2604)
* [pre-commit.ci] pre-commit autoupdate

updates:
- [github.com/astral-sh/ruff-pre-commit: v0.13.0 → v0.13.1](https://github.com/astral-sh/ruff-pre-commit/compare/v0.13.0...v0.13.1)
- [github.com/pre-commit/mirrors-mypy: v1.18.1 → v1.18.2](https://github.com/pre-commit/mirrors-mypy/compare/v1.18.1...v1.18.2)
- [github.com/python-jsonschema/check-jsonschema: 0.33.3 → 0.34.0](https://github.com/python-jsonschema/check-jsonschema/compare/0.33.3...0.34.0)

* add requests to the docs dependencies

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Joe Rickerby <joerick@mac.com>
2025-09-22 21:24:22 +01:00
Tim Felgentreff 7a67c6b5a9 Add GraalPy 25 and remove workarounds for that version. (#2597) 2025-09-22 21:23:29 +01:00
Grzegorz BokotaandJoe Rickerby b8a4fbc237 Improve information about configuration overriding (#2598)
* Improve information about configuration overriding

* remove obsolete "

* Update docs/configuration.md

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

---------

Co-authored-by: Joe Rickerby <joerick@mac.com>
2025-09-21 10:23:45 +01:00
Agriya Khetarpal 70de033a7f Replace the macos-13 images with the macos-15-intel images (GHA) (#2601)
Replace `macos-13` images with `macos-15-intel`
2025-09-21 10:23:21 +01:00
cibuildwheel-bot[bot]andcibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com> ce4c16f88f [Bot] Update dependencies (#2602)
Update dependencies

Co-authored-by: cibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com>
2025-09-21 10:17:10 +01:00
Malcolm Smith 66490f0536 Add CMAKE_CROSSCOMPILING_EMULATOR to Android CMake toolchain (#2591) 2025-09-20 23:50:51 +01:00
pre-commit-ci[bot]andpre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> 77b9e35d7c [pre-commit.ci] pre-commit autoupdate (#2594)
updates:
- [github.com/pre-commit/mirrors-mypy: v1.17.1 → v1.18.1](https://github.com/pre-commit/mirrors-mypy/compare/v1.17.1...v1.18.1)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2025-09-16 17:20:34 +05:30
cibuildwheel-bot[bot]andcibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com> 39e9da06c5 [Bot] Update dependencies (#2593)
Update dependencies

Co-authored-by: cibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com>
2025-09-16 17:20:22 +05:30
Henry Schreiner 9b8ce87f0a chore: linting updates (#2585)
Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>
2025-09-14 19:44:45 +02:00
Joe Rickerby 3a524160c3 Fix a few bugs in run_example_ci_config tooling (#2577)
* Fix a few bugs in run_example_ci_config tooling

Github-deploy.yml had a fix to make it work out-of-the-box.

* Add flaky marker on test_ssl

(due to external internet access during the test, it does occasionally fail)
2025-09-08 17:54:55 -04:00
pre-commit-ci[bot]andpre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> c294bab5aa [pre-commit.ci] pre-commit autoupdate (#2584)
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.12.11 → v0.12.12](https://github.com/astral-sh/ruff-pre-commit/compare/v0.12.11...v0.12.12)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2025-09-08 17:54:44 -04:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> 5a4e49a734 chore(deps): bump the actions group across 1 directory with 2 updates (#2582)
Bumps the actions group with 2 updates in the / directory: [actions/setup-python](https://github.com/actions/setup-python) and [actions/attest-build-provenance](https://github.com/actions/attest-build-provenance).


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

Updates `actions/attest-build-provenance` from 2.4.0 to 3.0.0
- [Release notes](https://github.com/actions/attest-build-provenance/releases)
- [Changelog](https://github.com/actions/attest-build-provenance/blob/main/RELEASE.md)
- [Commits](https://github.com/actions/attest-build-provenance/compare/e8998f949152b193b063cb0ec769d69d929409be...977bb373ede98d70efdf65b84cb5f73e068dcc2a)

---
updated-dependencies:
- dependency-name: actions/setup-python
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: actions
- dependency-name: actions/attest-build-provenance
  dependency-version: 3.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: actions
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-08 16:24:05 +01:00
pre-commit-ci[bot]pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>Joe Rickerby
4aa10a9378 [pre-commit.ci] pre-commit autoupdate (#2579)
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.12.10 → v0.12.11](https://github.com/astral-sh/ruff-pre-commit/compare/v0.12.10...v0.12.11)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Joe Rickerby <joerick@mac.com>
2025-09-08 16:03:20 +01:00
Malcolm Smith c8fb268a1b Android test updates (#2575)
* Install the test environment while simulating Android

* Pass build-verbosity setting through to the test runner
2025-09-08 15:58:43 +01:00
Russell Keith-Magee 841e718dee Add documentation for test dependency groups on mobile platforms. (#2574) 2025-09-08 15:58:24 +01:00
Malcolm Smith 0826975570 Android updates (#2568)
* Add Python 3.14 for Android

* Simplify GitHub Actions workflows

* Update tests

* Allow running `patchelf` even when the environment's `bin` directory is not on the PATH

* Search in both the environment's bin directory and the PATH

* Use `sysconfig.get_path`

* Fix lint warning
2025-09-08 15:58:03 +01:00
Hugo van Kemenade 3f076ba487 Move PyPy 3.10 to pypy-eol (#2521)
* Move PyPy 3.10 to pypy-eol

* Refactor PyPy selection
2025-09-08 15:57:14 +01:00
cibuildwheel-bot[bot]andcibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com> dac57ccc94 [Bot] Update dependencies (#2581)
Update dependencies

Co-authored-by: cibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com>
2025-09-08 14:14:49 +01:00
cibuildwheel-bot[bot]cibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com>Joe Rickerbymayeut
1d31ef4ab2 [Bot] Update dependencies (#2578)
* Update dependencies

* Fix pytest-rerunfailures version constraint

* update docker images (remove default setuptools for GraalPy)

---------

Co-authored-by: cibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com>
Co-authored-by: Joe Rickerby <joerick@mac.com>
Co-authored-by: mayeut <mayeut@users.noreply.github.com>
2025-09-06 15:22:22 +01:00
pre-commit-ci[bot]andpre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> 03ce2f2bc7 [pre-commit.ci] pre-commit autoupdate (#2573)
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.12.9 → v0.12.10](https://github.com/astral-sh/ruff-pre-commit/compare/v0.12.9...v0.12.10)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2025-08-30 20:46:43 +01:00
cibuildwheel-bot[bot]andcibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com> 6331390c93 [Bot] Update dependencies (#2572)
Update dependencies

Co-authored-by: cibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com>
2025-08-26 08:45:04 -04:00
Russell Keith-Magee 4b92d69e1b Switch Azure Pipelines iOS image (#2563)
* Revert Azure iOS runners to macos-14.

* Add warning about known macos-15 issues on Github Actions and Azure.

* Update workflow reference with actual ticket.
2025-08-20 19:51:06 -04:00
Henry Schreiner c923d83ad9 Bump version: v3.1.4 2025-08-19 14:16:52 -04:00
Agriya Khetarpal 55ee8e49bf chore: bump to Pyodide 0.28.2 (#2562)
Bump to Pyodide 0.28.2
2025-08-19 14:14:10 -04:00
Agriya KhetarpalHenry Schreinerpre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
afe486c21f feat: add a --clean-cache command to clean up locations specified at CIBW_CACHE_PATH (#2489)
* Add `clean_cache` to command-line arguments

* Add `--clean-cache` to parser

* Add logic

* Add test to clean cache when it exists

* Ad test to run cache cleaning when none exists

* Add test to run cache cleaning on unwritable path

* Use `main()` instead

* tests: move command tests

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

* Create cibuildwheel cache sentinel file

* Add sentinel to existing tests + add new test

* Add signature and switch to `CACHEDIR.TAG`

Co-authored-by: Henry Schreiner <HenrySchreinerIII@gmail.com>

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

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

* Another instance to replace with `CACHEDIR.TAG`

* Verify `CACHEDIR.TAG` signature

* Simplify code branching and control flow

* Add test

* Add link to `CACHEDIR.TAG` specification

* Write with UTF-8 encoding

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

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

---------

Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>
Co-authored-by: Henry Schreiner <henryschreineriii@gmail.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2025-08-19 11:53:27 -04:00
pre-commit-ci[bot]andpre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> 1c1ba8a22e [pre-commit.ci] pre-commit autoupdate (#2561)
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.12.8 → v0.12.9](https://github.com/astral-sh/ruff-pre-commit/compare/v0.12.8...v0.12.9)
- [github.com/python-jsonschema/check-jsonschema: 0.33.2 → 0.33.3](https://github.com/python-jsonschema/check-jsonschema/compare/0.33.2...0.33.3)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2025-08-19 08:44:56 -04:00
Agriya Khetarpal 33b75f491a chore: extend CODEOWNERS file to include platform-specific constraints files (#2559)
* Add more files to CODEOWNERS

* Uncomment cibuildwheel-maintainers for the entire constraints

* Core maintainers are all watching the repo anyway
2025-08-18 11:15:45 -04:00
cibuildwheel-bot[bot]andcibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com> c59c2fe70d [Bot] Update dependencies (#2556)
Update dependencies

Co-authored-by: cibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com>
2025-08-18 11:15:00 -04:00
Agriya Khetarpal 24b64c5cd1 chore: update Pyodide constraints (#2558)
* chore: update Pyodide constraints

* Bump pyodide-lock, pyodide-build, auditwheel-emscripten
2025-08-18 11:14:43 -04:00
mara004 6425e48fed docs: minor doc link fix (#2560)
minor doc fix (configuration.md)
2025-08-18 11:14:13 -04:00
Russell Keith-Magee 0264b4d03a Revert to macOS-14 image for ARM64 iOS testing (#2557)
* Explicitly set the Xcode version on GitHub Actions.

* Revert to macOS-14 for now.
2025-08-18 11:13:47 -04:00
Joe Rickerby 68f9762657 chore: Use the virtualenv release URL rather than the blob URL (#2555) 2025-08-14 20:44:48 +02:00
Henry Schreiner 95e827ece1 chore: color and suggest_on_error are now default (3.14rc1+) (#2554)
Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>
2025-08-14 20:44:05 +02:00
Henry Schreiner ff9a284f21 fix: add patchelf requirement for android (#2552)
Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>
2025-08-13 08:52:44 -04:00
cade3864de ci: rework tests to break out ios/android tests (#2519)
* ci: rework tests to break out ios/android tests

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

* Apply suggestions from code review

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Apply suggestions from code review

* ci: fix check for wheels

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

* Update .github/workflows/test.yml

* tests: pass via flag instead of envvar

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

* tests: apply to serial/parallel

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

* tests: join together marks

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

* tests: join together marks

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

* ci: break up azure job

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

* ci: use matrix for azure pipelines

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

* Try installing Java on macos as well

* Revert "Try installing Java on macos as well"

This reverts commit aedf0f5106d2467938705b85180a0b249d49b99d.

* Try to get the most basic android test running first

* Rename platform to test_select, move headers in run_tests

Maybe it's a personal thing, but the header location was really making
me have to think more than I needed to look at that file!

* Only run docker unit tests on machines that are testing linux

* Update the flag name in azure-pipelines too

* Update azure-pipelines.yml

---------

Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Matthieu Darbois <mayeut@users.noreply.github.com>
Co-authored-by: Joe Rickerby <joerick@mac.com>
2025-08-13 08:52:27 -04:00
Joe Rickerby 63bdd4f043 docs: Improve docs on how to skip free-threaded builds (#2549)
* Improve docs on how to skip free-threaded builds

* Add a reference to the Python Free-Threading Guide
2025-08-12 13:57:18 -04:00
Jon CrallandJoe Rickerby 5952330610 tests: fix and enable doctests (#2546)
* fix doctest

* Update cibuildwheel/oci_container.py

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

* Update cibuildwheel/oci_container.py

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

* Update cibuildwheel/oci_container.py

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

* Add xdoctest to CI

* Add doctests to run tests

* Replace test map with new native method

* Forgot key for arm64

* Allow doctests to be filtered on circleci

---------

Co-authored-by: Joe Rickerby <joerick@mac.com>
2025-08-12 09:06:12 -04:00
dependabot[bot]dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>Joe Rickerby
8db3538534 chore(deps): bump the actions group with 2 updates (#2551)
* chore(deps): bump the actions group with 2 updates

Bumps the actions group with 2 updates: [actions/checkout](https://github.com/actions/checkout) and [actions/download-artifact](https://github.com/actions/download-artifact).


Updates `actions/checkout` from 4 to 5
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v4...v5)

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

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: actions
- dependency-name: actions/download-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>

* Update actions versions in documentation/examples

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Joe Rickerby <joerick@mac.com>
2025-08-12 09:03:34 -04:00
pre-commit-ci[bot]andpre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> e5caaec292 [pre-commit.ci] pre-commit autoupdate (#2550)
updates:
- [github.com/pre-commit/pre-commit-hooks: v5.0.0 → v6.0.0](https://github.com/pre-commit/pre-commit-hooks/compare/v5.0.0...v6.0.0)
- [github.com/astral-sh/ruff-pre-commit: v0.12.7 → v0.12.8](https://github.com/astral-sh/ruff-pre-commit/compare/v0.12.7...v0.12.8)
- [github.com/shellcheck-py/shellcheck-py: v0.10.0.1 → v0.11.0.1](https://github.com/shellcheck-py/shellcheck-py/compare/v0.10.0.1...v0.11.0.1)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2025-08-12 09:02:23 -04:00
cibuildwheel-bot[bot]andcibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com> 5a1712daed [Bot] Update dependencies (#2542)
Update dependencies

Co-authored-by: cibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com>
2025-08-12 10:27:06 +01:00
Matthieu Darbois a4c6d16811 fix: ignore empty CIBW_ARCHS (#2541) 2025-08-11 10:50:25 -04:00
Malcolm Smith 78a246a901 fix: correct Android CMAKE_FIND_ROOT_PATH_MODE_PACKAGE value (#2547)
Change Android CMAKE_FIND_ROOT_PATH_MODE_PACKAGE from ONLY to BOTH
2025-08-11 10:49:48 -04:00
Joe Rickerby 47c5a31c1b fix: pyodide build fails when dependency-versions is set (#2548)
Remove auditwheel-emscripten as a top-level dep
2025-08-11 10:48:27 -04:00
pre-commit-ci[bot]andpre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> 3ebb6bd942 [pre-commit.ci] pre-commit autoupdate (#2543)
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.12.5 → v0.12.7](https://github.com/astral-sh/ruff-pre-commit/compare/v0.12.5...v0.12.7)
- [github.com/pre-commit/mirrors-mypy: v1.17.0 → v1.17.1](https://github.com/pre-commit/mirrors-mypy/compare/v1.17.0...v1.17.1)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2025-08-05 12:25:11 -04:00
Henry Schreiner 352e01339f Bump version: v3.1.3 2025-08-01 12:38:46 -04:00
Henry Schreiner c463e56ba2 tests: another iOS flaky spot (#2539)
* tests: another iOS flaky spot

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

* tests: missing interceptions

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

---------

Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>
2025-08-01 12:32:01 -04:00
Vytautas Liuolia 8c5c738023 docs(project): add Falcon to working examples (#2538) 2025-07-31 12:26:27 -04:00
Henry Schreiner feeb3992a7 tests: add flaky test handling (#2527)
* chore: add flaky test handling

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

* Update test_android.py

---------

Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>
2025-07-31 12:26:17 -04:00
Henry Schreiner 60b9cc95db fix: never call pip directly (#2537)
You can't change the running process in Windows. In pip 25.2, the format of the generated file changes, so this now breaks if you try to update to the latest pip (which can happen if deps are unpinned).
2025-07-31 12:26:07 -04:00
Tim Felgentreff e2c7102ed7 chore: remove some GraalPy Windows workarounds. (#2501)
GraalPy made a release where pytest works on Windows
2025-07-31 00:31:23 -04:00
Henry Schreiner 9e4e50bd76 Bump version: v3.1.2 2025-07-29 09:12:51 -06:00
pre-commit-ci[bot]andpre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> 8ef9414f60 [pre-commit.ci] pre-commit autoupdate (#2532)
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.12.4 → v0.12.5](https://github.com/astral-sh/ruff-pre-commit/compare/v0.12.4...v0.12.5)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2025-07-28 16:06:41 -06:00
Joe Rickerby 1953c04972 Adding @mhsmith as platform maintainer for Android (#2516) 2025-07-28 13:00:54 -06:00
Russell Keith-Magee 46a6d27995 Bump iOS support package versions. (#2530) 2025-07-28 12:26:52 -06:00
cibuildwheel-bot[bot]andcibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com> 0dc0b48e4d [Bot] Update dependencies (#2529)
Update dependencies

Co-authored-by: cibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com>
2025-07-28 08:20:49 -06:00
Matthieu Darbois b887417e0e fix: enable all shall not enable cpython-experimental-riscv64 (#2528) 2025-07-27 23:18:35 -06:00
Matthieu Darbois 36c5079ce5 tests: reduce testing time on iOS (#2523)
A number of tests only require to run with a single version of python.
This will reduce the time needed to run those tests.
2025-07-27 23:15:55 -06:00
Matthieu Darbois 68c03665d3 feat: add deprecation warning for cpython-experimental-riscv64 enable (#2526) 2025-07-27 15:58:03 -04:00
Matthieu Darbois 1c38fac9c8 fix: invalid warning on test-skip = ["*-macosx_universal2:arm64"] (#2522) 2025-07-27 09:13:38 -04:00
Henry SchreinerandMatthieu Darbois 140bc1a96a tests: mark and add skips (#2524)
* tests: mark and add skips

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

* fix comment

---------

Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>
Co-authored-by: Matthieu Darbois <mayeut@users.noreply.github.com>
2025-07-27 12:12:42 +02:00
Henry Schreiner 55fcb25edc fix: error on CIBW_FREE_THREADED_SUPPORT set (#2520)
Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>
2025-07-26 19:09:26 +02:00
Clément Robertandmayeut c89609aaf2 BUG: fix incorrect number of wheels in logs (#2517)
* BUG: fix incorrect number of wheels in logs

* add a test

---------

Co-authored-by: mayeut <mayeut@users.noreply.github.com>
2025-07-26 13:13:01 +02:00
tabedzkiHenry SchreinerJoe Rickerbypre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
13b086e3c6 docs: clarify language around Python requirements for local cibuildwheel usage (#2513)
* First set of changes to setup.md

* Update docs/setup.md

Co-authored-by: Henry Schreiner <HenrySchreinerIII@gmail.com>

* Update docs/setup.md

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

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

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

---------

Co-authored-by: Henry Schreiner <HenrySchreinerIII@gmail.com>
Co-authored-by: Joe Rickerby <joerick@mac.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2025-07-25 00:46:16 -04:00
Malcolm Smith 302af02853 fix(android): execute wheel via sys.executable (#2515)
* Android: execute `wheel` via `sys.executable`

* Suppress unhelpful cyclic-import warning
2025-07-24 16:38:22 -04:00
Matthieu Darbois 9361af3204 feat: riscv64 builds are now enabled by default (#2509)
PyPI now accepts `riscv64` uploads for manylinux/musllinux.
Those builds do not require an opt-in anymore.
2025-07-24 14:52:07 -04:00
Malcolm Smith 47c5a35421 Add Cirrus macOS as a runner that supports building for Android but not testing (#2514)
* Add Cirrus macOS as a runner that supports building for Android but not testing

* Try to trigger Cirrus by changing .cirrus.yml
2025-07-24 14:51:39 -04:00
109 changed files with 2437 additions and 1357 deletions
+2 -2
View File
@@ -46,8 +46,8 @@ linux_aarch64_task:
<<: *RUN_TESTS
windows_x86_task:
# The task takes ~55 minutes while the timeout happens
# after 60 minutes by default, let's allow some wiggle room.
# The task takes ~55 minutes while the timeout happens after 60 minutes by default,
# let's allow some wiggle room.
timeout_in: 120m
windows_container:
image: cirrusci/windowsservercore:visualstudio2022
+5
View File
@@ -1,2 +1,7 @@
# Specification files for platform maintainers
cibuildwheel/platforms/ios.py @freakboy3742
cibuildwheel/platforms/pyodide.py @hoodmane @ryanking13 @agriyakhetarpal
cibuildwheel/platforms/android.py @mhsmith
# Constraints files
cibuildwheel/resources/constraints-pyodide*.txt @hoodmane @ryanking13 @agriyakhetarpal
+3 -3
View File
@@ -11,7 +11,7 @@ jobs:
dist:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- uses: hynek/build-and-inspect-python-package@v2
@@ -27,13 +27,13 @@ jobs:
attestations: write
steps:
- uses: actions/download-artifact@v4
- uses: actions/download-artifact@v7
with:
name: Packages
path: dist
- name: Generate artifact attestation for sdist and wheel
uses: actions/attest-build-provenance@e8998f949152b193b063cb0ec769d69d929409be # v2.4.0
uses: actions/attest-build-provenance@977bb373ede98d70efdf65b84cb5f73e068dcc2a # v3.0.0
with:
subject-path: "dist/cibuildwheel-*"
+77 -36
View File
@@ -37,8 +37,8 @@ jobs:
name: Linters (mypy, ruff, etc.)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
- uses: actions/checkout@v6
- uses: actions/setup-python@v6
id: python
with:
python-version: "3.x"
@@ -47,56 +47,84 @@ jobs:
run: pipx run --python "${{ steps.python.outputs.python-path }}" nox -s pylint -- --output-format=github
test:
name: Test on ${{ matrix.os }} (${{ matrix.python_version }})
name: Test on ${{ matrix.os }} (${{ matrix.python_version }}) ${{ matrix.test_select }}
needs: lint
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, ubuntu-24.04-arm, windows-latest, windows-11-arm, macos-13, macos-15]
python_version: ['3.13']
include:
# Min Python
- os: ubuntu-latest
python_version: '3.11'
# Max Python
- os: ubuntu-latest
python_version: '3.14'
- os: ubuntu-latest
python_version: '3.13'
test_select: android
- os: ubuntu-24.04-arm
python_version: '3.13'
- os: windows-latest
python_version: '3.13'
- os: windows-11-arm
python_version: '3.13'
- os: macos-15-intel
python_version: '3.13'
- os: macos-15
python_version: '3.13'
- os: macos-15-intel
python_version: '3.13'
test_select: ios
- os: macos-15
python_version: '3.13'
test_select: ios
# Exercise iOS on a non-default simulator.
test_runtime: 'args: --simulator "iPhone 16e,OS=18.5"'
- os: macos-15-intel
python_version: '3.13'
test_select: android
# Exercise Android on a non-default simulator
test_runtime: 'args: --managed minVersion'
- os: macos-15
python_version: '3.13'
test_select: android
timeout-minutes: 180
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
- uses: actions/checkout@v6
- uses: actions/setup-python@v6
name: Install Python ${{ matrix.python_version }}
with:
python-version: ${{ matrix.python_version }}
allow-prereleases: true
- uses: astral-sh/setup-uv@v6
- uses: astral-sh/setup-uv@v7
- name: Free up disk space
if: runner.os == 'Linux'
if: runner.os == 'Linux' && matrix.test_select != 'android'
run: |
docker system prune -a -f
sudo rm -rf $ANDROID_HOME/ndk/{26,28}.* /opt/hostedtoolcache/CodeQL \
sudo rm -rf $ANDROID_HOME/ndk /opt/hostedtoolcache/CodeQL \
/usr/local/lib/node_modules /usr/local/share/chromium \
/usr/local/share/powershell
df -h
# https://github.blog/changelog/2024-04-02-github-actions-hardware-accelerated-android-virtualization-now-available/
- name: Enable KVM for Android emulator
if: runner.os == 'Linux' && runner.arch == 'X64'
run: |
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
sudo udevadm control --reload-rules
sudo udevadm trigger --name-match=kvm
df -m
# for oci_container unit tests
- name: Set up QEMU
if: runner.os == 'Linux'
uses: docker/setup-qemu-action@v3
- name: Set up Xcode
if: ${{ startsWith(matrix.os, 'macos-15') }}
run: |
# GitHub recommends explicitly selecting the desired Xcode version
sudo xcode-select --switch /Applications/Xcode_16.4.app
- name: Install dependencies
run: |
uv sync --no-dev --group test
- uses: joerick/pr-labels-action@v1.0.9
- name: Set CIBW_ENABLE
shell: bash
run: |
@@ -127,29 +155,35 @@ jobs:
output-dir: wheelhouse
env:
CIBW_ARCHS_MACOS: x86_64 universal2 arm64
CIBW_BUILD_FRONTEND: 'build[uv]'
CIBW_BUILD_FRONTEND: ${{ matrix.test_select && 'build' || 'build[uv]' }}
CIBW_PLATFORM: ${{ matrix.test_select }}
CIBW_TEST_RUNTIME: ${{ matrix.test_runtime }}
- name: Run a sample build (GitHub Action, only)
uses: ./
if: matrix.test_select == ''
with:
package-dir: sample_proj
output-dir: wheelhouse_only
only: cp312-${{ runner.os == 'Linux' && (runner.arch == 'ARM64' && 'manylinux_aarch64' || 'manylinux_x86_64') || (runner.os == 'Windows' && 'win_amd64' || 'macosx_x86_64') }}
only: cp313-${{ runner.os == 'Linux' && (runner.arch == 'ARM64' && 'manylinux_aarch64' || 'manylinux_x86_64') || (runner.os == 'Windows' && 'win_amd64' || 'macosx_x86_64') }}
- name: Create custom configuration file
shell: bash
run: |
cat > sample_proj/cibw.toml <<EOF
[tool.cibuildwheel]
# Only build on CPython 3.12 on native arch
# Only build on CPython 3.13 on native arch
archs = ["native"]
build = "cp312-*"
build = "cp313-*"
# Skip musllinux
skip = "*-musllinux*"
EOF
- name: Run a sample build (GitHub Action, config-file)
uses: ./
env:
CIBW_PLATFORM: ${{ matrix.test_select }}
CIBW_TEST_RUNTIME: ${{ matrix.test_runtime }}
with:
package-dir: sample_proj
output-dir: wheelhouse_config_file
@@ -159,17 +193,24 @@ jobs:
shell: bash
run: |
test $(find wheelhouse -name '*.whl' | wc -l) -ge 1
test $(find wheelhouse_only -name '*.whl' | wc -l) -eq 1
test $(find wheelhouse_config_file -name '*.whl' | wc -l) -eq 1
- uses: actions/upload-artifact@v4
- name: Check Action artifacts (native build only)
if: matrix.test_select == ''
shell: bash
run: |
test $(find wheelhouse_only -name '*.whl' | wc -l) -eq 1
- uses: actions/upload-artifact@v6
with:
name: cibw-wheels-${{ matrix.os }}-${{ strategy.job-index }}
path: wheelhouse/*.whl
- name: Test cibuildwheel
env:
CIBW_TEST_RUNTIME: ${{ matrix.test_runtime }}
run: |
uv run --no-sync bin/run_tests.py ${{ (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' || '' }}
emulated-archs:
name: Get qemu emulated architectures
@@ -178,11 +219,11 @@ jobs:
outputs:
archs: ${{ steps.archs.outputs.archs }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
- uses: actions/checkout@v6
- uses: actions/setup-python@v6
with:
python-version: "3.x"
- uses: astral-sh/setup-uv@v6
- uses: astral-sh/setup-uv@v7
- name: Install dependencies
run: uv sync --no-dev --group test
- name: Get qemu emulated architectures
@@ -201,11 +242,11 @@ jobs:
matrix:
arch: ${{ fromJSON(needs.emulated-archs.outputs.archs) }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
- uses: actions/checkout@v6
- uses: actions/setup-python@v6
with:
python-version: "3.x"
- uses: astral-sh/setup-uv@v6
- uses: astral-sh/setup-uv@v7
- name: Install dependencies
run: uv sync --no-dev --group test
@@ -221,12 +262,12 @@ jobs:
runs-on: ubuntu-24.04
timeout-minutes: 180
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
- uses: actions/checkout@v6
- uses: actions/setup-python@v6
name: Install Python 3.12
with:
python-version: '3.12'
- uses: astral-sh/setup-uv@v6
- uses: astral-sh/setup-uv@v7
- name: Install dependencies
run: uv sync --no-dev --group test
+3 -3
View File
@@ -30,9 +30,9 @@ jobs:
app-id: ${{ secrets.CIBUILDWHEEL_BOT_APP_ID }}
private-key: ${{ secrets.CIBUILDWHEEL_BOT_APP_PRIVATE_KEY }}
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- uses: wntrblm/nox@2025.05.01
- uses: wntrblm/nox@2025.11.12
- name: "Run update: dependencies"
run: nox --force-color -s update_constraints
@@ -43,7 +43,7 @@ jobs:
- name: Create Pull Request
if: github.ref == 'refs/heads/main' && github.repository == 'pypa/cibuildwheel'
uses: peter-evans/create-pull-request@v7
uses: peter-evans/create-pull-request@v8
with:
commit-message: Update dependencies
title: '[Bot] Update dependencies'
+1 -1
View File
@@ -21,7 +21,7 @@ jobs:
permissions:
contents: write
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- name: Update the ${{ env.TAG_NAME }} tag
id: update-major-minor-tag
+8 -8
View File
@@ -1,7 +1,7 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
rev: v6.0.0
hooks:
- id: check-case-conflict
- id: check-merge-conflict
@@ -14,14 +14,14 @@ repos:
- id: trailing-whitespace
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.12.4
rev: v0.14.9
hooks:
- id: ruff
- id: ruff-check
args: ["--fix", "--show-fixes"]
- id: ruff-format
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.17.0
rev: v1.19.1
hooks:
- id: mypy
name: mypy 3.11 on cibuildwheel/
@@ -49,12 +49,12 @@ repos:
- uv
- validate-pyproject
- id: mypy
name: mypy 3.13
args: ["--python-version=3.13"]
name: mypy 3.14
args: ["--python-version=3.14"]
additional_dependencies: *mypy-dependencies
- repo: https://github.com/shellcheck-py/shellcheck-py
rev: v0.10.0.1
rev: v0.11.0.1
hooks:
- id: shellcheck
@@ -83,7 +83,7 @@ repos:
- repo: https://github.com/python-jsonschema/check-jsonschema
rev: 0.33.2
rev: 0.36.0
hooks:
- id: check-dependabot
- id: check-github-actions
+69 -82
View File
@@ -29,14 +29,15 @@ While cibuildwheel itself requires a recent Python version to run (we support th
| CPython 3.9 | ✅ | ✅ | ✅ | ✅ | ✅² | ✅ | ✅ | ✅ | ✅ | ✅ | ✅⁵ | N/A | N/A | N/A |
| CPython 3.10 | ✅ | ✅ | ✅ | ✅ | ✅² | ✅ | ✅ | ✅ | ✅ | ✅ | ✅⁵ | N/A | N/A | N/A |
| CPython 3.11 | ✅ | ✅ | ✅ | ✅ | ✅² | ✅ | ✅ | ✅ | ✅ | ✅ | ✅⁵ | N/A | N/A | N/A |
| CPython 3.12 | ✅ | ✅ | ✅ | ✅ | ✅² | ✅ | ✅ | ✅ | ✅ | ✅ | ✅⁵ | N/A | N/A | ✅⁴ |
| CPython 3.13³ | ✅ | ✅ | ✅ | ✅ | ✅² | ✅ | ✅ | ✅ | ✅ | ✅ | ✅⁵ | ✅ | ✅ | N/A |
| CPython 3.14 | ✅ | ✅ | ✅ | ✅ | ✅² | ✅ | ✅ | ✅ | ✅ | ✅ | ✅⁵ | N/A | N/A | N/A |
| CPython 3.12 | ✅ | ✅ | ✅ | ✅ | ✅² | ✅ | ✅ | ✅ | ✅ | ✅ | ✅⁵ | N/A | N/A | ✅⁴ |
| CPython 3.13³ | ✅ | ✅ | ✅ | ✅ | ✅² | ✅ | ✅ | ✅ | ✅ | ✅ | ✅⁵ | ✅ | ✅ | ✅⁴ |
| CPython 3.14 | ✅ | ✅ | ✅ | ✅ | ✅² | ✅ | ✅ | ✅ | ✅ | ✅ | ✅⁵ | ✅ | ✅ | N/A |
| PyPy 3.8 v7.3 | ✅ | ✅ | ✅ | N/A | N/A | ✅¹ | ✅¹ | ✅¹ | N/A | N/A | N/A | N/A | N/A | N/A |
| PyPy 3.9 v7.3 | ✅ | ✅ | ✅ | N/A | N/A | ✅¹ | ✅¹ | ✅¹ | N/A | N/A | N/A | N/A | N/A | N/A |
| PyPy 3.10 v7.3 | ✅ | ✅ | ✅ | N/A | N/A | ✅¹ | ✅¹ | ✅¹ | N/A | N/A | N/A | N/A | N/A | N/A |
| PyPy 3.11 v7.3 | ✅ | ✅ | ✅ | N/A | N/A | ✅¹ | ✅¹ | ✅¹ | N/A | N/A | N/A | N/A | N/A | N/A |
| GraalPy 3.11 v24.2 | ✅ | ✅ | ✅ | N/A | N/A | ✅¹ | N/A | ✅¹ | N/A | N/A | N/A | N/A | N/A | N/A |
| GraalPy 3.12 v25.0 | ✅ | ✅ | ✅ | N/A | N/A | ✅¹ | N/A | ✅¹ | N/A | N/A | N/A | N/A | N/A | N/A |
<sup>¹ PyPy & GraalPy are only supported for manylinux wheels.</sup><br>
<sup>² Windows arm64 support is experimental.</sup><br>
@@ -44,7 +45,7 @@ While cibuildwheel itself requires a recent Python version to run (we support th
<sup>⁴ Experimental, not yet supported on PyPI, but can be used directly in web deployment. Use `--platform pyodide` to build.</sup><br>
<sup>⁵ manylinux armv7l support is experimental. As there are no RHEL based image for this architecture, it's using an Ubuntu based image instead.</sup><br>
- Builds manylinux, musllinux, macOS 10.9+ (10.13+ for Python 3.12+), and Windows wheels for CPython, PyPy, and GraalPy
- Builds manylinux, musllinux, macOS, and Windows wheels for CPython, PyPy, and GraalPy
- Works on GitHub Actions, Azure Pipelines, Travis CI, CircleCI, GitLab CI, and Cirrus CI
- Bundles shared library dependencies on Linux and macOS through [auditwheel](https://github.com/pypa/auditwheel) and [delocate](https://github.com/matthew-brett/delocate)
- Runs your library's tests against the wheel-installed version of your library
@@ -67,8 +68,9 @@ Usage
<sup>¹ [Requires emulation](https://cibuildwheel.pypa.io/en/stable/faq/#emulation), distributed separately. Other services may also support Linux ARM through emulation or third-party build hosts, but these are not tested in our CI.</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>
<!--intro-end-->
Example setup
@@ -88,16 +90,16 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, ubuntu-24.04-arm, windows-latest, windows-11-arm, macos-13, macos-latest]
os: [ubuntu-latest, ubuntu-24.04-arm, windows-latest, windows-11-arm, macos-15-intel, macos-latest]
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
# Used to host cibuildwheel
- uses: actions/setup-python@v5
- name: Install cibuildwheel
run: python -m pip install cibuildwheel==3.1.1
run: python -m pip install cibuildwheel==3.3.0
- name: Build wheels
run: python -m cibuildwheel --output-dir wheelhouse
@@ -157,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-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-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. |
| | [`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 |
<!--[[[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/).
@@ -178,22 +181,22 @@ Here are some repos that use cibuildwheel.
| Name | CI | OS | Notes |
|-----------------------------------|----|----|:------|
| [scikit-learn][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | The machine learning library. A complex but clean config using many of cibuildwheel's features to build a large project with Cython and C++ extensions. |
| [pytorch-fairseq][] | ![github icon][] | ![apple icon][] ![linux icon][] | Facebook AI Research Sequence-to-Sequence Toolkit written in Python. |
| [duckdb][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | DuckDB is an analytical in-process SQL database management system |
| [pytorch-fairseq][] | ![github icon][] | ![apple icon][] ![linux icon][] | Facebook AI Research Sequence-to-Sequence Toolkit written in Python. |
| [NumPy][] | ![github icon][] ![travisci icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | The fundamental package for scientific computing with Python. |
| [Tornado][] | ![github icon][] | ![linux icon][] ![apple icon][] ![windows icon][] | Tornado is a Python web framework and asynchronous networking library. Uses stable ABI for a small C extension. |
| [NCNN][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | ncnn is a high-performance neural network inference framework optimized for the mobile platform |
| [Tornado][] | ![github icon][] | ![linux icon][] ![apple icon][] ![windows icon][] | Tornado is a Python web framework and asynchronous networking library. Uses stable ABI for a small C extension. |
| [Matplotlib][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | The venerable Matplotlib, a Python library with C++ portions |
| [MyPy][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | The compiled version of MyPy using MyPyC. |
| [Prophet][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Tool for producing high quality forecasts for time series data that has multiple seasonality with linear or non-linear growth. |
| [Kivy][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Open source UI framework written in Python, running on Windows, Linux, macOS, Android and iOS |
[scikit-learn]: https://github.com/scikit-learn/scikit-learn
[pytorch-fairseq]: https://github.com/facebookresearch/fairseq
[duckdb]: https://github.com/duckdb/duckdb
[pytorch-fairseq]: https://github.com/facebookresearch/fairseq
[NumPy]: https://github.com/numpy/numpy
[Tornado]: https://github.com/tornadoweb/tornado
[NCNN]: https://github.com/Tencent/ncnn
[Tornado]: https://github.com/tornadoweb/tornado
[Matplotlib]: https://github.com/matplotlib/matplotlib
[MyPy]: https://github.com/mypyc/mypy_mypyc-wheels
[Prophet]: https://github.com/facebook/prophet
@@ -227,84 +230,67 @@ Changelog
<!-- [[[cog from readme_changelog import mini_changelog; print(mini_changelog()) ]]] -->
### v3.1.1
### v3.3.0
_24 July 2025_
_12 November 2025_
- 🐛 Fix a bug showing an incorrect wheel count at the end of execution, and misrepresenting test-only runs in the GitHub Action summary (#2512)
- 📚 Docs fix (#2510)
- 🐛 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.1.0
### v3.2.1
_23 July 2025_
_12 October 2025_
- 🛠 Update to CPython 3.14.0 final (#2614)
- 🐛 Fix the default MACOSX_DEPLOYMENT_TARGET on Python 3.14 (#2613)
- 📚 Docs improvements (#2617)
### v3.2.0
_22 September 2025_
- ✨ Adds GraalPy v25 (Python 3.12) support (#2597)
- 🛠 Update to CPython 3.14.0rc3 (#2602)
- 🛠 Adds CPython 3.14.0 prerelease support for Android, and a number of improvements to Android builds (#2568, #2591)
- 🛠 Improvements to testing on Android, passing environment markers when installing the venv, and providing more debug output when build-verbosity is set (#2575)
- ⚠️ PyPy 3.10 was moved to `pypy-eol` in the `enable` option, as it is now end-of-life. (#2521)
- 📚 Docs improvements (#2574, #2601, #2598)
### v3.1.4
_19 August 2025_
- ✨ Add a `--clean-cache` command to clean up our cache (#2489)
- 🛠 Update Python to 3.14rc2 and other patch version bumps (#2542, #2556)
- 🛠 Update Pyodide to 0.28.2 (#2562, #2558)
- 🐛 Fix resolution with `pyodide-build` when `dependency-versions` is set (#2548)
- 🐛 Set `CMAKE_FIND_ROOT_PATH_MODE_PACKAGE` to `BOTH` on Android (#2547)
- 🐛 Add `patchelf` dependency for platforms that can build Android wheels (#2552)
- 🐛 Ignore empty values for `CIBW_ARCHS` like most other environment variables (#2541)
- 💼 The `color` and `suggest_on_error` argparse options are now default in 3.14rc1+ (#2554)
- 💼 Use the virtualenv release URL instead of blob URL (should be more robust) (#2555)
- 🧪 For iOS, lowering to macos-14 is needed for now due to issues with GitHub's runner images (#2557)
- 🧪 Split out platforms iOS and Android in our tests (#2519)
- 🧪 Fix and enable doctests (#2546)
- 📚 Improve our docs on free-threading (#2549)
- 🌟 CPython 3.14 wheels are now built by default - without the `"cpython-prerelease"` `enable` set. It's time to build and upload these wheels to PyPI! This release includes CPython 3.14.0rc1, which is guaranteed to be ABI compatible with the final release. (#2507) Free-threading is no longer experimental in 3.14, so you have to skip it explicitly with `'cp31?t-*'` if you don't support it yet. (#2503)
- 🌟 Adds the ability to [build wheels for Android](https://cibuildwheel.pypa.io/en/stable/platforms/#android)! Set the [`platform` option](https://cibuildwheel.pypa.io/en/stable/options/#platform) to `android` on Linux or macOS to try it out! (#2349)
- 🌟 Adds Pyodide 0.28, which builds 3.13 wheels (#2487)
- ✨ Support for 32-bit `manylinux_2_28` (now a consistent default) and `manylinux_2_34` added (#2500)
- 🛠 Improved summary, will also use markdown summary output on GHA (#2469)
- 🛠 The riscv64 images now have a working default (as they are now part of pypy/manylinux), but are still experimental (and behind an `enable`) since you can't push them to PyPI yet (#2506)
- 🛠 Fixed a typo in the 3.9 MUSL riscv64 identifier (`cp39-musllinux_ricv64` -> `cp39-musllinux_riscv64`) (#2490)
- 🛠 Mistyping `--only` now shows the correct possibilities, and even suggests near matches on Python 3.14+ (#2499)
- 🛠 Only support one output from the repair step on linux like other platforms; auditwheel fixed this over four years ago! (#2478)
- 🛠 We now use pattern matching extensively (#2434)
- 📚 We now have platform maintainers for our special platforms and interpreters! (#2481)
### 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.0.1
_5 July 2025_
- 🛠 Updates CPython 3.14 prerelease to 3.14.0b3 (#2471)
- ✨ Adds a CPython 3.14 prerelease iOS build (only when prerelease builds are [enabled](https://cibuildwheel.pypa.io/en/stable/options/#enable)) (#2475)
### v3.0.0
_11 June 2025_
See @henryiii's [release post](https://iscinumpy.dev/post/cibuildwheel-3-0-0/) for more info on new features!
- 🌟 Adds the ability to [build wheels for iOS](https://cibuildwheel.pypa.io/en/stable/platforms/#ios)! Set the [`platform` option](https://cibuildwheel.pypa.io/en/stable/options/#platform) to `ios` on a Mac with the iOS toolchain to try it out! (#2286, #2363, #2432)
- 🌟 Adds support for the GraalPy interpreter! Enable for your project using the [`enable` option](https://cibuildwheel.pypa.io/en/stable/options/#enable). (#1538, #2411, #2414)
- ✨ Adds CPython 3.14 support, under the [`enable` option](https://cibuildwheel.pypa.io/en/stable/options/#enable) `cpython-prerelease`. This version of cibuildwheel uses 3.14.0b2. (#2390)
_While CPython is in beta, the ABI can change, so your wheels might not be compatible with the final release. For this reason, we don't recommend distributing wheels until RC1, at which point 3.14 will be available in cibuildwheel without the flag._ (#2390)
- ✨ Adds the [test-sources option](https://cibuildwheel.pypa.io/en/stable/options/#test-sources), which copies files and folders into the temporary working directory we run tests from. (#2062, #2284, #2420, #2437)
This is particularly important for iOS builds, which do not support placeholders in the `test-command`, but can also be useful for other platforms.
- ✨ Adds [`dependency-versions`](https://cibuildwheel.pypa.io/en/stable/options/#dependency-versions) inline syntax (#2122)
- ✨ Improves support for Pyodide builds and adds the experimental [`pyodide-version`](https://cibuildwheel.pypa.io/en/stable/options/#pyodide-version) option, which allows you to specify the version of Pyodide to use for builds. (#2002)
- ✨ Add `pyodide-prerelease` [enable](https://cibuildwheel.pypa.io/en/stable/options/#enable) option, with an early build of 0.28 (Python 3.13). (#2431)
- ✨ Adds the [`test-environment`](https://cibuildwheel.pypa.io/en/stable/options/#test-environment) option, which allows you to set environment variables for the test command. (#2388)
- ✨ Adds the [`xbuild-tools`](https://cibuildwheel.pypa.io/en/stable/options/#xbuild-tools) option, which allows you to specify tools safe for cross-compilation. Currently only used on iOS; will be useful for Android in the future. (#2317)
- 🛠 The default [manylinux image](https://cibuildwheel.pypa.io/en/stable/options/#linux-image) has changed from `manylinux2014` to `manylinux_2_28`. (#2330)
- 🛠 EOL images `manylinux1`, `manylinux2010`, `manylinux_2_24` and `musllinux_1_1` can no longer be specified by their shortname. The full OCI name can still be used for these images, if you wish. (#2316)
- 🛠 Invokes `build` rather than `pip wheel` to build wheels by default. You can control this via the [`build-frontend`](https://cibuildwheel.pypa.io/en/stable/options/#build-frontend) option. You might notice that you can see your build log output now! (#2321)
- 🛠 Build verbosity settings have been reworked to have consistent meanings between build backends when non-zero. (#2339)
- 🛠 Removed the `CIBW_PRERELEASE_PYTHONS` and `CIBW_FREE_THREADED_SUPPORT` options - these have been folded into the [`enable`](https://cibuildwheel.pypa.io/en/stable/options/#enable) option instead. (#2095)
- 🛠 Build environments no longer have setuptools and wheel preinstalled. (#2329)
- 🛠 Use the standard Schema line for the integrated JSONSchema. (#2433)
- ⚠️ Dropped support for building Python 3.6 and 3.7 wheels. If you need to build wheels for these versions, use cibuildwheel v2.23.3 or earlier. (#2282)
- ⚠️ The minimum Python version required to run cibuildwheel is now Python 3.11. You can still build wheels for Python 3.8 and newer. (#1912)
- ⚠️ 32-bit Linux wheels no longer built by default - the [arch](https://cibuildwheel.pypa.io/en/stable/options/#archs) was removed from `"auto"`. It now requires explicit `"auto32"`. Note that modern manylinux images (like the new default, `manylinux_2_28`) do not have 32-bit versions. (#2458)
- ⚠️ PyPy wheels no longer built by default, due to a change to our options system. To continue building PyPy wheels, you'll now need to set the [`enable` option](https://cibuildwheel.pypa.io/en/stable/options/#enable) to `pypy` or `pypy-eol`. (#2095)
- ⚠️ Dropped official support for Appveyor. If it was working for you before, it will probably continue to do so, but we can't be sure, because our CI doesn't run there anymore. (#2386)
- 📚 A reorganisation of the docs, and numerous updates. (#2280)
- 📚 Use Python 3.14 color output in docs CLI output. (#2407)
- 📚 Docs now primarily use the pyproject.toml name of options, rather than the environment variable name. (#2389)
- 📚 README table now matches docs and auto-updates. (#2427, #2428)
### v2.23.3
_26 April 2025_
- 🛠 Dependency updates, including Python 3.13.3 (#2371)
<!-- [[[end]]] (sum: K97aJ+f0EX) -->
<!-- [[[end]]] (sum: vS54piNR4b) -->
---
@@ -339,6 +325,7 @@ Platform maintainers:
- Hood Chatham [@hoodmane](https://github.com/hoodmane) (Pyodide)
- Gyeongjae Choi [@ryanking13](https://github.com/ryanking13) (Pyodide)
- Tim Felgentreff [@timfel](https://github.com/timfel) (GraalPy)
- Malcolm Smith [@mhsmith](https://github.com/mhsmith) (Android)
Credits
-------
+37 -17
View File
@@ -17,6 +17,10 @@ inputs:
description: 'Build a specific wheel only. No need for arch/platform if this is set'
required: false
default: ''
extras:
description: 'Comma-separated list of extras to install'
required: false
default: ''
branding:
icon: package
color: yellow
@@ -24,7 +28,7 @@ branding:
runs:
using: composite
steps:
- uses: actions/setup-python@v5
- uses: actions/setup-python@v6
id: python
with:
python-version: "3.11 - 3.13"
@@ -42,6 +46,8 @@ runs:
from pathlib import Path
from subprocess import run
EXTRAS = set(e.strip() for e in "${{ inputs.extras }}".split(",") if e.strip())
class EnvBuilder(venv.EnvBuilder):
def __init__(self):
@@ -53,7 +59,10 @@ runs:
def post_setup(self, context):
super().post_setup(context)
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")
@@ -62,30 +71,41 @@ runs:
shutil.rmtree(venv_path)
builder = EnvBuilder()
builder.create(venv_path)
cibw_path = [path for path in builder.bin_path.glob("cibuildwheel*") if path.stem == "cibuildwheel"][0]
cibw_bin = [p for p in builder.bin_path.glob("cibuildwheel*") if p.stem == "cibuildwheel"][0]
with open(os.environ["GITHUB_OUTPUT"], "at") as f:
f.write(f"cibw-path={cibw_path}\n")
f.write(f"cibw-bin={cibw_bin}\n")
f.write(f"prepend-path={builder.bin_path if 'uv' in EXTRAS else ''}\n")
print("::endgroup::")
EOF
shell: bash
# Redirecting stderr to stdout to fix interleaving issue in Actions.
- run: >
"${{ steps.cibw.outputs.cibw-path }}"
"${{ inputs.package-dir }}"
${{ inputs.output-dir != '' && format('--output-dir "{0}"', inputs.output-dir) || ''}}
${{ inputs.config-file != '' && format('--config-file "{0}"', inputs.config-file) || ''}}
${{ inputs.only != '' && format('--only "{0}"', inputs.only) || ''}}
2>&1
- run: |
prepend_path="${{ steps.cibw.outputs.prepend-path }}"
if [ -n "$prepend_path" ]; then
export PATH="$prepend_path:$PATH"
fi
"${{ steps.cibw.outputs.cibw-bin }}" \
"${{ inputs.package-dir }}" \
${{ inputs.output-dir != '' && format('--output-dir "{0}"', inputs.output-dir) || ''}} \
${{ inputs.config-file != '' && format('--config-file "{0}"', inputs.config-file) || ''}} \
${{ inputs.only != '' && format('--only "{0}"', inputs.only) || ''}} \
2>&1
shell: bash
if: runner.os != 'Windows'
# Windows needs powershell to interact nicely with Meson
- run: >
& "${{ steps.cibw.outputs.cibw-path }}"
"${{ inputs.package-dir }}"
${{ inputs.output-dir != '' && format('--output-dir "{0}"', inputs.output-dir) || ''}}
${{ inputs.config-file != '' && format('--config-file "{0}"', inputs.config-file) || ''}}
${{ inputs.only != '' && format('--only "{0}"', inputs.only) || ''}}
- run: |
$PrependPath = "${{ steps.cibw.outputs.prepend-path }}"
if ($PrependPath) {
$env:PATH = "$PrependPath;$env:PATH"
}
& "${{ steps.cibw.outputs.cibw-bin }}" `
"${{ inputs.package-dir }}" `
${{ inputs.output-dir != '' && format('--output-dir "{0}"', inputs.output-dir) || ''}} `
${{ inputs.config-file != '' && format('--config-file "{0}"', inputs.config-file) || ''}} `
${{ inputs.only != '' && format('--only "{0}"', inputs.only) || ''}}
shell: pwsh
if: runner.os == 'Windows'
+46 -47
View File
@@ -16,62 +16,61 @@ pr:
- noxfile.py
jobs:
- job: linux_311
- job: tests
strategy:
matrix:
linux_311:
imageName: "ubuntu-latest"
pythonVersion: "3.11"
testSelect: "native"
android_311:
imageName: "ubuntu-latest"
pythonVersion: "3.11"
testSelect: "android"
macos_311:
imageName: "macos-latest"
pythonVersion: "3.11"
testSelect: "native"
ios_311:
imageName: "macos-14" # See https://github.com/actions/runner-images/issues/12777
pythonVersion: "3.11"
testSelect: "ios"
android_macos_311:
imageName: "macos-latest"
pythonVersion: "3.11"
testSelect: "android"
windows_311:
imageName: "windows-latest"
pythonVersion: "3.11"
testSelect: "native"
timeoutInMinutes: 180
pool: {vmImage: 'ubuntu-latest'}
pool:
vmImage: $(imageName)
steps:
- task: UsePythonVersion@0
inputs:
versionSpec: '3.11'
versionSpec: $(pythonVersion)
- task: JavaToolInstaller@0
condition: and(eq(variables['testSelect'], 'android'), eq(variables['Agent.OS'], 'Linux'))
inputs:
versionSpec: '17'
jdkArchitectureOption: 'x64'
jdkSourceOption: 'PreInstalled'
- bash: |
docker run --rm --privileged docker.io/tonistiigi/binfmt:latest --install all
python -m pip install -U pip
python -m pip install -e. --group test
if [ "$(Build.SourceBranch)" = "refs/heads/main" ]; then
echo "INFO: Exporting CIBW_ENABLE=all for main branch test run."
export CIBW_ENABLE=all
else
echo "INFO: CIBW_ENABLE not set for this branch ($(Build.SourceBranch))."
fi
python ./bin/run_tests.py
- job: macos_311
pool: {vmImage: 'macOS-latest'}
timeoutInMinutes: 120
steps:
- task: UsePythonVersion@0
inputs:
versionSpec: '3.11'
- bash: |
python -m pip install -U pip
python -m pip install -e. --group test
if [ "$(Build.SourceBranch)" = "refs/heads/main" ]; then
echo "INFO: Exporting CIBW_ENABLE=all for main branch test run."
export CIBW_ENABLE=all
else
echo "INFO: CIBW_ENABLE not set for this branch ($(Build.SourceBranch))."
fi
python ./bin/run_tests.py
- bash: docker run --rm --privileged docker.io/tonistiigi/binfmt:latest --install all
condition: and(eq(variables['imageName'], 'ubuntu-latest'), eq(variables['testSelect'], 'native'))
displayName: 'Install binfmt on Linux'
- bash: python -m pip install -U pip && python -m pip install -e. --group test
displayName: 'Update pip and install cibuildwheel --group test'
- bash: echo "##vso[task.setvariable variable=CIBW_ENABLE;]all"
condition: eq(variables['Build.SourceBranch'], 'refs/heads/main')
displayName: Set CIBW_ENABLE to all (main branch)
- job: windows_311
pool: {vmImage: 'windows-latest'}
timeoutInMinutes: 180
steps:
- task: UsePythonVersion@0
inputs:
versionSpec: '3.11'
- bash: |
python -m pip install -U pip
python -m pip install -e. --group test
if [ "$(Build.SourceBranch)" = "refs/heads/main" ]; then
echo "INFO: Exporting CIBW_ENABLE=all for main branch test run."
export CIBW_ENABLE=all
else
echo "INFO: CIBW_ENABLE not set for this branch ($(Build.SourceBranch))."
fi
python ./bin/run_tests.py
echo "CIBW_ENABLE = $CIBW_ENABLE"
python ./bin/run_tests.py --test-select $(testSelect)
displayName: 'Run tests'
+2 -2
View File
@@ -68,8 +68,8 @@ def bump_version() -> None:
sys.exit(1)
# fmt: off
print( 'Current version:', current_version)
new_version = input(' New version: ').strip()
print( "Current version:", current_version)
new_version = input(" New version: ").strip()
# fmt: on
try:
+20 -6
View File
@@ -6,17 +6,12 @@
import argparse
import copy
import functools
import json
import sys
from typing import Any
import yaml
make_parser = functools.partial(argparse.ArgumentParser, allow_abbrev=False)
if sys.version_info >= (3, 14):
make_parser = functools.partial(make_parser, color=True, suggest_on_error=True)
parser = make_parser()
parser = argparse.ArgumentParser(allow_abbrev=False)
parser.add_argument("--schemastore", action="store_true", help="Generate schema_store version")
args = parser.parse_args()
@@ -229,6 +224,24 @@ properties:
test-environment:
description: Set environment variables for the test environment
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)
@@ -309,6 +322,7 @@ items:
test-sources: {"$ref": "#/$defs/inherit"}
test-requires: {"$ref": "#/$defs/inherit"}
test-environment: {"$ref": "#/$defs/inherit"}
test-runtime: {"$ref": "#/$defs/inherit"}
"""
)
+3 -3
View File
@@ -23,7 +23,7 @@ import textwrap
import urllib.request
import xml.dom.minidom
from collections.abc import Iterable, Mapping, Sequence
from datetime import datetime
from datetime import UTC, datetime
from io import StringIO
from pathlib import Path
from typing import Any, Self, TextIO
@@ -77,7 +77,7 @@ class Project:
self.notes = notes
else:
self.num_stars = 0
self.pushed_at = datetime.utcnow()
self.pushed_at = datetime.now(UTC)
name_len = len(self.name) + 4
self.__class__.NAME = max(self.__class__.NAME, name_len)
@@ -124,7 +124,7 @@ class Project:
return f"[{self.name}]: {self.url}"
def info(self) -> str:
days = (datetime.utcnow() - self.pushed_at).days
days = (datetime.now(UTC) - self.pushed_at).days
return f"<!-- {self.name}: {self.num_stars}, last pushed {days} days ago -->"
+34 -4
View File
@@ -2,6 +2,7 @@
import os
import re
import shutil
import subprocess
import sys
@@ -13,7 +14,7 @@ from urllib.parse import quote
import click
DIR = Path(__file__).parent.resolve()
DIR = Path(__file__).parent.parent.resolve()
def shell(cmd: str, *, check: bool, **kwargs: object) -> subprocess.CompletedProcess[str]:
@@ -38,6 +39,29 @@ class CIService(typing.NamedTuple):
name: str
dst_config_path: str
badge_md: str
config_file_transform: typing.Callable[[str], str] = lambda x: x # identity by default
def github_config_file_transform(content: str) -> str:
# one of the the github configs only builds on main, so we need to remove that restriction
# so our example build will run on the test branch.
#
# replace:
# """
# push:
# branches:
# - main
# """
# with:
# """
# push:
# """"
content = re.sub(
r"push:\n\s+branches:\n\s+- main",
"push:",
content,
)
return content
services = [
@@ -54,7 +78,8 @@ services = [
CIService(
name="github",
dst_config_path=".github/workflows/example.yml",
badge_md="[![Build](https://github.com/pypa/cibuildwheel/workflows/Build/badge.svg?branch={branch})](https://github.com/pypa/cibuildwheel/actions)",
badge_md="[![Build](https://github.com/pypa/cibuildwheel/actions/workflows/example.yml/badge.svg?branch={branch})](https://github.com/pypa/cibuildwheel/actions?query=branch%3A{branch})",
config_file_transform=github_config_file_transform,
),
CIService(
name="travis-ci",
@@ -93,6 +118,8 @@ def run_example_ci_configs(config_files=None):
if len(config_files) == 0:
config_files = Path("examples").glob("*-minimal.yml")
else:
config_files = [Path(f) for f in config_files]
# check each CI service has at most 1 config file
configs_by_service = set()
@@ -125,12 +152,15 @@ def run_example_ci_configs(config_files=None):
dst_config_file = example_project / service.dst_config_path
dst_config_file.parent.mkdir(parents=True, exist_ok=True)
shutil.copyfile(config_file, dst_config_file)
contents = config_file.read_text(encoding="utf8")
contents = service.config_file_transform(contents)
dst_config_file.write_text(contents, encoding="utf8")
subprocess.run(["git", "add", example_project], check=True)
message = textwrap.dedent(
f"""\
Test example minimal configs
Test example CI configs
Testing files: {[str(f) for f in config_files]}
Generated from branch: {previous_branch}
+51 -19
View File
@@ -2,7 +2,6 @@
import argparse
import functools
import os
import subprocess
import sys
@@ -14,10 +13,7 @@ if __name__ == "__main__":
else:
default_cpu_count = os.process_cpu_count() or 2
make_parser = functools.partial(argparse.ArgumentParser, allow_abbrev=False)
if sys.version_info >= (3, 14):
make_parser = functools.partial(make_parser, color=True, suggest_on_error=True)
parser = make_parser()
parser = argparse.ArgumentParser(allow_abbrev=False)
parser.add_argument(
"--run-podman", action="store_true", default=False, help="run podman tests (linux only)"
)
@@ -27,26 +23,66 @@ if __name__ == "__main__":
default=default_cpu_count,
help="number of processes to use for testing",
)
parser.add_argument(
"--test-select",
choices={"all", "native", "android", "ios", "pyodide"},
default="all",
help="Either 'native' or 'android'/'ios'/'pyodide'",
)
args = parser.parse_args()
# move cwd to the project root
os.chdir(Path(__file__).resolve().parents[1])
# doc tests
doc_test_args = [sys.executable, "-m", "pytest", "cibuildwheel"]
print(
"\n\n================================== DOC TESTS ==================================",
flush=True,
)
result = subprocess.run(doc_test_args, check=False)
if result.returncode not in (0, 5):
# Allow case where no doctests are collected (returncode 5) because
# circleci sets an explicit "-k" filter that disables doctests. There
# isn't a pattern that will only select doctests. This can be removed
# and have check=True if the circleci PYTEST_ADDOPTS is removed.
raise subprocess.CalledProcessError(
result.returncode, result.args, output=result.stdout, stderr=result.stderr
)
# unit tests
print(
"\n\n================================== UNIT TESTS ==================================",
flush=True,
)
unit_test_args = [sys.executable, "-m", "pytest", "unit_test"]
if sys.platform.startswith("linux") and os.environ.get("CIBW_PLATFORM", "linux") == "linux":
if (
sys.platform.startswith("linux")
and os.environ.get("CIBW_PLATFORM", "linux") == "linux"
and args.test_select in ["all", "native"]
):
# run the docker unit tests only on Linux
unit_test_args += ["--run-docker"]
if args.run_podman:
unit_test_args += ["--run-podman"]
subprocess.run(unit_test_args, check=True)
print(
"\n\n================================== UNIT TESTS ==================================",
"\n\n=========================== SERIAL INTEGRATION TESTS ===========================",
flush=True,
)
subprocess.run(unit_test_args, check=True)
match args.test_select:
case "all":
marks = []
case "native":
marks = ["not pyodide", "not android", "not ios"]
case mark:
marks = [f"{mark}"]
# Run the serial integration tests without multiple processes
serial_integration_test_args = [
@@ -54,7 +90,7 @@ if __name__ == "__main__":
"-m",
"pytest",
"-m",
"serial",
f"{' and '.join(['serial', *marks])}",
"-x",
"--durations",
"0",
@@ -62,19 +98,19 @@ if __name__ == "__main__":
"test",
"-vv",
]
print(
"\n\n=========================== SERIAL INTEGRATION TESTS ===========================",
flush=True,
)
subprocess.run(serial_integration_test_args, check=True)
# Non-serial integration tests
print(
"\n\n========================= NON-SERIAL INTEGRATION TESTS =========================",
flush=True,
)
integration_test_args = [
sys.executable,
"-m",
"pytest",
"-m",
"not serial",
f"{' and '.join(['not serial', *marks])}",
f"--numprocesses={args.num_processes}",
"-x",
"--durations",
@@ -87,8 +123,4 @@ if __name__ == "__main__":
if sys.platform.startswith("linux") and args.run_podman:
integration_test_args += ["--run-podman"]
print(
"\n\n========================= NON-SERIAL INTEGRATION TESTS =========================",
flush=True,
)
subprocess.run(integration_test_args, check=True)
+1 -5
View File
@@ -2,7 +2,6 @@
import argparse
import functools
import os
import subprocess
import sys
@@ -13,10 +12,7 @@ if __name__ == "__main__":
# move cwd to the project root
os.chdir(Path(__file__).resolve().parents[1])
make_parser = functools.partial(argparse.ArgumentParser, allow_abbrev=False)
if sys.version_info >= (3, 14):
make_parser = functools.partial(make_parser, color=True, suggest_on_error=True)
parser = make_parser(description="Runs a sample build")
parser = argparse.ArgumentParser(description="Runs a sample build", allow_abbrev=False)
parser.add_argument("project_python_path", nargs="?", default="test.test_0_basic.basic_project")
options = parser.parse_args()
+2
View File
@@ -71,6 +71,8 @@ images = [
"pypy_aarch64",
],
),
# manylinux_2_35 images
PyPAImage("manylinux_2_35", ["armv7l"]),
# manylinux_2_39 images
PyPAImage("manylinux_2_39", ["riscv64"]),
# musllinux_1_2 images
+43 -70
View File
@@ -1,7 +1,6 @@
#!/usr/bin/env python3
import copy
import difflib
import logging
import operator
@@ -34,47 +33,20 @@ RESOURCES_DIR: Final[Path] = DIR / "cibuildwheel/resources"
ArchStr = Literal["32", "64", "ARM64"]
class ConfigWinCP(TypedDict):
class Config(TypedDict):
identifier: str
version: str
arch: str
class ConfigWinPP(TypedDict):
identifier: str
version: str
arch: str
class ConfigUrl(Config):
url: str
class ConfigWinGP(TypedDict):
identifier: str
version: str
url: str
class ConfigApple(TypedDict):
identifier: str
version: str
url: str
class ConfigAndroid(TypedDict):
identifier: str
version: str
url: str
class ConfigPyodide(TypedDict):
identifier: str
version: str
class ConfigPyodide(Config):
default_pyodide_version: str
node_version: str
AnyConfig = ConfigWinCP | ConfigWinPP | ConfigWinGP | ConfigApple | ConfigAndroid | ConfigPyodide
# The following set of "Versions" classes allow the initial call to the APIs to
# be cached and reused in the `update_version_*` methods.
@@ -106,7 +78,7 @@ class WindowsVersions:
self.version_dict = {Version(v): v for v in cp_info["versions"]}
def update_version_windows(self, spec: Specifier) -> ConfigWinCP | None:
def update_version_windows(self, spec: Specifier) -> Config | None:
# Specifier.filter selects all non pre-releases that match the spec,
# unless there are only pre-releases, then it selects pre-releases
# instead (like pip)
@@ -121,10 +93,9 @@ class WindowsVersions:
flags = "t" if self.free_threaded else ""
version = versions[0]
identifier = f"cp{version.major}{version.minor}{flags}-{self.arch}"
return ConfigWinCP(
return Config(
identifier=identifier,
version=self.version_dict[version],
arch=self.arch_str,
)
@@ -146,7 +117,7 @@ class GraalPyVersions:
self.releases = [r for r in releases if "graalpy_version" in r and "python_version" in r]
def update_version(self, identifier: str, spec: Specifier) -> AnyConfig:
def update_version(self, identifier: str, spec: Specifier) -> ConfigUrl:
if "x86_64" in identifier or "amd64" in identifier:
arch = "x86_64"
elif "arm64" in identifier or "aarch64" in identifier:
@@ -156,7 +127,9 @@ class GraalPyVersions:
raise RuntimeError(msg)
gpspec_str = identifier.split("-")[0].split("_")[1]
gpspec = Specifier("==24.2.*") if gpspec_str == "242" else Specifier(f"=={gpspec_str}.*")
if "." not in gpspec_str and len(gpspec_str) == 3:
gpspec_str = gpspec_str[:2] + "." + gpspec_str[-1]
gpspec = Specifier(f"=={gpspec_str}.*")
releases = [r for r in self.releases if spec.contains(r["python_version"])]
releases = [r for r in self.releases if gpspec.contains(r["graalpy_version"])]
@@ -172,11 +145,9 @@ class GraalPyVersions:
if "macosx" in identifier:
arch = "x86_64" if "x86_64" in identifier else "arm64"
config = ConfigApple
platform = "macos"
elif "win" in identifier:
arch = "aarch64" if "arm64" in identifier else "x86_64"
config = ConfigWinGP
platform = "windows"
else:
msg = "GraalPy provides downloads for macOS and Windows and is included for manylinux"
@@ -191,7 +162,7 @@ class GraalPyVersions:
and rf["name"].startswith(f"graalpy-{gpversion.major}")
)
return config(
return ConfigUrl(
identifier=identifier,
version=f"{version.major}.{version.minor}",
url=url,
@@ -223,7 +194,7 @@ class PyPyVersions:
]
return urls[0] if urls else ""
def update_version_windows(self, spec: Specifier) -> ConfigWinCP:
def update_version_windows(self, spec: Specifier) -> ConfigUrl:
releases = [r for r in self.releases if spec.contains(r["python_version"])]
releases = sorted(releases, key=operator.itemgetter("pypy_version"))
releases = [r for r in releases if self.get_arch_file(r)]
@@ -239,14 +210,13 @@ class PyPyVersions:
identifier = f"pp{version.major}{version.minor}-{version_arch}"
url = self.get_arch_file(release)
return ConfigWinPP(
return ConfigUrl(
identifier=identifier,
version=f"{version.major}.{version.minor}",
arch=self.arch,
url=url,
)
def update_version_macos(self, spec: Specifier) -> ConfigApple:
def update_version_macos(self, spec: Specifier) -> ConfigUrl:
if self.arch not in {"64", "ARM64"}:
msg = f"'{self.arch}' arch not supported yet on macOS"
raise RuntimeError(msg)
@@ -270,7 +240,7 @@ class PyPyVersions:
if "" in rf["platform"] == "darwin" and rf["arch"] == arch
)
return ConfigApple(
return ConfigUrl(
identifier=identifier,
version=f"{version.major}.{version.minor}",
url=url,
@@ -298,16 +268,11 @@ class CPythonVersions:
uri = int(release["resource_uri"].rstrip("/").split("/")[-1])
self.versions_dict[version] = uri
def update_version_macos(
self, identifier: str, version: Version, spec: Specifier
) -> ConfigApple | None:
def update_version(self, identifier: str, spec: Specifier, file_ident: str) -> ConfigUrl | None:
# see note above on Specifier.filter
unsorted_versions = spec.filter(self.versions_dict)
sorted_versions = sorted(unsorted_versions, reverse=True)
macver = "x10.9" if version <= Version("3.8.9999") else "11"
file_ident = f"macos{macver}.pkg"
for new_version in sorted_versions:
# Find the first patch version that contains the requested file
uri = self.versions_dict[new_version]
@@ -319,7 +284,7 @@ class CPythonVersions:
urls = [rf["url"] for rf in file_info if file_ident in rf["url"]]
if urls:
return ConfigApple(
return ConfigUrl(
identifier=identifier,
version=f"{new_version.major}.{new_version.minor}",
url=urls[0],
@@ -327,9 +292,17 @@ class CPythonVersions:
return None
def update_version_macos(
self, identifier: str, version: Version, spec: Specifier
) -> ConfigUrl | None:
macver = "x10.9" if version <= Version("3.8.9999") else "11"
return self.update_version(identifier, spec, f"macos{macver}.pkg")
class AndroidVersions:
# This should be replaced with official python.org downloads once they're available.
def update_version_android(self, identifier: str, spec: Specifier) -> ConfigUrl | None:
return self.update_version(identifier, spec, android_triplet(identifier))
class MavenVersions:
MAVEN_URL = "https://repo.maven.apache.org/maven2/com/chaquo/python/python"
def __init__(self) -> None:
@@ -343,18 +316,16 @@ class AndroidVersions:
assert isinstance(version_str, str), version_str
self.versions.append(Version(version_str))
def update_version_android(
self, identifier: str, version: Version, spec: Specifier
) -> ConfigAndroid | None:
def update_version_android(self, identifier: str, spec: Specifier) -> ConfigUrl | None:
sorted_versions = sorted(spec.filter(self.versions), reverse=True)
# Return a config using the highest version for the given specifier.
if sorted_versions:
max_version = sorted_versions[0]
triplet = android_triplet(identifier)
return ConfigAndroid(
return ConfigUrl(
identifier=identifier,
version=str(version),
version=f"{max_version.major}.{max_version.minor}",
url=f"{self.MAVEN_URL}/{max_version}/python-{max_version}-{triplet}.tar.gz",
)
else:
@@ -390,11 +361,11 @@ class CPythonIOSVersions:
if filename.endswith("-iOS-support"):
self.versions_dict[version][int(build[1:])] = asset["browser_download_url"]
def update_version_ios(self, identifier: str, version: Version) -> ConfigApple | None:
def update_version_ios(self, identifier: str, version: Version) -> ConfigUrl | None:
# Return a config using the highest build number for the given version.
urls = [url for _, url in sorted(self.versions_dict.get(version, {}).items())]
if urls:
return ConfigApple(
return ConfigUrl(
identifier=identifier,
version=str(version),
url=urls[-1],
@@ -450,11 +421,11 @@ class AllVersions:
self.windows_t_arm64 = WindowsVersions("ARM64", True)
self.windows_pypy_64 = PyPyVersions("64")
self.macos_cpython = CPythonVersions()
self.cpython = CPythonVersions()
self.macos_pypy = PyPyVersions("64")
self.macos_pypy_arm64 = PyPyVersions("ARM64")
self.android = AndroidVersions()
self.maven = MavenVersions()
self.ios_cpython = CPythonIOSVersions()
self.graalpy = GraalPyVersions()
@@ -466,13 +437,12 @@ class AllVersions:
version = Version(config["version"])
spec = Specifier(f"=={version.major}.{version.minor}.*")
log.info("Reading in %r -> %s @ %s", str(identifier), spec, version)
orig_config = copy.copy(config)
config_update: AnyConfig | None = None
config_update: Config | None = None
# We need to use ** in update due to MyPy (probably a bug)
if "macosx" in identifier:
if identifier.startswith("cp"):
config_update = self.macos_cpython.update_version_macos(identifier, version, spec)
config_update = self.cpython.update_version_macos(identifier, version, spec)
elif identifier.startswith("pp"):
if "macosx_x86_64" in identifier:
config_update = self.macos_pypy.update_version_macos(spec)
@@ -498,7 +468,10 @@ class AllVersions:
elif "win_arm64" in identifier and identifier.startswith("cp"):
config_update = self.windows_arm64.update_version_windows(spec)
elif "android" in identifier:
config_update = self.android.update_version_android(identifier, version, spec)
# Python 3.13 is released by Chaquopy on Maven Central.
# Python 3.14 and newer have official releases on python.org.
versions = self.maven if identifier.startswith("cp313") else self.cpython
config_update = versions.update_version_android(identifier, spec)
elif "ios" in identifier:
config_update = self.ios_cpython.update_version_ios(identifier, version)
elif "pyodide" in identifier:
@@ -507,10 +480,10 @@ class AllVersions:
)
assert config_update is not None, f"{identifier} not found!"
config.update(**config_update)
if config != orig_config:
log.info(" Updated %s to %s", orig_config, config)
if config_update != config:
log.info(" Updated %s to %s", config, config_update)
config.clear()
config.update(**config_update)
@click.command()
+31 -30
View File
@@ -4,17 +4,18 @@
import dataclasses
import difflib
import logging
import subprocess
import tomllib
from pathlib import Path
from typing import Final
import click
import rich
from packaging.version import InvalidVersion, Version
from packaging.version import Version
from rich.logging import RichHandler
from rich.syntax import Syntax
from cibuildwheel.extra import github_api_request
log = logging.getLogger("cibw")
# Looking up the dir instead of using utils.resources_dir
@@ -30,32 +31,26 @@ GET_VIRTUALENV_URL_TEMPLATE: Final[str] = (
@dataclasses.dataclass(frozen=True, order=True)
class VersionTuple:
name: str
download_url: str
version: Version
version_string: str
def git_ls_remote_versions(url: str) -> list[VersionTuple]:
versions: list[VersionTuple] = []
tags = subprocess.run(
["git", "ls-remote", "--tags", url], check=True, text=True, capture_output=True
).stdout.splitlines()
for tag in tags:
_, ref = tag.split()
assert ref.startswith("refs/tags/")
version_string = ref[10:]
try:
version = Version(version_string)
if version.is_devrelease:
log.info("Ignoring development release %r", str(version))
continue
if version.is_prerelease:
log.info("Ignoring pre-release %r", str(version))
continue
versions.append(VersionTuple(version, version_string))
except InvalidVersion:
log.warning("Ignoring ref %r", ref)
versions.sort(reverse=True)
return versions
def get_latest_virtualenv_release() -> VersionTuple:
response = github_api_request("repos/pypa/get-virtualenv/releases/latest")
tag_name = response["tag_name"]
asset = next(
(asset for asset in response["assets"] if asset["name"] == "virtualenv.pyz"),
None,
)
if not asset:
msg = "No asset named 'virtualenv.pyz' found in the latest release of get-virtualenv."
raise RuntimeError(msg)
return VersionTuple(
version=Version(tag_name), name=tag_name, download_url=asset["browser_download_url"]
)
@click.command()
@@ -78,14 +73,20 @@ def update_virtualenv(force: bool, level: str) -> None:
with toml_file_path.open("rb") as f:
configurations = tomllib.load(f)
default = configurations.pop("default")
version = str(default["version"])
versions = git_ls_remote_versions(GET_VIRTUALENV_GITHUB)
if versions[0].version > Version(version):
version = versions[0].version_string
local_version = str(default["version"])
latest_release = get_latest_virtualenv_release()
if latest_release.version > Version(local_version):
version = latest_release.name
url = latest_release.download_url
else:
version = local_version
url = default["url"]
configurations["default"] = {
"version": version,
"url": GET_VIRTUALENV_URL_TEMPLATE.format(version=version),
"url": url,
}
result_toml = "".join(
f'{key} = {{ version = "{value["version"]}", url = "{value["url"]}" }}\n'
+1 -1
View File
@@ -1 +1 @@
__version__ = "3.1.1"
__version__ = "3.3.0"
+110 -32
View File
@@ -1,7 +1,6 @@
import argparse
import contextlib
import dataclasses
import functools
import os
import shutil
import sys
@@ -9,7 +8,7 @@ import tarfile
import textwrap
import traceback
import typing
from collections.abc import Iterable, Sequence
from collections.abc import Generator, Iterable, Sequence
from pathlib import Path
from tempfile import mkdtemp
from typing import Any, Literal, TextIO
@@ -24,7 +23,7 @@ from cibuildwheel.options import CommandLineArguments, Options, compute_options
from cibuildwheel.platforms import ALL_PLATFORM_MODULES, get_build_identifiers, native_platform
from cibuildwheel.selector import BuildSelector, EnableGroup, selector_matches
from cibuildwheel.typing import PLATFORMS, PlatformName
from cibuildwheel.util.file import CIBW_CACHE_PATH
from cibuildwheel.util.file import CIBW_CACHE_PATH, ensure_cache_sentinel
from cibuildwheel.util.helpers import strtobool
from cibuildwheel.util.resources import read_all_configs
@@ -80,16 +79,14 @@ def main_inner(global_options: GlobalOptions) -> None:
rather than exiting directly.
"""
make_parser = functools.partial(argparse.ArgumentParser, allow_abbrev=False)
if sys.version_info >= (3, 14):
make_parser = functools.partial(make_parser, color=True, suggest_on_error=True)
parser = make_parser(
parser = argparse.ArgumentParser(
description="Build wheels for all the platforms.",
epilog="""
Most options are supplied via environment variables or in
--config-file (pyproject.toml usually). See
https://github.com/pypa/cibuildwheel#options for info.
""",
allow_abbrev=False,
)
parser.add_argument(
@@ -182,6 +179,12 @@ def main_inner(global_options: GlobalOptions) -> None:
help="Print the build identifiers matched by the current invocation and exit.",
)
parser.add_argument(
"--clean-cache",
action="store_true",
help="Clear the cibuildwheel cache and exit.",
)
parser.add_argument(
"--allow-empty",
action="store_true",
@@ -199,6 +202,48 @@ def main_inner(global_options: GlobalOptions) -> None:
global_options.print_traceback_on_error = args.debug_traceback
if args.clean_cache:
if not CIBW_CACHE_PATH.exists():
print(f"Cache directory does not exist: {CIBW_CACHE_PATH}")
sys.exit(0)
sentinel_file = CIBW_CACHE_PATH / "CACHEDIR.TAG"
if not sentinel_file.exists():
print(
f"Error: {CIBW_CACHE_PATH} does not appear to be a cibuildwheel cache directory.",
"Only directories with a CACHEDIR.TAG sentinel file can be cleaned.",
sep="\n",
file=sys.stderr,
)
sys.exit(1)
# Verify signature to ensure it's a proper cache dir
# See https://bford.info/cachedir/ for more
try:
sentinel_content = sentinel_file.read_text(encoding="utf-8")
except OSError as e:
print(f"Error reading cache directory tag: {e}", file=sys.stderr)
sys.exit(1)
if not sentinel_content.startswith("Signature: 8a477f597d28d172789f06886806bc55"):
print(
f"Error: {sentinel_file} does not contain a valid cache directory signature.",
"For safety, only properly signed cache directories can be cleaned.",
sep="\n",
file=sys.stderr,
)
sys.exit(1)
print(f"Clearing cache directory: {CIBW_CACHE_PATH}")
try:
shutil.rmtree(CIBW_CACHE_PATH)
print("Cache cleared successfully.")
except OSError as e:
print(f"Error clearing cache: {e}", file=sys.stderr)
sys.exit(1)
sys.exit(0)
args.package_dir = args.package_dir.resolve()
# This are always relative to the base directory, even in SDist builds
@@ -269,7 +314,7 @@ def _compute_platform(args: CommandLineArguments) -> PlatformName:
if args.only:
return _compute_platform_only(args.only)
elif platform_option_value != "auto":
return typing.cast(PlatformName, platform_option_value)
return typing.cast("PlatformName", platform_option_value)
return native_platform()
@@ -312,6 +357,7 @@ def build_in_directory(args: CommandLineArguments) -> None:
# create the cache dir before it gets printed & builds performed
CIBW_CACHE_PATH.mkdir(parents=True, exist_ok=True)
ensure_cache_sentinel(CIBW_CACHE_PATH)
print_preamble(platform=platform, options=options, identifiers=identifiers)
@@ -369,41 +415,61 @@ def print_preamble(platform: str, options: Options, identifiers: Sequence[str])
print(f"Cache folder: {CIBW_CACHE_PATH}")
print()
warnings = detect_warnings(options=options, identifiers=identifiers)
warnings = detect_warnings(options=options)
for warning in warnings:
log.warning(warning)
error_list = list(detect_errors(options=options, identifiers=identifiers))
if error_list:
for error in error_list:
log.error(error)
msg = "\n".join(error_list)
raise errors.ConfigurationError(msg)
print("Here we go!\n")
def detect_warnings(*, options: Options, identifiers: Iterable[str]) -> list[str]:
warnings = []
python_version_deprecation = ((3, 11), 3)
if sys.version_info[:2] < python_version_deprecation[0]:
python_version = ".".join(map(str, python_version_deprecation[0]))
msg = (
f"cibuildwheel {python_version_deprecation[1]} will require Python {python_version}+, "
"please upgrade the Python version used to run cibuildwheel. "
"This does not affect the versions you can target when building wheels. See: https://cibuildwheel.pypa.io/en/stable/#what-does-it-do"
def detect_errors(*, options: Options, identifiers: Iterable[str]) -> Generator[str, None, None]:
# Check for deprecated CIBW_FREE_THREADED_SUPPORT environment variable
if "CIBW_FREE_THREADED_SUPPORT" in os.environ:
yield (
"CIBW_FREE_THREADED_SUPPORT environment variable is no longer supported. "
'Use tool.cibuildwheel.enable = ["cpython-freethreading"] in pyproject.toml '
"or set CIBW_ENABLE=cpython-freethreading instead."
)
warnings.append(msg)
# warn about deprecated {python} and {pip}
# Deprecated {python} and {pip}
for option_name in ["test_command", "before_build"]:
option_values = [getattr(options.build_options(i), option_name) for i in identifiers]
if any(o and ("{python}" in o or "{pip}" in o) for o in option_values):
# Reminder: in an f-string, double braces means literal single brace
msg = (
yield (
f"{option_name}: '{{python}}' and '{{pip}}' are no longer supported "
"and have been removed in cibuildwheel 3. Simply use 'python' or 'pip' instead."
)
raise errors.ConfigurationError(msg)
def detect_warnings(*, options: Options) -> Generator[str, None, None]:
python_version_deprecation = ((3, 11), 3)
if sys.version_info[:2] < python_version_deprecation[0]:
python_version = ".".join(map(str, python_version_deprecation[0]))
yield (
f"cibuildwheel {python_version_deprecation[1]} will require Python {python_version}+, "
"please upgrade the Python version used to run cibuildwheel. "
"This does not affect the versions you can target when building wheels. See: https://cibuildwheel.pypa.io/en/stable/#what-does-it-do"
)
build_selector = options.globals.build_selector
test_selector = options.globals.test_selector
if EnableGroup.CPythonExperimentalRiscV64 in build_selector.enable:
yield (
"'cpython-experimental-riscv64' enable is deprecated and will be removed in a future version. "
"It should be removed from tool.cibuildwheel.enable in pyproject.toml "
"or CIBW_ENABLE environment variable."
)
all_valid_identifiers = [
config.identifier
for module in ALL_PLATFORM_MODULES.values()
@@ -417,27 +483,25 @@ def detect_warnings(*, options: Options, identifiers: Iterable[str]) -> list[str
identifier for identifier in all_valid_identifiers if enabled_selector(identifier)
]
warnings += check_for_invalid_selectors(
yield from check_for_invalid_selectors(
selector_name="build",
selector_value=build_selector.build_config,
all_valid_identifiers=all_valid_identifiers,
all_enabled_identifiers=all_enabled_identifiers,
)
warnings += check_for_invalid_selectors(
yield from check_for_invalid_selectors(
selector_name="skip",
selector_value=build_selector.skip_config,
all_valid_identifiers=all_valid_identifiers,
all_enabled_identifiers=all_enabled_identifiers,
)
warnings += check_for_invalid_selectors(
yield from check_for_invalid_selectors(
selector_name="test_skip",
selector_value=test_selector.skip_config,
all_valid_identifiers=all_valid_identifiers,
all_enabled_identifiers=all_enabled_identifiers,
)
return warnings
def check_for_invalid_selectors(
*,
@@ -449,17 +513,31 @@ def check_for_invalid_selectors(
warnings = []
for selector in selector_value.split():
if not any(selector_matches(selector, i) for i in all_enabled_identifiers):
selector_ = selector
if selector_name == "test_skip":
# macosx_universal2 uses an additional identifier for tests which ends with ":{arch}"
values = selector.split(":")
universal2_identifiers = filter(
lambda x: x.endswith("-macosx_universal2"), all_valid_identifiers
)
if len(values) == 2 and any(
selector_matches(selector_, f"{i}:{arch}")
for i in universal2_identifiers
for arch in ["arm64", "x86_64"]
):
# just ignore the arch part in the rest of the check
selector_ = values[0]
if not any(selector_matches(selector_, i) for i in all_enabled_identifiers):
msg = f"Invalid {selector_name} selector: {selector!r}. "
error_type: type = errors.ConfigurationError
if any(selector_matches(selector, i) for i in all_valid_identifiers):
if any(selector_matches(selector_, i) for i in all_valid_identifiers):
msg += "This selector matches a group that wasn't enabled. Enable it using the `enable` option or remove this selector. "
if "p2" in selector or "p35" in selector:
if "p2" in selector_ or "p35" in selector_:
msg += f"cibuildwheel 3.x no longer supports Python < 3.8. Please use the 1.x series or update `{selector_name}`. "
error_type = errors.DeprecationError
if "p36" in selector or "p37" in selector:
if "p36" in selector_ or "p37" in selector_:
msg += f"cibuildwheel 3.x no longer supports Python < 3.8. Please use the 2.x series or update `{selector_name}`. "
error_type = errors.DeprecationError
+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]:
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]:
@@ -98,4 +98,4 @@ def get_pyodide_xbuildenv_info() -> PyodideXBuildEnvInfo:
"https://pyodide.github.io/pyodide/api/pyodide-cross-build-environments.json"
)
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}"
raise ValueError(msg)
name = typing.cast(BuildFrontendName, name)
name = typing.cast("BuildFrontendName", name)
args = config_dict.get("args") or []
return cls(name=name, args=args)
+1 -1
View File
@@ -242,7 +242,7 @@ class Logger:
github_summary = self._github_step_summary(duration=duration, options=options)
Path(summary_path).write_text(filter_ansi_codes(github_summary), encoding="utf-8")
n_wheels = len([info for info in self.summary if not info.filename])
n_wheels = len([info for info in self.summary if info.filename])
s = "s" if n_wheels > 1 else ""
duration_str = humanize.naturaldelta(duration)
print()
+42 -9
View File
@@ -36,6 +36,28 @@ class OCIPlatform(Enum):
RISCV64 = "linux/riscv64"
S390X = "linux/s390x"
@classmethod
def native(cls) -> "OCIPlatform":
"""Return the current OCI platform, or raise ValueError if unknown."""
arch = platform.machine().lower()
mapping = {
"i386": cls.i386,
"i686": cls.i386,
"x86_64": cls.AMD64,
"amd64": cls.AMD64,
"armv7l": cls.ARMV7,
"aarch64": cls.ARM64,
"arm64": cls.ARM64,
"ppc64le": cls.PPC64LE,
"riscv64": cls.RISCV64,
"s390x": cls.S390X,
}
try:
return mapping[arch]
except KeyError as ex:
msg = f"Unsupported platform architecture: {arch}"
raise OSError(msg) from ex
@dataclasses.dataclass(frozen=True)
class OCIContainerEngineConfig:
@@ -56,7 +78,7 @@ class OCIContainerEngineConfig:
msg = f"unknown container engine {name}"
raise ValueError(msg)
name = typing.cast(ContainerEngineName, name)
name = typing.cast("ContainerEngineName", name)
# 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 []
disable_host_mount_options = (
@@ -94,11 +116,14 @@ DEFAULT_ENGINE = OCIContainerEngineConfig("docker")
def _check_engine_version(engine: OCIContainerEngineConfig) -> None:
try:
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:
case "docker":
client_api_version = FlexibleVersion(version_info["Client"]["ApiVersion"])
server_api_version = FlexibleVersion(version_info["Server"]["ApiVersion"])
client_api_version = FlexibleVersion(version_info["client"]["apiversion"])
server_api_version = FlexibleVersion(version_info["server"]["apiversion"])
# --platform support was introduced in 1.32 as experimental, 1.41 removed the experimental flag
version = min(client_api_version, server_api_version)
minimum_version = FlexibleVersion("1.41")
@@ -113,9 +138,9 @@ def _check_engine_version(engine: OCIContainerEngineConfig) -> None:
)
case "podman":
# podman uses the same version string for "Version" & "ApiVersion"
client_version = FlexibleVersion(version_info["Client"]["Version"])
if "Server" in version_info:
server_version = FlexibleVersion(version_info["Server"]["Version"])
client_version = FlexibleVersion(version_info["client"]["version"])
if "server" in version_info:
server_version = FlexibleVersion(version_info["server"]["version"])
else:
server_version = client_version
# --platform support was introduced in v3
@@ -152,11 +177,19 @@ class OCIContainer:
back to cibuildwheel.
Example:
>>> # xdoctest: +REQUIRES(LINUX)
>>> from cibuildwheel.oci_container import * # NOQA
>>> from cibuildwheel.options import _get_pinned_container_images
>>> import pytest
>>> try:
... oci_platform = OCIPlatform.native()
... except OSError as ex:
... pytest.skip(str(ex))
>>> if oci_platform != OCIPlatform.AMD64:
... pytest.skip('only runs on amd64')
>>> image = _get_pinned_container_images()['x86_64']['manylinux2014']
>>> # Test the default container
>>> with OCIContainer(image=image) as self:
>>> with OCIContainer(image=image, oci_platform=oci_platform) as self:
... self.call(["echo", "hello world"])
... self.call(["cat", "/proc/1/cgroup"])
... print(self.get_environment())
@@ -485,7 +518,7 @@ class OCIContainer:
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:
# used as an EnvironmentExecutor to evaluate commands and capture output
+38 -3
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 .typing import PLATFORMS, PlatformName
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
MANYLINUX_ARCHS: Final[tuple[str, ...]] = (
@@ -63,6 +63,7 @@ class CommandLineArguments:
allow_empty: bool
debug_traceback: bool
enable: list[str]
clean_cache: bool
@classmethod
def defaults(cls) -> Self:
@@ -77,6 +78,7 @@ class CommandLineArguments:
print_build_identifiers=False,
debug_traceback=False,
enable=[],
clean_cache=False,
)
@@ -90,6 +92,20 @@ class GlobalOptions:
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)
class BuildOptions:
globals: GlobalOptions
@@ -108,6 +124,7 @@ class BuildOptions:
test_extras: str
test_groups: list[str]
test_environment: ParsedEnvironment
test_runtime: TestRuntimeConfig
build_verbosity: int
build_frontend: BuildFrontendConfig
config_settings: str
@@ -391,6 +408,7 @@ class OptionsReader:
by the platform.
Example:
>>> # xdoctest: +SKIP
>>> options_reader = OptionsReader(config_file, platform='macos')
>>> options_reader.get('cool-color')
@@ -657,7 +675,9 @@ class Options:
)
requires_python = None if requires_python_str is None else SpecifierSet(requires_python_str)
archs_config_str = args.archs or self.reader.get("archs", option_format=ListFormat(sep=" "))
archs_config_str = args.archs or self.reader.get(
"archs", option_format=ListFormat(sep=" "), ignore_empty=True
)
architectures = Architecture.parse_config(archs_config_str, platform=self.platform)
# Process `--only`
@@ -665,7 +685,7 @@ class Options:
build_config = args.only
skip_config = ""
architectures = Architecture.all_archs(self.platform)
enable = set(EnableGroup)
enable |= EnableGroup.all_groups()
build_selector = BuildSelector(
build_config=build_config,
@@ -756,6 +776,20 @@ class Options:
msg = f"Malformed environment option {test_environment_config!r}"
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", option_format=ListFormat(sep=" ")
).split()
@@ -863,6 +897,7 @@ class Options:
test_command=test_command,
test_sources=test_sources,
test_environment=test_environment,
test_runtime=test_runtime,
test_requires=[*test_requires, *test_requirements_from_groups],
test_extras=test_extras,
test_groups=test_groups,
+10 -7
View File
@@ -1,16 +1,19 @@
from __future__ import annotations
import sys
from collections.abc import Sequence
from pathlib import Path
from typing import Final, Protocol
from typing import TYPE_CHECKING, Final, Protocol
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.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):
+90 -36
View File
@@ -6,6 +6,7 @@ import re
import shlex
import shutil
import subprocess
import sysconfig
from collections.abc import Iterable, Iterator
from dataclasses import dataclass
from os.path import relpath
@@ -21,7 +22,7 @@ from elftools.common.exceptions import ELFError
from elftools.elf.elffile import ELFFile
from filelock import FileLock
from .. import errors, platforms
from .. import errors, platforms # pylint: disable=cyclic-import
from ..architecture import Architecture, arch_synonym
from ..frontend import get_build_frontend_extra_flags, parse_config_settings
from ..logger import log
@@ -33,14 +34,12 @@ from ..util.file import CIBW_CACHE_PATH, copy_test_sources, download, move_file
from ..util.helpers import prepare_command
from ..util.packaging import find_compatible_wheel
from ..util.python_build_standalone import create_python_build_standalone_environment
from ..venv import constraint_flags, virtualenv
from ..venv import constraint_flags, ensure_uv, virtualenv
def android_triplet(identifier: str) -> str:
return {
"arm64_v8a": "aarch64-linux-android",
"x86_64": "x86_64-linux-android",
}[parse_identifier(identifier)[1]]
ANDROID_TRIPLET = {
"arm64_v8a": "aarch64-linux-android",
"x86_64": "x86_64-linux-android",
}
def parse_identifier(identifier: str) -> tuple[str, str]:
@@ -52,6 +51,10 @@ def parse_identifier(identifier: str) -> tuple[str, str]:
return (f"{major}.{minor}", arch)
def android_triplet(identifier: str) -> str:
return ANDROID_TRIPLET[parse_identifier(identifier)[1]]
@dataclass(frozen=True)
class PythonConfiguration:
version: str
@@ -146,7 +149,7 @@ def build(options: Options, tmp_path: Path) -> None:
built_wheel = build_wheel(state)
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
if compatible_wheel is None:
@@ -186,6 +189,11 @@ def setup_env(
* android_env, which uses the environment while simulating running on Android.
"""
log.step("Setting up build environment...")
build_frontend = build_options.build_frontend.name
use_uv = build_frontend == "build[uv]"
if use_uv:
ensure_uv()
pip = ["pip"] if not use_uv else ["uv", "pip"]
# Create virtual environment
python_exe = create_python_build_standalone_environment(
@@ -196,16 +204,16 @@ def setup_env(
version=config.version, tmp_dir=build_path
)
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)
# Apply custom environment variables, and check environment is still valid
build_env = build_options.environment.as_dictionary(build_env)
build_env["PIP_DISABLE_PIP_VERSION_CHECK"] = "1"
for command in ["python", "pip"]:
which = call("which", command, env=build_env, capture_stdout=True).strip()
if which != f"{venv_dir}/bin/{command}":
for command in ["python"] if use_uv else ["python", "pip"]:
command_path = call("which", command, env=build_env, capture_stdout=True).strip()
if command_path != f"{venv_dir}/bin/{command}":
msg = (
f"{command} available on PATH doesn't match our installed instance. If you "
f"have modified PATH, ensure that you don't overwrite cibuildwheel's entry "
@@ -218,11 +226,10 @@ def setup_env(
android_env = setup_android_env(config, python_dir, venv_dir, build_env)
# Install build tools
build_frontend = build_options.build_frontend
if build_frontend.name != "build":
if build_frontend not in {"build", "build[uv]"}:
msg = "Android requires the build frontend to be 'build'"
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
# `get_requires_for_build` can run arbitrary code in setup.py scripts, which may be
@@ -242,13 +249,13 @@ def setup_env(
pb = ProjectBuilder.from_isolated_env(AndroidEnv(), build_options.package_dir)
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(
"wheel", parse_config_settings(build_options.config_settings)
)
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
@@ -273,11 +280,15 @@ def create_cmake_toolchain(
set(CMAKE_SYSTEM_VERSION 1)
# Tell CMake where to look for headers and libraries.
list(INSERT CMAKE_FIND_ROOT_PATH 0 {python_dir}/prefix)
set(CMAKE_FIND_ROOT_PATH "{python_dir}/prefix")
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE BOTH)
# Allow CMake to run Python in the simulated Android environment when
# policy CMP0190 is active.
set(CMAKE_CROSSCOMPILING_EMULATOR /bin/sh -c [["$0" "$@"]])
"""
),
file=toolchain_file,
@@ -434,7 +445,11 @@ def repair_wheel(state: BuildState, built_wheel: Path) -> Path:
if state.options.repair_command:
shell(
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,
)
@@ -507,17 +522,28 @@ def repair_default(
new_soname = soname_with_hash(src_path)
dst_path = libs_dir / new_soname
shutil.copyfile(src_path, dst_path)
call("patchelf", "--set-soname", new_soname, dst_path)
call(which("patchelf"), "--set-soname", new_soname, dst_path)
for path in paths_to_patch:
call("patchelf", "--replace-needed", old_soname, new_soname, path)
call(which("patchelf"), "--replace-needed", old_soname, new_soname, path)
call(
"patchelf",
which("patchelf"),
"--set-rpath",
f"${{ORIGIN}}/{relpath(libs_dir, path.parent)}",
path,
)
call("wheel", "pack", unpacked_dir, "-d", repaired_wheel_dir)
call(which("wheel"), "pack", unpacked_dir, "-d", repaired_wheel_dir)
# If cibuildwheel was called without activating its environment, its scripts directory
# will not be on the PATH.
def which(cmd: str) -> str:
scripts_dir = sysconfig.get_path("scripts")
result = shutil.which(cmd, path=scripts_dir + os.pathsep + os.environ["PATH"])
if result is None:
msg = f"Couldn't find {cmd!r} in {scripts_dir} or on the PATH"
raise errors.FatalError(msg)
return result
def elf_file_filter(paths: Iterable[Path]) -> Iterator[tuple[Path, ELFFile]]:
@@ -543,12 +569,17 @@ def soname_with_hash(src_path: Path) -> str:
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
if not (test_command and state.options.test_selector(state.config.identifier)):
return
log.step("Testing wheel...")
use_uv = build_frontend == "build[uv]"
if use_uv:
ensure_uv()
pip = ["pip"] if not use_uv else ["uv", "pip"]
native_arch = arch_synonym(platform.machine(), platforms.native_platform(), "android")
if state.config.arch != native_arch:
log.warning(
@@ -564,20 +595,28 @@ def test_wheel(state: BuildState, wheel: Path) -> None:
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.
site_packages_dir = state.build_path / "site-packages"
site_packages_dir.mkdir()
call(
"pip",
*pip,
"install",
"--only-binary=:all:",
"--platform",
sysconfig_print("get_platform()", state.android_env).replace("-", "_"),
*platform_args,
"--target",
site_packages_dir,
f"{wheel}{state.options.test_extras}",
*state.options.test_requires,
env=state.build_env,
env=state.android_env,
)
# Copy test-sources.
@@ -601,8 +640,11 @@ def test_wheel(state: BuildState, wheel: Path) -> None:
# Parse test-command.
test_args = shlex.split(test_command)
if test_args[:2] in [["python", "-c"], ["python", "-m"]]:
test_args[:3] = [test_args[1], test_args[2], "--"]
if test_args[0] in ["python", "python3"] and any(arg in test_args for arg in ["-c", "-m"]):
# 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"]:
# We transform some commands into the `python -m` form, but this is deprecated.
msg = (
@@ -611,24 +653,36 @@ def test_wheel(state: BuildState, wheel: Path) -> None:
"If this works, all you need to do is add that to your test command."
)
log.warning(msg)
test_args[:1] = ["-m", test_args[0], "--"]
test_args.insert(0, "-m")
else:
msg = (
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)
# 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.
call(
state.python_dir / "android.py",
"test",
"--managed",
"maxVersion",
"--site-packages",
site_packages_dir,
"--cwd",
cwd_dir,
*emulator_args,
*(["-v"] if state.options.build_verbosity > 0 else []),
*test_runtime_args,
"--",
*test_args,
env=state.build_env,
)
+37 -19
View File
@@ -2,27 +2,23 @@ from __future__ import annotations
import dataclasses
import os
import platform
import shlex
import shutil
import subprocess
import sys
import textwrap
from collections.abc import Sequence, Set
from pathlib import Path
from typing import assert_never
from typing import TYPE_CHECKING, assert_never
from filelock import FileLock
from .. import errors
from ..architecture import Architecture
from ..environment import ParsedEnvironment
from ..frontend import (
BuildFrontendName,
get_build_frontend_extra_flags,
)
from ..logger import log
from ..options import Options
from ..selector import BuildSelector
from ..util import resources
from ..util.cmd import call, shell, split_command
from ..util.file import (
@@ -33,13 +29,19 @@ from ..util.file import (
)
from ..util.helpers import prepare_command, unwrap_preserving_paragraphs
from ..util.packaging import (
combine_constraints,
find_compatible_wheel,
get_pip_version,
)
from ..venv import constraint_flags, virtualenv
from .macos import install_cpython as install_build_cpython
if TYPE_CHECKING:
from collections.abc import Sequence, Set
from ..architecture import Architecture
from ..environment import ParsedEnvironment
from ..options import Options
from ..selector import BuildSelector
@dataclasses.dataclass(frozen=True, kw_only=True)
class PythonConfiguration:
@@ -461,7 +463,6 @@ def build(options: Options, tmp_path: Path) -> None:
build_frontend=build_frontend.name,
xbuild_tools=build_options.xbuild_tools,
)
pip_version = get_pip_version(env)
compatible_wheel = find_compatible_wheel(built_wheels, config.identifier)
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_env = env.copy()
build_env["VIRTUALENV_PIP"] = pip_version
if constraints_path:
combine_constraints(build_env, constraints_path, None)
match build_frontend.name:
case "pip":
# 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}",
"--no-deps",
*extra_flags,
env=build_env,
env=env,
)
case "build":
call(
@@ -519,7 +515,7 @@ def build(options: Options, tmp_path: Path) -> None:
"--wheel",
f"--outdir={built_wheel_dir}",
*extra_flags,
env=build_env,
env=env,
)
case _:
assert_never(build_frontend)
@@ -537,9 +533,7 @@ def build(options: Options, tmp_path: Path) -> None:
elif config.arch != os.uname().machine:
log.step("Skipping tests on non-native simulator architecture")
else:
test_env = build_options.test_environment.as_dictionary(
prev_environment=build_env
)
test_env = build_options.test_environment.as_dictionary(prev_environment=env)
if build_options.before_test:
before_test_prepared = prepare_command(
@@ -653,11 +647,35 @@ def build(options: Options, tmp_path: Path) -> None:
)
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(
"python",
testbed_path,
"run",
*(["--verbose"] if build_options.build_verbosity > 0 else []),
*test_runtime_args,
"--",
*final_command,
env=test_env,
+9 -3
View File
@@ -6,7 +6,7 @@ import textwrap
from collections import OrderedDict
from collections.abc import Iterable, Iterator, Sequence, Set
from pathlib import Path, PurePath, PurePosixPath
from typing import assert_never
from typing import TYPE_CHECKING, assert_never
from .. import errors
from ..architecture import Architecture
@@ -15,12 +15,14 @@ from ..logger import log
from ..oci_container import OCIContainer, OCIContainerEngineConfig, OCIPlatform
from ..options import BuildOptions, Options
from ..selector import BuildSelector
from ..typing import PathOrStr
from ..util import resources
from ..util.file import copy_test_sources
from ..util.helpers import prepare_command, unwrap
from ..util.packaging import find_compatible_wheel
if TYPE_CHECKING:
from ..typing import PathOrStr
ARCHITECTURE_OCI_PLATFORM_MAP = {
Architecture.x86_64: OCIPlatform.AMD64,
Architecture.i686: OCIPlatform.i386,
@@ -320,7 +322,11 @@ def build_in_container(
if build_options.repair_command:
log.step("Repairing wheel...")
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)
else:
+17 -19
View File
@@ -32,8 +32,8 @@ from ..util.file import (
move_file,
)
from ..util.helpers import prepare_command, unwrap
from ..util.packaging import combine_constraints, find_compatible_wheel, get_pip_version
from ..venv import constraint_flags, find_uv, virtualenv
from ..util.packaging import find_compatible_wheel, get_pip_version
from ..venv import constraint_flags, ensure_uv, virtualenv
@functools.cache
@@ -60,7 +60,7 @@ def get_macos_version() -> tuple[int, int]:
capture_stdout=True,
)
version = tuple(map(int, version_str.split(".")[:2]))
return typing.cast(tuple[int, int], version)
return typing.cast("tuple[int, int]", version)
@functools.cache
@@ -141,7 +141,8 @@ def install_cpython(_tmp: Path, version: str, url: str, free_threading: bool) ->
# let the user know & provide a link to the installer
msg = inspect.cleandoc(
f"""
Error: CPython {version} is not installed.
Framework CPython {version} not detected as installed in:
{installation_path}
cibuildwheel will not perform system-wide installs when running outside of CI.
To build locally, install CPython {version} on this machine, or, disable this
version of Python using CIBW_SKIP=cp{version.replace(".", "")}-macosx_*
@@ -216,8 +217,9 @@ def setup_python(
environment: ParsedEnvironment,
build_frontend: BuildFrontendName,
) -> tuple[Path, dict[str, str]]:
uv_path = find_uv()
use_uv = build_frontend == "build[uv]"
if use_uv:
ensure_uv()
tmp.mkdir()
implementation_id = python_configuration.identifier.split("-")[0]
@@ -289,8 +291,11 @@ def setup_python(
# For arm64, the minimal deployment target is 11.0.
# On x86_64 (or universal2), use 10.9 as a default.
# CPython 3.12.6+ needs 10.13.
# CPython 3.14.0 needs 10.15.
if config_is_arm64:
default_target = "11.0"
elif Version(python_configuration.version) >= Version("3.14"):
default_target = "10.15"
elif Version(python_configuration.version) >= Version("3.12"):
default_target = "10.13"
elif python_configuration.identifier.startswith("pp") and Version(
@@ -366,14 +371,13 @@ def setup_python(
env=env,
)
case "build[uv]":
assert uv_path is not None
call(
uv_path,
"uv",
"pip",
"install",
"--upgrade",
"delocate",
"build[virtualenv, uv]",
"build",
*constraint_flags(dependency_constraint),
env=env,
)
@@ -410,11 +414,9 @@ def build(options: Options, tmp_path: Path) -> None:
build_options = options.build_options(config.identifier)
build_frontend = build_options.build_frontend
use_uv = build_frontend.name == "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"]
if use_uv:
ensure_uv()
pip = ["pip"] if not use_uv else ["uv", "pip"]
log.build_start(config.identifier)
identifier_tmp_dir = tmp_path / config.identifier
@@ -461,12 +463,6 @@ def build(options: Options, tmp_path: Path) -> None:
)
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:
case "pip":
@@ -525,6 +521,8 @@ def build(options: Options, tmp_path: Path) -> None:
wheel=built_wheel,
dest_dir=repaired_wheel_dir,
delocate_archs=delocate_archs,
package=build_options.package_dir,
project=".",
)
shell(repair_command_prepared, env=env)
else:
+6 -9
View File
@@ -32,7 +32,7 @@ from ..util.file import (
move_file,
)
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 (
PythonBuildStandaloneError,
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}"
raise ValueError(msg)
return typing.cast(list[PyodideXBuildEnvInfo], xbuildenvs_info["environments"])
return typing.cast("list[PyodideXBuildEnvInfo]", xbuildenvs_info["environments"])
def get_xbuildenv_version_info(
@@ -284,9 +284,8 @@ def setup_python(
"pip",
"install",
"--upgrade",
"auditwheel-emscripten",
"build[virtualenv]",
"pyodide-build",
"build[virtualenv]",
*constraint_flags(constraints_path),
env=env,
)
@@ -420,17 +419,13 @@ def build(options: Options, tmp_path: Path) -> None:
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(
"pyodide",
"build",
build_options.package_dir,
f"--outdir={built_wheel_dir}",
*extra_flags,
env=build_env,
env=env,
)
built_wheel = next(built_wheel_dir.glob("*.whl"))
@@ -444,6 +439,8 @@ def build(options: Options, tmp_path: Path) -> None:
build_options.repair_command,
wheel=built_wheel,
dest_dir=repaired_wheel_dir,
package=build_options.package_dir,
project=".",
)
shell(repair_command_prepared, env=env)
log.step_end()
+24 -22
View File
@@ -23,8 +23,8 @@ from ..util import resources
from ..util.cmd import call, shell
from ..util.file import CIBW_CACHE_PATH, copy_test_sources, download, extract_zip, move_file
from ..util.helpers import prepare_command, unwrap
from ..util.packaging import combine_constraints, find_compatible_wheel, get_pip_version
from ..venv import constraint_flags, find_uv, virtualenv
from ..util.packaging import find_compatible_wheel, get_pip_version
from ..venv import constraint_flags, ensure_uv, virtualenv
def get_nuget_args(
@@ -54,10 +54,17 @@ def get_nuget_args(
@dataclasses.dataclass(frozen=True, kw_only=True)
class PythonConfiguration:
version: str
arch: str
identifier: str
url: str | None = None
@property
def arch(self) -> str:
return {
"win32": "32",
"win_amd64": "64",
"win_arm64": "ARM64",
}[self.identifier.split("-")[-1]]
def all_python_configurations() -> list[PythonConfiguration]:
config_dicts = resources.read_python_configs("windows")
@@ -265,7 +272,8 @@ def setup_python(
build_frontend = "build"
use_uv = build_frontend == "build[uv]"
uv_path = find_uv()
if use_uv:
ensure_uv()
log.step("Setting up build environment...")
venv_path = tmp / "venv"
@@ -316,13 +324,12 @@ def setup_python(
env=env,
)
case "build[uv]":
assert uv_path is not None
call(
uv_path,
"uv",
"pip",
"install",
"--upgrade",
"build[virtualenv]",
"build",
*constraint_flags(dependency_constraint),
env=env,
)
@@ -332,11 +339,11 @@ def setup_python(
setup_setuptools_cross_compile(tmp, python_configuration, python_libs_base, env)
setup_rust_cross_compile(tmp, python_configuration, python_libs_base, env)
if implementation_id.startswith("gp"):
# GraalPy fails to discover compilers, setup the relevant environment
if implementation_id.startswith("gp311"):
# GraalPy 24 fails to discover compilers, setup the relevant environment
# variables. Adapted from
# https://github.com/microsoft/vswhere/wiki/Start-Developer-Command-Prompt
# Remove when https://github.com/oracle/graalpython/issues/492 is fixed.
# Remove when GraalPy 24.x is dropped.
vcpath = call(
Path(os.environ["PROGRAMFILES(X86)"])
/ "Microsoft Visual Studio"
@@ -446,28 +453,21 @@ def build(options: Options, tmp_path: Path) -> None:
)
if (
config.identifier.startswith("gp")
config.identifier.startswith("gp311")
and build_frontend.name == "build"
and "--no-isolation" not in extra_flags
and "-n" not in extra_flags
):
# GraalPy fails to discover its standard library when a venv is created
# GraalPy 24 fails to discover its standard library when a venv is created
# from a virtualenv seeded executable. See
# https://github.com/oracle/graalpython/issues/491 and remove this once
# fixed upstream.
# GraalPy 24 is dropped.
log.notice(
"Disabling build isolation to workaround GraalPy bug. If the build fails, consider using pip or build[uv] as build frontend."
)
shell("graalpy -m pip install setuptools wheel", env=env)
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:
case "pip":
# Path.resolve() is needed. Without it pip wheel may try to fetch package from pypi.org
@@ -481,7 +481,7 @@ def build(options: Options, tmp_path: Path) -> None:
f"--wheel-dir={built_wheel_dir}",
"--no-deps",
*extra_flags,
env=build_env,
env=env,
)
case "build" | "build[uv]":
if (
@@ -499,7 +499,7 @@ def build(options: Options, tmp_path: Path) -> None:
"--wheel",
f"--outdir={built_wheel_dir}",
*extra_flags,
env=build_env,
env=env,
)
case _:
assert_never(build_frontend)
@@ -518,6 +518,8 @@ def build(options: Options, tmp_path: Path) -> None:
build_options.repair_command,
wheel=built_wheel,
dest_dir=repaired_wheel_dir,
package=build_options.package_dir,
project=".",
)
shell(repair_command_prepared, env=env)
else:
+1 -1
View File
@@ -50,7 +50,7 @@ class Analyzer(ast.NodeVisitor):
)
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:
self.requires_python = version
+11 -7
View File
@@ -68,16 +68,20 @@ def initialize() -> None:
# sysconfig ###############################################################
#
# We don't change the actual sys.base_prefix and base_exec_prefix, because that
# 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,
# Load the sysconfigdata file, generating its name from sys.abiflags,
# sys.platform, and sys.implementation._multiarch.
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
# sys.platform, sysconfig.get_config_var("ANDROID_API_LEVEL") (see localized_vars in
# android.py), and os.uname.
+59 -52
View File
@@ -23,6 +23,7 @@ python_configurations = [
{ identifier = "pp310-manylinux_x86_64", version = "3.10", path_str = "/opt/python/pp310-pypy310_pp73" },
{ identifier = "pp311-manylinux_x86_64", version = "3.11", path_str = "/opt/python/pp311-pypy311_pp73" },
{ identifier = "gp311_242-manylinux_x86_64", version = "3.11", path_str = "/opt/python/graalpy311-graalpy242_311_native" },
{ identifier = "gp312_250-manylinux_x86_64", version = "3.12", path_str = "/opt/python/graalpy312-graalpy250_312_native" },
{ identifier = "cp38-manylinux_aarch64", version = "3.8", path_str = "/opt/python/cp38-cp38" },
{ identifier = "cp39-manylinux_aarch64", version = "3.9", path_str = "/opt/python/cp39-cp39" },
{ identifier = "cp310-manylinux_aarch64", version = "3.10", path_str = "/opt/python/cp310-cp310" },
@@ -73,6 +74,7 @@ python_configurations = [
{ identifier = "pp310-manylinux_aarch64", version = "3.10", path_str = "/opt/python/pp310-pypy310_pp73" },
{ identifier = "pp311-manylinux_aarch64", version = "3.11", path_str = "/opt/python/pp311-pypy311_pp73" },
{ identifier = "gp311_242-manylinux_aarch64", version = "3.11", path_str = "/opt/python/graalpy311-graalpy242_311_native" },
{ identifier = "gp312_250-manylinux_aarch64", version = "3.12", path_str = "/opt/python/graalpy312-graalpy250_312_native" },
{ identifier = "pp38-manylinux_i686", version = "3.8", path_str = "/opt/python/pp38-pypy38_pp73" },
{ identifier = "pp39-manylinux_i686", version = "3.9", path_str = "/opt/python/pp39-pypy39_pp73" },
{ identifier = "pp310-manylinux_i686", version = "3.10", path_str = "/opt/python/pp310-pypy310_pp73" },
@@ -159,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_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 = "cp313-macosx_x86_64", version = "3.13", url = "https://www.python.org/ftp/python/3.13.5/python-3.13.5-macos11.pkg" },
{ identifier = "cp313-macosx_arm64", version = "3.13", url = "https://www.python.org/ftp/python/3.13.5/python-3.13.5-macos11.pkg" },
{ identifier = "cp313-macosx_universal2", version = "3.13", url = "https://www.python.org/ftp/python/3.13.5/python-3.13.5-macos11.pkg" },
{ identifier = "cp313t-macosx_x86_64", version = "3.13", url = "https://www.python.org/ftp/python/3.13.5/python-3.13.5-macos11.pkg" },
{ identifier = "cp313t-macosx_arm64", version = "3.13", url = "https://www.python.org/ftp/python/3.13.5/python-3.13.5-macos11.pkg" },
{ identifier = "cp313t-macosx_universal2", version = "3.13", url = "https://www.python.org/ftp/python/3.13.5/python-3.13.5-macos11.pkg" },
{ identifier = "cp314-macosx_x86_64", version = "3.14", url = "https://www.python.org/ftp/python/3.14.0/python-3.14.0rc1-macos11.pkg" },
{ identifier = "cp314-macosx_arm64", version = "3.14", url = "https://www.python.org/ftp/python/3.14.0/python-3.14.0rc1-macos11.pkg" },
{ identifier = "cp314-macosx_universal2", version = "3.14", url = "https://www.python.org/ftp/python/3.14.0/python-3.14.0rc1-macos11.pkg" },
{ identifier = "cp314t-macosx_x86_64", version = "3.14", url = "https://www.python.org/ftp/python/3.14.0/python-3.14.0rc1-macos11.pkg" },
{ identifier = "cp314t-macosx_arm64", version = "3.14", url = "https://www.python.org/ftp/python/3.14.0/python-3.14.0rc1-macos11.pkg" },
{ identifier = "cp314t-macosx_universal2", version = "3.14", url = "https://www.python.org/ftp/python/3.14.0/python-3.14.0rc1-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.11/python-3.13.11-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.11/python-3.13.11-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.11/python-3.13.11-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.2/python-3.14.2-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.2/python-3.14.2-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.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_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" },
@@ -181,61 +183,66 @@ 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 = "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 = "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.1/graalpy-25.0.1-macos-aarch64.tar.gz" },
]
[windows]
python_configurations = [
{ identifier = "cp38-win32", version = "3.8.10", arch = "32" },
{ identifier = "cp38-win_amd64", version = "3.8.10", arch = "64" },
{ identifier = "cp39-win32", version = "3.9.13", arch = "32" },
{ identifier = "cp39-win_amd64", version = "3.9.13", arch = "64" },
{ identifier = "cp310-win32", version = "3.10.11", arch = "32" },
{ identifier = "cp310-win_amd64", version = "3.10.11", arch = "64" },
{ identifier = "cp311-win32", version = "3.11.9", arch = "32" },
{ identifier = "cp311-win_amd64", version = "3.11.9", arch = "64" },
{ identifier = "cp312-win32", version = "3.12.10", arch = "32" },
{ identifier = "cp312-win_amd64", version = "3.12.10", arch = "64" },
{ identifier = "cp313-win32", version = "3.13.5", arch = "32" },
{ identifier = "cp313t-win32", version = "3.13.5", arch = "32" },
{ identifier = "cp313-win_amd64", version = "3.13.5", arch = "64" },
{ identifier = "cp313t-win_amd64", version = "3.13.5", arch = "64" },
{ identifier = "cp314-win32", version = "3.14.0-rc1", arch = "32" },
{ identifier = "cp314t-win32", version = "3.14.0-rc1", arch = "32" },
{ identifier = "cp314-win_amd64", version = "3.14.0-rc1", arch = "64" },
{ identifier = "cp314t-win_amd64", version = "3.14.0-rc1", arch = "64" },
{ identifier = "cp39-win_arm64", version = "3.9.10", arch = "ARM64" },
{ identifier = "cp310-win_arm64", version = "3.10.11", arch = "ARM64" },
{ identifier = "cp311-win_arm64", version = "3.11.9", arch = "ARM64" },
{ identifier = "cp312-win_arm64", version = "3.12.10", arch = "ARM64" },
{ identifier = "cp313-win_arm64", version = "3.13.5", arch = "ARM64" },
{ identifier = "cp313t-win_arm64", version = "3.13.5", arch = "ARM64" },
{ identifier = "cp314-win_arm64", version = "3.14.0-rc1", arch = "ARM64" },
{ identifier = "cp314t-win_arm64", version = "3.14.0-rc1", arch = "ARM64" },
{ identifier = "pp38-win_amd64", version = "3.8", arch = "64", url = "https://downloads.python.org/pypy/pypy3.8-v7.3.11-win64.zip" },
{ identifier = "pp39-win_amd64", version = "3.9", arch = "64", url = "https://downloads.python.org/pypy/pypy3.9-v7.3.16-win64.zip" },
{ identifier = "pp310-win_amd64", version = "3.10", arch = "64", url = "https://downloads.python.org/pypy/pypy3.10-v7.3.19-win64.zip" },
{ identifier = "pp311-win_amd64", version = "3.11", arch = "64", url = "https://downloads.python.org/pypy/pypy3.11-v7.3.20-win64.zip" },
{ identifier = "gp311_242-win_amd64", version = "3.11", arch = "64", url = "https://github.com/oracle/graalpython/releases/download/graal-24.2.2/graalpy-24.2.2-windows-amd64.zip" },
{ identifier = "cp38-win32", version = "3.8.10" },
{ identifier = "cp38-win_amd64", version = "3.8.10" },
{ identifier = "cp39-win32", version = "3.9.13" },
{ identifier = "cp39-win_amd64", version = "3.9.13" },
{ identifier = "cp310-win32", version = "3.10.11" },
{ identifier = "cp310-win_amd64", version = "3.10.11" },
{ identifier = "cp311-win32", version = "3.11.9" },
{ identifier = "cp311-win_amd64", version = "3.11.9" },
{ identifier = "cp312-win32", version = "3.12.10" },
{ identifier = "cp312-win_amd64", version = "3.12.10" },
{ identifier = "cp313-win32", version = "3.13.11" },
{ identifier = "cp313t-win32", version = "3.13.11" },
{ identifier = "cp313-win_amd64", version = "3.13.11" },
{ identifier = "cp313t-win_amd64", version = "3.13.11" },
{ identifier = "cp314-win32", version = "3.14.2" },
{ identifier = "cp314t-win32", version = "3.14.2" },
{ identifier = "cp314-win_amd64", version = "3.14.2" },
{ identifier = "cp314t-win_amd64", version = "3.14.2" },
{ identifier = "cp39-win_arm64", version = "3.9.10" },
{ identifier = "cp310-win_arm64", version = "3.10.11" },
{ identifier = "cp311-win_arm64", version = "3.11.9" },
{ identifier = "cp312-win_arm64", version = "3.12.10" },
{ identifier = "cp313-win_arm64", version = "3.13.11" },
{ identifier = "cp313t-win_arm64", version = "3.13.11" },
{ identifier = "cp314-win_arm64", version = "3.14.2" },
{ 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 = "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 = "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 = "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]
python_configurations = [
{ 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.0", node_version = "v22" },
{ identifier = "cp313-pyodide_wasm32", version = "3.13", default_pyodide_version = "0.29.0", node_version = "v22" },
]
[android]
python_configurations = [
{ identifier = "cp313-android_arm64_v8a", version = "3.13", url = "https://repo.maven.apache.org/maven2/com/chaquo/python/python/3.13.5+20250722.214220/python-3.13.5+20250722.214220-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.5+20250722.214220/python-3.13.5+20250722.214220-x86_64-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.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.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.2/python-3.14.2-x86_64-linux-android.tar.gz" },
]
[ios]
python_configurations = [
{ identifier = "cp313-ios_arm64_iphoneos", version = "3.13", url = "https://github.com/beeware/Python-Apple-support/releases/download/3.13-b9/Python-3.13-iOS-support.b9.tar.gz" },
{ identifier = "cp313-ios_x86_64_iphonesimulator", version = "3.13", url = "https://github.com/beeware/Python-Apple-support/releases/download/3.13-b9/Python-3.13-iOS-support.b9.tar.gz" },
{ identifier = "cp313-ios_arm64_iphonesimulator", version = "3.13", url = "https://github.com/beeware/Python-Apple-support/releases/download/3.13-b9/Python-3.13-iOS-support.b9.tar.gz" },
{ identifier = "cp314-ios_arm64_iphoneos", version = "3.14", url = "https://github.com/beeware/Python-Apple-support/releases/download/3.14-b5/Python-3.14-iOS-support.b5.tar.gz" },
{ identifier = "cp314-ios_x86_64_iphonesimulator", version = "3.14", url = "https://github.com/beeware/Python-Apple-support/releases/download/3.14-b5/Python-3.14-iOS-support.b5.tar.gz" },
{ identifier = "cp314-ios_arm64_iphonesimulator", version = "3.14", url = "https://github.com/beeware/Python-Apple-support/releases/download/3.14-b5/Python-3.14-iOS-support.b5.tar.gz" },
{ identifier = "cp313-ios_arm64_iphoneos", version = "3.13", url = "https://github.com/beeware/Python-Apple-support/releases/download/3.13-b12/Python-3.13-iOS-support.b12.tar.gz" },
{ identifier = "cp313-ios_x86_64_iphonesimulator", version = "3.13", url = "https://github.com/beeware/Python-Apple-support/releases/download/3.13-b12/Python-3.13-iOS-support.b12.tar.gz" },
{ identifier = "cp313-ios_arm64_iphonesimulator", version = "3.13", url = "https://github.com/beeware/Python-Apple-support/releases/download/3.13-b12/Python-3.13-iOS-support.b12.tar.gz" },
{ identifier = "cp314-ios_arm64_iphoneos", version = "3.14", url = "https://github.com/beeware/Python-Apple-support/releases/download/3.14-b8/Python-3.14-iOS-support.b8.tar.gz" },
{ identifier = "cp314-ios_x86_64_iphonesimulator", version = "3.14", url = "https://github.com/beeware/Python-Apple-support/releases/download/3.14-b8/Python-3.14-iOS-support.b8.tar.gz" },
{ identifier = "cp314-ios_arm64_iphonesimulator", version = "3.14", url = "https://github.com/beeware/Python-Apple-support/releases/download/3.14-b8/Python-3.14-iOS-support.b8.tar.gz" },
]
@@ -569,6 +569,39 @@
],
"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": {
"type": "array",
"description": "An overrides array",
@@ -638,6 +671,9 @@
},
"test-environment": {
"$ref": "#/$defs/inherit"
},
"test-runtime": {
"$ref": "#/$defs/inherit"
}
}
},
@@ -748,6 +784,9 @@
},
"test-environment": {
"$ref": "#/properties/test-environment"
},
"test-runtime": {
"$ref": "#/properties/test-runtime"
}
}
}
@@ -876,6 +915,9 @@
},
"test-environment": {
"$ref": "#/properties/test-environment"
},
"test-runtime": {
"$ref": "#/properties/test-runtime"
}
}
},
@@ -936,6 +978,9 @@
},
"test-environment": {
"$ref": "#/properties/test-environment"
},
"test-runtime": {
"$ref": "#/properties/test-runtime"
}
}
},
@@ -1009,6 +1054,9 @@
},
"test-environment": {
"$ref": "#/properties/test-environment"
},
"test-runtime": {
"$ref": "#/properties/test-runtime"
}
}
},
@@ -1069,6 +1117,9 @@
},
"test-environment": {
"$ref": "#/properties/test-environment"
},
"test-runtime": {
"$ref": "#/properties/test-runtime"
}
}
},
@@ -1129,6 +1180,9 @@
},
"test-environment": {
"$ref": "#/properties/test-environment"
},
"test-runtime": {
"$ref": "#/properties/test-runtime"
}
}
},
@@ -1189,6 +1243,9 @@
},
"test-environment": {
"$ref": "#/properties/test-environment"
},
"test-runtime": {
"$ref": "#/properties/test-runtime"
}
}
}
@@ -2,20 +2,20 @@
# nox -s update_constraints
annotated-types==0.7.0
# via pydantic
anyio==4.9.0
anyio==4.12.0
# via httpx
auditwheel-emscripten==0.1.0
auditwheel-emscripten==0.2.0
# via pyodide-build
build==1.2.2.post1
# via
# -r .nox/update_constraints/tmp/constraints-pyodide.in
# pyodide-build
certifi==2025.7.14
certifi==2025.11.12
# via
# httpcore
# httpx
# requests
charset-normalizer==3.4.2
charset-normalizer==3.4.4
# via requests
click==8.1.8
# via
@@ -23,7 +23,7 @@ click==8.1.8
# typer
distlib==0.4.0
# via virtualenv
filelock==3.18.0
filelock==3.20.0
# via virtualenv
h11==0.16.0
# via httpcore
@@ -31,14 +31,14 @@ httpcore==1.0.9
# via httpx
httpx==0.28.1
# via unearth
idna==3.10
idna==3.11
# via
# anyio
# httpx
# requests
leb128==1.0.8
# via auditwheel-emscripten
markdown-it-py==3.0.0
markdown-it-py==4.0.0
# via rich
mdurl==0.1.2
# via markdown-it-py
@@ -48,66 +48,64 @@ packaging==25.0
# build
# pyodide-build
# unearth
pip==25.1.1
pip==25.3
# via -r .nox/update_constraints/tmp/constraints-pyodide.in
platformdirs==4.3.8
platformdirs==4.5.1
# via
# pyodide-build
# virtualenv
pydantic==2.11.7
pydantic==2.12.5
# via
# pyodide-build
# pyodide-lock
pydantic-core==2.33.2
pydantic-core==2.41.5
# via pydantic
pygments==2.19.2
# via rich
pyodide-build==0.30.5
pyodide-build==0.30.9
# via -r .nox/update_constraints/tmp/constraints-pyodide.in
pyodide-cli==0.3.0
pyodide-cli==0.4.0
# via
# auditwheel-emscripten
# pyodide-build
pyodide-lock==0.1.0a7
pyodide-lock==0.1.0
# via pyodide-build
pyproject-hooks==1.2.0
# via build
requests==2.32.4
requests==2.32.5
# via pyodide-build
resolvelib==1.2.0
resolvelib==1.2.1
# via pyodide-build
rich==14.0.0
rich==14.2.0
# via
# pyodide-build
# pyodide-cli
# typer
ruamel-yaml==0.18.14
ruamel-yaml==0.18.16
# via pyodide-build
ruamel-yaml-clib==0.2.12
ruamel-yaml-clib==0.2.15
# via ruamel-yaml
shellingham==1.5.4
# via typer
sniffio==1.3.1
# via anyio
typer==0.16.0
typer==0.20.0
# via
# auditwheel-emscripten
# pyodide-build
# pyodide-cli
typing-extensions==4.14.1
typing-extensions==4.15.0
# via
# anyio
# pydantic
# pydantic-core
# typer
# typing-inspection
typing-inspection==0.4.1
typing-inspection==0.4.2
# via pydantic
unearth==0.17.5
unearth==0.18.1
# via pyodide-build
urllib3==2.5.0
urllib3==2.6.2
# via requests
virtualenv==20.32.0
virtualenv==20.35.4
# via
# build
# pyodide-build
@@ -2,20 +2,20 @@
# nox -s update_constraints
annotated-types==0.7.0
# via pydantic
anyio==4.9.0
anyio==4.12.0
# via httpx
auditwheel-emscripten==0.1.0
auditwheel-emscripten==0.2.0
# via pyodide-build
build==1.2.2.post1
# via
# -r .nox/update_constraints/tmp/constraints-pyodide.in
# pyodide-build
certifi==2025.7.14
certifi==2025.11.12
# via
# httpcore
# httpx
# requests
charset-normalizer==3.4.2
charset-normalizer==3.4.4
# via requests
click==8.1.8
# via
@@ -23,7 +23,7 @@ click==8.1.8
# typer
distlib==0.4.0
# via virtualenv
filelock==3.18.0
filelock==3.20.0
# via virtualenv
h11==0.16.0
# via httpcore
@@ -31,14 +31,14 @@ httpcore==1.0.9
# via httpx
httpx==0.28.1
# via unearth
idna==3.10
idna==3.11
# via
# anyio
# httpx
# requests
leb128==1.0.8
# via auditwheel-emscripten
markdown-it-py==3.0.0
markdown-it-py==4.0.0
# via rich
mdurl==0.1.2
# via markdown-it-py
@@ -48,65 +48,63 @@ packaging==25.0
# build
# pyodide-build
# unearth
pip==25.1.1
pip==25.3
# via -r .nox/update_constraints/tmp/constraints-pyodide.in
platformdirs==4.3.8
platformdirs==4.5.1
# via
# pyodide-build
# virtualenv
pydantic==2.11.7
pydantic==2.12.5
# via
# pyodide-build
# pyodide-lock
pydantic-core==2.33.2
pydantic-core==2.41.5
# via pydantic
pygments==2.19.2
# via rich
pyodide-build==0.30.5
pyodide-build==0.30.9
# via -r .nox/update_constraints/tmp/constraints-pyodide.in
pyodide-cli==0.3.0
pyodide-cli==0.4.0
# via
# auditwheel-emscripten
# pyodide-build
pyodide-lock==0.1.0a7
pyodide-lock==0.1.0
# via pyodide-build
pyproject-hooks==1.2.0
# via build
requests==2.32.4
requests==2.32.5
# via pyodide-build
resolvelib==1.2.0
resolvelib==1.2.1
# via pyodide-build
rich==14.0.0
rich==14.2.0
# via
# pyodide-build
# pyodide-cli
# typer
ruamel-yaml==0.18.14
ruamel-yaml==0.18.16
# via pyodide-build
ruamel-yaml-clib==0.2.12
ruamel-yaml-clib==0.2.15
# via ruamel-yaml
shellingham==1.5.4
# via typer
sniffio==1.3.1
# via anyio
typer==0.16.0
typer==0.20.0
# via
# auditwheel-emscripten
# pyodide-build
# pyodide-cli
typing-extensions==4.14.1
typing-extensions==4.15.0
# via
# pydantic
# pydantic-core
# typer
# typing-inspection
typing-inspection==0.4.1
typing-inspection==0.4.2
# via pydantic
unearth==0.17.5
unearth==0.18.1
# via pyodide-build
urllib3==2.5.0
urllib3==2.6.2
# via requests
virtualenv==20.32.0
virtualenv==20.35.4
# via
# build
# pyodide-build
@@ -1,34 +1,36 @@
# This file was autogenerated by uv via the following command:
# nox -s update_constraints
altgraph==0.17.4
altgraph==0.17.5
# via macholib
build==1.2.2.post1
build==1.3.0
# via -r cibuildwheel/resources/constraints.in
delocate==0.13.0
# via -r cibuildwheel/resources/constraints.in
distlib==0.4.0
# via virtualenv
filelock==3.18.0
filelock==3.20.0
# via virtualenv
importlib-metadata==8.7.0
# via build
macholib==1.16.3
macholib==1.16.4
# via delocate
packaging==25.0
# via
# build
# delocate
pip==25.1.1
pip==25.3
# via -r cibuildwheel/resources/constraints.in
platformdirs==4.3.8
platformdirs==4.5.1
# via virtualenv
pyproject-hooks==1.2.0
# via build
tomli==2.2.1
tomli==2.3.0
# via build
typing-extensions==4.14.1
# via delocate
virtualenv==20.32.0
typing-extensions==4.15.0
# via
# delocate
# virtualenv
virtualenv==20.35.4
# via -r cibuildwheel/resources/constraints.in
zipp==3.23.0
# via importlib-metadata
@@ -1,28 +1,28 @@
# This file was autogenerated by uv via the following command:
# nox -s update_constraints
altgraph==0.17.4
altgraph==0.17.5
# via macholib
build==1.2.2.post1
build==1.3.0
# via -r cibuildwheel/resources/constraints.in
delocate==0.13.0
# via -r cibuildwheel/resources/constraints.in
distlib==0.4.0
# via virtualenv
filelock==3.18.0
filelock==3.20.0
# via virtualenv
macholib==1.16.3
macholib==1.16.4
# via delocate
packaging==25.0
# via
# build
# delocate
pip==25.1.1
pip==25.3
# via -r cibuildwheel/resources/constraints.in
platformdirs==4.3.8
platformdirs==4.5.1
# via virtualenv
pyproject-hooks==1.2.0
# via build
typing-extensions==4.14.1
typing-extensions==4.15.0
# via delocate
virtualenv==20.32.0
virtualenv==20.35.4
# via -r cibuildwheel/resources/constraints.in
@@ -1,28 +1,28 @@
# This file was autogenerated by uv via the following command:
# nox -s update_constraints
altgraph==0.17.4
altgraph==0.17.5
# via macholib
build==1.2.2.post1
build==1.3.0
# via -r cibuildwheel/resources/constraints.in
delocate==0.13.0
# via -r cibuildwheel/resources/constraints.in
distlib==0.4.0
# via virtualenv
filelock==3.18.0
filelock==3.20.0
# via virtualenv
macholib==1.16.3
macholib==1.16.4
# via delocate
packaging==25.0
# via
# build
# delocate
pip==25.1.1
pip==25.3
# via -r cibuildwheel/resources/constraints.in
platformdirs==4.3.8
platformdirs==4.5.1
# via virtualenv
pyproject-hooks==1.2.0
# via build
typing-extensions==4.14.1
typing-extensions==4.15.0
# via delocate
virtualenv==20.32.0
virtualenv==20.35.4
# via -r cibuildwheel/resources/constraints.in
@@ -1,28 +1,28 @@
# This file was autogenerated by uv via the following command:
# nox -s update_constraints
altgraph==0.17.4
altgraph==0.17.5
# via macholib
build==1.2.2.post1
build==1.3.0
# via -r cibuildwheel/resources/constraints.in
delocate==0.13.0
# via -r cibuildwheel/resources/constraints.in
distlib==0.4.0
# via virtualenv
filelock==3.18.0
filelock==3.20.0
# via virtualenv
macholib==1.16.3
macholib==1.16.4
# via delocate
packaging==25.0
# via
# build
# delocate
pip==25.1.1
pip==25.3
# via -r cibuildwheel/resources/constraints.in
platformdirs==4.3.8
platformdirs==4.5.1
# via virtualenv
pyproject-hooks==1.2.0
# via build
typing-extensions==4.14.1
typing-extensions==4.15.0
# via delocate
virtualenv==20.32.0
virtualenv==20.35.4
# via -r cibuildwheel/resources/constraints.in
@@ -1,28 +1,28 @@
# This file was autogenerated by uv via the following command:
# nox -s update_constraints
altgraph==0.17.4
altgraph==0.17.5
# via macholib
build==1.2.2.post1
build==1.3.0
# via -r cibuildwheel/resources/constraints.in
delocate==0.13.0
# via -r cibuildwheel/resources/constraints.in
distlib==0.4.0
# via virtualenv
filelock==3.18.0
filelock==3.20.0
# via virtualenv
macholib==1.16.3
macholib==1.16.4
# via delocate
packaging==25.0
# via
# build
# delocate
pip==25.1.1
pip==25.3
# via -r cibuildwheel/resources/constraints.in
platformdirs==4.3.8
platformdirs==4.5.1
# via virtualenv
pyproject-hooks==1.2.0
# via build
typing-extensions==4.14.1
typing-extensions==4.15.0
# via delocate
virtualenv==20.32.0
virtualenv==20.35.4
# via -r cibuildwheel/resources/constraints.in
@@ -1,6 +1,6 @@
# This file was autogenerated by uv via the following command:
# nox -s update_constraints
altgraph==0.17.4
altgraph==0.17.5
# via macholib
build==1.2.2.post1
# via -r cibuildwheel/resources/constraints.in
@@ -12,7 +12,7 @@ filelock==3.16.1
# via virtualenv
importlib-metadata==8.5.0
# via build
macholib==1.16.3
macholib==1.16.4
# via delocate
packaging==25.0
# via
@@ -24,11 +24,13 @@ platformdirs==4.3.6
# via virtualenv
pyproject-hooks==1.2.0
# via build
tomli==2.2.1
tomli==2.3.0
# via build
typing-extensions==4.13.2
# via delocate
virtualenv==20.32.0
# via
# delocate
# virtualenv
virtualenv==20.35.4
# via -r cibuildwheel/resources/constraints.in
zipp==3.20.2
# via importlib-metadata
+12 -10
View File
@@ -1,34 +1,36 @@
# This file was autogenerated by uv via the following command:
# nox -s update_constraints
altgraph==0.17.4
altgraph==0.17.5
# via macholib
build==1.2.2.post1
build==1.3.0
# via -r cibuildwheel/resources/constraints.in
delocate==0.13.0
# via -r cibuildwheel/resources/constraints.in
distlib==0.4.0
# via virtualenv
filelock==3.18.0
filelock==3.19.1
# via virtualenv
importlib-metadata==8.7.0
# via build
macholib==1.16.3
macholib==1.16.4
# via delocate
packaging==25.0
# via
# build
# delocate
pip==25.1.1
pip==25.3
# via -r cibuildwheel/resources/constraints.in
platformdirs==4.3.8
platformdirs==4.4.0
# via virtualenv
pyproject-hooks==1.2.0
# via build
tomli==2.2.1
tomli==2.3.0
# via build
typing-extensions==4.14.1
# via delocate
virtualenv==20.32.0
typing-extensions==4.15.0
# via
# delocate
# virtualenv
virtualenv==20.35.4
# via -r cibuildwheel/resources/constraints.in
zipp==3.23.0
# via importlib-metadata
+8 -8
View File
@@ -1,28 +1,28 @@
# This file was autogenerated by uv via the following command:
# nox -s update_constraints
altgraph==0.17.4
altgraph==0.17.5
# via macholib
build==1.2.2.post1
build==1.3.0
# via -r cibuildwheel/resources/constraints.in
delocate==0.13.0
# via -r cibuildwheel/resources/constraints.in
distlib==0.4.0
# via virtualenv
filelock==3.18.0
filelock==3.20.0
# via virtualenv
macholib==1.16.3
macholib==1.16.4
# via delocate
packaging==25.0
# via
# build
# delocate
pip==25.1.1
pip==25.3
# via -r cibuildwheel/resources/constraints.in
platformdirs==4.3.8
platformdirs==4.5.1
# via virtualenv
pyproject-hooks==1.2.0
# via build
typing-extensions==4.14.1
typing-extensions==4.15.0
# via delocate
virtualenv==20.32.0
virtualenv==20.35.4
# via -r cibuildwheel/resources/constraints.in
+1
View File
@@ -25,6 +25,7 @@ test-requires = []
test-extras = []
test-groups = []
test-environment = {}
test-runtime = {}
container-engine = "docker"
+3 -2
View File
@@ -1,3 +1,4 @@
url = "https://nodejs.org/dist/"
v22 = "v22.17.1"
v20 = "v20.19.4"
v24 = "v24.12.0"
v22 = "v22.21.1"
v20 = "v20.19.6"
+34 -33
View File
@@ -1,53 +1,54 @@
[x86_64]
manylinux2014 = quay.io/pypa/manylinux2014_x86_64:2025.07.23-1
manylinux_2_28 = quay.io/pypa/manylinux_2_28_x86_64:2025.07.23-1
manylinux_2_34 = quay.io/pypa/manylinux_2_34_x86_64:2025.07.23-1
musllinux_1_2 = quay.io/pypa/musllinux_1_2_x86_64:2025.07.23-1
manylinux2014 = quay.io/pypa/manylinux2014_x86_64:2025.12.13-1
manylinux_2_28 = quay.io/pypa/manylinux_2_28_x86_64:2025.12.13-1
manylinux_2_34 = quay.io/pypa/manylinux_2_34_x86_64:2025.12.13-1
musllinux_1_2 = quay.io/pypa/musllinux_1_2_x86_64:2025.12.13-1
[i686]
manylinux2014 = quay.io/pypa/manylinux2014_i686:2025.07.23-1
manylinux_2_28 = quay.io/pypa/manylinux_2_28_i686:2025.07.23-1
manylinux_2_34 = quay.io/pypa/manylinux_2_34_i686:2025.07.23-1
musllinux_1_2 = quay.io/pypa/musllinux_1_2_i686:2025.07.23-1
manylinux2014 = quay.io/pypa/manylinux2014_i686:2025.12.13-1
manylinux_2_28 = quay.io/pypa/manylinux_2_28_i686:2025.12.13-1
manylinux_2_34 = quay.io/pypa/manylinux_2_34_i686:2025.12.13-1
musllinux_1_2 = quay.io/pypa/musllinux_1_2_i686:2025.12.13-1
[aarch64]
manylinux2014 = quay.io/pypa/manylinux2014_aarch64:2025.07.23-1
manylinux_2_28 = quay.io/pypa/manylinux_2_28_aarch64:2025.07.23-1
manylinux_2_34 = quay.io/pypa/manylinux_2_34_aarch64:2025.07.23-1
musllinux_1_2 = quay.io/pypa/musllinux_1_2_aarch64:2025.07.23-1
manylinux2014 = quay.io/pypa/manylinux2014_aarch64:2025.12.13-1
manylinux_2_28 = quay.io/pypa/manylinux_2_28_aarch64:2025.12.13-1
manylinux_2_34 = quay.io/pypa/manylinux_2_34_aarch64:2025.12.13-1
musllinux_1_2 = quay.io/pypa/musllinux_1_2_aarch64:2025.12.13-1
[ppc64le]
manylinux2014 = quay.io/pypa/manylinux2014_ppc64le:2025.07.23-1
manylinux_2_28 = quay.io/pypa/manylinux_2_28_ppc64le:2025.07.23-1
manylinux_2_34 = quay.io/pypa/manylinux_2_34_ppc64le:2025.07.23-1
musllinux_1_2 = quay.io/pypa/musllinux_1_2_ppc64le:2025.07.23-1
manylinux2014 = quay.io/pypa/manylinux2014_ppc64le:2025.12.13-1
manylinux_2_28 = quay.io/pypa/manylinux_2_28_ppc64le:2025.12.13-1
manylinux_2_34 = quay.io/pypa/manylinux_2_34_ppc64le:2025.12.13-1
musllinux_1_2 = quay.io/pypa/musllinux_1_2_ppc64le:2025.12.13-1
[s390x]
manylinux2014 = quay.io/pypa/manylinux2014_s390x:2025.07.23-1
manylinux_2_28 = quay.io/pypa/manylinux_2_28_s390x:2025.07.23-1
manylinux_2_34 = quay.io/pypa/manylinux_2_34_s390x:2025.07.23-1
musllinux_1_2 = quay.io/pypa/musllinux_1_2_s390x:2025.07.23-1
manylinux2014 = quay.io/pypa/manylinux2014_s390x:2025.12.13-1
manylinux_2_28 = quay.io/pypa/manylinux_2_28_s390x:2025.12.13-1
manylinux_2_34 = quay.io/pypa/manylinux_2_34_s390x:2025.12.13-1
musllinux_1_2 = quay.io/pypa/musllinux_1_2_s390x:2025.12.13-1
[pypy_x86_64]
manylinux2014 = quay.io/pypa/manylinux2014_x86_64:2025.07.23-1
manylinux_2_28 = quay.io/pypa/manylinux_2_28_x86_64:2025.07.23-1
manylinux_2_34 = quay.io/pypa/manylinux_2_34_x86_64:2025.07.23-1
manylinux2014 = quay.io/pypa/manylinux2014_x86_64:2025.12.13-1
manylinux_2_28 = quay.io/pypa/manylinux_2_28_x86_64:2025.12.13-1
manylinux_2_34 = quay.io/pypa/manylinux_2_34_x86_64:2025.12.13-1
[pypy_i686]
manylinux2014 = quay.io/pypa/manylinux2014_i686:2025.07.23-1
manylinux_2_28 = quay.io/pypa/manylinux_2_28_i686:2025.07.23-1
manylinux_2_34 = quay.io/pypa/manylinux_2_34_i686:2025.07.23-1
manylinux2014 = quay.io/pypa/manylinux2014_i686:2025.12.13-1
manylinux_2_28 = quay.io/pypa/manylinux_2_28_i686:2025.12.13-1
manylinux_2_34 = quay.io/pypa/manylinux_2_34_i686:2025.12.13-1
[pypy_aarch64]
manylinux2014 = quay.io/pypa/manylinux2014_aarch64:2025.07.23-1
manylinux_2_28 = quay.io/pypa/manylinux_2_28_aarch64:2025.07.23-1
manylinux_2_34 = quay.io/pypa/manylinux_2_34_aarch64:2025.07.23-1
manylinux2014 = quay.io/pypa/manylinux2014_aarch64:2025.12.13-1
manylinux_2_28 = quay.io/pypa/manylinux_2_28_aarch64:2025.12.13-1
manylinux_2_34 = quay.io/pypa/manylinux_2_34_aarch64:2025.12.13-1
[armv7l]
manylinux_2_31 = quay.io/pypa/manylinux_2_31_armv7l:2025.07.23-1
musllinux_1_2 = quay.io/pypa/musllinux_1_2_armv7l:2025.07.23-1
manylinux_2_31 = quay.io/pypa/manylinux_2_31_armv7l:2025.12.13-1
manylinux_2_35 = quay.io/pypa/manylinux_2_35_armv7l:2025.12.13-1
musllinux_1_2 = quay.io/pypa/musllinux_1_2_armv7l:2025.12.13-1
[riscv64]
manylinux_2_39 = quay.io/pypa/manylinux_2_39_riscv64:2025.07.23-1
musllinux_1_2 = quay.io/pypa/musllinux_1_2_riscv64:2025.07.23-1
manylinux_2_39 = quay.io/pypa/manylinux_2_39_riscv64:2025.12.13-1
musllinux_1_2 = quay.io/pypa/musllinux_1_2_riscv64:2025.12.13-1
@@ -1,455 +1,483 @@
{
"releases": [
{
"tag": "20250712",
"tag": "20251209",
"assets": [
{
"name": "cpython-3.10.18+20250712-aarch64-apple-darwin-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.10.18%2B20250712-aarch64-apple-darwin-install_only.tar.gz"
"name": "cpython-3.10.19+20251209-aarch64-apple-darwin-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.10.19%2B20251209-aarch64-apple-darwin-install_only.tar.gz"
},
{
"name": "cpython-3.10.18+20250712-aarch64-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.10.18%2B20250712-aarch64-unknown-linux-gnu-install_only.tar.gz"
"name": "cpython-3.10.19+20251209-aarch64-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.10.19%2B20251209-aarch64-unknown-linux-gnu-install_only.tar.gz"
},
{
"name": "cpython-3.10.18+20250712-armv7-unknown-linux-gnueabi-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.10.18%2B20250712-armv7-unknown-linux-gnueabi-install_only.tar.gz"
"name": "cpython-3.10.19+20251209-aarch64-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.10.19%2B20251209-aarch64-unknown-linux-musl-install_only.tar.gz"
},
{
"name": "cpython-3.10.18+20250712-armv7-unknown-linux-gnueabihf-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.10.18%2B20250712-armv7-unknown-linux-gnueabihf-install_only.tar.gz"
"name": "cpython-3.10.19+20251209-armv7-unknown-linux-gnueabi-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.10.19%2B20251209-armv7-unknown-linux-gnueabi-install_only.tar.gz"
},
{
"name": "cpython-3.10.18+20250712-i686-pc-windows-msvc-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.10.18%2B20250712-i686-pc-windows-msvc-install_only.tar.gz"
"name": "cpython-3.10.19+20251209-armv7-unknown-linux-gnueabihf-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.10.19%2B20251209-armv7-unknown-linux-gnueabihf-install_only.tar.gz"
},
{
"name": "cpython-3.10.18+20250712-ppc64le-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.10.18%2B20250712-ppc64le-unknown-linux-gnu-install_only.tar.gz"
"name": "cpython-3.10.19+20251209-i686-pc-windows-msvc-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.10.19%2B20251209-i686-pc-windows-msvc-install_only.tar.gz"
},
{
"name": "cpython-3.10.18+20250712-riscv64-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.10.18%2B20250712-riscv64-unknown-linux-gnu-install_only.tar.gz"
"name": "cpython-3.10.19+20251209-ppc64le-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.10.19%2B20251209-ppc64le-unknown-linux-gnu-install_only.tar.gz"
},
{
"name": "cpython-3.10.18+20250712-s390x-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.10.18%2B20250712-s390x-unknown-linux-gnu-install_only.tar.gz"
"name": "cpython-3.10.19+20251209-riscv64-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.10.19%2B20251209-riscv64-unknown-linux-gnu-install_only.tar.gz"
},
{
"name": "cpython-3.10.18+20250712-x86_64-apple-darwin-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.10.18%2B20250712-x86_64-apple-darwin-install_only.tar.gz"
"name": "cpython-3.10.19+20251209-s390x-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.10.19%2B20251209-s390x-unknown-linux-gnu-install_only.tar.gz"
},
{
"name": "cpython-3.10.18+20250712-x86_64-pc-windows-msvc-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.10.18%2B20250712-x86_64-pc-windows-msvc-install_only.tar.gz"
"name": "cpython-3.10.19+20251209-x86_64-apple-darwin-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.10.19%2B20251209-x86_64-apple-darwin-install_only.tar.gz"
},
{
"name": "cpython-3.10.18+20250712-x86_64-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.10.18%2B20250712-x86_64-unknown-linux-gnu-install_only.tar.gz"
"name": "cpython-3.10.19+20251209-x86_64-pc-windows-msvc-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.10.19%2B20251209-x86_64-pc-windows-msvc-install_only.tar.gz"
},
{
"name": "cpython-3.10.18+20250712-x86_64-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.10.18%2B20250712-x86_64-unknown-linux-musl-install_only.tar.gz"
"name": "cpython-3.10.19+20251209-x86_64-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.10.19%2B20251209-x86_64-unknown-linux-gnu-install_only.tar.gz"
},
{
"name": "cpython-3.10.18+20250712-x86_64_v2-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.10.18%2B20250712-x86_64_v2-unknown-linux-gnu-install_only.tar.gz"
"name": "cpython-3.10.19+20251209-x86_64-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.10.19%2B20251209-x86_64-unknown-linux-musl-install_only.tar.gz"
},
{
"name": "cpython-3.10.18+20250712-x86_64_v2-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.10.18%2B20250712-x86_64_v2-unknown-linux-musl-install_only.tar.gz"
"name": "cpython-3.10.19+20251209-x86_64_v2-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.10.19%2B20251209-x86_64_v2-unknown-linux-gnu-install_only.tar.gz"
},
{
"name": "cpython-3.10.18+20250712-x86_64_v3-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.10.18%2B20250712-x86_64_v3-unknown-linux-gnu-install_only.tar.gz"
"name": "cpython-3.10.19+20251209-x86_64_v2-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.10.19%2B20251209-x86_64_v2-unknown-linux-musl-install_only.tar.gz"
},
{
"name": "cpython-3.10.18+20250712-x86_64_v3-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.10.18%2B20250712-x86_64_v3-unknown-linux-musl-install_only.tar.gz"
"name": "cpython-3.10.19+20251209-x86_64_v3-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.10.19%2B20251209-x86_64_v3-unknown-linux-gnu-install_only.tar.gz"
},
{
"name": "cpython-3.10.18+20250712-x86_64_v4-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.10.18%2B20250712-x86_64_v4-unknown-linux-gnu-install_only.tar.gz"
"name": "cpython-3.10.19+20251209-x86_64_v3-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.10.19%2B20251209-x86_64_v3-unknown-linux-musl-install_only.tar.gz"
},
{
"name": "cpython-3.10.18+20250712-x86_64_v4-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.10.18%2B20250712-x86_64_v4-unknown-linux-musl-install_only.tar.gz"
"name": "cpython-3.10.19+20251209-x86_64_v4-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.10.19%2B20251209-x86_64_v4-unknown-linux-gnu-install_only.tar.gz"
},
{
"name": "cpython-3.11.13+20250712-aarch64-apple-darwin-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.11.13%2B20250712-aarch64-apple-darwin-install_only.tar.gz"
"name": "cpython-3.10.19+20251209-x86_64_v4-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.10.19%2B20251209-x86_64_v4-unknown-linux-musl-install_only.tar.gz"
},
{
"name": "cpython-3.11.13+20250712-aarch64-pc-windows-msvc-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.11.13%2B20250712-aarch64-pc-windows-msvc-install_only.tar.gz"
"name": "cpython-3.11.14+20251209-aarch64-apple-darwin-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.11.14%2B20251209-aarch64-apple-darwin-install_only.tar.gz"
},
{
"name": "cpython-3.11.13+20250712-aarch64-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.11.13%2B20250712-aarch64-unknown-linux-gnu-install_only.tar.gz"
"name": "cpython-3.11.14+20251209-aarch64-pc-windows-msvc-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.11.14%2B20251209-aarch64-pc-windows-msvc-install_only.tar.gz"
},
{
"name": "cpython-3.11.13+20250712-armv7-unknown-linux-gnueabi-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.11.13%2B20250712-armv7-unknown-linux-gnueabi-install_only.tar.gz"
"name": "cpython-3.11.14+20251209-aarch64-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.11.14%2B20251209-aarch64-unknown-linux-gnu-install_only.tar.gz"
},
{
"name": "cpython-3.11.13+20250712-armv7-unknown-linux-gnueabihf-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.11.13%2B20250712-armv7-unknown-linux-gnueabihf-install_only.tar.gz"
"name": "cpython-3.11.14+20251209-aarch64-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.11.14%2B20251209-aarch64-unknown-linux-musl-install_only.tar.gz"
},
{
"name": "cpython-3.11.13+20250712-i686-pc-windows-msvc-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.11.13%2B20250712-i686-pc-windows-msvc-install_only.tar.gz"
"name": "cpython-3.11.14+20251209-armv7-unknown-linux-gnueabi-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.11.14%2B20251209-armv7-unknown-linux-gnueabi-install_only.tar.gz"
},
{
"name": "cpython-3.11.13+20250712-ppc64le-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.11.13%2B20250712-ppc64le-unknown-linux-gnu-install_only.tar.gz"
"name": "cpython-3.11.14+20251209-armv7-unknown-linux-gnueabihf-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.11.14%2B20251209-armv7-unknown-linux-gnueabihf-install_only.tar.gz"
},
{
"name": "cpython-3.11.13+20250712-riscv64-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.11.13%2B20250712-riscv64-unknown-linux-gnu-install_only.tar.gz"
"name": "cpython-3.11.14+20251209-i686-pc-windows-msvc-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.11.14%2B20251209-i686-pc-windows-msvc-install_only.tar.gz"
},
{
"name": "cpython-3.11.13+20250712-s390x-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.11.13%2B20250712-s390x-unknown-linux-gnu-install_only.tar.gz"
"name": "cpython-3.11.14+20251209-ppc64le-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.11.14%2B20251209-ppc64le-unknown-linux-gnu-install_only.tar.gz"
},
{
"name": "cpython-3.11.13+20250712-x86_64-apple-darwin-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.11.13%2B20250712-x86_64-apple-darwin-install_only.tar.gz"
"name": "cpython-3.11.14+20251209-riscv64-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.11.14%2B20251209-riscv64-unknown-linux-gnu-install_only.tar.gz"
},
{
"name": "cpython-3.11.13+20250712-x86_64-pc-windows-msvc-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.11.13%2B20250712-x86_64-pc-windows-msvc-install_only.tar.gz"
"name": "cpython-3.11.14+20251209-s390x-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.11.14%2B20251209-s390x-unknown-linux-gnu-install_only.tar.gz"
},
{
"name": "cpython-3.11.13+20250712-x86_64-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.11.13%2B20250712-x86_64-unknown-linux-gnu-install_only.tar.gz"
"name": "cpython-3.11.14+20251209-x86_64-apple-darwin-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.11.14%2B20251209-x86_64-apple-darwin-install_only.tar.gz"
},
{
"name": "cpython-3.11.13+20250712-x86_64-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.11.13%2B20250712-x86_64-unknown-linux-musl-install_only.tar.gz"
"name": "cpython-3.11.14+20251209-x86_64-pc-windows-msvc-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.11.14%2B20251209-x86_64-pc-windows-msvc-install_only.tar.gz"
},
{
"name": "cpython-3.11.13+20250712-x86_64_v2-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.11.13%2B20250712-x86_64_v2-unknown-linux-gnu-install_only.tar.gz"
"name": "cpython-3.11.14+20251209-x86_64-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.11.14%2B20251209-x86_64-unknown-linux-gnu-install_only.tar.gz"
},
{
"name": "cpython-3.11.13+20250712-x86_64_v2-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.11.13%2B20250712-x86_64_v2-unknown-linux-musl-install_only.tar.gz"
"name": "cpython-3.11.14+20251209-x86_64-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.11.14%2B20251209-x86_64-unknown-linux-musl-install_only.tar.gz"
},
{
"name": "cpython-3.11.13+20250712-x86_64_v3-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.11.13%2B20250712-x86_64_v3-unknown-linux-gnu-install_only.tar.gz"
"name": "cpython-3.11.14+20251209-x86_64_v2-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.11.14%2B20251209-x86_64_v2-unknown-linux-gnu-install_only.tar.gz"
},
{
"name": "cpython-3.11.13+20250712-x86_64_v3-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.11.13%2B20250712-x86_64_v3-unknown-linux-musl-install_only.tar.gz"
"name": "cpython-3.11.14+20251209-x86_64_v2-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.11.14%2B20251209-x86_64_v2-unknown-linux-musl-install_only.tar.gz"
},
{
"name": "cpython-3.11.13+20250712-x86_64_v4-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.11.13%2B20250712-x86_64_v4-unknown-linux-gnu-install_only.tar.gz"
"name": "cpython-3.11.14+20251209-x86_64_v3-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.11.14%2B20251209-x86_64_v3-unknown-linux-gnu-install_only.tar.gz"
},
{
"name": "cpython-3.11.13+20250712-x86_64_v4-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.11.13%2B20250712-x86_64_v4-unknown-linux-musl-install_only.tar.gz"
"name": "cpython-3.11.14+20251209-x86_64_v3-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.11.14%2B20251209-x86_64_v3-unknown-linux-musl-install_only.tar.gz"
},
{
"name": "cpython-3.12.11+20250712-aarch64-apple-darwin-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.12.11%2B20250712-aarch64-apple-darwin-install_only.tar.gz"
"name": "cpython-3.11.14+20251209-x86_64_v4-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.11.14%2B20251209-x86_64_v4-unknown-linux-gnu-install_only.tar.gz"
},
{
"name": "cpython-3.12.11+20250712-aarch64-pc-windows-msvc-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.12.11%2B20250712-aarch64-pc-windows-msvc-install_only.tar.gz"
"name": "cpython-3.11.14+20251209-x86_64_v4-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.11.14%2B20251209-x86_64_v4-unknown-linux-musl-install_only.tar.gz"
},
{
"name": "cpython-3.12.11+20250712-aarch64-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.12.11%2B20250712-aarch64-unknown-linux-gnu-install_only.tar.gz"
"name": "cpython-3.12.12+20251209-aarch64-apple-darwin-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.12.12%2B20251209-aarch64-apple-darwin-install_only.tar.gz"
},
{
"name": "cpython-3.12.11+20250712-armv7-unknown-linux-gnueabi-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.12.11%2B20250712-armv7-unknown-linux-gnueabi-install_only.tar.gz"
"name": "cpython-3.12.12+20251209-aarch64-pc-windows-msvc-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.12.12%2B20251209-aarch64-pc-windows-msvc-install_only.tar.gz"
},
{
"name": "cpython-3.12.11+20250712-armv7-unknown-linux-gnueabihf-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.12.11%2B20250712-armv7-unknown-linux-gnueabihf-install_only.tar.gz"
"name": "cpython-3.12.12+20251209-aarch64-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.12.12%2B20251209-aarch64-unknown-linux-gnu-install_only.tar.gz"
},
{
"name": "cpython-3.12.11+20250712-i686-pc-windows-msvc-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.12.11%2B20250712-i686-pc-windows-msvc-install_only.tar.gz"
"name": "cpython-3.12.12+20251209-aarch64-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.12.12%2B20251209-aarch64-unknown-linux-musl-install_only.tar.gz"
},
{
"name": "cpython-3.12.11+20250712-ppc64le-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.12.11%2B20250712-ppc64le-unknown-linux-gnu-install_only.tar.gz"
"name": "cpython-3.12.12+20251209-armv7-unknown-linux-gnueabi-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.12.12%2B20251209-armv7-unknown-linux-gnueabi-install_only.tar.gz"
},
{
"name": "cpython-3.12.11+20250712-riscv64-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.12.11%2B20250712-riscv64-unknown-linux-gnu-install_only.tar.gz"
"name": "cpython-3.12.12+20251209-armv7-unknown-linux-gnueabihf-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.12.12%2B20251209-armv7-unknown-linux-gnueabihf-install_only.tar.gz"
},
{
"name": "cpython-3.12.11+20250712-s390x-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.12.11%2B20250712-s390x-unknown-linux-gnu-install_only.tar.gz"
"name": "cpython-3.12.12+20251209-i686-pc-windows-msvc-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.12.12%2B20251209-i686-pc-windows-msvc-install_only.tar.gz"
},
{
"name": "cpython-3.12.11+20250712-x86_64-apple-darwin-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.12.11%2B20250712-x86_64-apple-darwin-install_only.tar.gz"
"name": "cpython-3.12.12+20251209-ppc64le-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.12.12%2B20251209-ppc64le-unknown-linux-gnu-install_only.tar.gz"
},
{
"name": "cpython-3.12.11+20250712-x86_64-pc-windows-msvc-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.12.11%2B20250712-x86_64-pc-windows-msvc-install_only.tar.gz"
"name": "cpython-3.12.12+20251209-riscv64-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.12.12%2B20251209-riscv64-unknown-linux-gnu-install_only.tar.gz"
},
{
"name": "cpython-3.12.11+20250712-x86_64-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.12.11%2B20250712-x86_64-unknown-linux-gnu-install_only.tar.gz"
"name": "cpython-3.12.12+20251209-s390x-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.12.12%2B20251209-s390x-unknown-linux-gnu-install_only.tar.gz"
},
{
"name": "cpython-3.12.11+20250712-x86_64-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.12.11%2B20250712-x86_64-unknown-linux-musl-install_only.tar.gz"
"name": "cpython-3.12.12+20251209-x86_64-apple-darwin-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.12.12%2B20251209-x86_64-apple-darwin-install_only.tar.gz"
},
{
"name": "cpython-3.12.11+20250712-x86_64_v2-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.12.11%2B20250712-x86_64_v2-unknown-linux-gnu-install_only.tar.gz"
"name": "cpython-3.12.12+20251209-x86_64-pc-windows-msvc-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.12.12%2B20251209-x86_64-pc-windows-msvc-install_only.tar.gz"
},
{
"name": "cpython-3.12.11+20250712-x86_64_v2-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.12.11%2B20250712-x86_64_v2-unknown-linux-musl-install_only.tar.gz"
"name": "cpython-3.12.12+20251209-x86_64-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.12.12%2B20251209-x86_64-unknown-linux-gnu-install_only.tar.gz"
},
{
"name": "cpython-3.12.11+20250712-x86_64_v3-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.12.11%2B20250712-x86_64_v3-unknown-linux-gnu-install_only.tar.gz"
"name": "cpython-3.12.12+20251209-x86_64-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.12.12%2B20251209-x86_64-unknown-linux-musl-install_only.tar.gz"
},
{
"name": "cpython-3.12.11+20250712-x86_64_v3-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.12.11%2B20250712-x86_64_v3-unknown-linux-musl-install_only.tar.gz"
"name": "cpython-3.12.12+20251209-x86_64_v2-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.12.12%2B20251209-x86_64_v2-unknown-linux-gnu-install_only.tar.gz"
},
{
"name": "cpython-3.12.11+20250712-x86_64_v4-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.12.11%2B20250712-x86_64_v4-unknown-linux-gnu-install_only.tar.gz"
"name": "cpython-3.12.12+20251209-x86_64_v2-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.12.12%2B20251209-x86_64_v2-unknown-linux-musl-install_only.tar.gz"
},
{
"name": "cpython-3.12.11+20250712-x86_64_v4-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.12.11%2B20250712-x86_64_v4-unknown-linux-musl-install_only.tar.gz"
"name": "cpython-3.12.12+20251209-x86_64_v3-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.12.12%2B20251209-x86_64_v3-unknown-linux-gnu-install_only.tar.gz"
},
{
"name": "cpython-3.13.5+20250712-aarch64-apple-darwin-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.13.5%2B20250712-aarch64-apple-darwin-install_only.tar.gz"
"name": "cpython-3.12.12+20251209-x86_64_v3-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.12.12%2B20251209-x86_64_v3-unknown-linux-musl-install_only.tar.gz"
},
{
"name": "cpython-3.13.5+20250712-aarch64-pc-windows-msvc-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.13.5%2B20250712-aarch64-pc-windows-msvc-install_only.tar.gz"
"name": "cpython-3.12.12+20251209-x86_64_v4-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.12.12%2B20251209-x86_64_v4-unknown-linux-gnu-install_only.tar.gz"
},
{
"name": "cpython-3.13.5+20250712-aarch64-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.13.5%2B20250712-aarch64-unknown-linux-gnu-install_only.tar.gz"
"name": "cpython-3.12.12+20251209-x86_64_v4-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.12.12%2B20251209-x86_64_v4-unknown-linux-musl-install_only.tar.gz"
},
{
"name": "cpython-3.13.5+20250712-armv7-unknown-linux-gnueabi-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.13.5%2B20250712-armv7-unknown-linux-gnueabi-install_only.tar.gz"
"name": "cpython-3.13.11+20251209-aarch64-apple-darwin-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.13.11%2B20251209-aarch64-apple-darwin-install_only.tar.gz"
},
{
"name": "cpython-3.13.5+20250712-armv7-unknown-linux-gnueabihf-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.13.5%2B20250712-armv7-unknown-linux-gnueabihf-install_only.tar.gz"
"name": "cpython-3.13.11+20251209-aarch64-pc-windows-msvc-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.13.11%2B20251209-aarch64-pc-windows-msvc-install_only.tar.gz"
},
{
"name": "cpython-3.13.5+20250712-i686-pc-windows-msvc-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.13.5%2B20250712-i686-pc-windows-msvc-install_only.tar.gz"
"name": "cpython-3.13.11+20251209-aarch64-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.13.11%2B20251209-aarch64-unknown-linux-gnu-install_only.tar.gz"
},
{
"name": "cpython-3.13.5+20250712-ppc64le-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.13.5%2B20250712-ppc64le-unknown-linux-gnu-install_only.tar.gz"
"name": "cpython-3.13.11+20251209-aarch64-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.13.11%2B20251209-aarch64-unknown-linux-musl-install_only.tar.gz"
},
{
"name": "cpython-3.13.5+20250712-riscv64-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.13.5%2B20250712-riscv64-unknown-linux-gnu-install_only.tar.gz"
"name": "cpython-3.13.11+20251209-armv7-unknown-linux-gnueabi-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.13.11%2B20251209-armv7-unknown-linux-gnueabi-install_only.tar.gz"
},
{
"name": "cpython-3.13.5+20250712-s390x-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.13.5%2B20250712-s390x-unknown-linux-gnu-install_only.tar.gz"
"name": "cpython-3.13.11+20251209-armv7-unknown-linux-gnueabihf-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.13.11%2B20251209-armv7-unknown-linux-gnueabihf-install_only.tar.gz"
},
{
"name": "cpython-3.13.5+20250712-x86_64-apple-darwin-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.13.5%2B20250712-x86_64-apple-darwin-install_only.tar.gz"
"name": "cpython-3.13.11+20251209-i686-pc-windows-msvc-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.13.11%2B20251209-i686-pc-windows-msvc-install_only.tar.gz"
},
{
"name": "cpython-3.13.5+20250712-x86_64-pc-windows-msvc-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.13.5%2B20250712-x86_64-pc-windows-msvc-install_only.tar.gz"
"name": "cpython-3.13.11+20251209-ppc64le-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.13.11%2B20251209-ppc64le-unknown-linux-gnu-install_only.tar.gz"
},
{
"name": "cpython-3.13.5+20250712-x86_64-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.13.5%2B20250712-x86_64-unknown-linux-gnu-install_only.tar.gz"
"name": "cpython-3.13.11+20251209-riscv64-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.13.11%2B20251209-riscv64-unknown-linux-gnu-install_only.tar.gz"
},
{
"name": "cpython-3.13.5+20250712-x86_64-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.13.5%2B20250712-x86_64-unknown-linux-musl-install_only.tar.gz"
"name": "cpython-3.13.11+20251209-s390x-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.13.11%2B20251209-s390x-unknown-linux-gnu-install_only.tar.gz"
},
{
"name": "cpython-3.13.5+20250712-x86_64_v2-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.13.5%2B20250712-x86_64_v2-unknown-linux-gnu-install_only.tar.gz"
"name": "cpython-3.13.11+20251209-x86_64-apple-darwin-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.13.11%2B20251209-x86_64-apple-darwin-install_only.tar.gz"
},
{
"name": "cpython-3.13.5+20250712-x86_64_v2-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.13.5%2B20250712-x86_64_v2-unknown-linux-musl-install_only.tar.gz"
"name": "cpython-3.13.11+20251209-x86_64-pc-windows-msvc-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.13.11%2B20251209-x86_64-pc-windows-msvc-install_only.tar.gz"
},
{
"name": "cpython-3.13.5+20250712-x86_64_v3-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.13.5%2B20250712-x86_64_v3-unknown-linux-gnu-install_only.tar.gz"
"name": "cpython-3.13.11+20251209-x86_64-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.13.11%2B20251209-x86_64-unknown-linux-gnu-install_only.tar.gz"
},
{
"name": "cpython-3.13.5+20250712-x86_64_v3-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.13.5%2B20250712-x86_64_v3-unknown-linux-musl-install_only.tar.gz"
"name": "cpython-3.13.11+20251209-x86_64-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.13.11%2B20251209-x86_64-unknown-linux-musl-install_only.tar.gz"
},
{
"name": "cpython-3.13.5+20250712-x86_64_v4-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.13.5%2B20250712-x86_64_v4-unknown-linux-gnu-install_only.tar.gz"
"name": "cpython-3.13.11+20251209-x86_64_v2-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.13.11%2B20251209-x86_64_v2-unknown-linux-gnu-install_only.tar.gz"
},
{
"name": "cpython-3.13.5+20250712-x86_64_v4-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.13.5%2B20250712-x86_64_v4-unknown-linux-musl-install_only.tar.gz"
"name": "cpython-3.13.11+20251209-x86_64_v2-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.13.11%2B20251209-x86_64_v2-unknown-linux-musl-install_only.tar.gz"
},
{
"name": "cpython-3.14.0b4+20250712-aarch64-apple-darwin-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.14.0b4%2B20250712-aarch64-apple-darwin-install_only.tar.gz"
"name": "cpython-3.13.11+20251209-x86_64_v3-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.13.11%2B20251209-x86_64_v3-unknown-linux-gnu-install_only.tar.gz"
},
{
"name": "cpython-3.14.0b4+20250712-aarch64-pc-windows-msvc-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.14.0b4%2B20250712-aarch64-pc-windows-msvc-install_only.tar.gz"
"name": "cpython-3.13.11+20251209-x86_64_v3-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.13.11%2B20251209-x86_64_v3-unknown-linux-musl-install_only.tar.gz"
},
{
"name": "cpython-3.14.0b4+20250712-aarch64-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.14.0b4%2B20250712-aarch64-unknown-linux-gnu-install_only.tar.gz"
"name": "cpython-3.13.11+20251209-x86_64_v4-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.13.11%2B20251209-x86_64_v4-unknown-linux-gnu-install_only.tar.gz"
},
{
"name": "cpython-3.14.0b4+20250712-armv7-unknown-linux-gnueabi-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.14.0b4%2B20250712-armv7-unknown-linux-gnueabi-install_only.tar.gz"
"name": "cpython-3.13.11+20251209-x86_64_v4-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.13.11%2B20251209-x86_64_v4-unknown-linux-musl-install_only.tar.gz"
},
{
"name": "cpython-3.14.0b4+20250712-armv7-unknown-linux-gnueabihf-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.14.0b4%2B20250712-armv7-unknown-linux-gnueabihf-install_only.tar.gz"
"name": "cpython-3.14.2+20251209-aarch64-apple-darwin-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.14.2%2B20251209-aarch64-apple-darwin-install_only.tar.gz"
},
{
"name": "cpython-3.14.0b4+20250712-i686-pc-windows-msvc-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.14.0b4%2B20250712-i686-pc-windows-msvc-install_only.tar.gz"
"name": "cpython-3.14.2+20251209-aarch64-pc-windows-msvc-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.14.2%2B20251209-aarch64-pc-windows-msvc-install_only.tar.gz"
},
{
"name": "cpython-3.14.0b4+20250712-ppc64le-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.14.0b4%2B20250712-ppc64le-unknown-linux-gnu-install_only.tar.gz"
"name": "cpython-3.14.2+20251209-aarch64-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.14.2%2B20251209-aarch64-unknown-linux-gnu-install_only.tar.gz"
},
{
"name": "cpython-3.14.0b4+20250712-riscv64-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.14.0b4%2B20250712-riscv64-unknown-linux-gnu-install_only.tar.gz"
"name": "cpython-3.14.2+20251209-aarch64-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.14.2%2B20251209-aarch64-unknown-linux-musl-install_only.tar.gz"
},
{
"name": "cpython-3.14.0b4+20250712-s390x-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.14.0b4%2B20250712-s390x-unknown-linux-gnu-install_only.tar.gz"
"name": "cpython-3.14.2+20251209-armv7-unknown-linux-gnueabi-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.14.2%2B20251209-armv7-unknown-linux-gnueabi-install_only.tar.gz"
},
{
"name": "cpython-3.14.0b4+20250712-x86_64-apple-darwin-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.14.0b4%2B20250712-x86_64-apple-darwin-install_only.tar.gz"
"name": "cpython-3.14.2+20251209-armv7-unknown-linux-gnueabihf-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.14.2%2B20251209-armv7-unknown-linux-gnueabihf-install_only.tar.gz"
},
{
"name": "cpython-3.14.0b4+20250712-x86_64-pc-windows-msvc-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.14.0b4%2B20250712-x86_64-pc-windows-msvc-install_only.tar.gz"
"name": "cpython-3.14.2+20251209-i686-pc-windows-msvc-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.14.2%2B20251209-i686-pc-windows-msvc-install_only.tar.gz"
},
{
"name": "cpython-3.14.0b4+20250712-x86_64-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.14.0b4%2B20250712-x86_64-unknown-linux-gnu-install_only.tar.gz"
"name": "cpython-3.14.2+20251209-ppc64le-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.14.2%2B20251209-ppc64le-unknown-linux-gnu-install_only.tar.gz"
},
{
"name": "cpython-3.14.0b4+20250712-x86_64-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.14.0b4%2B20250712-x86_64-unknown-linux-musl-install_only.tar.gz"
"name": "cpython-3.14.2+20251209-riscv64-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.14.2%2B20251209-riscv64-unknown-linux-gnu-install_only.tar.gz"
},
{
"name": "cpython-3.14.0b4+20250712-x86_64_v2-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.14.0b4%2B20250712-x86_64_v2-unknown-linux-gnu-install_only.tar.gz"
"name": "cpython-3.14.2+20251209-s390x-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.14.2%2B20251209-s390x-unknown-linux-gnu-install_only.tar.gz"
},
{
"name": "cpython-3.14.0b4+20250712-x86_64_v2-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.14.0b4%2B20250712-x86_64_v2-unknown-linux-musl-install_only.tar.gz"
"name": "cpython-3.14.2+20251209-x86_64-apple-darwin-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.14.2%2B20251209-x86_64-apple-darwin-install_only.tar.gz"
},
{
"name": "cpython-3.14.0b4+20250712-x86_64_v3-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.14.0b4%2B20250712-x86_64_v3-unknown-linux-gnu-install_only.tar.gz"
"name": "cpython-3.14.2+20251209-x86_64-pc-windows-msvc-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.14.2%2B20251209-x86_64-pc-windows-msvc-install_only.tar.gz"
},
{
"name": "cpython-3.14.0b4+20250712-x86_64_v3-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.14.0b4%2B20250712-x86_64_v3-unknown-linux-musl-install_only.tar.gz"
"name": "cpython-3.14.2+20251209-x86_64-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.14.2%2B20251209-x86_64-unknown-linux-gnu-install_only.tar.gz"
},
{
"name": "cpython-3.14.0b4+20250712-x86_64_v4-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.14.0b4%2B20250712-x86_64_v4-unknown-linux-gnu-install_only.tar.gz"
"name": "cpython-3.14.2+20251209-x86_64-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.14.2%2B20251209-x86_64-unknown-linux-musl-install_only.tar.gz"
},
{
"name": "cpython-3.14.0b4+20250712-x86_64_v4-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.14.0b4%2B20250712-x86_64_v4-unknown-linux-musl-install_only.tar.gz"
"name": "cpython-3.14.2+20251209-x86_64_v2-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.14.2%2B20251209-x86_64_v2-unknown-linux-gnu-install_only.tar.gz"
},
{
"name": "cpython-3.9.23+20250712-aarch64-apple-darwin-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.9.23%2B20250712-aarch64-apple-darwin-install_only.tar.gz"
"name": "cpython-3.14.2+20251209-x86_64_v2-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.14.2%2B20251209-x86_64_v2-unknown-linux-musl-install_only.tar.gz"
},
{
"name": "cpython-3.9.23+20250712-aarch64-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.9.23%2B20250712-aarch64-unknown-linux-gnu-install_only.tar.gz"
"name": "cpython-3.14.2+20251209-x86_64_v3-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.14.2%2B20251209-x86_64_v3-unknown-linux-gnu-install_only.tar.gz"
},
{
"name": "cpython-3.9.23+20250712-armv7-unknown-linux-gnueabi-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.9.23%2B20250712-armv7-unknown-linux-gnueabi-install_only.tar.gz"
"name": "cpython-3.14.2+20251209-x86_64_v3-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.14.2%2B20251209-x86_64_v3-unknown-linux-musl-install_only.tar.gz"
},
{
"name": "cpython-3.9.23+20250712-armv7-unknown-linux-gnueabihf-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.9.23%2B20250712-armv7-unknown-linux-gnueabihf-install_only.tar.gz"
"name": "cpython-3.14.2+20251209-x86_64_v4-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.14.2%2B20251209-x86_64_v4-unknown-linux-gnu-install_only.tar.gz"
},
{
"name": "cpython-3.9.23+20250712-i686-pc-windows-msvc-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.9.23%2B20250712-i686-pc-windows-msvc-install_only.tar.gz"
"name": "cpython-3.14.2+20251209-x86_64_v4-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.14.2%2B20251209-x86_64_v4-unknown-linux-musl-install_only.tar.gz"
},
{
"name": "cpython-3.9.23+20250712-ppc64le-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.9.23%2B20250712-ppc64le-unknown-linux-gnu-install_only.tar.gz"
"name": "cpython-3.15.0a2+20251209-aarch64-apple-darwin-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.15.0a2%2B20251209-aarch64-apple-darwin-install_only.tar.gz"
},
{
"name": "cpython-3.9.23+20250712-riscv64-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.9.23%2B20250712-riscv64-unknown-linux-gnu-install_only.tar.gz"
"name": "cpython-3.15.0a2+20251209-aarch64-pc-windows-msvc-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.15.0a2%2B20251209-aarch64-pc-windows-msvc-install_only.tar.gz"
},
{
"name": "cpython-3.9.23+20250712-s390x-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.9.23%2B20250712-s390x-unknown-linux-gnu-install_only.tar.gz"
"name": "cpython-3.15.0a2+20251209-aarch64-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.15.0a2%2B20251209-aarch64-unknown-linux-gnu-install_only.tar.gz"
},
{
"name": "cpython-3.9.23+20250712-x86_64-apple-darwin-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.9.23%2B20250712-x86_64-apple-darwin-install_only.tar.gz"
"name": "cpython-3.15.0a2+20251209-aarch64-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.15.0a2%2B20251209-aarch64-unknown-linux-musl-install_only.tar.gz"
},
{
"name": "cpython-3.9.23+20250712-x86_64-pc-windows-msvc-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.9.23%2B20250712-x86_64-pc-windows-msvc-install_only.tar.gz"
"name": "cpython-3.15.0a2+20251209-armv7-unknown-linux-gnueabi-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.15.0a2%2B20251209-armv7-unknown-linux-gnueabi-install_only.tar.gz"
},
{
"name": "cpython-3.9.23+20250712-x86_64-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.9.23%2B20250712-x86_64-unknown-linux-gnu-install_only.tar.gz"
"name": "cpython-3.15.0a2+20251209-armv7-unknown-linux-gnueabihf-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.15.0a2%2B20251209-armv7-unknown-linux-gnueabihf-install_only.tar.gz"
},
{
"name": "cpython-3.9.23+20250712-x86_64-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.9.23%2B20250712-x86_64-unknown-linux-musl-install_only.tar.gz"
"name": "cpython-3.15.0a2+20251209-i686-pc-windows-msvc-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.15.0a2%2B20251209-i686-pc-windows-msvc-install_only.tar.gz"
},
{
"name": "cpython-3.9.23+20250712-x86_64_v2-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.9.23%2B20250712-x86_64_v2-unknown-linux-gnu-install_only.tar.gz"
"name": "cpython-3.15.0a2+20251209-ppc64le-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.15.0a2%2B20251209-ppc64le-unknown-linux-gnu-install_only.tar.gz"
},
{
"name": "cpython-3.9.23+20250712-x86_64_v2-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.9.23%2B20250712-x86_64_v2-unknown-linux-musl-install_only.tar.gz"
"name": "cpython-3.15.0a2+20251209-riscv64-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.15.0a2%2B20251209-riscv64-unknown-linux-gnu-install_only.tar.gz"
},
{
"name": "cpython-3.9.23+20250712-x86_64_v3-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.9.23%2B20250712-x86_64_v3-unknown-linux-gnu-install_only.tar.gz"
"name": "cpython-3.15.0a2+20251209-s390x-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.15.0a2%2B20251209-s390x-unknown-linux-gnu-install_only.tar.gz"
},
{
"name": "cpython-3.9.23+20250712-x86_64_v3-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.9.23%2B20250712-x86_64_v3-unknown-linux-musl-install_only.tar.gz"
"name": "cpython-3.15.0a2+20251209-x86_64-apple-darwin-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.15.0a2%2B20251209-x86_64-apple-darwin-install_only.tar.gz"
},
{
"name": "cpython-3.9.23+20250712-x86_64_v4-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.9.23%2B20250712-x86_64_v4-unknown-linux-gnu-install_only.tar.gz"
"name": "cpython-3.15.0a2+20251209-x86_64-pc-windows-msvc-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.15.0a2%2B20251209-x86_64-pc-windows-msvc-install_only.tar.gz"
},
{
"name": "cpython-3.9.23+20250712-x86_64_v4-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250712/cpython-3.9.23%2B20250712-x86_64_v4-unknown-linux-musl-install_only.tar.gz"
"name": "cpython-3.15.0a2+20251209-x86_64-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.15.0a2%2B20251209-x86_64-unknown-linux-gnu-install_only.tar.gz"
},
{
"name": "cpython-3.15.0a2+20251209-x86_64-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.15.0a2%2B20251209-x86_64-unknown-linux-musl-install_only.tar.gz"
},
{
"name": "cpython-3.15.0a2+20251209-x86_64_v2-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.15.0a2%2B20251209-x86_64_v2-unknown-linux-gnu-install_only.tar.gz"
},
{
"name": "cpython-3.15.0a2+20251209-x86_64_v2-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.15.0a2%2B20251209-x86_64_v2-unknown-linux-musl-install_only.tar.gz"
},
{
"name": "cpython-3.15.0a2+20251209-x86_64_v3-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.15.0a2%2B20251209-x86_64_v3-unknown-linux-gnu-install_only.tar.gz"
},
{
"name": "cpython-3.15.0a2+20251209-x86_64_v3-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.15.0a2%2B20251209-x86_64_v3-unknown-linux-musl-install_only.tar.gz"
},
{
"name": "cpython-3.15.0a2+20251209-x86_64_v4-unknown-linux-gnu-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.15.0a2%2B20251209-x86_64_v4-unknown-linux-gnu-install_only.tar.gz"
},
{
"name": "cpython-3.15.0a2+20251209-x86_64_v4-unknown-linux-musl-install_only.tar.gz",
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251209/cpython-3.15.0a2%2B20251209-x86_64_v4-unknown-linux-musl-install_only.tar.gz"
}
]
}
+1 -1
View File
@@ -1 +1 @@
default = { version = "20.32.0", url = "https://github.com/pypa/get-virtualenv/blob/20.32.0/public/virtualenv.pyz?raw=true" }
default = { version = "20.35.4", url = "https://github.com/pypa/get-virtualenv/releases/download/20.35.4/virtualenv.pyz" }
+5 -7
View File
@@ -39,7 +39,7 @@ class EnableGroup(StrEnum):
@classmethod
def all_groups(cls) -> frozenset["EnableGroup"]:
return frozenset(cls)
return frozenset(set(cls) - {cls.CPythonExperimentalRiscV64})
@classmethod
def parse_option_value(cls, value: str) -> frozenset["EnableGroup"]:
@@ -89,13 +89,11 @@ class BuildSelector:
return False
if EnableGroup.CPythonPrerelease not in self.enable and fnmatch(build_id, "cp315*"):
return False
if EnableGroup.PyPy not in self.enable and fnmatch(build_id, "pp31*"):
is_pypy_eol = fnmatch(build_id, "pp3?-*") or fnmatch(build_id, "pp310-*")
is_pypy = fnmatch(build_id, "pp*") and not is_pypy_eol
if EnableGroup.PyPy not in self.enable and is_pypy:
return False
if EnableGroup.PyPyEoL not in self.enable and fnmatch(build_id, "pp3?-*"):
return False
if EnableGroup.CPythonExperimentalRiscV64 not in self.enable and fnmatch(
build_id, "*_riscv64"
):
if EnableGroup.PyPyEoL not in self.enable and is_pypy_eol:
return False
if EnableGroup.GraalPy not in self.enable and fnmatch(build_id, "gp*"):
return False
+1 -1
View File
@@ -72,7 +72,7 @@ def call(
if not capture_stdout:
return None
sys.stderr.write(result.stderr)
return typing.cast(str, result.stdout)
return typing.cast("str", result.stdout)
def shell(
+20
View File
@@ -20,6 +20,26 @@ CIBW_CACHE_PATH: Final[Path] = Path(
).resolve()
def ensure_cache_sentinel(cache_path: Path) -> None:
"""Create a sentinel file to mark a cibuildwheel cache directory.
We help prevent accidental deletion of non-cache directories with this.
Args:
cache_path: The cache directory path where the sentinel should be created
"""
if cache_path.exists():
sentinel_file = cache_path / "CACHEDIR.TAG"
if not sentinel_file.exists():
sentinel_file.write_text(
"Signature: 8a477f597d28d172789f06886806bc55\n"
"# This file is a cache directory tag created by cibuildwheel.\n"
"# For information about cache directory tags, see:\n"
"# https://www.brynosaurus.com/cachedir/",
encoding="utf-8",
)
def download(url: str, dest: Path) -> None:
print(f"+ Download {url} to {dest}")
dest_dir = dest.parent
+2 -2
View File
@@ -20,8 +20,8 @@ def format_safe(template: str, **kwargs: str | os.PathLike[str]) -> str:
>>> format_safe('{a} {b[4]:3f}', a='123')
'123 {b[4]:3f}'
To avoid variable expansion, precede with a single backslash e.g.
>>> format_safe('\\{a} {b}', a='123')
To avoid variable expansion, precede with a single hash e.g.
>>> format_safe('#{a} {b}', a='123')
'{a} {b}'
"""
+1 -28
View File
@@ -1,5 +1,5 @@
import shlex
from collections.abc import Mapping, MutableMapping, Sequence
from collections.abc import Mapping, Sequence
from dataclasses import dataclass, field
from pathlib import Path, PurePath
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 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
def get_python_build_standalone_release_data() -> PythonBuildStandaloneReleaseData:
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):
+16 -9
View File
@@ -1,4 +1,3 @@
import contextlib
import functools
import os
import shutil
@@ -108,6 +107,7 @@ def virtualenv(
assert python.exists()
if use_uv:
ensure_uv()
call("uv", "venv", venv_path, "--python", python)
else:
virtualenv_app, virtualenv_version = _ensure_virtualenv(version)
@@ -143,6 +143,8 @@ def virtualenv(
venv_env["VIRTUAL_ENV"] = str(venv_path)
if not use_uv and pip_version == "embed":
call(
"python",
"-m",
"pip",
"install",
"--upgrade",
@@ -154,12 +156,17 @@ def virtualenv(
return venv_env
def find_uv() -> Path | None:
# Prefer uv in our environment
with contextlib.suppress(ImportError, FileNotFoundError):
from uv import find_uv_bin # noqa: PLC0415
def ensure_uv() -> None:
"""
Ensures uv is available on PATH. Raises an error with a helpful message if not found.
return Path(find_uv_bin())
uv_on_path = shutil.which("uv")
return Path(uv_on_path) if uv_on_path else None
When using build-frontend=build[uv], callers must ensure uv is available
on PATH before invoking cibuildwheel.
"""
if shutil.which("uv") is None:
msg = (
"uv not found on PATH. When using build-frontend=build[uv], "
"ensure uv is installed and available on PATH. "
"You can install it with 'pip install uv' or see https://docs.astral.sh/uv/getting-started/installation/"
)
raise FileNotFoundError(msg)
+76 -1
View File
@@ -4,6 +4,81 @@ title: Changelog
# Changelog
### 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
_12 October 2025_
- 🛠 Update to CPython 3.14.0 final (#2614)
- 🐛 Fix the default MACOSX_DEPLOYMENT_TARGET on Python 3.14 (#2613)
- 📚 Docs improvements (#2617)
### v3.2.0
_22 September 2025_
- ✨ Adds GraalPy v25 (Python 3.12) support (#2597)
- 🛠 Update to CPython 3.14.0rc3 (#2602)
- 🛠 Adds CPython 3.14.0 prerelease support for Android, and a number of improvements to Android builds (#2568, #2591)
- 🛠 Improvements to testing on Android, passing environment markers when installing the venv, and providing more debug output when build-verbosity is set (#2575)
- ⚠️ PyPy 3.10 was moved to `pypy-eol` in the `enable` option, as it is now end-of-life. (#2521)
- 📚 Docs improvements (#2574, #2601, #2598)
### v3.1.4
_19 August 2025_
- ✨ Add a `--clean-cache` command to clean up our cache (#2489)
- 🛠 Update Python to 3.14rc2 and other patch version bumps (#2542, #2556)
- 🛠 Update Pyodide to 0.28.2 (#2562, #2558)
- 🐛 Fix resolution with `pyodide-build` when `dependency-versions` is set (#2548)
- 🐛 Set `CMAKE_FIND_ROOT_PATH_MODE_PACKAGE` to `BOTH` on Android (#2547)
- 🐛 Add `patchelf` dependency for platforms that can build Android wheels (#2552)
- 🐛 Ignore empty values for `CIBW_ARCHS` like most other environment variables (#2541)
- 💼 The `color` and `suggest_on_error` argparse options are now default in 3.14rc1+ (#2554)
- 💼 Use the virtualenv release URL instead of blob URL (should be more robust) (#2555)
- 🧪 For iOS, lowering to macos-14 is needed for now due to issues with GitHub's runner images (#2557)
- 🧪 Split out platforms iOS and Android in our tests (#2519)
- 🧪 Fix and enable doctests (#2546)
- 📚 Improve our docs on free-threading (#2549)
### 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)
### v3.1.1
_24 July 2025_
@@ -25,7 +100,7 @@ _23 July 2025_
- 🛠 Fixed a typo in the 3.9 MUSL riscv64 identifier (`cp39-musllinux_ricv64` -> `cp39-musllinux_riscv64`) (#2490)
- 🛠 Mistyping `--only` now shows the correct possibilities, and even suggests near matches on Python 3.14+ (#2499)
- 🛠 Only support one output from the repair step on linux like other platforms; auditwheel fixed this over four years ago! (#2478)
- 🛠 We now use pattern matching extensively (#2434)
- 💼 We now use pattern matching extensively (#2434)
- 📚 We now have platform maintainers for our special platforms and interpreters! (#2481)
+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
`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 make uv available for cibuildwheel to use.
!!! tab "pipx"
The GitHub Actions runners have pipx installed, so you can easily build in
+8 -5
View File
@@ -79,7 +79,7 @@ cibuildwheel to run tests, add the following YAML to your CI config file:
You can configure cibuildwheel with a config file, such as `pyproject.toml`.
Options have the same names as the environment variable overrides, but are
placed in `[tool.cibuildwheel]` and are lower case, with dashes, following
common [TOML][https://toml.io] practice. Anything placed in subsections `linux`, `windows`,
common [TOML](https://toml.io) practice. Anything placed in subsections `linux`, `windows`,
`macos`, or `pyodide` will only affect those platforms. Lists can be used
instead of strings for items that are naturally a list. Multiline strings also
work just like in the environment variables. Environment variables will take
@@ -112,7 +112,8 @@ The complete set of defaults for the current version of cibuildwheel are shown b
One feature specific to the configuration files is the ability to override
settings based on selectors. To use, add a ``tool.cibuildwheel.overrides``
array, and specify a ``select`` string. Then any options you set will only
array, and specify a ``select`` string, referencing the [build identifier](options.md#build-skip) (not wheel name!).
Then any options you set will only
apply to items that match that selector. These are applied in order, with later
matches overriding earlier ones if multiple selectors match. Environment
variables always override static configuration.
@@ -120,9 +121,11 @@ variables always override static configuration.
A few of the options below have special handling in overrides. A different
`before-all` will trigger a new container to launch on Linux, and cannot be
overridden on macOS or Windows. Overriding the image on linux will also
trigger new containers, one per image. Some commands are not supported;
`output-dir`, build/skip/test_skip selectors, and architectures cannot be
overridden.
trigger new containers, one per image.
!!! note "Some commands are not supported"
The ``output-dir``, ``build``, ``skip``, ``test_skip`` selectors, and architectures cannot be overridden.
You can specify a table of overrides in `inherit={}`, any list or table in this
list will inherit from previous overrides or the main configuration. The valid
+9 -2
View File
@@ -172,13 +172,13 @@
- name: pyzmq
gh: zeromq/pyzmq
ci: [github, circleci]
ci: [github]
os: [windows, apple, linux]
ci_config: .github/workflows/wheels.yml
notes: |
Python bindings for zeromq, the networking library.
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
gh: python-rapidjson/python-rapidjson
@@ -664,3 +664,10 @@
os: [apple, linux, windows]
pypi: streaming-form-data
notes: Streaming parser for multipart/form-data written in Cython
- name: falcon
gh: falconry/falcon
ci: [github]
os: [apple, linux, windows]
pypi: falcon
notes: Falcon is a no-magic ASGI/WSGI API and microservices framework; it uses cibuildwheel for (optional) Cython extensions.
+2 -2
View File
@@ -29,7 +29,7 @@ GitHub actions has pipx in all the runners as a supported package manager, as we
name: Make SDist
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
with:
fetch-depth: 0 # Optional, use if you use setuptools_scm
submodules: true # Optional, use if you have submodules
@@ -54,7 +54,7 @@ Then, you need to publish the artifacts that the previous jobs have built. This
runs-on: ubuntu-latest
if: github.event_name == 'release' && github.event.action == 'published'
steps:
- uses: actions/download-artifact@v4
- uses: actions/download-artifact@v5
with:
pattern: cibw-*
path: dist
+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:
```yaml
uses: pypa/cibuildwheel@v3.1.1
uses: pypa/cibuildwheel@v3.3.0
```
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
# requirements-cibw.txt
cibuildwheel==3.1.1
cibuildwheel==3.3.0
```
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
python3 -m pip install pipx
pipx run cibuildwheel==3.1.1 --output-dir wheelhouse
pipx run cibuildwheel==3.3.0 --output-dir wheelhouse
pipx run twine upload wheelhouse/*.whl
```
+1 -1
View File
@@ -11,7 +11,7 @@ import rich.text
def define_env(env: Any) -> None:
"Hook function for mkdocs-macros"
@env.macro # type: ignore[misc]
@env.macro # type: ignore[untyped-decorator]
def subprocess_run(*args: str) -> str:
"Run a subprocess and return the stdout"
env = os.environ.copy()
+97 -48
View File
@@ -59,23 +59,23 @@ When setting the options, you can use shell-style globbing syntax, as per [fnmat
| Python 3.10 | cp310-macosx_x86_64<br/>cp310-macosx_universal2<br/>cp310-macosx_arm64 | cp310-win_amd64<br/>cp310-win32<br/>cp310-win_arm64 | cp310-manylinux_x86_64<br/>cp310-manylinux_i686<br/>cp310-musllinux_x86_64<br/>cp310-musllinux_i686 | cp310-manylinux_aarch64<br/>cp310-manylinux_ppc64le<br/>cp310-manylinux_s390x<br/>cp310-manylinux_armv7l<br/>cp310-manylinux_riscv64<br/>cp310-musllinux_aarch64<br/>cp310-musllinux_ppc64le<br/>cp310-musllinux_s390x<br/>cp310-musllinux_armv7l<br/>cp310-musllinux_riscv64 | | | |
| Python 3.11 | cp311-macosx_x86_64<br/>cp311-macosx_universal2<br/>cp311-macosx_arm64 | cp311-win_amd64<br/>cp311-win32<br/>cp311-win_arm64 | cp311-manylinux_x86_64<br/>cp311-manylinux_i686<br/>cp311-musllinux_x86_64<br/>cp311-musllinux_i686 | cp311-manylinux_aarch64<br/>cp311-manylinux_ppc64le<br/>cp311-manylinux_s390x<br/>cp311-manylinux_armv7l<br/>cp311-manylinux_riscv64<br/>cp311-musllinux_aarch64<br/>cp311-musllinux_ppc64le<br/>cp311-musllinux_s390x<br/>cp311-musllinux_armv7l<br/>cp311-musllinux_riscv64 | | | |
| Python 3.12 | cp312-macosx_x86_64<br/>cp312-macosx_universal2<br/>cp312-macosx_arm64 | cp312-win_amd64<br/>cp312-win32<br/>cp312-win_arm64 | cp312-manylinux_x86_64<br/>cp312-manylinux_i686<br/>cp312-musllinux_x86_64<br/>cp312-musllinux_i686 | cp312-manylinux_aarch64<br/>cp312-manylinux_ppc64le<br/>cp312-manylinux_s390x<br/>cp312-manylinux_armv7l<br/>cp312-manylinux_riscv64<br/>cp312-musllinux_aarch64<br/>cp312-musllinux_ppc64le<br/>cp312-musllinux_s390x<br/>cp312-musllinux_armv7l<br/>cp312-musllinux_riscv64 | | | cp312-pyodide_wasm32 |
| Python 3.13 | cp313-macosx_x86_64<br/>cp313-macosx_universal2<br/>cp313-macosx_arm64 | cp313-win_amd64<br/>cp313-win32<br/>cp313-win_arm64 | cp313-manylinux_x86_64<br/>cp313-manylinux_i686<br/>cp313-musllinux_x86_64<br/>cp313-musllinux_i686 | cp313-manylinux_aarch64<br/>cp313-manylinux_ppc64le<br/>cp313-manylinux_s390x<br/>cp313-manylinux_armv7l<br/>cp313-manylinux_riscv64<br/>cp313-musllinux_aarch64<br/>cp313-musllinux_ppc64le<br/>cp313-musllinux_s390x<br/>cp313-musllinux_armv7l<br/>cp313-musllinux_riscv64 | cp313-android_arm64_v8a<br/>cp313-android_x86_64 | cp313-ios_arm64_iphoneos<br/>cp313-ios_arm64_iphonesimulator<br/>cp313-ios_x86_64_iphonesimulator | cp313-pyodide_wasm32 |
| Python 3.14 | cp314-macosx_x86_64<br/>cp314-macosx_universal2<br/>cp314-macosx_arm64 | cp314-win_amd64<br/>cp314-win32<br/>cp314-win_arm64 | cp314-manylinux_x86_64<br/>cp314-manylinux_i686<br/>cp314-musllinux_x86_64<br/>cp314-musllinux_i686 | cp314-manylinux_aarch64<br/>cp314-manylinux_ppc64le<br/>cp314-manylinux_s390x<br/>cp314-manylinux_armv7l<br/>cp314-manylinux_riscv64<br/>cp314-musllinux_aarch64<br/>cp314-musllinux_ppc64le<br/>cp314-musllinux_s390x<br/>cp314-musllinux_armv7l<br/>cp314-musllinux_riscv64 | cp314-ios_arm64_iphoneos<br/>cp314-ios_arm64_iphonesimulator<br/>cp314-ios_x86_64_iphonesimulator | |
| Python 3.13 | cp313-macosx_x86_64<br/>cp313-macosx_universal2<br/>cp313-macosx_arm64<br><br>cp313t-macosx_x86_64<br/>cp313t-macosx_universal2<br/>cp313t-macosx_arm64 | cp313-win_amd64<br/>cp313-win32<br/>cp313-win_arm64<br><br>cp313t-win_amd64<br/>cp313t-win32<br/>cp313t-win_arm64 | cp313-manylinux_x86_64<br/>cp313-manylinux_i686<br/>cp313-musllinux_x86_64<br/>cp313-musllinux_i686<br><br>cp313t-manylinux_x86_64<br/>cp313t-manylinux_i686<br/>cp313t-musllinux_x86_64<br/>cp313t-musllinux_i686 | cp313-manylinux_aarch64<br/>cp313-manylinux_ppc64le<br/>cp313-manylinux_s390x<br/>cp313-manylinux_armv7l<br/>cp313-manylinux_riscv64<br/>cp313-musllinux_aarch64<br/>cp313-musllinux_ppc64le<br/>cp313-musllinux_s390x<br/>cp313-musllinux_armv7l<br/>cp313-musllinux_riscv64<br><br>cp313t-manylinux_aarch64<br/>cp313t-manylinux_ppc64le<br/>cp313t-manylinux_s390x<br/>cp313t-manylinux_armv7l<br/>cp313t-manylinux_riscv64<br/>cp313t-musllinux_aarch64<br/>cp313t-musllinux_ppc64le<br/>cp313t-musllinux_s390x<br/>cp313t-musllinux_armv7l<br/>cp313t-musllinux_riscv64 | cp313-android_arm64_v8a<br/>cp313-android_x86_64 | cp313-ios_arm64_iphoneos<br/>cp313-ios_arm64_iphonesimulator<br/>cp313-ios_x86_64_iphonesimulator | cp313-pyodide_wasm32 |
| Python 3.14 | cp314-macosx_x86_64<br/>cp314-macosx_universal2<br/>cp314-macosx_arm64<br><br>cp314t-macosx_x86_64<br/>cp314t-macosx_universal2<br/>cp314t-macosx_arm64 | cp314-win_amd64<br/>cp314-win32<br/>cp314-win_arm64<br><br>cp314t-win_amd64<br/>cp314t-win32<br/>cp314t-win_arm64 | cp314-manylinux_x86_64<br/>cp314-manylinux_i686<br/>cp314-musllinux_x86_64<br/>cp314-musllinux_i686<br><br>cp314t-manylinux_x86_64<br/>cp314t-manylinux_i686<br/>cp314t-musllinux_x86_64<br/>cp314t-musllinux_i686 | cp314-manylinux_aarch64<br/>cp314-manylinux_ppc64le<br/>cp314-manylinux_s390x<br/>cp314-manylinux_armv7l<br/>cp314-manylinux_riscv64<br/>cp314-musllinux_aarch64<br/>cp314-musllinux_ppc64le<br/>cp314-musllinux_s390x<br/>cp314-musllinux_armv7l<br/>cp314-musllinux_riscv64<br><br>cp314t-manylinux_aarch64<br/>cp314t-manylinux_ppc64le<br/>cp314t-manylinux_s390x<br/>cp314t-manylinux_armv7l<br/>cp314t-manylinux_riscv64<br/>cp314t-musllinux_aarch64<br/>cp314t-musllinux_ppc64le<br/>cp314t-musllinux_s390x<br/>cp314t-musllinux_armv7l<br/>cp314t-musllinux_riscv64 | cp314-android_arm64_v8a<br/>cp314-android_x86_64 | cp314-ios_arm64_iphoneos<br/>cp314-ios_arm64_iphonesimulator<br/>cp314-ios_x86_64_iphonesimulator | |
| PyPy3.8 v7.3 | pp38-macosx_x86_64<br/>pp38-macosx_arm64 | pp38-win_amd64 | pp38-manylinux_x86_64<br/>pp38-manylinux_i686 | pp38-manylinux_aarch64 | | | |
| PyPy3.9 v7.3 | pp39-macosx_x86_64<br/>pp39-macosx_arm64 | pp39-win_amd64 | pp39-manylinux_x86_64<br/>pp39-manylinux_i686 | pp39-manylinux_aarch64 | | | |
| PyPy3.10 v7.3 | pp310-macosx_x86_64<br/>pp310-macosx_arm64 | pp310-win_amd64 | pp310-manylinux_x86_64<br/>pp310-manylinux_i686 | pp310-manylinux_aarch64 | | | |
| PyPy3.11 v7.3 | pp311-macosx_x86_64<br/>pp311-macosx_arm64 | pp311-win_amd64 | pp311-manylinux_x86_64<br/>pp311-manylinux_i686 | pp311-manylinux_aarch64 | | | |
| GraalPy 3.11 v24.2 | gp311_242-macosx_x86_64<br/>gp311_242-macosx_arm64 | gp311_242-win_amd64 | gp311_242-manylinux_x86_64 | gp311_242-manylinux_aarch64 | | |
| GraalPy 3.12 v25.0 | gp312_250-macosx_x86_64<br/>gp312_250-macosx_arm64 | gp312_250-win_amd64 | gp312_250-manylinux_x86_64 | gp312_250-manylinux_aarch64 | | |
The list of supported and currently selected build identifiers can also be retrieved by passing the `--print-build-identifiers` flag to cibuildwheel.
The format is `python_tag-platform_tag`, with tags similar to those in [PEP 425](https://www.python.org/dev/peps/pep-0425/#details).
Windows arm64 platform support is experimental.
Linux riscv64 platform support is experimental and requires an explicit opt-in through [`enable`](#enable).
See the [cibuildwheel 2 documentation](https://cibuildwheel.pypa.io/en/2.x/) for past end-of-life versions of Python.
#### Examples
#### Examples {: #build-skip-examples }
!!! tab examples "pyproject.toml"
@@ -107,6 +107,12 @@ See the [cibuildwheel 2 documentation](https://cibuildwheel.pypa.io/en/2.x/) for
# Disable building PyPy wheels on all platforms
skip = "pp*"
# Disable free-threading builds on all platforms
skip = "cp3??t-*"
# Disable free-threading builds on Windows
skip = "cp3??t-win*"
```
!!! tab examples "Environment variables"
@@ -138,12 +144,16 @@ See the [cibuildwheel 2 documentation](https://cibuildwheel.pypa.io/en/2.x/) for
# Disable building PyPy wheels on all platforms
CIBW_SKIP: pp*
# Disable free-threading builds on all platforms
CIBW_SKIP: "cp3??t-*"
# Disable free-threading builds on Windows
CIBW_SKIP: "cp3??t-win*"
```
Separate multiple selectors with a space.
It is generally recommended to set `CIBW_BUILD` as an environment variable, though `skip`
tends to be useful in a config file; you can statically declare that you don't
support a specific build, for example.
@@ -201,8 +211,6 @@ Options:
to use [`build`](#build-skip) with this option to target specific
architectures via build selectors.
Linux riscv64 platform support is experimental and requires an explicit opt-in through [`enable`](#enable).
Default: `auto`
| Runner | `native` | `auto` | `auto64` | `auto32` |
@@ -347,18 +355,11 @@ values are:
- `cpython-prerelease`: Enables beta versions of Pythons if any are available
(May-July, approximately).
- `cpython-freethreading`: [PEP 703](https://www.python.org/dev/peps/pep-0703)
introduced variants of CPython that can be built without the Global
Interpreter Lock (GIL). Those variants are also known as free-threaded /
no-gil. This will enable building these wheels for 3.13, which was considered
experimental. The build identifiers for those variants have a `t` suffix in
their `python_tag` (e.g. `cp313t-manylinux_x86_64`). Starting in 3.14,
free-threaded builds are no longer experimental, so this enable is not needed.
- `cpython-freethreading`: Enable experimental free-threaded builds for CPython 3.13.
Free-threading wheels for 3.14+ are available without this flag, as it's [no
longer considered experimental](https://peps.python.org/pep-0779/).
- `pypy`: Enable PyPy.
- `pypy-eol`: Enable PyPy versions that have passed end of life (if still available).
- `cpython-experimental-riscv64`: Enable experimental riscv64 builds. Those builds
are disabled by default as they can't be uploaded to PyPI and a PEP will most likely
be required before this can happen.
- `graalpy`: Enable GraalPy.
- `pyodide-prerelease`: Pyodide versions that haven't released yet, if one is
available. Safe if you are shipping a site with an early build, not for
@@ -374,7 +375,15 @@ values are:
that version of Python will become available without this flag.
!!! note
Free threading was experimental in 3.13: [Whats New In Python 3.13](https://docs.python.org/3.13/whatsnew/3.13.html#free-threaded-cpython)
[PEP 703](https://www.python.org/dev/peps/pep-0703) introduced variants of
CPython that can be built without the Global Interpreter Lock (GIL). Those
variants are also known as free-threaded / no-gil. The build identifiers for
those variants have a `t` suffix in their `python_tag` (e.g.
`cp313t-manylinux_x86_64`).
Free threading was [experimental in 3.13](https://docs.python.org/3.13/whatsnew/3.13.html#free-threaded-cpython), so it required an explicit enable flag. But, as noted above, free-threading doesn't require an enable flag for 3.14+.
For more info on building for free-threading, see the [Python Free-Threading Guide](https://py-free-threading.github.io/).
Default: empty.
@@ -398,13 +407,9 @@ without disabling your other enables.
```toml
[tool.cibuildwheel]
# Enable free-threaded support
# Enable free-threaded support for CPython 3.13
enable = ["cpython-freethreading"]
# Skip building free-threaded compatible wheels on Windows
enable = ["cpython-freethreading"]
skip = "*t-win*"
# Include all PyPy versions
enable = ["pypy", "pypy-eol"]
```
@@ -416,18 +421,14 @@ without disabling your other enables.
# Include latest Python beta
CIBW_ENABLE: cpython-prerelease
# Include free-threaded support
# Include free-threaded support for CPython 3.13
CIBW_ENABLE: cpython-freethreading
# Include both
CIBW_ENABLE: cpython-prerelease cpython-freethreading
# Skip building free-threaded compatible wheels on Windows
CIBW_ENABLE: cpython-freethreading
CIBW_SKIP: *t-win*
# Include all PyPy versions
CIBW_ENABLE = pypy pypy-eol
CIBW_ENABLE: pypy pypy-eol
```
@@ -469,16 +470,22 @@ Default: `build`
Choose which build frontend to use.
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
all build and test environments. This will generally speed up cibuildwheel.
Make sure you have an external uv on Windows and macOS, either by
pre-installing it, or installing cibuildwheel with the uv extra,
`cibuildwheel[uv]`. uv currently does not support Windows on ARM,
musllinux on s390x, Android, or iOS. Legacy dependencies like
setuptools on Python < 3.12 and pip are not installed if using uv.
You can use "build\[uv\]", which will use [uv][] everywhere possible, both
through `--installer=uv` passed to build, as well as when making all build and
test environments. This will generally speed up cibuildwheel.
On Android and Pyodide, only "build" is supported.
When using `build[uv]`, ensure uv is available on PATH. You can do this by:
- Pre-installing uv (e.g., via `pip install uv` or using `astral-sh/setup-uv`
in GitHub Actions)
- Installing cibuildwheel with the `uv` extra by manually passing
`cibuildwheel[uv]` to installers
- Using the `extras: "uv"` option in the [cibuildwheel action](ci-services.md#github-actions),
which installs uv in an isolated environment
uv currently does not support iOS or musllinux on s390x, ppc64le and riscv64.
On Android and Pyodide, the "pip" frontend is not supported.
You can specify extra arguments to pass to the build frontend using the
optional `args` option.
@@ -571,6 +578,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 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.
@@ -756,9 +764,9 @@ Platform-specific environment variables also available:<br/>
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
`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.
### `before-build` {: #before-build env-var toml}
@@ -904,6 +912,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
- `{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`.
Platform-specific environment variables are also available:<br/>
@@ -1033,7 +1043,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-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`.
@@ -1316,7 +1326,7 @@ The available Pyodide versions are determined by the version of `pyodide-build`
### `test-command` {: #test-command env-var toml}
> 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
set, your wheel will not be installed after building.
@@ -1344,11 +1354,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 Android and iOS, the command is parsed by `shlex.split`, and is required to
be in one of the following forms:
On Android and iOS, the command is parsed by `shlex.split`, and must be a Python
command:
* `python -c command ...` (Android only)
* `python -m module-name ...`
* On Android, the command must must begin with `python` or `python3`, and contain `-m`
or `-c`.
* On iOS, the command must begin with `python -m`.
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`
@@ -1576,7 +1587,7 @@ tests. This can be used to avoid having to redefine test dependencies in
`test-requires` if they are already defined in `pyproject.toml`.
Platform-specific environment variables are also available:<br/>
`CIBW_TEST_GROUPS_MACOS` | `CIBW_TEST_GROUPS_WINDOWS` | `CIBW_TEST_GROUPS_LINUX` | `CIBW_TEST_GROUPS_PYODIDE`
`CIBW_TEST_GROUPS_MACOS` | `CIBW_TEST_GROUPS_WINDOWS` | `CIBW_TEST_GROUPS_LINUX` | `CIBW_TEST_GROUPS_ANDROID` | `CIBW_TEST_GROUPS_IOS` | `CIBW_TEST_GROUPS_PYODIDE`
#### Examples
@@ -1667,6 +1678,41 @@ Platform-specific environment variables are also available:<br/>
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
@@ -1724,6 +1770,9 @@ Settings that are not supported for a specific frontend will log a warning.
The default build frontend is `build`, which does show build backend output by
default.
On Android and iOS, a positive verbosity level will also show more detailed logs from
the test harness.
Platform-specific environment variables are also available:<br/>
`CIBW_BUILD_VERBOSITY_MACOS` | `CIBW_BUILD_VERBOSITY_WINDOWS` | `CIBW_BUILD_VERBOSITY_LINUX` | `CIBW_BUILD_VERBOSITY_ANDROID` | `CIBW_BUILD_VERBOSITY_IOS` | `CIBW_BUILD_VERBOSITY_PYODIDE`
+18 -10
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:
- 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.
@@ -63,7 +63,8 @@ macOS builds will honor the `MACOSX_DEPLOYMENT_TARGET` environment variable to c
| Arch | Python version range | Minimum target |
|-------|----------------------|----------------|
| Intel | CPython 3.8-3.11 | 10.9 |
| Intel | CPython 3.12+ | 10.13 |
| Intel | CPython 3.12-3.13 | 10.13 |
| Intel | CPython 3.14+ | 10.15 |
| AS | CPython or PyPy | 11 |
| Intel | PyPy 3.8 | 10.13 |
| Intel | PyPy 3.9+ | 10.15 |
@@ -121,7 +122,7 @@ See [GitHub issue 1333](https://github.com/pypa/cibuildwheel/issues/1333) for mo
It's easiest to build `x86_64` wheels on `x86_64` runners, and `arm64` wheels on `arm64` runners.
On GitHub Actions, `macos-14` runners are `arm64`, and `macos-13` runners are `x86_64`. So all you need to do is ensure both are in your build matrix.
On GitHub Actions, `macos-14` runners are `arm64`, and `macos-15-intel` runners are `x86_64`. So all you need to do is ensure both are in your build matrix.
#### Cross-compiling
@@ -205,7 +206,6 @@ It also requires the following commands to be on the `PATH`:
* `curl`
* `java` (or set the `JAVA_HOME` environment variable)
* `patchelf` (if the wheel links against any external libraries)
### Android version compatibility
@@ -214,6 +214,11 @@ minimum supported [API level](https://developer.android.com/tools/releases/platf
for generated wheels. This will default to the minimum API level of the selected Python
version.
If the [`repair-wheel-command`](options.md#repair-wheel-command) adds any libraries to
the wheel, then `ANDROID_API_LEVEL` must be at least 24. This is already the default
when building for Python 3.14 and later, but you may need to set it when building for
Python 3.13.
### Build frontend support
Android builds only support the `build` frontend. In principle, support for the
@@ -228,16 +233,17 @@ 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
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
nested virtualization. CI platforms known to meet this requirement are:
* GitHub Actions Linux x86_64
On Linux, the emulator needs access to the KVM virtualization interface. This may
require adding your user to a group, or [changing your udev
rules](https://github.blog/changelog/2024-04-02-github-actions-hardware-accelerated-android-virtualization-now-available/).
If the emulator fails to start, try running `$ANDROID_HOME/emulator/emulator
-accel-check`.
require adding your user to a group, or changing your udev rules. On GitHub
Actions, cibuildwheel will do this automatically using the commands shown
[here](https://github.blog/changelog/2024-04-02-github-actions-hardware-accelerated-android-virtualization-now-available/).
The Android test environment can't support running shell scripts, so the
[`test-command`](options.md#test-command) must be a Python command  see its
@@ -253,7 +259,7 @@ to one of the following URLs:
## iOS {: #ios}
### System requirements
### System requirements {: #ios-system-requirements}
You must be building on a macOS machine, with Xcode installed. The Xcode installation must have an iOS SDK available, with all license agreements agreed to by the user. To check if an iOS SDK is available, open the Xcode settings panel, and check the Platforms tab. This will also ensure that license agreements have been acknowledged.
@@ -316,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 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.
+2
View File
@@ -23,6 +23,8 @@ cibuildwheel
!!!tip
You can pass the `--platform linux` option to cibuildwheel to build Linux wheels, even if you're not on Linux. On most machines, the easiest builds to try are the Linux builds. You don't need any software installed except a Docker daemon, such as [Docker Desktop](https://www.docker.com/get-started/). Each platform that cibuildwheel supports has its own system requirements and platform-specific behaviors. See the [platforms page](platforms.md) for details.
When building locally for macOS or iOS, regardless of the Python you use to invoke cibuildwheel, you'll need [official Python.org](https://www.python.org/downloads/) installations on your machine. `cibuildwheel` won't perform the build using unofficial Python installations such as from `brew` or `uv`.
You should see the builds taking place. You can experiment with [options](options.md) using pyproject.toml or environment variables.
!!! tab "pyproject.toml"
+38 -36
View File
@@ -9,11 +9,11 @@ title: Working examples
| Name | CI | OS | Notes |
|-----------------------------------|----|----|:------|
| [scikit-learn][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | The machine learning library. A complex but clean config using many of cibuildwheel's features to build a large project with Cython and C++ extensions. |
| [pytorch-fairseq][] | ![github icon][] | ![apple icon][] ![linux icon][] | Facebook AI Research Sequence-to-Sequence Toolkit written in Python. |
| [duckdb][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | DuckDB is an analytical in-process SQL database management system |
| [pytorch-fairseq][] | ![github icon][] | ![apple icon][] ![linux icon][] | Facebook AI Research Sequence-to-Sequence Toolkit written in Python. |
| [NumPy][] | ![github icon][] ![travisci icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | The fundamental package for scientific computing with Python. |
| [Tornado][] | ![github icon][] | ![linux icon][] ![apple icon][] ![windows icon][] | Tornado is a Python web framework and asynchronous networking library. Uses stable ABI for a small C extension. |
| [NCNN][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | ncnn is a high-performance neural network inference framework optimized for the mobile platform |
| [Tornado][] | ![github icon][] | ![linux icon][] ![apple icon][] ![windows icon][] | Tornado is a Python web framework and asynchronous networking library. Uses stable ABI for a small C extension. |
| [Matplotlib][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | The venerable Matplotlib, a Python library with C++ portions |
| [MyPy][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | The compiled version of MyPy using MyPyC. |
| [Prophet][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Tool for producing high quality forecasts for time series data that has multiple seasonality with linear or non-linear growth. |
@@ -23,9 +23,10 @@ title: Working examples
| [uvloop][] | ![github icon][] | ![apple icon][] ![linux icon][] | Ultra fast asyncio event loop. |
| [psutil][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Cross-platform lib for process and system monitoring in Python |
| [Google Benchmark][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | A microbenchmark support library |
| [falcon][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Falcon is a no-magic ASGI/WSGI API and microservices framework; it uses cibuildwheel for (optional) Cython extensions. |
| [PyGame][] | ![github icon][] | ![apple icon][] ![linux icon][] | 🐍🎮 pygame (the library) is a Free and Open Source python programming language library for making multimedia applications like games built on top of the excellent SDL library. C, Python, Native, OpenGL. |
| [vaex][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Out-of-Core hybrid Apache Arrow/NumPy DataFrame for Python, ML, visualization and exploration of big tabular data at a billion rows per second 🚀 |
| [Apache Beam][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Apache Beam is a unified programming model for Batch and Streaming data processing. |
| [PyGame][] | ![github icon][] | ![apple icon][] ![linux icon][] | 🐍🎮 pygame (the library) is a Free and Open Source python programming language library for making multimedia applications like games built on top of the excellent SDL library. C, Python, Native, OpenGL. |
| [asyncpg][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | A fast PostgreSQL Database Client Library for Python/asyncio. |
| [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. |
@@ -34,14 +35,14 @@ title: Working examples
| [cvxpy][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | A Python-embedded modeling language for convex optimization problems. |
| [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). |
| [websockets][] | ![travisci icon][] | ![apple icon][] ![linux icon][] | Library for building WebSocket servers and clients. Mostly written in Python, with a small C 'speedups' extension module. |
| [River][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | 🌊 Online machine learning in Python |
| [websockets][] | ![travisci icon][] | ![apple icon][] ![linux icon][] | Library for building WebSocket servers and clients. Mostly written in Python, with a small C 'speedups' extension module. |
| [aiortc][] | ![github icon][] | ![apple icon][] ![linux icon][] | WebRTC and ORTC implementation for Python using asyncio. |
| [OpenSpiel][] | ![github icon][] | ![apple icon][] ![linux icon][] | OpenSpiel is a collection of environments and algorithms for research in general reinforcement learning and search/planning in games. |
| [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 |
| [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. |
| [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][] | ![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 |
| [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 |
@@ -53,51 +54,51 @@ title: Working examples
| [pikepdf][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | A Python library for reading and writing PDF, powered by QPDF |
| [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. |
| [Psycopg 3][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | A modern implementation of a PostgreSQL adapter for Python |
| [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 |
| [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. |
| [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. |
| [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 |
| [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. |
| [DeepForest][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | An Efficient, Scalable and Optimized Python Framework for Deep Forest (2021.2.1) |
| [AutoPy][] | ![travisci icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Includes a Windows Travis build. |
| [H3-py][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Python bindings for H3, a hierarchical hexagonal geospatial indexing system |
| [DeepForest][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | An Efficient, Scalable and Optimized Python Framework for Deep Forest (2021.2.1) |
| [time-machine][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Time mocking library using only the CPython C API. |
| [mosec][] | ![github icon][] | ![linux icon][] ![apple icon][] | A machine learning model serving framework powered by Rust |
| [Picologging][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | A high-performance logging library for Python. |
| [pybind11 cmake_example][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Example pybind11 module built with a CMake-based build system |
| [markupsafe][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Safely add untrusted strings to HTML/XML markup. |
| [pybind11 cmake_example][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Example pybind11 module built with a CMake-based build system |
| [Rtree][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Rtree: spatial index for Python GIS |
| [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 |
| [tgcalls][] | ![github icon][] | ![apple icon][] ![windows icon][] | Python `pybind11` binding to Telegram's WebRTC library with third party dependencies like `OpenSSL`, `MozJPEG`, `FFmpeg`, etc. |
| [sourmash][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Quickly search, compare, and analyze genomic and metagenomic data sets. |
| [python-rapidjson][] | ![travisci icon][] ![gitlab icon][] | ![windows icon][] ![linux icon][] | Python wrapper around rapidjson |
| [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. |
| [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 |
| [cyvcf2][] | ![github icon][] | ![apple icon][] ![linux icon][] | cython + htslib == fast VCF and BCF processing |
| [jq.py][] | ![travisci icon][] | ![apple icon][] ![linux icon][] | Python bindings for jq |
| [cyvcf2][] | ![github icon][] | ![apple icon][] ![linux icon][] | cython + htslib == fast VCF and BCF processing |
| [Confluent client for Kafka][] | ![travisci icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | setup in `tools/wheels/build-wheels.bat` |
| [matrixprofile][] | ![travisci icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | A Python 3 library making time series data mining tasks, utilizing matrix profile algorithms, accessible to everyone. |
| [Tokenizer][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Fast and customizable text tokenization library with BPE and SentencePiece support |
| [Confluent client for Kafka][] | ![travisci icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | setup in `tools/wheels/build-wheels.bat` |
| [iminuit][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Jupyter-friendly Python interface for C++ MINUIT2 |
| [pillow-heif][] | ![github icon][] ![cirrusci icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Bindings to libheif library with third party dependencies. Fully automated CI for tests and publishing including Apple Silicon builds. |
| [keyvi][] | ![github icon][] | ![linux icon][] ![apple icon][] | FST based key value index highly optimized for size and lookup performance, utilizes ccache action for improved runtime |
| [PyGLM][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Fast OpenGL Mathematics (GLM) for Python |
| [TgCrypto][] | ![travisci icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Includes a Windows Travis build. |
| [iDynTree][] | ![github icon][] | ![linux icon][] | Uses manylinux_2_24 |
| [streaming-form-data][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Streaming parser for multipart/form-data written in Cython |
| [TgCrypto][] | ![travisci icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Includes a Windows Travis build. |
| [power-grid-model][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Python/C++ library for distribution power system analysis |
| [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 |
| [Imagecodecs (fork)][] | ![azurepipelines icon][] | ![apple icon][] ![linux icon][] | Over 20 external dependencies in compiled libraries, custom docker image, `libomp`, `openblas` and `install_name_tool` for macOS. |
| [bx-python][] | ![travisci icon][] | ![apple icon][] ![linux icon][] | A library that includes Cython extensions. |
| [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. |
| [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 |
| [fathon][] | ![travisci icon][] | ![apple icon][] ![linux icon][] | python package for DFA (Detrended Fluctuation Analysis) and related algorithms |
@@ -109,21 +110,21 @@ title: Working examples
| [cf-units][] | ![github icon][] | ![apple icon][] ![linux icon][] | Units of measure as required by the Climate and Forecast (CF) Metadata Conventions |
| [numpythia][] | ![github icon][] | ![apple icon][] ![linux icon][] | The interface between PYTHIA and NumPy |
| [pyjet][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | The interface between FastJet and NumPy |
| [ril][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | A python binding to Rust Imaging library using maturin and Pyo3, utilizes Github Action cache to improve speed. Builds abi3 wheels. |
| [SiPM][] | ![github icon][] | ![apple icon][] ![linux icon][] | High performance library for SiPM detectors simulation using C++17, OpenMP and AVX2 intrinsics. |
| [GSD][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Cython and NumPy project with 64-bit wheels. |
| [ril][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | A python binding to Rust Imaging library using maturin and Pyo3, utilizes Github Action cache to improve speed. Builds abi3 wheels. |
| [aalink][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Async Python interface for Ableton Link. |
| [GSD][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Cython and NumPy project with 64-bit wheels. |
| [werpy][] | ![github icon][] | ![windows icon][] ![linux icon][] ![apple icon][] | An ultra-fast python package using optimized dynamic programming to compute the Word Error Rate (WER). |
| [CorrectionLib][] | ![github icon][] | ![apple icon][] ![linux icon][] | Structured JSON powered correction library for HEP, designed for the CMS experiment at CERN. |
| [xmlstarlet][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Python 3.6+ CFFI bindings with true MSVC build. |
| [werpy][] | ![github icon][] | ![windows icon][] ![linux icon][] ![apple icon][] | An ultra-fast python package using optimized dynamic programming to compute the Word Error Rate (WER). |
| [pybind11 cross build example][] | ![github icon][] ![gitlab icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Same as pybind11 cmake_example but used to demo Linux ARM + Windows + macOS builds on GitLab |
[scikit-learn]: https://github.com/scikit-learn/scikit-learn
[pytorch-fairseq]: https://github.com/facebookresearch/fairseq
[duckdb]: https://github.com/duckdb/duckdb
[pytorch-fairseq]: https://github.com/facebookresearch/fairseq
[NumPy]: https://github.com/numpy/numpy
[Tornado]: https://github.com/tornadoweb/tornado
[NCNN]: https://github.com/Tencent/ncnn
[Tornado]: https://github.com/tornadoweb/tornado
[Matplotlib]: https://github.com/matplotlib/matplotlib
[MyPy]: https://github.com/mypyc/mypy_mypyc-wheels
[Prophet]: https://github.com/facebook/prophet
@@ -133,9 +134,10 @@ title: Working examples
[uvloop]: https://github.com/MagicStack/uvloop
[psutil]: https://github.com/giampaolo/psutil
[Google Benchmark]: https://github.com/google/benchmark
[falcon]: https://github.com/falconry/falcon
[PyGame]: https://github.com/pygame/pygame
[vaex]: https://github.com/vaexio/vaex
[Apache Beam]: https://github.com/apache/beam
[PyGame]: https://github.com/pygame/pygame
[asyncpg]: https://github.com/MagicStack/asyncpg
[cmake]: https://github.com/scikit-build/cmake-python-distributions
[pyinstrument]: https://github.com/joerick/pyinstrument
@@ -144,14 +146,14 @@ title: Working examples
[cvxpy]: https://github.com/cvxpy/cvxpy
[twisted-iocpsupport]: https://github.com/twisted/twisted-iocpsupport
[pedalboard]: https://github.com/spotify/pedalboard
[websockets]: https://github.com/python-websockets/websockets
[River]: https://github.com/online-ml/river
[websockets]: https://github.com/python-websockets/websockets
[aiortc]: https://github.com/aiortc/aiortc
[OpenSpiel]: https://github.com/google-deepmind/open_spiel
[Dependency Injector]: https://github.com/ets-labs/python-dependency-injector
[UltraJSON]: https://github.com/ultrajson/ultrajson
[pyzmq]: https://github.com/zeromq/pyzmq
[CTranslate2]: https://github.com/OpenNMT/CTranslate2
[pyzmq]: https://github.com/zeromq/pyzmq
[Implicit]: https://github.com/benfred/implicit
[tinyobjloader]: https://github.com/tinyobjloader/tinyobjloader
[vispy]: https://github.com/vispy/vispy
@@ -163,51 +165,51 @@ title: Working examples
[pikepdf]: https://github.com/pikepdf/pikepdf
[numexpr]: https://github.com/pydata/numexpr
[Wrapt]: https://github.com/GrahamDumpleton/wrapt
[Psycopg 3]: https://github.com/psycopg/psycopg
[h5py]: https://github.com/h5py/h5py
[envd]: https://github.com/tensorchord/envd
[Psycopg 3]: https://github.com/psycopg/psycopg
[OpenColorIO]: https://github.com/AcademySoftwareFoundation/OpenColorIO
[ruptures]: https://github.com/deepcharles/ruptures
[aioquic]: https://github.com/aiortc/aioquic
[SimpleJSON]: https://github.com/simplejson/simplejson
[OpenTimelineIO]: https://github.com/AcademySoftwareFoundation/OpenTimelineIO
[SimpleJSON]: https://github.com/simplejson/simplejson
[PyTables]: https://github.com/PyTables/PyTables
[google neuroglancer]: https://github.com/google/neuroglancer
[Parselmouth]: https://github.com/YannickJadoul/Parselmouth
[DeepForest]: https://github.com/LAMDA-NJU/Deep-Forest
[AutoPy]: https://github.com/autopilot-rs/autopy
[H3-py]: https://github.com/uber/h3-py
[DeepForest]: https://github.com/LAMDA-NJU/Deep-Forest
[time-machine]: https://github.com/adamchainz/time-machine
[mosec]: https://github.com/mosecorg/mosec
[Picologging]: https://github.com/microsoft/picologging
[pybind11 cmake_example]: https://github.com/pybind/cmake_example
[markupsafe]: https://github.com/pallets/markupsafe
[pybind11 cmake_example]: https://github.com/pybind/cmake_example
[Rtree]: https://github.com/Toblerity/rtree
[KDEpy]: https://github.com/tommyod/KDEpy
[dd-trace-py]: https://github.com/DataDog/dd-trace-py
[tgcalls]: https://github.com/MarshalX/tgcalls
[sourmash]: https://github.com/sourmash-bio/sourmash
[python-rapidjson]: https://github.com/python-rapidjson/python-rapidjson
[pybind11 python_example]: https://github.com/pybind/python_example
[sourmash]: https://github.com/sourmash-bio/sourmash
[abess]: https://github.com/abess-team/abess
[python-snappy]: https://github.com/intake/python-snappy
[cyvcf2]: https://github.com/brentp/cyvcf2
[jq.py]: https://github.com/mwilliamson/jq.py
[cyvcf2]: https://github.com/brentp/cyvcf2
[Confluent client for Kafka]: https://github.com/confluentinc/confluent-kafka-python
[matrixprofile]: https://github.com/matrix-profile-foundation/matrixprofile
[Tokenizer]: https://github.com/OpenNMT/Tokenizer
[Confluent client for Kafka]: https://github.com/confluentinc/confluent-kafka-python
[iminuit]: https://github.com/scikit-hep/iminuit
[pillow-heif]: https://github.com/bigcat88/pillow_heif
[keyvi]: https://github.com/KeyviDev/keyvi
[PyGLM]: https://github.com/Zuzu-Typ/PyGLM
[TgCrypto]: https://github.com/pyrogram/tgcrypto
[iDynTree]: https://github.com/robotology/idyntree
[streaming-form-data]: https://github.com/siddhantgoel/streaming-form-data
[TgCrypto]: https://github.com/pyrogram/tgcrypto
[power-grid-model]: https://github.com/PowerGridModel/power-grid-model
[streaming-form-data]: https://github.com/siddhantgoel/streaming-form-data
[pybase64]: https://github.com/mayeut/pybase64
[Imagecodecs (fork)]: https://github.com/czaki/imagecodecs_build
[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
[Python-WebRTC]: https://github.com/MarshalX/python-webrtc
[pybind11 scikit_build_example]: https://github.com/pybind/scikit_build_example
[fathon]: https://github.com/stfbnc/fathon
@@ -219,13 +221,13 @@ title: Working examples
[cf-units]: https://github.com/SciTools/cf-units
[numpythia]: https://github.com/scikit-hep/numpythia
[pyjet]: https://github.com/scikit-hep/pyjet
[ril]: https://github.com/Cryptex-github/ril-py
[SiPM]: https://github.com/EdoPro98/SimSiPM
[GSD]: https://github.com/glotzerlab/gsd
[ril]: https://github.com/Cryptex-github/ril-py
[aalink]: https://github.com/artfwo/aalink
[GSD]: https://github.com/glotzerlab/gsd
[werpy]: https://github.com/analyticsinmotion/werpy
[CorrectionLib]: https://github.com/cms-nanoAOD/correctionlib
[xmlstarlet]: https://github.com/dimitern/xmlstarlet
[werpy]: https://github.com/analyticsinmotion/werpy
[pybind11 cross build example]: https://github.com/wbarnha/pybind_cmake_example_crossbuild
[github icon]: data/readme_icons/github.svg
+3 -3
View File
@@ -6,7 +6,7 @@ jobs:
- bash: |
set -o errexit
python3 -m pip install --upgrade pip
pip3 install cibuildwheel==3.1.1
pip3 install cibuildwheel==3.3.0
displayName: Install dependencies
- bash: cibuildwheel --output-dir wheelhouse .
displayName: Build wheels
@@ -20,7 +20,7 @@ jobs:
- bash: |
set -o errexit
python3 -m pip install --upgrade pip
python3 -m pip install cibuildwheel==3.1.1
python3 -m pip install cibuildwheel==3.3.0
displayName: Install dependencies
- bash: cibuildwheel --output-dir wheelhouse .
displayName: Build wheels
@@ -34,7 +34,7 @@ jobs:
- bash: |
set -o errexit
python -m pip install --upgrade pip
pip install cibuildwheel==3.1.1
pip install cibuildwheel==3.3.0
displayName: Install dependencies
- bash: cibuildwheel --output-dir wheelhouse .
displayName: Build wheels
+3 -3
View File
@@ -11,7 +11,7 @@ jobs:
- run:
name: Build the Linux wheels.
command: |
python3 -m pip install --user cibuildwheel==3.1.1
python3 -m pip install --user cibuildwheel==3.3.0
cibuildwheel --output-dir wheelhouse
- store_artifacts:
path: wheelhouse/
@@ -28,7 +28,7 @@ jobs:
- run:
name: Build the Linux aarch64 wheels.
command: |
python3 -m pip install --user cibuildwheel==3.1.1
python3 -m pip install --user cibuildwheel==3.3.0
python3 -m cibuildwheel --output-dir wheelhouse
- store_artifacts:
path: wheelhouse/
@@ -44,7 +44,7 @@ jobs:
name: Build the OS X wheels.
command: |
sudo softwareupdate --install-rosetta --agree-to-license # for python<=3.8 or x86_64/universal2 tests
pip3 install cibuildwheel==3.1.1
pip3 install cibuildwheel==3.3.0
cibuildwheel --output-dir wheelhouse
- store_artifacts:
path: wheelhouse/
+1 -1
View File
@@ -1,6 +1,6 @@
build_and_store_wheels: &BUILD_AND_STORE_WHEELS
install_cibuildwheel_script:
- python -m pip install cibuildwheel==3.1.1
- python -m pip install cibuildwheel==3.3.0
run_cibuildwheel_script:
- cibuildwheel
wheels_artifacts:
+1 -1
View File
@@ -1,6 +1,6 @@
build_and_store_wheels: &BUILD_AND_STORE_WHEELS
install_cibuildwheel_script:
- python -m pip install cibuildwheel==3.1.1
- python -m pip install cibuildwheel==3.3.0
run_cibuildwheel_script:
- cibuildwheel
wheels_artifacts:
+14 -22
View File
@@ -26,8 +26,8 @@ jobs:
- os: windows-arm
runs-on: windows-11-arm
- os: macos-intel
# macos-13 was the last x86_64 runner
runs-on: macos-13
# macos-15-intel is the last x86_64 runner
runs-on: macos-15-intel
- os: macos-arm
# macos-14+ (including latest) are ARM64 runners
runs-on: macos-latest
@@ -35,8 +35,11 @@ jobs:
runs-on: ubuntu-latest
platform: android
- os: android-arm
runs-on: macos-latest
# GitHub Actions doesnt currently support the Android emulator on any ARM
# runner. So we build on a non-ARM runner, which will skip the tests.
runs-on: ubuntu-latest
platform: android
archs: arm64_v8a
- os: ios
runs-on: macos-latest
platform: ios
@@ -45,25 +48,13 @@ jobs:
platform: pyodide
steps:
- uses: actions/checkout@v4
# GitHub Actions can't currently run the Android emulator on macOS.
- name: Skip Android tests on macOS
if: matrix.os == 'android-arm'
run: echo "CIBW_TEST_COMMAND=" >> "$GITHUB_ENV"
# https://github.blog/changelog/2024-04-02-github-actions-hardware-accelerated-android-virtualization-now-available/
- name: Enable KVM for Android emulator
if: matrix.os == 'android-intel'
run: |
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
sudo udevadm control --reload-rules
sudo udevadm trigger --name-match=kvm
- uses: actions/checkout@v5
- name: Build wheels
uses: pypa/cibuildwheel@v3.1.1
uses: pypa/cibuildwheel@v3.3.0
env:
CIBW_PLATFORM: ${{ matrix.platform || 'auto' }}
CIBW_ARCHS: ${{ matrix.archs || 'auto' }}
# Can also be configured directly, using `with:`
# with:
# package-dir: .
@@ -79,7 +70,7 @@ jobs:
name: Build source distribution
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- name: Build sdist
run: pipx run build --sdist
@@ -99,7 +90,7 @@ jobs:
# or, alternatively, upload to PyPI on every tag starting with 'v' (remove on: release above to use this)
# if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
steps:
- uses: actions/download-artifact@v4
- uses: actions/download-artifact@v5
with:
# unpacks all CIBW artifacts into dist/
pattern: cibw-*
@@ -107,5 +98,6 @@ jobs:
merge-multiple: true
- uses: pypa/gh-action-pypi-publish@release/v1
with:
# To test: repository-url: https://test.pypi.org/legacy/
# To test uploads to TestPyPI, uncomment the following:
# with:
# repository-url: https://test.pypi.org/legacy/
+4 -4
View File
@@ -8,14 +8,14 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
# macos-13 is an intel runner, macos-14 is apple silicon
os: [ubuntu-latest, ubuntu-24.04-arm, windows-latest, windows-11-arm, macos-13, macos-14]
# macos-15-intel is an Intel runner, macos-14 is Apple silicon
os: [ubuntu-latest, ubuntu-24.04-arm, windows-latest, windows-11-arm, macos-15-intel, macos-14]
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- name: Build wheels
uses: pypa/cibuildwheel@v3.1.1
uses: pypa/cibuildwheel@v3.3.0
# env:
# CIBW_SOME_OPTION: value
# ...
+4 -4
View File
@@ -8,14 +8,14 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
# macos-13 is an intel runner, macos-14 is apple silicon
os: [ubuntu-latest, ubuntu-24.04-arm, windows-latest, windows-11-arm, macos-13, macos-14]
# macos-15-intel is an Intel runner, macos-14 is Apple silicon
os: [ubuntu-latest, ubuntu-24.04-arm, windows-latest, windows-11-arm, macos-15-intel, macos-14]
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- name: Build wheels
run: pipx run cibuildwheel==3.1.1
run: pipx run cibuildwheel==3.3.0
- uses: actions/upload-artifact@v4
with:
+4 -4
View File
@@ -8,11 +8,11 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
# macos-13 is an intel runner, macos-14 is apple silicon
os: [ubuntu-latest, ubuntu-24.04-arm, windows-latest, windows-11-arm, macos-13, macos-14]
# macos-15-intel is an Intel runner, macos-14 is Apple silicon
os: [ubuntu-latest, ubuntu-24.04-arm, windows-latest, windows-11-arm, macos-15-intel, macos-14]
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- name: Set up QEMU
if: runner.os == 'Linux' && runner.arch == 'X64'
@@ -21,7 +21,7 @@ jobs:
platforms: all
- name: Build wheels
uses: pypa/cibuildwheel@v3.1.1
uses: pypa/cibuildwheel@v3.3.0
env:
# configure cibuildwheel on Linux to build native archs ('auto'),
# and to split the remaining architectures between the x86_64 and
+3 -3
View File
@@ -12,7 +12,7 @@ linux:
DOCKER_TLS_CERTDIR: ""
script:
- curl -sSL https://get.docker.com/ | sh
- python -m pip install cibuildwheel==3.1.1
- python -m pip install cibuildwheel==3.3.0
- cibuildwheel --output-dir wheelhouse
artifacts:
paths:
@@ -23,7 +23,7 @@ windows:
before_script:
- choco install python -y --allow-downgrade --version 3.12.4
- choco install git.install -y
- py -m pip install cibuildwheel==3.1.1
- py -m pip install cibuildwheel==3.3.0
script:
- py -m cibuildwheel --output-dir wheelhouse --platform windows
artifacts:
@@ -35,7 +35,7 @@ windows:
macos:
image: macos-14-xcode-15
before_script:
- python3 -m pip install cibuildwheel==3.1.1
- python3 -m pip install cibuildwheel==3.3.0
script:
- python3 -m cibuildwheel --output-dir wheelhouse
artifacts:
+1 -1
View File
@@ -14,7 +14,7 @@ linux:
- curl -sSL https://get.docker.com/ | sh
# Warning: This is extremely slow, be careful with how many wheels you build
- docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
- python -m pip install cibuildwheel==3.1.1
- python -m pip install cibuildwheel==3.3.0
# Assuming your CI runner's default architecture is x86_64...
- cibuildwheel --output-dir wheelhouse --platform linux --archs aarch64
artifacts:
+1 -1
View File
@@ -20,7 +20,7 @@ jobs:
- ln -s /c/Python312/python.exe /c/Python312/python3.exe
install:
- python3 -m pip install cibuildwheel==3.1.1
- python3 -m pip install cibuildwheel==3.3.0
script:
# 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
install:
- python3 -m pip install cibuildwheel==3.1.1
- python3 -m pip install cibuildwheel==3.3.0
script:
# build the wheels, put them into './wheelhouse'
+2 -2
View File
@@ -52,7 +52,7 @@ jobs:
- stage: deploy
name: Build and deploy Linux wheels
services: docker
install: python3 -m pip install cibuildwheel==3.1.1 twine
install: python3 -m pip install cibuildwheel==3.3.0 twine
script: python3 -m cibuildwheel --output-dir wheelhouse
after_success: python3 -m twine upload --skip-existing wheelhouse/*.whl
# Deploy on windows
@@ -60,7 +60,7 @@ jobs:
name: Build and deploy Windows wheels
os: windows
language: shell
install: python3 -m pip install cibuildwheel==3.1.1 twine
install: python3 -m pip install cibuildwheel==3.3.0 twine
script: python3 -m cibuildwheel --output-dir wheelhouse
after_success: python3 -m twine upload --skip-existing wheelhouse/*.whl
+1
View File
@@ -58,6 +58,7 @@ def tests(session: nox.Session) -> None:
session.run("pytest", *session.posargs)
else:
unit_test_args = ["--run-docker"] if sys.platform.startswith("linux") else []
session.run("pytest", "cibuildwheel") # run doctests
session.run("pytest", "unit_test", *unit_test_args)
session.run("pytest", "test", "-x", "--durations", "0", "--timeout=2400", "test")
+20 -4
View File
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
[project]
name = "cibuildwheel"
version = "3.1.1"
version = "3.3.0"
description = "Build Python wheels on CI with minimal configuration."
readme = "README.md"
license = "BSD-2-Clause"
@@ -45,6 +45,8 @@ dependencies = [
"filelock",
"humanize",
"packaging>=20.9",
# patchelf is used for Android
"patchelf; (sys_platform == 'linux' or sys_platform == 'darwin') and (platform_machine == 'x86_64' or platform_machine == 'arm64' or platform_machine == 'aarch64')",
"platformdirs",
"pyelftools>=0.29",
"wheel>=0.33.6",
@@ -77,7 +79,7 @@ bin = [
docs = [
"jinja2>=3.1.2",
"mkdocs-include-markdown-plugin==6.2.2",
"mkdocs-macros-plugin",
"mkdocs-macros-plugin>=1.4.1",
"mkdocs==1.6.1",
"pymdown-extensions",
"rich",
@@ -88,10 +90,12 @@ test = [
"jinja2",
"pytest-timeout",
"pytest-xdist",
"pytest-rerunfailures!=16.0",
"pytest>=6",
"setuptools",
"tomli_w",
"validate-pyproject",
"xdoctest",
]
dev = [
{include-group = "bin"},
@@ -102,13 +106,16 @@ dev = [
[tool.pytest.ini_options]
minversion = "6.0"
addopts = ["-ra", "--showlocals", "--strict-markers", "--strict-config"]
addopts = ["-ra", "--showlocals", "--strict-markers", "--strict-config", "--xdoctest", "--ignore-glob=*venv*"]
junit_family = "xunit2"
xfail_strict = true
filterwarnings = ["error"]
log_cli_level = "INFO"
log_level = "INFO"
markers = [
"serial: tests that must *not* be run in parallel (deselect with '-m \"not serial\"')",
"ios: tests that run on iOS",
"android: tests that run on Android",
"pyodide: tests that run on Pyodide",
]
[tool.mypy]
@@ -209,6 +216,15 @@ extend-select = [
"EXE", # flake8-executable
"PYI", # flake8-pyi
"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 = [
"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"]
+28 -8
View File
@@ -1,5 +1,6 @@
import json
import os
import shutil
import subprocess
from collections.abc import Generator
@@ -11,7 +12,6 @@ from cibuildwheel.ci import detect_ci_provider
from cibuildwheel.options import CommandLineArguments, Options
from cibuildwheel.selector import EnableGroup
from cibuildwheel.typing import PLATFORMS
from cibuildwheel.venv import find_uv
from .utils import DEFAULT_CIBW_ENABLE, EMULATED_ARCHS, get_platform
@@ -154,19 +154,39 @@ def docker_warmup_fixture(
@pytest.fixture(params=["pip", "build"])
def build_frontend_env_nouv(request: pytest.FixtureRequest) -> dict[str, str]:
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")
return {"CIBW_BUILD_FRONTEND": frontend}
@pytest.fixture
def build_frontend_env(build_frontend_env_nouv: dict[str, str]) -> dict[str, str]:
frontend = build_frontend_env_nouv["CIBW_BUILD_FRONTEND"]
if frontend != "build" or get_platform() == "pyodide" or find_uv() is None:
return build_frontend_env_nouv
@pytest.fixture(params=["pip", "build", "build[uv]"])
def build_frontend_env(request: pytest.FixtureRequest) -> dict[str, str]:
frontend = request.param
marks = {m.name for m in request.node.iter_markers()}
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_available = shutil.which("uv") is not None
if not uv_available and frontend == "build[uv]":
pytest.skip("Can't find uv, so skipping uv tests")
if uv_available 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
+2 -2
View File
@@ -41,7 +41,7 @@ def test_abi3(tmp_path):
add_env={
# free_threaded, GraalPy, and PyPy do not have a Py_LIMITED_API equivalent, just build one of those
# also limit the number of builds for test performance reasons
"CIBW_BUILD": "cp39-* cp310-* pp310-* gp311_242-* cp312-* cp313t-*",
"CIBW_BUILD": "cp39-* cp310-* pp310-* gp312_250-* cp312-* cp313t-*",
"CIBW_ENABLE": "all",
},
)
@@ -64,7 +64,7 @@ def test_abi3(tmp_path):
"cp310-abi3", # <-- ABI3, works with 3.10 and 3.12
"cp313-cp313t",
"pp310-pypy310_pp73",
"graalpy311-graalpy242_311_native",
"graalpy312-graalpy250_312_native",
],
)
+167 -52
View File
@@ -1,7 +1,9 @@
import os
import platform
import re
import sys
from dataclasses import dataclass
from pathlib import Path
from shutil import rmtree
from subprocess import CalledProcessError
from textwrap import dedent
@@ -12,6 +14,9 @@ import pytest
from .test_projects import new_c_project
from .utils import cibuildwheel_run, expected_wheels
pytestmark = pytest.mark.android
CIBW_PLATFORM = os.environ.get("CIBW_PLATFORM", "android")
if CIBW_PLATFORM != "android":
pytest.skip(f"{CIBW_PLATFORM=}", allow_module_level=True)
@@ -27,24 +32,25 @@ if (platform.system(), platform.machine()) not in [
allow_module_level=True,
)
# Detect CI services which have the Android SDK pre-installed.
ci_supports_build = any(
key in os.environ
for key in [
"GITHUB_ACTIONS",
"TF_BUILD", # Azure Pipelines
]
)
# Azure Pipelines does not set the CI variable.
ci = any(key in os.environ for key in ["CI", "TF_BUILD"])
if "ANDROID_HOME" not in os.environ:
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)
else:
pytest.skip(msg, allow_module_level=True)
# 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):
@@ -52,7 +58,7 @@ def needs_emulator(test):
# application ID, so these tests must be run serially.
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)
return test
@@ -89,16 +95,40 @@ def test_android_home(tmp_path, capfd):
assert "ANDROID_HOME environment variable is not set" in capfd.readouterr().err
def test_frontend_good(tmp_path):
# 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
def test_expected_wheels(tmp_path, spam_env):
# Since this test covers all Python versions, check the cross venv.
test_module = "_cross_venv_test_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(
"spam", "0.1.0", platform="android", machine_arch=native_arch.android_abi
)
@needs_emulator
def test_frontend_good(tmp_path, build_frontend_env):
new_c_project().generate(tmp_path)
wheels = cibuildwheel_run(
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"]
@pytest.mark.parametrize("frontend", ["build[uv]", "pip"])
@pytest.mark.parametrize("frontend", ["pip"])
def test_frontend_bad(frontend, tmp_path, capfd):
new_c_project().generate(tmp_path)
with pytest.raises(CalledProcessError):
@@ -109,14 +139,6 @@ def test_frontend_bad(frontend, tmp_path, capfd):
assert "Android requires the build frontend to be 'build'" in capfd.readouterr().err
def test_expected_wheels(tmp_path):
new_c_project().generate(tmp_path)
wheels = cibuildwheel_run(tmp_path, add_env={"CIBW_PLATFORM": "android"})
assert wheels == expected_wheels(
"spam", "0.1.0", platform="android", machine_arch=native_arch.android_abi
)
@needs_emulator
def test_archs(tmp_path, capfd):
new_c_project().generate(tmp_path)
@@ -216,12 +238,20 @@ def spam_env(tmp_path):
print("Spam test passed")
"""
)
project.files["test_empty.py"] = dedent(
"""\
def test_empty():
pass
"""
)
project.generate(tmp_path)
return {
**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_COMMAND": "python -m pytest",
}
@@ -229,7 +259,8 @@ def spam_env(tmp_path):
@pytest.mark.parametrize(
("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 "),
("pytest test_spam.py", "=== 1 passed in "),
],
@@ -246,27 +277,25 @@ def test_test_command_good(command, expected_output, tmp_path, spam_env, capfd):
) 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
@pytest.mark.parametrize(
("command", "expected_output"),
[
# Build-time failure: unrecognized command
(
"./test_spam.py",
"Test command './test_spam.py' is not supported on Android. "
"Supported commands are 'python -m' and 'python -c'.",
),
# 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",
),
# Build-time failure
("./test_spam.py", BAD_FORMAT_ERROR.format("./test_spam.py")),
("python test_spam.py", BAD_FORMAT_ERROR.format("python test_spam.py")),
("pytest {project}", BAD_PLACEHOLDER_ERROR.format("pytest {project}")),
("pytest {package}", BAD_PLACEHOLDER_ERROR.format("pytest {package}")),
# Runtime failure
("pytest test_ham.py", "not found: test_ham.py"),
],
@@ -277,6 +306,29 @@ def test_test_command_bad(command, expected_output, tmp_path, spam_env, capfd):
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
def test_package_subdir(tmp_path, spam_env, capfd):
spam_paths = list(tmp_path.iterdir())
@@ -285,17 +337,11 @@ def test_package_subdir(tmp_path, spam_env, capfd):
for path in spam_paths:
path.rename(package_dir / path.name)
test_filename = "package/" + spam_env["CIBW_TEST_SOURCES"]
cibuildwheel_run(
tmp_path,
package_dir,
add_env={
**spam_env,
"CIBW_TEST_SOURCES": test_filename,
"CIBW_TEST_COMMAND": f"python -m pytest {test_filename}",
},
spam_env["CIBW_TEST_SOURCES"] = " ".join(
f"package/{path}" for path in spam_env["CIBW_TEST_SOURCES"].split()
)
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
@@ -312,6 +358,65 @@ def test_no_test_sources(tmp_path, capfd):
) in capfd.readouterr().err
@needs_emulator
def test_environment_markers(tmp_path):
project = new_c_project()
test_filename = "test_environment_markers.py"
project.files[test_filename] = dedent(
"""\
import pytest
def test_android():
import certifi
def test_not_android():
try:
import platformdirs
except ImportError:
pass
else:
pytest.fail("`platformdirs` should not have been installed")
"""
)
project.generate(tmp_path)
cibuildwheel_run(
tmp_path,
add_env={
**cp313_env,
"CIBW_TEST_COMMAND": f"python -m pytest {test_filename}",
"CIBW_TEST_SOURCES": test_filename,
"CIBW_TEST_REQUIRES": "pytest certifi;sys_platform=='android' platformdirs;sys_platform!='android'",
},
)
@needs_emulator
def test_verbosity(tmp_path, capfd):
new_c_project().generate(tmp_path)
test_env = {
**cp313_env,
"CIBW_TEST_COMMAND": """python -c 'print("Hello world")'""",
}
verbose_lines = [
"> Task :app:packageDebug", # Gradle
"I/TestRunner: run started: 1 tests", # Logcat
]
cibuildwheel_run(tmp_path, add_env=test_env)
stdout = capfd.readouterr().out
for line in verbose_lines:
assert line not in stdout
cibuildwheel_run(
tmp_path,
add_env={**test_env, "CIBW_BUILD_VERBOSITY": "1"},
)
stdout = capfd.readouterr().out
for line in verbose_lines:
assert line in stdout
@needs_emulator
def test_api_level(tmp_path, capfd):
project = new_c_project()
@@ -349,11 +454,21 @@ def test_libcxx(tmp_path, capfd):
project_dir = tmp_path / "project"
output_dir = tmp_path / "output"
# cibuildwheel should be able to run `patchelf` and `wheel` even when its
# environment's `bin` directory is not on the PATH.
non_venv_path = ":".join(
item for item in os.environ["PATH"].split(":") if Path(item) != Path(sys.executable).parent
)
# A C++ package should include libc++, and the extension module should be able to
# find it using DT_RUNPATH.
new_c_project(setup_py_extension_args_add="language='c++'").generate(project_dir)
script = 'import spam; print(", ".join(f"{s}: {spam.filter(s)}" for s in ["ham", "spam"]))'
cp313_test_env = {**cp313_env, "CIBW_TEST_COMMAND": f"python -c '{script}'"}
cp313_test_env = {
**cp313_env,
"CIBW_TEST_COMMAND": f"python -c '{script}'",
"PATH": non_venv_path,
}
# Including external libraries requires API level 24.
with pytest.raises(CalledProcessError):
+1 -3
View File
@@ -63,9 +63,7 @@ def test(tmp_path, build_frontend_env):
# the 'false ||' bit is to ensure this command runs in a shell on
# mac/linux.
"CIBW_TEST_COMMAND": f"false || {utils.invoke_pytest()} {{project}}/test",
# pytest fails on GraalPy 24.2.0 on Windows so we skip it there
# until https://github.com/oracle/graalpython/issues/490 is fixed
"CIBW_TEST_COMMAND_WINDOWS": "where graalpy || pytest {project}/test",
"CIBW_TEST_COMMAND_WINDOWS": "pytest {project}/test",
**build_frontend_env,
},
)
+40
View File
@@ -1,4 +1,5 @@
import subprocess
import textwrap
from contextlib import nullcontext as does_not_raise
import pytest
@@ -56,3 +57,42 @@ def test(tmp_path, capfd):
# We only produced one wheel (perhaps Pyodide)
# check that it has the right name
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"]
+81 -57
View File
@@ -1,5 +1,7 @@
import json
import platform
import re
import subprocess
import textwrap
from pathlib import Path
@@ -9,40 +11,62 @@ from cibuildwheel.util import resources
from . import test_projects, utils
project_with_expected_version_checks = test_projects.new_c_project(
setup_py_add=textwrap.dedent(
r"""
import subprocess
import os
import sys
VERSION_REGEX = r"([\w-]+)==([^\s]+)"
versions_output_text = subprocess.check_output(
[sys.executable, '-m', 'pip', 'freeze', '--all', '-qq'],
universal_newlines=True,
)
versions = versions_output_text.strip().splitlines()
CHECK_VERSIONS_SCRIPT = """\
'''
Checks that the versions in the env var EXPECTED_VERSIONS match those
installed in the active venv.
'''
import os, subprocess, sys, json
# `versions` now looks like:
# ['pip==x.x.x', 'setuptools==x.x.x', 'wheel==x.x.x']
print('Gathered versions', versions)
expected_version = os.environ['EXPECTED_PIP_VERSION']
assert f'pip=={expected_version}' in versions, (
f'error: pip version should equal {expected_version}'
)
"""
)
versions_raw = json.loads(
subprocess.check_output([
sys.executable, '-m', 'pip', 'list', '--format=json',
], text=True)
)
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"""
[build-system]
requires = ["setuptools", "pip"]
build-backend = "setuptools.build_meta"
for name, expected_version in expected_versions.items():
if name not in versions:
continue
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]:
@@ -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}")
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(".", "")
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":
constraint_filename = f"constraints-pyodide{version_no_dot}.txt"
else:
@@ -77,16 +105,13 @@ def test_pinned_versions(tmp_path, python_version, build_frontend_env_nouv):
constraint_file = resources.PATH / constraint_filename
constraint_versions = get_versions_from_constraint_file(constraint_file)
build_environment["EXPECTED_PIP_VERSION"] = constraint_versions["pip"]
cibw_environment_option = " ".join(f"{k}={v}" for k, v in build_environment.items())
# build and test the wheels
# build and test the wheels (dependency version check occurs before-build)
actual_wheels = utils.cibuildwheel_run(
project_dir,
add_env={
"CIBW_BUILD": build_pattern,
"CIBW_ENVIRONMENT": cibw_environment_option,
"CIBW_BUILD": f"[cp]p{version_no_dot}-*",
"CIBW_BEFORE_BUILD": f"python {before_build_script.name}",
"EXPECTED_VERSIONS": json.dumps(constraint_versions),
**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")
project_dir = tmp_path / "project"
project_with_expected_version_checks.generate(project_dir)
test_projects.new_c_project().generate(project_dir)
tool_versions = {
"pip": "23.1.2",
"build": "1.2.2",
"delocate": "0.10.3",
}
@@ -120,6 +146,7 @@ def test_dependency_constraints(method, tmp_path, build_frontend_env_nouv):
textwrap.dedent(
"""
pip=={pip}
build=={build}
delocate=={delocate}
""".format(**tool_versions)
)
@@ -133,45 +160,42 @@ def test_dependency_constraints(method, tmp_path, build_frontend_env_nouv):
msg = f"Unknown method: {method}"
raise ValueError(msg)
build_environment = {}
skip = ""
if (
utils.get_platform() == "windows"
and method == "file"
and build_frontend_env_nouv["CIBW_BUILD_FRONTEND"] == "build"
):
# GraalPy fails to discover its standard library when a venv is created
# GraalPy 24 fails to discover its standard library when a venv is created
# from a virtualenv seeded executable. See
# https://github.com/oracle/graalpython/issues/491 and remove this once
# fixed upstream.
build_frontend_env_nouv["CIBW_SKIP"] = "gp*"
# GraalPy 24 is dropped
skip = "gp311*"
for package_name, version in tool_versions.items():
env_name = f"EXPECTED_{package_name.upper()}_VERSION"
build_environment[env_name] = version
# cross-platform Python script for dependency constraint checks
before_build_script = project_dir / "check_versions.py"
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
# build and test the wheels (dependency version check occurs pre-build)
actual_wheels = utils.cibuildwheel_run(
project_dir,
add_env={
"CIBW_ENVIRONMENT": cibw_environment_option,
"CIBW_SKIP": skip,
"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,
},
single_python=True,
)
# 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 (
utils.get_platform() == "windows"
and method == "file"
and build_frontend_env_nouv["CIBW_BUILD_FRONTEND"] == "build"
):
if skip == "gp*":
# See reference to https://github.com/oracle/graalpython/issues/491
# above
expected_wheels = [w for w in expected_wheels if "graalpy" not in w]
expected_wheels = [w for w in expected_wheels if "graalpy311" not in w]
assert set(actual_wheels) == set(expected_wheels)
+18 -8
View File
@@ -12,6 +12,12 @@ from cibuildwheel.ci import CIProvider, detect_ci_provider
from . import test_projects, utils
pytestmark = pytest.mark.ios
CIBW_PLATFORM = os.environ.get("CIBW_PLATFORM", "ios")
if CIBW_PLATFORM != "ios":
pytest.skip(f"{CIBW_PLATFORM=}", allow_module_level=True)
basic_project_files = {
"tests/test_platform.py": f"""
import platform
@@ -43,7 +49,9 @@ def skip_if_ios_testing_not_supported() -> None:
# it's easy to overload the CI machine if there are multiple test processes
# running multithreaded processes. Therefore, they're put in the serial group,
# which is guaranteed to run single-process.
# This can also fail the first time sometimes.
@pytest.mark.serial
@pytest.mark.flaky(reruns=2)
@pytest.mark.parametrize(
"build_config",
[
@@ -92,9 +100,7 @@ def test_ios_platforms(tmp_path, build_config, monkeypatch, capfd):
)
# The expected wheels were produced.
expected_wheels = utils.expected_wheels(
"spam", "0.1.0", platform="ios", python_abi_tags=["cp313-cp313", "cp314-cp314"]
)
expected_wheels = utils.expected_wheels("spam", "0.1.0", platform="ios")
assert set(actual_wheels) == set(expected_wheels)
# The user was notified that the cross-build tool was found.
@@ -163,6 +169,7 @@ def test_ios_testing_with_placeholder(tmp_path, capfd):
@pytest.mark.serial
@pytest.mark.flaky(reruns=2)
def test_ios_test_command_short_circuit(tmp_path, capfd):
skip_if_ios_testing_not_supported()
@@ -230,6 +237,7 @@ def test_no_xbuild_tool_definition(tmp_path, capfd):
project_dir,
add_env={
"CIBW_PLATFORM": "ios",
"CIBW_BUILD": "cp313-*",
"CIBW_TEST_SKIP": "*",
},
)
@@ -239,7 +247,7 @@ def test_no_xbuild_tool_definition(tmp_path, capfd):
"spam",
"0.1.0",
platform="ios",
python_abi_tags=["cp313-cp313", "cp314-cp314"],
python_abi_tags=["cp313-cp313"],
)
assert set(actual_wheels) == set(expected_wheels)
@@ -263,13 +271,14 @@ def test_empty_xbuild_tool_definition(tmp_path, capfd):
project_dir,
add_env={
"CIBW_PLATFORM": "ios",
"CIBW_BUILD": "cp313-*",
"CIBW_TEST_SKIP": "*",
"CIBW_XBUILD_TOOLS": "",
},
)
expected_wheels = utils.expected_wheels(
"spam", "0.1.0", platform="ios", python_abi_tags=["cp313-cp313", "cp314-cp314"]
"spam", "0.1.0", platform="ios", python_abi_tags=["cp313-cp313"]
)
assert set(actual_wheels) == set(expected_wheels)
@@ -299,6 +308,7 @@ def test_ios_test_command_without_python_dash_m(tmp_path, capfd):
project_dir,
add_env={
"CIBW_PLATFORM": "ios",
"CIBW_BUILD": "cp313-*",
"CIBW_TEST_COMMAND": "pytest ./tests",
"CIBW_TEST_SOURCES": "tests",
"CIBW_TEST_REQUIRES": "pytest",
@@ -307,11 +317,11 @@ def test_ios_test_command_without_python_dash_m(tmp_path, capfd):
)
expected_wheels = utils.expected_wheels(
"spam", "0.1.0", platform="ios", python_abi_tags=["cp313-cp313", "cp314-cp314"]
"spam", "0.1.0", platform="ios", python_abi_tags=["cp313-cp313"]
)
assert set(actual_wheels) == set(expected_wheels)
out, err = capfd.readouterr()
_, err = capfd.readouterr()
assert "iOS tests configured with a test command which doesn't start with 'python -m'" in err
@@ -335,5 +345,5 @@ def test_ios_test_command_invalid(tmp_path, capfd):
"CIBW_XBUILD_TOOLS": "",
},
)
out, err = capfd.readouterr()
_, err = capfd.readouterr()
assert "iOS tests configured with a test command which doesn't start with 'python -m'" in err
+2 -2
View File
@@ -84,7 +84,7 @@ def test(manylinux_image, tmp_path):
"CIBW_MANYLINUX_PYPY_I686_IMAGE": manylinux_image,
}
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"
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":
# 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]
assert set(actual_wheels) == set(expected_wheels)
+8 -1
View File
@@ -1,4 +1,5 @@
import contextlib
import os
import subprocess
import sys
import textwrap
@@ -9,6 +10,12 @@ from cibuildwheel.util.file import CIBW_CACHE_PATH
from . import test_projects, utils
pytestmark = pytest.mark.pyodide
CIBW_PLATFORM = os.environ.get("CIBW_PLATFORM", "pyodide")
if CIBW_PLATFORM != "pyodide":
pytest.skip(f"{CIBW_PLATFORM=}", allow_module_level=True)
basic_project = test_projects.new_c_project()
basic_project.files["check_node.py"] = r"""
import sys
@@ -97,7 +104,7 @@ def test_pyodide_version_incompatible(tmp_path, capfd):
},
)
out, err = capfd.readouterr()
_, err = capfd.readouterr()
assert "is not compatible with the pyodide-build version" in err
+3
View File
@@ -1,6 +1,8 @@
import socket
import textwrap
import pytest
from . import test_projects, utils
project_with_ssl_tests = test_projects.new_c_project(
@@ -19,6 +21,7 @@ project_with_ssl_tests = test_projects.new_c_project(
)
@pytest.mark.flaky(reruns=2)
def test(tmp_path):
# this test checks that SSL is working in the build environment using
# some checks in setup.py.
+4 -12
View File
@@ -81,9 +81,7 @@ def test(tmp_path):
# the 'false ||' bit is to ensure this command runs in a shell on
# mac/linux.
"CIBW_TEST_COMMAND": f"false || {utils.invoke_pytest()} {{project}}/test",
# pytest fails on GraalPy 24.2.0 on Windows so we skip it there
# until https://github.com/oracle/graalpython/issues/490 is fixed
"CIBW_TEST_COMMAND_WINDOWS": "COLOR 00 || where graalpy || pytest {project}/test",
"CIBW_TEST_COMMAND_WINDOWS": "COLOR 00 || pytest {project}/test",
},
)
@@ -104,9 +102,7 @@ def test_extras_require(tmp_path):
# the 'false ||' bit is to ensure this command runs in a shell on
# mac/linux.
"CIBW_TEST_COMMAND": f"false || {utils.invoke_pytest()} {{project}}/test",
# pytest fails on GraalPy 24.2.0 on Windows so we skip it there
# until https://github.com/oracle/graalpython/issues/490 is fixed
"CIBW_TEST_COMMAND_WINDOWS": "COLOR 00 || where graalpy || pytest {project}/test",
"CIBW_TEST_COMMAND_WINDOWS": "COLOR 00 || pytest {project}/test",
},
single_python=True,
)
@@ -138,9 +134,7 @@ def test_dependency_groups(tmp_path):
# the 'false ||' bit is to ensure this command runs in a shell on
# mac/linux.
"CIBW_TEST_COMMAND": f"false || {utils.invoke_pytest()} {{project}}/test",
# pytest fails on GraalPy 24.2.0 on Windows so we skip it there
# until https://github.com/oracle/graalpython/issues/490 is fixed
"CIBW_TEST_COMMAND_WINDOWS": "COLOR 00 || where graalpy || pytest {project}/test",
"CIBW_TEST_COMMAND_WINDOWS": "COLOR 00 || pytest {project}/test",
},
single_python=True,
)
@@ -230,9 +224,7 @@ def test_test_sources(tmp_path):
project_dir,
add_env={
"CIBW_TEST_REQUIRES": "pytest",
# pytest fails on GraalPy 24.2.0 on Windows so we skip it there
# until https://github.com/oracle/graalpython/issues/490 is fixed
"CIBW_TEST_COMMAND_WINDOWS": "where graalpy || pytest",
"CIBW_TEST_COMMAND_WINDOWS": "pytest",
"CIBW_TEST_COMMAND": utils.invoke_pytest(),
"CIBW_TEST_SOURCES": "test",
},
+24 -5
View File
@@ -51,7 +51,7 @@ def get_platform() -> str:
raise Exception(msg)
DEFAULT_CIBW_ENABLE = "cpython-freethreading cpython-prerelease cpython-experimental-riscv64"
DEFAULT_CIBW_ENABLE = "cpython-freethreading cpython-prerelease"
def get_enable_groups() -> frozenset[EnableGroup]:
@@ -261,9 +261,20 @@ def _expected_wheels(
musllinux_versions = ["musllinux_1_2"]
if platform == "pyodide" and python_abi_tags is None:
python_abi_tags = ["cp312-cp312", "cp313-cp313"]
elif platform in {"android", "ios"} and python_abi_tags is None:
python_abi_tags = ["cp313-cp313"]
python_abi_tags = [
"cp312-cp312",
"cp313-cp313",
]
elif platform == "android" and python_abi_tags is None: # noqa: SIM114
python_abi_tags = [
"cp313-cp313",
"cp314-cp314",
]
elif platform == "ios" and python_abi_tags is None:
python_abi_tags = [
"cp313-cp313",
"cp314-cp314",
]
elif python_abi_tags is None:
python_abi_tags = [
"cp38-cp38",
@@ -287,16 +298,17 @@ def _expected_wheels(
python_abi_tags += [
"pp38-pypy38_pp73",
"pp39-pypy39_pp73",
"pp310-pypy310_pp73",
]
if EnableGroup.PyPy in enable_groups:
python_abi_tags += [
"pp310-pypy310_pp73",
"pp311-pypy311_pp73",
]
if EnableGroup.GraalPy in enable_groups:
python_abi_tags += [
"graalpy311-graalpy242_311_native",
"graalpy312-graalpy250_312_native",
]
if machine_arch == "ARM64" and platform == "windows":
@@ -354,6 +366,13 @@ def _expected_wheels(
elif python_abi_tag.startswith("cp"):
if python_abi_tag.startswith(("cp38", "cp39", "cp310", "cp311")):
min_macosx = macosx_deployment_target
elif python_abi_tag.startswith(("cp312", "cp313")):
min_macosx = _floor_macosx(macosx_deployment_target, "10.13")
else:
min_macosx = _floor_macosx(macosx_deployment_target, "10.15")
elif python_abi_tag.startswith("graalpy"):
if python_abi_tag.startswith("graalpy311"):
min_macosx = macosx_deployment_target
else:
min_macosx = _floor_macosx(macosx_deployment_target, "10.13")
else:
+2 -12
View File
@@ -16,7 +16,6 @@ def test_build():
assert build_selector("cp312-manylinux_x86_64")
assert build_selector("cp313-manylinux_x86_64")
assert build_selector("cp314-manylinux_x86_64")
assert build_selector("pp310-manylinux_x86_64")
assert build_selector("pp311-manylinux_x86_64")
assert build_selector("cp36-manylinux_i686")
assert build_selector("cp37-manylinux_i686")
@@ -62,8 +61,8 @@ def test_build_filter_pypy():
skip_config="",
enable=frozenset([EnableGroup.PyPy]),
)
assert build_selector("pp310-manylinux_x86_64")
assert build_selector("pp311-manylinux_x86_64")
assert not build_selector("pp310-manylinux_x86_64")
assert not build_selector("pp38-manylinux_x86_64")
assert not build_selector("pp39-manylinux_x86_64")
@@ -74,8 +73,8 @@ def test_build_filter_pypy_eol():
skip_config="",
enable=frozenset([EnableGroup.PyPyEoL]),
)
assert not build_selector("pp310-manylinux_x86_64")
assert not build_selector("pp311-manylinux_x86_64")
assert build_selector("pp310-manylinux_x86_64")
assert build_selector("pp38-manylinux_x86_64")
assert build_selector("pp39-manylinux_x86_64")
@@ -217,15 +216,6 @@ def test_build_free_threaded_python():
assert build_selector("cp313t-manylinux_x86_64")
def test_build_riscv64_enable():
build_selector = BuildSelector(build_config="*", skip_config="")
assert not build_selector("cp313-manylinux_riscv64")
build_selector = BuildSelector(
build_config="*", skip_config="", enable=frozenset([EnableGroup.CPythonExperimentalRiscV64])
)
assert build_selector("cp313-manylinux_riscv64")
def test_testing_selector():
# This is not a global import to keep pytest from collecting it as a test
test_selector = cibuildwheel.selector.TestSelector(skip_config="cp36-*")
+5 -21
View File
@@ -27,12 +27,8 @@ def patched_environment(
def test_x86(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
arch = "32"
environment: dict[str, str] = {}
configuration = PythonConfiguration(
version="irrelevant", arch=arch, identifier="irrelevant", url=None
)
configuration = PythonConfiguration(version="irrelevant", identifier="cp314-win32", url=None)
setup_setuptools_cross_compile(tmp_path, configuration, tmp_path, environment)
with patched_environment(monkeypatch, environment):
@@ -43,11 +39,9 @@ def test_x86(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
def test_x64(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
arch = "64"
environment: dict[str, str] = {}
configuration = PythonConfiguration(
version="irrelevant", arch=arch, identifier="irrelevant", url=None
version="irrelevant", identifier="cp313-win_amd64", url=None
)
setup_setuptools_cross_compile(tmp_path, configuration, tmp_path, environment)
@@ -62,11 +56,9 @@ def test_x64(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
detect_ci_provider() == CIProvider.azure_pipelines, reason="arm64 not recognised on azure"
)
def test_arm(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
arch = "ARM64"
environment: dict[str, str] = {}
configuration = PythonConfiguration(
version="irrelevant", arch=arch, identifier="irrelevant", url=None
version="irrelevant", identifier="cp312-win_arm64", url=None
)
setup_setuptools_cross_compile(tmp_path, configuration, tmp_path, environment)
@@ -78,24 +70,16 @@ def test_arm(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
def test_env_set(tmp_path: Path) -> None:
arch = "32"
environment = {"VSCMD_ARG_TGT_ARCH": "x64"}
configuration = PythonConfiguration(
version="irrelevant", arch=arch, identifier="irrelevant", url=None
)
configuration = PythonConfiguration(version="irrelevant", identifier="cp313t-win32", url=None)
with pytest.raises(FatalError, match="VSCMD_ARG_TGT_ARCH"):
setup_setuptools_cross_compile(tmp_path, configuration, tmp_path, environment)
def test_env_blank(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
arch = "32"
environment = {"VSCMD_ARG_TGT_ARCH": ""}
configuration = PythonConfiguration(
version="irrelevant", arch=arch, identifier="irrelevant", url=None
)
configuration = PythonConfiguration(version="irrelevant", identifier="cp312-win32", url=None)
setup_setuptools_cross_compile(tmp_path, configuration, tmp_path, environment)
with patched_environment(monkeypatch, environment):

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