Compare commits

..
78 Commits
Author SHA1 Message Date
Joe Rickerby d04cacbc98 Bump version: v2.23.2 2025-03-24 21:25:38 +00:00
Matthieu Darbois 5f4e019684 [2.x] Update dependencies (#2334) 2025-03-24 21:17:56 +00:00
Henry Schreiner 2efa648f38 fix: always resolve --python argument (#2328) (#2331)
fix: always resolve --python argument (#2328)

fix: always resolve the --python argument

Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>
2025-03-23 15:03:30 -04:00
Joe Rickerby 42728e866b Bump version: v2.23.1 2025-03-15 17:58:14 +00:00
Joe Rickerby 6e1527b153 Fix unit test when other warnings are present 2025-03-15 17:54:37 +00:00
Matthieu Darbois c25fe60385 fix: image deprecation warning (#2314) 2025-03-15 17:54:37 +00:00
Henry SchreinerandJoe Rickerby a880bf5105 fix: warn on deprecated images being set (#2312)
* fix: warn on deprecated images being set

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

* fix: handle repeated warning messages

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

* Apply suggestions from code review

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

* fix: try making the warnings once per Options

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

---------

Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>
Co-authored-by: Joe Rickerby <joerick@mac.com>
2025-03-15 17:54:37 +00:00
Joe Rickerby c087d85b69 Update dependencies 2025-03-15 17:54:37 +00:00
Joe Rickerby 6cccd09a31 Bump version: v2.23.0 2025-03-01 13:27:50 +00:00
Matthieu Darbois aa1534d2a3 chore(2.x): update dependencies (#2294) 2025-03-01 11:49:19 +00:00
mayeut ee23dd147b fix(test): implement retry for test_container_removed
The test is flaky on some platforms. Implement retry rather than just skip.
2025-02-25 14:22:19 -05:00
Matthieu Darbois 55037e9716 ci/doc: move azure macOS build to macOS-13 (#2101)
The macOS-12 environment is deprecated.
2025-02-25 14:22:19 -05:00
Joe Rickerby 8874ee2048 Remove specific Python versions from the update-dependencies job
The requirements pinning is done by uv now, so we don't need to
run the versions of Python to do the pinning anymore.

Cherry-picked from 37f7f611b208f48d4bb80a35eb31e39e47102930
2025-02-25 14:22:19 -05:00
mayeut f76d345e81 chore: bump dependencies 2025-02-25 14:22:19 -05:00
Agriya Khetarpal 5a5e514fbd Bump to Pyodide 0.27 (#2117)
* Bump to Pyodide 0.27

* Update the Pyodide target's constraints
2025-02-25 14:22:19 -05:00
Matthieu Darbois 017abbba68 feature: add PyPy 3.11 (#2268) 2025-02-25 14:22:19 -05:00
Matthieu Darbois bb1fd3320e feat: Add support for ubuntu-24.04-arm GHA runner (#2135)
* ci(gha): add tests on ubuntu-24.04-arm

* address review comments
2025-02-25 14:22:19 -05:00
Matthieu Darbois 98a6f3bf64 chore: use pypa/manylinux for manylinux_2_31_armv7l (#2269) 2025-02-25 14:22:19 -05:00
Henry Schreiner ee63bf16da Bump version: v2.22.0 2024-11-23 01:44:09 -05:00
Alex Waygood d3eeba7967 chore: bump Ruff to 0.8.0 (#2092) 2024-11-22 16:18:12 -05:00
Agriya KhetarpalandHenry Schreiner 109020ed2d Updates for Pyodide builds after pyodide-build was unvendored (#2090)
* Fix typos and capitalise

* Add docstring for `install_xbuildenv` function

* Include Emscripten, Pyodide version in logger messages

* Mark separation of pyodide-build and Pyodide

* Bump to Pyodide 0.26.4 (py3.12.7) + pyodide-build 0.29.0

* Use pyodide-build version as the source of truth

* Update Pyodide constraints

* Use 3.12 as the Python version instead of 3.12.7

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

* chore: appease the formatter

---------

Co-authored-by: Henry Schreiner <HenrySchreinerIII@gmail.com>
2024-11-22 16:17:51 -05:00
pre-commit-ci[bot]andpre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> fd990007be [pre-commit.ci] pre-commit autoupdate (#2087)
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.7.3 → v0.7.4](https://github.com/astral-sh/ruff-pre-commit/compare/v0.7.3...v0.7.4)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2024-11-20 01:18:10 -05:00
Henry SchreinerandMatthieu Darbois e158f22d51 ci: update gitlab for dependency-groups (#2089)
* ci: update gitlab for dependency-groups

* Update .gitlab-ci.yml

* Apply suggestions from code review

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

---------

Co-authored-by: Matthieu Darbois <mayeut@users.noreply.github.com>
2024-11-20 01:17:54 -05:00
8f21eb17be chore: use dependency-groups (#2064)
* chore: use dependency-groups

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

* ci: use dep groups in other CIs

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

* Apply suggestions from code review

* chore: read dep groups in noxfile

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

* Apply suggestions from code review

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

* Add dev environment instructions

---------

Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>
Co-authored-by: Matthieu Darbois <mayeut@users.noreply.github.com>
Co-authored-by: Joe Rickerby <joerick@mac.com>
2024-11-19 19:30:06 +01:00
aac31ae2fb docs: fix update scripts usage (#2067)
* Update contributing.md

* Update options.md

* Update options.md

* Update docs/contributing.md

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

* Update contributing.md

* Apply suggestions from code review

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

---------

Co-authored-by: Henry Schreiner <HenrySchreinerIII@gmail.com>
Co-authored-by: Matthieu Darbois <mayeut@users.noreply.github.com>
2024-11-18 03:27:05 -05:00
Matthieu Darbois b882b84e47 fix: update the macOS image used on Cirrus CI (#2085)
Use `ghcr.io/cirruslabs/macos-runner:sonoma` instead of `ghcr.io/cirruslabs/macos-sonoma-xcode` which is not supported anymore.
2024-11-18 03:26:39 -05:00
cibuildwheel-bot[bot]andcibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com> 243085f047 [Bot] Update dependencies (#2086)
Update dependencies

Co-authored-by: cibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com>
2024-11-18 03:26:20 -05:00
Matthieu Darbois df6f886390 feat: add manylinux armv7l (#2052) 2024-11-15 19:07:24 -05:00
Matthieu Darbois 6f21f84a71 fix: capture stderr in utils.call when capture_stdout is True (#2076) 2024-11-14 11:40:59 -05:00
Henry Schreinerandmayeut 393e0352e8 feat: adding enable (#2048)
* feat: adding enable

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

* refactor: use recommended term

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

* fix: use `cached_property` for `Options` properties

* fix: warn on PyPy default

---------

Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>
Co-authored-by: mayeut <mayeut@users.noreply.github.com>
2024-11-14 11:39:52 -05:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> 9459533408 chore(deps): bump actions/attest-build-provenance from 1.4.3 to 1.4.4 in the actions group (#2078)
chore(deps): bump actions/attest-build-provenance in the actions group

Bumps the actions group with 1 update: [actions/attest-build-provenance](https://github.com/actions/attest-build-provenance).


Updates `actions/attest-build-provenance` from 1.4.3 to 1.4.4
- [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/1c608d11d69870c2092266b3f9a6f3abbf17002c...ef244123eb79f2f7a7e75d99086184180e6d0018)

---
updated-dependencies:
- dependency-name: actions/attest-build-provenance
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: actions
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-12 08:43:41 +01:00
pre-commit-ci[bot]andpre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> d9f987df66 [pre-commit.ci] pre-commit autoupdate (#2079)
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.7.2 → v0.7.3](https://github.com/astral-sh/ruff-pre-commit/compare/v0.7.2...v0.7.3)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2024-11-12 08:43:18 +01:00
cibuildwheel-bot[bot]andcibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com> f97c1fb99b [Bot] Update dependencies (#2077)
Update dependencies

Co-authored-by: cibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com>
2024-11-11 09:15:02 +01:00
Matthieu Darbois 5cdddb2d46 fix: error message when manylinux-interpreters ensure ... failed (#2066)
* review: address review comments from #1630

* fix: error message when `manylinux-interpreters ensure ...` failed

* fix: error message when `manylinux-interpreters ensure ...` failed (option b)
2024-11-09 11:06:13 +01:00
pre-commit-ci[bot]andpre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> e18a6e9eb0 [pre-commit.ci] pre-commit autoupdate (#2073)
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.7.1 → v0.7.2](https://github.com/astral-sh/ruff-pre-commit/compare/v0.7.1...v0.7.2)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2024-11-05 01:58:32 -05:00
Aarni Koskela c42b1cecf1 tests: fix CIBW_CONFIG_SETTIGNS typo in test (#2071)
fix: Fix CIBW_CONFIG_SETTIGNS typo in test

Caught with https://github.com/crate-ci/typos
2024-11-05 01:57:51 -05:00
Grzegorz Bokota c940bed415 docs: fix travis link in readme (#2072)
fix travis link in readme
2024-11-05 01:57:17 -05:00
cibuildwheel-bot[bot]andcibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com> 530f52dc9c [Bot] Update dependencies (#2059)
Update dependencies

Co-authored-by: cibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com>
2024-11-05 07:41:08 +01:00
Henry SchreinerandMatthieu Darbois cc1d977359 feat: support test-groups (#2063)
* feat: support test-groups

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

* refactor: address review comments

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

* tests: add a integration test

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

* Apply suggestions from code review

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

* fix: better error messages based on feedback

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

---------

Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>
Co-authored-by: Matthieu Darbois <mayeut@users.noreply.github.com>
2024-11-04 21:25:01 +01:00
omahs d2c7614c3a docs: fix typos (#2061)
* docs: fix typo

* docs: fix typos

* docs: fix typos
2024-11-01 11:39:32 +00:00
Joe Rickerby 66d45de432 repair-wheel-command docs and error message improvements (#2058)
* Fix bug in docs for running abi3audit in repair-wheel-command on windows

* Better error message for misconfigured repair-wheel-command
2024-10-28 23:22:03 -04:00
pre-commit-ci[bot]pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>Henry Schreiner
eaa861622a [pre-commit.ci] pre-commit autoupdate (#2060)
* [pre-commit.ci] pre-commit autoupdate

updates:
- [github.com/astral-sh/ruff-pre-commit: v0.7.0 → v0.7.1](https://github.com/astral-sh/ruff-pre-commit/compare/v0.7.0...v0.7.1)
- [github.com/pre-commit/mirrors-mypy: v1.12.1 → v1.13.0](https://github.com/pre-commit/mirrors-mypy/compare/v1.12.1...v1.13.0)

* 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>
2024-10-28 23:17:29 -04:00
Matthieu DarboisandHenry Schreiner 7c3b0fbee8 chore: add warning when running cibuildwheel with python<3.11 (#2050)
* chore: add warning when running cibuildwheel with python<3.11

* fix: use `log.warning` to print warnings in `print_preamble`

* Better warning & doc update

* address review comments

* Update README.md

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

---------

Co-authored-by: Henry Schreiner <HenrySchreinerIII@gmail.com>
2024-10-25 22:07:29 +02:00
Henry Schreiner b98602705f chore: stricter mypy (#2053)
* chore: improve mypy

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

* chore(types): type functions in tests

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

* chore(types): No partial types in tests

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

---------

Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>
2024-10-22 10:16:59 -04:00
pre-commit-ci[bot]pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>Henry Schreiner
b4d1e17765 [pre-commit.ci] pre-commit autoupdate (#2054)
* [pre-commit.ci] pre-commit autoupdate

updates:
- [github.com/astral-sh/ruff-pre-commit: v0.6.9 → v0.7.0](https://github.com/astral-sh/ruff-pre-commit/compare/v0.6.9...v0.7.0)
- [github.com/pre-commit/mirrors-mypy: v1.11.2 → v1.12.1](https://github.com/pre-commit/mirrors-mypy/compare/v1.11.2...v1.12.1)

* chore: mypy bug fixed

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

---------

Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Henry Schreiner <henryschreineriii@gmail.com>
2024-10-22 00:45:06 -04:00
cibuildwheel-bot[bot]andcibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com> 4e93d9153e [Bot] Update dependencies (#2051)
Update dependencies

Co-authored-by: cibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com>
2024-10-21 10:38:46 -04:00
Matthieu Darbois 1001c837de fix: re-raise subprocess.CalledProcessError when uname -m fails on arm (#2049) 2024-10-19 23:02:40 -04:00
Henry Schreiner 18f54c08e2 docs: print a couple slighly more detailed error messages (#2044)
Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>
2024-10-18 08:52:05 -04:00
Matthieu Darbois 5b7119ecef linux: use Python 3.9 in before_all (#2043)
Also use Python 3.9 for utility python in oci_container.
2024-10-17 01:25:09 -04:00
cibuildwheel-bot[bot]andcibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com> ddbd67cbde [Bot] Update dependencies (#2040)
Update dependencies

Co-authored-by: cibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com>
2024-10-15 13:09:49 +02:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> 84ac771415 chore(deps): bump wntrblm/nox from 2024.04.15 to 2024.10.09 in the actions group (#2041)
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 2024.04.15 to 2024.10.09
- [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/2024.04.15...2024.10.09)

---
updated-dependencies:
- dependency-name: wntrblm/nox
  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>
2024-10-15 13:09:03 +02:00
pre-commit-ci[bot]andpre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> e792bb9705 [pre-commit.ci] pre-commit autoupdate (#2042)
updates:
- [github.com/python-jsonschema/check-jsonschema: 0.29.3 → 0.29.4](https://github.com/python-jsonschema/check-jsonschema/compare/0.29.3...0.29.4)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2024-10-15 13:08:49 +02:00
Joe Rickerby 7940a4c0e7 Bump version: v2.21.3 2024-10-09 09:04:53 +01:00
Henry Schreiner 3d3159b37b docs: update for 3.13.0 final (#2035)
Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>
2024-10-08 10:26:58 -04:00
cibuildwheel-bot[bot]andcibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com> 0319c431de [Bot] Update dependencies (#2032)
Update dependencies

Co-authored-by: cibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com>
2024-10-08 01:47:21 -04:00
Matthieu Darbois 80ae9a50c9 fix: do not subclass wheel.bdist_wheel command in ABI3 test (#2030)
fix: do not subclass bdist_wheel command in ABI3 test

With bdist_wheel becoming a first-class citizen command of setuptools, this trick might not work in the future.
2024-10-07 18:26:20 -04:00
pre-commit-ci[bot]andpre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> 006f1e6ec6 [pre-commit.ci] pre-commit autoupdate (#2033)
updates:
- [github.com/pre-commit/pre-commit-hooks: v4.6.0 → v5.0.0](https://github.com/pre-commit/pre-commit-hooks/compare/v4.6.0...v5.0.0)
- [github.com/astral-sh/ruff-pre-commit: v0.6.8 → v0.6.9](https://github.com/astral-sh/ruff-pre-commit/compare/v0.6.8...v0.6.9)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2024-10-07 18:25:09 -04:00
Joe Rickerby f185952832 Bump version: v2.21.2 2024-10-02 22:51:53 +01:00
Henry Schreinerandmayeut d5c6a83aeb ci: update job slightly (#2028)
* ci: update job slightly

* Ignore check-wheel-content W002

---------

Co-authored-by: mayeut <mayeut@users.noreply.github.com>
2024-10-02 14:52:36 -04:00
cibuildwheel-bot[bot]andcibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com> 2e8e511106 [Bot] Update dependencies (#2029)
Update dependencies

Co-authored-by: cibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com>
2024-10-02 15:59:31 +02:00
Joe RickerbyHenry SchreinerMatthieu Darboispre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
ec591cdf47 Add note about the planned change of the manylinux default (#1992)
* Add note about the planned change of the manylinux default

* Update docs/options.md

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

* Change date to 6th May

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

* no manylinux_2_28 pypy_i686 image

* no manylinux_2_28 i686 image

* [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: Matthieu Darbois <mayeut@users.noreply.github.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2024-10-02 14:29:22 +02:00
Henry Schreiner ee7fa96f6d chore: remove a couple of things pylint is unhappy about (#2027)
Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>
2024-10-02 00:22:40 -04:00
Henry Schreiner d625d18b91 ci: add 3.13 classifier (#2026)
Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>
2024-10-02 00:22:31 -04:00
cibuildwheel-bot[bot]andcibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com> 895eae340a [Bot] Update dependencies (#2025)
Update dependencies

Co-authored-by: cibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com>
2024-10-02 00:22:22 -04:00
Matthieu DarboisandHenry Schreiner 9fad66fcfb feat: add musllinux armv7l (#2017)
* feature: add musllinux armv7l

* fix: local armv7l images

* fix python 3.8 tests

* address review comments

---------

Co-authored-by: Henry Schreiner <HenrySchreinerIII@gmail.com>
2024-10-01 10:33:57 -04:00
zachlewispre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>mayeut
dfd01af9aa fix: more reliably validate Podman API version (#2016)
* fix: parse version strings that include dashes

It's possible for some container engines to report their versions with a dash (e.g., "4.9.4-rhel"), which breaks packaging.version.Version's ability to parse the string. This commit introduces a version_from_string method which santizies the version string and returns an instance of Version.

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

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

* cleanup: pacify ruff

* cleanup: further pacify ruff

* fix: properly define _version_from_string method

Also, lift the method up and prefix with a "_" to better match the existing conventions

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

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

* refactor: more robust podman ver check

Use the "podman --version" command instead of "podman version -f {{json .}}" for better reliability across distributions.

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

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

* fix: oci engine version check

Lower Docker API check to 1.41
Podman versions are not PEP440 compliant, remove distro specific suffixes before parsing.
Add tests with real-world outputs and some made up ones.

* fix: UX on OCIEngineTooOldError

* Add FlexibleVersion

per review comment

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: mayeut <mayeut@users.noreply.github.com>
2024-10-01 01:10:58 -04:00
cibuildwheel-bot[bot]andcibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com> 735e88deba [Bot] Update dependencies (#2022)
Update dependencies

Co-authored-by: cibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com>
2024-10-01 01:09:19 -04:00
pre-commit-ci[bot]andpre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> bb2f6652b7 [pre-commit.ci] pre-commit autoupdate (#2023)
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.6.7 → v0.6.8](https://github.com/astral-sh/ruff-pre-commit/compare/v0.6.7...v0.6.8)
- [github.com/python-jsonschema/check-jsonschema: 0.29.2 → 0.29.3](https://github.com/python-jsonschema/check-jsonschema/compare/0.29.2...0.29.3)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2024-10-01 01:08:09 -04:00
pre-commit-ci[bot]andpre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> 6dcd7dd34b [pre-commit.ci] pre-commit autoupdate (#2019)
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.6.5 → v0.6.7](https://github.com/astral-sh/ruff-pre-commit/compare/v0.6.5...v0.6.7)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2024-09-24 08:37:07 +02:00
cibuildwheel-bot[bot]andcibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com> 1327af5077 [Bot] Update dependencies (#2018)
Update dependencies

Co-authored-by: cibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com>
2024-09-23 13:19:50 +02:00
cibuildwheel-bot[bot]andcibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com> 311f64987b [Bot] Update dependencies (#2014)
Update dependencies

Co-authored-by: cibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com>
2024-09-17 12:12:53 -04:00
Henry Schreiner 08e5b97e57 ci: modernize update workflow (#2010) 2024-09-17 07:54:17 +02:00
Henry Schreiner d4a2945fcc Bump version: v2.21.1 2024-09-16 21:04:46 -04:00
pre-commit-ci[bot] 9913c03128 [pre-commit.ci] pre-commit autoupdate (#2013) 2024-09-16 20:32:04 -04:00
cibuildwheel-bot[bot] c0e28d3401 fix: support uv 0.4.10+ on Linux and update dependencies (#2008) 2024-09-16 20:31:48 -04:00
Matthieu Darbois 8c42e7980c fix: file ownership of files copied into the container (#2007)
Revert to using `cat`/`tar` to copy files/folders into the container.
2024-09-16 23:12:19 +01:00
Henry Schreiner 01ecd4e011 docs: bump pinned versions (#2011)
Trying to fix ci; might need to add `pathspec` if this isn't enough.
2024-09-16 14:01:04 -04:00
Matthieu Darbois 33da1f7d14 fix: do not use uv to setup python on windows when conditions are not met (#2005)
* fix: do not use `uv` to setup python on windows when conditions are not met

* add `can_use_uv` on macOS
2024-09-16 12:03:19 -04:00
100 changed files with 1738 additions and 878 deletions
+2 -2
View File
@@ -10,7 +10,7 @@ fi
$PYTHON --version
$PYTHON -m venv venv
venv/bin/python -m pip install -U pip
venv/bin/python -m pip install -e ".[dev]"
venv/bin/python -m pip install -U pip dependency-groups
venv/bin/python -m dependency_groups test | xargs venv/bin/python -m pip install -e.
venv/bin/python -m pip freeze
venv/bin/python --version
+4 -3
View File
@@ -2,7 +2,8 @@ only_if: changesInclude('.cirrus.yml') || ($CIRRUS_BRANCH == "main" && !changesI
run_tests: &RUN_TESTS
install_cibuildwheel_script:
- python -m pip install -e ".[dev]" pytest-custom-exit-code
- python -m pip install dependency-groups
- python -m dependency_groups test | xargs python -m pip install -e.
run_cibuildwheel_tests_script:
- python ./bin/run_tests.py
@@ -52,7 +53,7 @@ windows_x86_task:
macos_arm64_task:
macos_instance:
image: ghcr.io/cirruslabs/macos-sonoma-xcode
image: ghcr.io/cirruslabs/macos-runner:sonoma
env:
PATH: /opt/homebrew/opt/python@3.10/libexec/bin:$PATH
@@ -62,7 +63,7 @@ macos_arm64_task:
macos_arm64_cp38_task:
macos_instance:
image: ghcr.io/cirruslabs/macos-sonoma-xcode
image: ghcr.io/cirruslabs/macos-runner:sonoma
env:
PATH: /opt/homebrew/opt/python@3.10/libexec/bin:$PATH
+5 -13
View File
@@ -13,16 +13,7 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Build SDist and wheel
run: pipx run build
- uses: actions/upload-artifact@v4
with:
name: cibw-sdist
path: dist/*
- name: Check metadata
run: pipx run twine check dist/*
- uses: hynek/build-and-inspect-python-package@v2
publish:
needs: [dist]
@@ -38,13 +29,14 @@ jobs:
steps:
- uses: actions/download-artifact@v4
with:
pattern: cibw-*
name: Packages
path: dist
merge-multiple: true
- name: Generate artifact attestation for sdist and wheel
uses: actions/attest-build-provenance@1c608d11d69870c2092266b3f9a6f3abbf17002c # v1.4.3
uses: actions/attest-build-provenance@ef244123eb79f2f7a7e75d99086184180e6d0018 # v1.4.4
with:
subject-path: "dist/cibuildwheel-*"
- uses: pypa/gh-action-pypi-publish@release/v1
with:
attestations: true
+21 -17
View File
@@ -4,6 +4,7 @@ on:
push:
branches:
- main
- 2.x
pull_request:
paths-ignore:
- 'docs/**'
@@ -37,8 +38,8 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-13, macos-14]
python_version: ['3.12']
os: [ubuntu-latest, ubuntu-24.04-arm, windows-latest, macos-13, macos-14]
python_version: ['3.13']
include:
- os: ubuntu-latest
python_version: '3.8'
@@ -49,8 +50,9 @@ jobs:
name: Install Python ${{ matrix.python_version }}
with:
python-version: ${{ matrix.python_version }}
allow-prereleases: true
- uses: yezz123/setup-uv@v4
- uses: astral-sh/setup-uv@v3
# free some space to prevent reaching GHA disk space limits
- name: Clean docker images
@@ -66,11 +68,11 @@ jobs:
- name: Install dependencies
run: |
uv pip install --system ".[test]"
uv sync --no-dev --group test
- name: Generate a sample project
run: |
python -m test.test_projects test.test_0_basic.basic_project sample_proj
uv run -m test.test_projects test.test_0_basic.basic_project sample_proj
- name: Run a sample build (GitHub Action)
uses: ./
@@ -88,7 +90,7 @@ jobs:
with:
package-dir: sample_proj
output-dir: wheelhouse_only
only: cp312-${{ runner.os == 'Linux' && 'manylinux_x86_64' || (runner.os == 'Windows' && 'win_amd64' || 'macosx_x86_64') }}
only: cp312-${{ 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
@@ -109,7 +111,7 @@ jobs:
output-dir: wheelhouse_config_file
config-file: sample_proj/cibw.toml
- name: Check Action artefacts
- name: Check Action artifacts
shell: bash
run: |
test $(find wheelhouse -name '*.whl' | wc -l) -ge 1
@@ -123,7 +125,7 @@ jobs:
- name: Test cibuildwheel
run: |
python ./bin/run_tests.py --run-podman
uv run bin/run_tests.py ${{ (runner.os == 'Linux' && runner.arch == 'X64') && '--run-podman' || '' }}
emulated-archs:
name: Get qemu emulated architectures
@@ -136,12 +138,13 @@ jobs:
- uses: actions/setup-python@v5
with:
python-version: "3.x"
- uses: astral-sh/setup-uv@v3
- name: Install dependencies
run: python -m pip install ".[test]"
run: uv sync --no-dev --group test
- name: Get qemu emulated architectures
id: archs
run: |
OUTPUT=$(python -c "from json import dumps; from test.utils import EMULATED_ARCHS; print(dumps(EMULATED_ARCHS))")
OUTPUT=$(uv run python -c "from json import dumps; from test.utils import EMULATED_ARCHS; print(dumps(EMULATED_ARCHS))")
echo "${OUTPUT}"
echo "archs=${OUTPUT}" >> "$GITHUB_OUTPUT"
@@ -158,17 +161,18 @@ jobs:
- uses: actions/setup-python@v5
with:
python-version: "3.x"
- uses: astral-sh/setup-uv@v3
- name: Install dependencies
run: python -m pip install ".[test,uv]"
run: uv sync --no-dev --group test
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Run the emulation tests
run: pytest --run-emulation ${{ matrix.arch }} test/test_emulation.py
run: uv run pytest --run-emulation ${{ matrix.arch }} test/test_emulation.py
test-pyodide:
name: Test cibuildwheel building pyodide wheels
name: Test cibuildwheel building Pyodide wheels
needs: lint
runs-on: ubuntu-24.04
timeout-minutes: 180
@@ -178,14 +182,14 @@ jobs:
name: Install Python 3.12
with:
python-version: '3.12'
- uses: astral-sh/setup-uv@v3
- name: Install dependencies
run: |
python -m pip install ".[test]"
run: uv sync --no-dev --group test
- name: Generate a sample project
run: |
python -m test.test_projects test.test_0_basic.basic_project sample_proj
uv run -m test.test_projects test.test_0_basic.basic_project sample_proj
- name: Run a sample build (GitHub Action)
uses: ./
@@ -197,6 +201,6 @@ jobs:
- name: Run tests with 'CIBW_PLATFORM' set to 'pyodide'
run: |
python ./bin/run_tests.py
uv run ./bin/run_tests.py
env:
CIBW_PLATFORM: pyodide
+12 -14
View File
@@ -20,11 +20,19 @@ jobs:
if: github.repository_owner == 'pypa' || github.event_name != 'schedule'
runs-on: ubuntu-latest
steps:
# we use this step to grab a Github App auth token, so that PRs generated by this workflow
# run the GHA tests.
- uses: actions/create-github-app-token@v1
id: generate-token
if: github.ref == 'refs/heads/main' && github.repository == 'pypa/cibuildwheel'
with:
app_id: ${{ secrets.CIBUILDWHEEL_BOT_APP_ID }}
private_key: ${{ secrets.CIBUILDWHEEL_BOT_APP_PRIVATE_KEY }}
- uses: actions/checkout@v4
- uses: wntrblm/nox@2024.04.15
with:
python-versions: "3.7, 3.8, 3.9, 3.10, 3.11, 3.12, 3.13"
- uses: wntrblm/nox@2024.10.09
- name: "Run update: dependencies"
run: nox --force-color -s update_constraints
@@ -33,15 +41,6 @@ jobs:
- name: "Run update: docs user projects"
run: nox --force-color -s update_proj -- --auth=${{ secrets.GITHUB_TOKEN }}
# we use this step to grab a Github App auth token, so that PRs generated by this workflow
# run the GHA tests.
- uses: tibdex/github-app-token@v2
id: generate-token
if: github.ref == 'refs/heads/main' && github.repository == 'pypa/cibuildwheel'
with:
app_id: ${{ secrets.CIBUILDWHEEL_BOT_APP_ID }}
private_key: ${{ secrets.CIBUILDWHEEL_BOT_APP_PRIVATE_KEY }}
- name: Create Pull Request
if: github.ref == 'refs/heads/main' && github.repository == 'pypa/cibuildwheel'
uses: peter-evans/create-pull-request@v7
@@ -53,7 +52,6 @@ jobs:
PR generated by "Update dependencies" [workflow](https://github.com/${{github.repository}}/actions/runs/${{github.run_id}}).
branch: update-dependencies-pr
committer: "cibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com>"
author: "cibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com>"
sign-commits: true
token: ${{ steps.generate-token.outputs.token }}
delete-branch: true
+6 -3
View File
@@ -16,7 +16,8 @@ linux:
script:
- curl -sSL https://get.docker.com/ | sh
- docker run --rm --privileged docker.io/tonistiigi/binfmt:latest --install all
- python -m pip install -e ".[dev]" pytest-custom-exit-code
- python -m pip install dependency-groups
- python -m dependency_groups test | xargs python -m pip install -e. pytest-custom-exit-code
- python ./bin/run_tests.py
windows:
@@ -26,7 +27,8 @@ windows:
before_script:
- choco install python -y --version 3.12.4
script:
- py -m pip install -e ".[dev]" pytest-custom-exit-code
- py -m pip install dependency-groups
- py -m pip install -e. pytest-custom-exit-code $(py -m dependency_groups test)
- py bin\run_tests.py
tags:
- saas-windows-medium-amd64
@@ -36,7 +38,8 @@ macos:
variables:
PYTEST_ADDOPTS: -k "unit_test or test_0_basic" --suppress-no-test-exit-code
script:
- python3 -m pip install -e ".[dev]" pytest-custom-exit-code
- python3 -m pip install dependency-groups
- python3 -m dependency_groups test | xargs python3 -m pip install -e. pytest-custom-exit-code
- python3 ./bin/run_tests.py
tags:
- saas-macos-medium-m1
+8 -4
View File
@@ -1,7 +1,7 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.6.0
rev: v5.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.6.4
rev: v0.8.0
hooks:
- id: ruff
args: ["--fix", "--show-fixes"]
- id: ruff-format
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.11.2
rev: v1.13.0
hooks:
- id: mypy
name: mypy 3.8 on cibuildwheel/
@@ -29,9 +29,12 @@ repos:
args: ["--python-version=3.8"]
additional_dependencies: &mypy-dependencies
- bracex
- dependency-groups>=1.2
- nox
- orjson
- packaging
- pygithub
- pytest
- rich
- tomli
- tomli_w
@@ -40,6 +43,7 @@ repos:
- types-jinja2
- types-pyyaml
- types-requests
- types-setuptools
- uv
- validate-pyproject
- id: mypy
@@ -77,7 +81,7 @@ repos:
- repo: https://github.com/python-jsonschema/check-jsonschema
rev: 0.29.2
rev: 0.29.4
hooks:
- id: check-dependabot
- id: check-github-actions
+1 -3
View File
@@ -10,6 +10,4 @@ build:
- asdf plugin add uv
- asdf install uv latest
- asdf global uv latest
- uv venv
- uv pip install -e.[docs]
- NO_COLOR=1 .venv/bin/mkdocs build --strict --site-dir $READTHEDOCS_OUTPUT/html
- NO_COLOR=1 uv run --no-dev --group docs mkdocs build --strict --site-dir $READTHEDOCS_OUTPUT/html
+2 -2
View File
@@ -57,8 +57,8 @@ jobs:
install:
- if [ "${TRAVIS_OS_NAME}" == "linux" ]; then docker run --rm --privileged docker.io/tonistiigi/binfmt:latest --install all; fi
- $PYTHON -m pip install -U pip
- $PYTHON -m pip install -e ".[test]" pytest-custom-exit-code
- $PYTHON -m pip install -U pip dependency-groups
- $PYTHON -m dependency_groups test | xargs $PYTHON -m pip install -e.
script: |
# travis_wait disable the output while waiting
+66 -80
View File
@@ -4,7 +4,7 @@ cibuildwheel
[![PyPI](https://img.shields.io/pypi/v/cibuildwheel.svg)](https://pypi.python.org/pypi/cibuildwheel)
[![Documentation Status](https://readthedocs.org/projects/cibuildwheel/badge/?version=stable)](https://cibuildwheel.pypa.io/en/stable/?badge=stable)
[![Actions Status](https://github.com/pypa/cibuildwheel/workflows/Test/badge.svg)](https://github.com/pypa/cibuildwheel/actions)
[![Travis Status](https://img.shields.io/travis/com/pypa/cibuildwheel/main?logo=travis)](https://travis-ci.com/pypa/cibuildwheel)
[![Travis Status](https://img.shields.io/travis/com/pypa/cibuildwheel/main?logo=travis)](https://travis-ci.com/github/pypa/cibuildwheel)
[![Appveyor status](https://ci.appveyor.com/api/projects/status/gt3vwl88yt0y3hur/branch/main?svg=true)](https://ci.appveyor.com/project/joerick/cibuildwheel/branch/main)
[![CircleCI Status](https://img.shields.io/circleci/build/gh/pypa/cibuildwheel/main?logo=circleci)](https://circleci.com/gh/pypa/cibuildwheel)
[![Azure Status](https://dev.azure.com/joerick0429/cibuildwheel/_apis/build/status/pypa.cibuildwheel?branchName=main)](https://dev.azure.com/joerick0429/cibuildwheel/_build/latest?definitionId=4&branchName=main)
@@ -22,27 +22,31 @@ Python wheels are great. Building them across **Mac, Linux, Windows**, on **mult
What does it do?
----------------
| | macOS Intel | macOS Apple Silicon | Windows 64bit | Windows 32bit | Windows Arm64 | manylinux<br/>musllinux x86_64 | manylinux<br/>musllinux i686 | manylinux<br/>musllinux aarch64 | manylinux<br/>musllinux ppc64le | manylinux<br/>musllinux s390x | Pyodide |
|----------------|----|-----|-----|-----|-----|----|-----|----|-----|-----|-----|
| CPython 3.6 | ✅ | N/A | ✅ | ✅ | N/A | ✅ | ✅ | ✅ | ✅ | ✅ | N/A |
| CPython 3.7 | ✅ | N/A | ✅ | ✅ | N/A | ✅ | ✅ | ✅ | ✅ | ✅ | N/A |
| CPython 3.8 | ✅ | | ✅ | ✅ | N/A | ✅ | ✅ | ✅ | ✅ | ✅ | N/A |
| CPython 3.9 | ✅ | | ✅ | ✅ | ✅² | ✅ | ✅ | ✅ | ✅ | ✅ | N/A |
| CPython 3.10 | ✅ | ✅ | ✅ | ✅ | ✅² | ✅ | ✅ | ✅ | ✅ | ✅ | N/A |
| CPython 3.11 | ✅ | ✅ | ✅ | ✅ | ✅² | ✅ | ✅ | ✅ | ✅ | ✅ | N/A |
| CPython 3.12 | ✅ | ✅ | ✅ | ✅ | ✅² | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| CPython 3.1 | ✅ | ✅ | ✅ | ✅ | ✅² | ✅ | ✅ | ✅ | ✅ | ✅ | N/A |
| PyPy 3.7 v7.3 | ✅ | N/A | ✅ | N/A | N/A | ✅¹ | ✅¹ | ✅¹ | N/A | N/A | N/A |
| PyPy 3.8 v7.3 | ✅ | ✅ | ✅ | 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 |
| PyPy 3.10 v7.3 | ✅ | ✅ | ✅ | N/A | N/A | ✅¹ | ✅¹ | ✅¹ | N/A | N/A | N/A |
While cibuildwheel itself requires a recent Python version to run (we support the last three releases), it can target the following versions to build wheels:
| | macOS Intel | macOS Apple Silicon | Windows 64bit | Windows 32bit | Windows Arm64 | manylinux<br/>musllinux x86_64 | manylinux<br/>musllinux i686 | manylinux<br/>musllinux aarch64 | manylinux<br/>musllinux ppc64le | manylinux<br/>musllinux s390x | manylinux<br/>musllinux armv7l | Pyodide |
|----------------|----|-----|-----|-----|-----|----|-----|----|-----|-----|---|-----|
| CPython 3.6 | ✅ | N/A | ✅ | ✅ | N/A | ✅ | ✅ | ✅ | ✅ | ✅ | ✅⁵ | N/A |
| CPython 3.7 | ✅ | N/A | ✅ | ✅ | N/A | ✅ | ✅ | ✅ | ✅ | ✅ | ✅⁵ | N/A |
| CPython 3.8 | ✅ | ✅ | ✅ | ✅ | N/A | ✅ | ✅ | ✅ | ✅ | ✅ | ✅⁵ | N/A |
| CPython 3.9 | ✅ | ✅ | ✅ | ✅ | ✅² | ✅ | ✅ | ✅ | ✅ | ✅ | ✅⁵ | N/A |
| CPython 3.10 | ✅ | ✅ | ✅ | ✅ | ✅² | ✅ | ✅ | ✅ | ✅ | ✅ | ✅⁵ | N/A |
| CPython 3.11 | ✅ | ✅ | ✅ | ✅ | ✅² | ✅ | ✅ | ✅ | ✅ | ✅ | ✅⁵ | N/A |
| CPython 3.12 | ✅ | | ✅ | ✅ | ✅² | ✅ | ✅ | ✅ | ✅ | ✅ | ✅⁵ | ✅⁴ |
| CPython 3.13³ | ✅ | ✅ | ✅ | ✅ | ✅² | ✅ | ✅ | ✅ | ✅ | ✅ | ✅⁵ | N/A |
| PyPy 3.7 v7.3 | ✅ | N/A | ✅ | N/A | N/A | ✅¹ | ✅¹ | ✅¹ | N/A | N/A | N/A | N/A |
| PyPy 3.8 v7.3 | ✅ | ✅ | ✅ | 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 |
| PyPy 3.10 v7.3 | ✅ | ✅ | ✅ | 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 |
<sup>¹ PyPy is only supported for manylinux wheels.</sup><br>
<sup>² Windows arm64 support is experimental.</sup><br>
<sup>³ CPython 3.13 is built by default using Python RCs, starting with cibuildwheel 2.20. Free-threaded mode will still require opt-in using [`CIBW_FREE_THREADED_SUPPORT`](https://cibuildwheel.pypa.io/en/stable/options/#free-threaded-support).</sup><br>
<sup>³ Free-threaded mode requires opt-in using [`CIBW_FREE_THREADED_SUPPORT`](https://cibuildwheel.pypa.io/en/stable/options/#free-threaded-support).</sup><br>
<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+, and Windows wheels for CPython and PyPy
- Builds manylinux, musllinux, macOS 10.9+ (10.13+ for Python 3.12+), and Windows wheels for CPython and PyPy
- Works on GitHub Actions, Azure Pipelines, Travis CI, AppVeyor, 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
@@ -56,7 +60,7 @@ Usage
| | Linux | macOS | Windows | Linux ARM | macOS ARM | Windows ARM |
|-----------------|-------|-------|---------|-----------|-----------|-------------|
| GitHub Actions | ✅ | ✅ | ✅ | ✅¹ | ✅ | ✅² |
| GitHub Actions | ✅ | ✅ | ✅ | ✅ | ✅ | ✅² |
| Azure Pipelines | ✅ | ✅ | ✅ | | ✅ | ✅² |
| Travis CI | ✅ | | ✅ | ✅ | | |
| AppVeyor | ✅ | ✅ | ✅ | | ✅ | ✅² |
@@ -85,7 +89,7 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-13, macos-14]
os: [ubuntu-latest, ubuntu-24.04-arm, windows-latest, macos-13, macos-latest]
steps:
- uses: actions/checkout@v4
@@ -94,7 +98,7 @@ jobs:
- uses: actions/setup-python@v5
- name: Install cibuildwheel
run: python -m pip install cibuildwheel==2.21.0
run: python -m pip install cibuildwheel==2.23.2
- name: Build wheels
run: python -m cibuildwheel --output-dir wheelhouse
@@ -211,72 +215,54 @@ Changelog
<!-- this section was generated by bin/update_readme_changelog.py -- do not edit manually -->
### v2.21.0
### v2.23.2
_13 September 2024_
_24 March 2025_
- ⚠️ Update CPython 3.12 to 3.12.6, which changes the macOS minimum deployment target on CPython 3.12 from macOS 10.9 to macOS 10.13 (#1998)
- 🛠 Changes the behaviour when inheriting `config-settings` in TOML overrides - rather than extending each key, which is rarely useful, individual keys will override previously set values. (#1803)
- 🛠 Update CPython 3.13 to 3.13.0rc2 (#1998)
- ✨ Adds support for multiarch OCI images (#1961)
- 🐛 Fixes some bugs building Linux wheels on macOS. (#1961)
- ⚠️ Changes the minimum version of Docker/Podman to Docker API version 1.43, Podman API version 3. The only mainstream runner this should affect is Travis Graviton2 runners - if so you can [upgrade your version of Docker](https://github.com/pypa/cibuildwheel/pull/1961#issuecomment-2304060019). (#1961)
- 🐛 Workaround an issue with pyodide builds when running cibuildwheel with a Python that was installed via UV (#2328 via #2331)
- 🛠 Dependency updates, including a manylinux update that fixes an ['undefined symbol' error](https://github.com/pypa/manylinux/issues/1760) in gcc-toolset (#2334)
### v2.23.1
_15 March 2025_
- ⚠️ Added warnings when the shorthand values `manylinux1`, `manylinux2010`, `manylinux_2_24`, and `musllinux_1_1` are used to specify the images in linux builds. The shorthand to these (unmaintainted) images will be removed in v3.0. If you want to keep using these images, explicitly opt-in using the full image URL, which can be found in [this file](https://github.com/pypa/cibuildwheel/blob/v2.23.1/cibuildwheel/resources/pinned_docker_images.cfg). (#2312)
- 🛠 Dependency updates, including a manylinux update which fixes an [issue with rustup](https://github.com/pypa/cibuildwheel/issues/2303). (#2315)
### v2.23.0
_1 March 2025_
- ✨ Adds official support for the new GitHub Actions Arm runners. In fact these worked out-of-the-box, now we include them in our tests and example configs. (#2135 via #2281)
- ✨ Adds support for building PyPy 3.11 wheels (#2268 via #2281)
- 🛠 Adopts the beta pypa/manylinux image for armv7l builds (#2269 via #2281)
- 🛠 Dependency updates, including Pyodide 0.27 (#2117 and #2281)
### v2.22.0
_23 November 2024_
- 🌟 Added a new `CIBW_ENABLE`/`enable` feature that replaces `CIBW_FREETHREADED_SUPPORT`/`free-threaded-support` and `CIBW_PRERELEASE_PYTHONS` with a system that supports both. In cibuildwheel 3, this will also include a PyPy setting and the deprecated options will be removed. (#2048)
- 🌟 [Dependency groups](https://peps.python.org/pep-0735/) are now supported for tests. Use `CIBW_TEST_GROUPS`/`test-groups` to specify groups in `[dependency-groups]` for testing. (#2063)
- 🌟 Support for the experimental Ubuntu-based ARMv7l manylinux image (#2052)
- ✨ Show a warning when cibuildwheel is run from Python 3.10 or older; cibuildwheel 3.0 will require Python 3.11 or newer as host (#2050)
- 🐛 Fix issue with stderr interfering with checking the docker version (#2074)
- 🛠 Python 3.9 is now used in `CIBW_BEFORE_ALL`/`before-all` on linux, replacing 3.8, which is now EoL (#2043)
- 🛠 Error messages for producing a pure-Python wheel are slightly more informative (#2044)
- 🛠 Better error when `uname -m` fails on ARM (#2049)
- 🛠 Better error when repair fails and docs for abi3audit on Windows (#2058)
- 🛠 Better error when `manylinux-interpreters ensure` fails (#2066)
- 🛠 Update Pyodide to 0.26.4, and adapt to the unbundled pyodide-build (now 0.29) (#2090)
- 🛠 Now cibuildwheel uses dependency-groups for development dependencies (#2064, #2085)
- 📚 Docs updates and tidy ups (#2061, #2067, #2072)
### v2.20.0
### v2.21.3
_4 August 2024_
_9 October 2024_
- 🌟 CPython 3.13 wheels are now built by default - without the `CIBW_PRERELEASE_PYTHONS` flag. It's time to build and upload these wheels to PyPI! This release includes CPython 3.13.0rc1, which is guaranteed to be ABI compatible with the final release. Free-threading is still behind a flag/config option. (#1950)
- ✨ Provide a `CIBW_ALLOW_EMPTY` environment variable as an alternative to the command line flag. (#1937)
- 🐛 Don't use uv on PyPy3.8 on Windows, it stopped working starting in 0.2.25. Note that PyPy 3.8 is EoL. (#1868)
- 🛠 Set the `VSCMD_ARG_TGT_ARCH` variable based on target arch. (#1876)
- 🛠 Undo cleaner output on pytest 8-8.2 now that 8.3 is out. (#1943)
- 📚 Update examples to use Python 3.12 on host (cibuildwheel will require Python 3.11+ on the host machine starting in October 2024) (#1919)
### v2.19.2
_2 July 2024_
- 🐛 Update manylinux2014 pins to versions that support past-EoL CentOS 7 mirrors. (#1917)
- 🐛 Support `--no-isolation` with `build[uv]` build-frontend. (#1889)
- 🛠 Provide attestations for releases at <https://github.com/pypa/cibuildwheel/attestations>. (#1916)
- 🛠 Provide CPython 3.13.0b3. (#1913)
- 🛠 Remove some workarounds now that pip 21.1 is available. (#1891, #1892)
- 📚 Remove nosetest from our docs. (#1821)
- 📚 Document the macOS ARM workaround for 3.8 on GHA. (#1871)
- 📚 GitLab CI + macOS is now a supported platform with an example. (#1911)
### v2.19.1
_13 June 2024_
- 🐛 Don't require setup-python on GHA for Pyodide (#1868)
- 🐛 Specify full python path for uv (fixes issue in 0.2.10 & 0.2.11) (#1881)
- 🛠 Update for pip 24.1b2 on CPython 3.13. (#1879)
- 🛠 Fix a warning in our schema generation script. (#1866)
- 🛠 Cleaner output on pytest 8-8.2. (#1865)
### v2.19.0
_10 June 2024_
See the [release post](https://iscinumpy.dev/post/cibuildwheel-2-19-0/) for more info on new features!
- 🌟 Add Pyodide platform. Set with `--platform pyodide` or `CIBW_PLATFORM: pyodide` on Linux with a host Python 3.12 to build WebAssembly wheels. Not accepted on PyPI currently, but usable directly in a website using Pyodide, for live docs, etc. (#1456, #1859)
- 🌟 Add `build[uv]` backend, which will take a pre-existing uv install (or install `cibuildwheel[uv]`) and use `uv` for all environment setup and installs on Python 3.8+. This is significantly faster in most cases. (#1856)
- ✨ Add free-threaded macOS builds and update CPython to 3.13.0b2. (#1854)
- 🐛 Issue copying a wheel to a non-existent output dir fixed. (#1851, #1862)
- 🐛 Better determinism for the test environment seeding. (#1835)
- 🛠 `VIRTUAL_ENV` variable now set. (#1842)
- 🛠 Remove a pip<21.3 workaround. (#1842)
- 🛠 Error handling was refactored to use exceptions. (#1719)
- 🛠 Hardcoded paths in tests avoided. (#1834)
- 🛠 Single Python tests made more generic. (#1835)
- 🛠 Sped up our ci by splitting up emulation tests. (#1839)
- 🛠 Update CPython 3.13 to 3.13.0 final release (#2032)
- 📚 Docs updates and tidy ups (#2035)
<!-- END bin/update_readme_changelog.py -->
+7 -4
View File
@@ -14,17 +14,19 @@ jobs:
versionSpec: '3.8'
- bash: |
docker run --rm --privileged docker.io/tonistiigi/binfmt:latest --install all
python -m pip install -e ".[dev]"
python -m pip install dependency-groups
python -m dependency_groups test | xargs python -m pip install -e.
python ./bin/run_tests.py
- job: macos_38
pool: {vmImage: 'macOS-12'}
pool: {vmImage: 'macOS-13'}
steps:
- task: UsePythonVersion@0
inputs:
versionSpec: '3.8'
- bash: |
python -m pip install -e ".[dev]"
python -m pip install dependency-groups
python -m dependency_groups test | xargs python -m pip install -e.
python ./bin/run_tests.py --num-processes 2
- job: windows_38
@@ -35,5 +37,6 @@ jobs:
inputs:
versionSpec: '3.8'
- bash: |
python -m pip install -e ".[dev]"
python -m pip install dependency-groups
python -m dependency_groups test | xargs python -m pip install -e.
python ./bin/run_tests.py
+24
View File
@@ -26,6 +26,12 @@ $defs:
- append
default: none
description: How to inherit the parent's value.
enable:
enum:
- cpython-freethreading
- cpython-prerelease
- pypy
description: A Python version or flavor to enable.
additionalProperties: false
description: cibuildwheel's settings.
type: object
@@ -99,6 +105,13 @@ properties:
default: pinned
description: Specify how cibuildwheel controls the versions of the tools it uses
type: string
enable:
description: Enable or disable certain builds.
oneOf:
- $ref: "#/$defs/enable"
- type: array
items:
$ref: "#/$defs/enable"
environment:
description: Set environment variables needed during the build.
type: string_table
@@ -110,9 +123,13 @@ properties:
type: boolean
default: false
description: The project supports free-threaded builds of Python (PEP703)
deprecated: Use the `enable` option instead.
manylinux-aarch64-image:
type: string
description: Specify alternative manylinux / musllinux container images
manylinux-armv7l-image:
type: string
description: Specify alternative manylinux / musllinux container images
manylinux-i686-image:
type: string
description: Specify alternative manylinux / musllinux container images
@@ -137,6 +154,9 @@ properties:
musllinux-aarch64-image:
type: string
description: Specify alternative manylinux / musllinux container images
musllinux-armv7l-image:
type: string
description: Specify alternative manylinux / musllinux container images
musllinux-i686-image:
type: string
description: Specify alternative manylinux / musllinux container images
@@ -161,6 +181,9 @@ properties:
test-extras:
description: Install your wheel for testing using `extras_require`
type: string_array
test-groups:
description: Install extra groups when testing
type: string_array
test-requires:
description: Install Python dependencies before running the tests
type: string_array
@@ -255,6 +278,7 @@ del non_global_options["build"]
del non_global_options["skip"]
del non_global_options["test-skip"]
del non_global_options["free-threaded-support"]
del non_global_options["enable"]
overrides["items"]["properties"]["select"]["oneOf"] = string_array
overrides["items"]["properties"] |= non_global_options.copy()
+10 -8
View File
@@ -3,27 +3,29 @@
from __future__ import annotations
import os
import subprocess
import sys
import textwrap
import time
from pathlib import Path
from subprocess import run
import click
def shell(cmd, *, check: bool, **kwargs):
return run([cmd], shell=True, check=check, **kwargs)
def shell(cmd: str, *, check: bool, **kwargs: object) -> subprocess.CompletedProcess[str]:
return subprocess.run([cmd], shell=True, check=check, **kwargs) # type: ignore[call-overload, no-any-return]
def git_repo_has_changes():
unstaged_changes = shell("git diff-index --quiet HEAD --", check=False).returncode != 0
staged_changes = shell("git diff-index --quiet --cached HEAD --", check=False).returncode != 0
def git_repo_has_changes() -> bool:
unstaged_changes: bool = shell("git diff-index --quiet HEAD --", check=False).returncode != 0
staged_changes: bool = (
shell("git diff-index --quiet --cached HEAD --", check=False).returncode != 0
)
return unstaged_changes or staged_changes
@click.command()
def main():
def main() -> None:
project_root = Path(__file__).parent / ".."
os.chdir(project_root)
@@ -57,7 +59,7 @@ def main():
PR generated by `{os.path.basename(__file__)}`.
"""
)
run(
subprocess.run(
[
"gh",
"pr",
+4 -2
View File
@@ -172,7 +172,9 @@ def get_projects(
return sorted((Project(item, github) for item in config), reverse=online)
def render_projects(projects: Sequence[Project], *, dest_path: Path, include_info: bool = True):
def render_projects(
projects: Sequence[Project], *, dest_path: Path, include_info: bool = True
) -> str:
io = StringIO()
print = functools.partial(builtins.print, file=io)
@@ -203,7 +205,7 @@ def insert_projects_table(
projects: Sequence[Project],
input_filename: str,
include_info: bool = True,
):
) -> None:
text = file.read_text()
projects_table = render_projects(projects, include_info=include_info, dest_path=file)
+8 -8
View File
@@ -4,29 +4,29 @@ from __future__ import annotations
import os
import shutil
import subprocess
import sys
import textwrap
import time
import typing
from glob import glob
from pathlib import Path
from subprocess import run
from urllib.parse import quote
import click
def shell(cmd, *, check: bool, **kwargs):
return run([cmd], shell=True, check=check, **kwargs)
def shell(cmd: str, *, check: bool, **kwargs: object) -> subprocess.CompletedProcess[str]:
return subprocess.run([cmd], shell=True, check=check, **kwargs) # type: ignore[call-overload, no-any-return]
def git_repo_has_changes():
def git_repo_has_changes() -> bool:
unstaged_changes = shell("git diff-index --quiet HEAD --", check=False).returncode != 0
staged_changes = shell("git diff-index --quiet --cached HEAD --", check=False).returncode != 0
return unstaged_changes or staged_changes
def generate_basic_project(path):
def generate_basic_project(path: Path) -> None:
sys.path.insert(0, "")
from test.test_projects.c import new_c_project
@@ -79,7 +79,7 @@ services = [
]
def ci_service_for_config_file(config_file):
def ci_service_for_config_file(config_file: str) -> CIService:
filename = Path(config_file).name
try:
@@ -134,7 +134,7 @@ def run_example_ci_configs(config_files=None):
dst_config_file.parent.mkdir(parents=True, exist_ok=True)
shutil.copyfile(src_config_file, dst_config_file)
run(["git", "add", example_project], check=True)
subprocess.run(["git", "add", example_project], check=True)
message = textwrap.dedent(
f"""\
Test example minimal configs
@@ -144,7 +144,7 @@ def run_example_ci_configs(config_files=None):
Time: {timestamp}
"""
)
run(["git", "commit", "--no-verify", "--message", message], check=True)
subprocess.run(["git", "commit", "--no-verify", "--message", message], check=True)
shell(f"git subtree --prefix={example_project} push origin {branch_name}", check=True)
print("---")
+19
View File
@@ -6,6 +6,7 @@ from dataclasses import dataclass
from pathlib import Path
import requests
from packaging.version import Version
DIR = Path(__file__).parent.resolve()
RESOURCES = DIR.parent / "cibuildwheel/resources"
@@ -53,6 +54,8 @@ images = [
Image("manylinux_2_28", "s390x", "quay.io/pypa/manylinux_2_28_s390x", None),
Image("manylinux_2_28", "pypy_x86_64", "quay.io/pypa/manylinux_2_28_x86_64", None),
Image("manylinux_2_28", "pypy_aarch64", "quay.io/pypa/manylinux_2_28_aarch64", None),
# manylinux_2_31 images
Image("manylinux_2_31", "armv7l", "quay.io/pypa/manylinux_2_31_armv7l", None),
# musllinux_1_1 images
Image("musllinux_1_1", "x86_64", "quay.io/pypa/musllinux_1_1_x86_64", None),
Image("musllinux_1_1", "i686", "quay.io/pypa/musllinux_1_1_i686", None),
@@ -65,6 +68,7 @@ images = [
Image("musllinux_1_2", "aarch64", "quay.io/pypa/musllinux_1_2_aarch64", None),
Image("musllinux_1_2", "ppc64le", "quay.io/pypa/musllinux_1_2_ppc64le", None),
Image("musllinux_1_2", "s390x", "quay.io/pypa/musllinux_1_2_s390x", None),
Image("musllinux_1_2", "armv7l", "quay.io/pypa/musllinux_1_2_armv7l", None),
]
config = configparser.ConfigParser()
@@ -90,6 +94,21 @@ for image in images:
for (name, info) in tags_dict.items()
if info["manifest_digest"] == latest_tag["manifest_digest"]
)
elif image.image_name.startswith("ghcr.io/"):
repository = image.image_name[8:]
response = requests.get(
"https://ghcr.io/token", params={"scope": f"repository:{repository}:pull"}
)
response.raise_for_status()
token = response.json()["token"]
response = requests.get(
f"https://ghcr.io/v2/{repository}/tags/list",
headers={"Authorization": f"Bearer {token}"},
)
response.raise_for_status()
ghcr_tags = [(Version(tag), tag) for tag in response.json()["tags"] if tag != "latest"]
ghcr_tags.sort(reverse=True)
tag_name = ghcr_tags[0][1]
else:
response = requests.get(f"https://hub.docker.com/v2/repositories/{image.image_name}/tags")
response.raise_for_status()
+1 -1
View File
@@ -18,7 +18,7 @@ except ImportError:
)
def main():
def main() -> None:
subprocess.run(["mkdocs", "build"], check=True)
hti = Html2Image(custom_flags=["--force-device-scale-factor=2"])
+1 -1
View File
@@ -20,7 +20,7 @@ README_CHANGELOG_SECTION = re.compile(
)
def main():
def main() -> None:
changelog_text = CHANGELOG_FILE.read_text()
readme_text = README_FILE.read_text()
+1 -1
View File
@@ -36,7 +36,7 @@ class VersionTuple:
version_string: str
def git_ls_remote_versions(url) -> list[VersionTuple]:
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
+1 -1
View File
@@ -1,3 +1,3 @@
from __future__ import annotations
__version__ = "2.21.0"
__version__ = "2.23.2"
+15 -7
View File
@@ -271,7 +271,6 @@ class PlatformModule(Protocol):
def build(self, options: Options, tmp_path: Path) -> None: ...
# pylint: disable-next=inconsistent-return-statements
def get_platform_module(platform: PlatformName) -> PlatformModule:
if platform == "linux":
return cibuildwheel.linux
@@ -381,14 +380,13 @@ def print_preamble(platform: str, options: Options, identifiers: Sequence[str])
print()
print(f"Cache folder: {CIBW_CACHE_PATH}")
print()
warnings = detect_warnings(options=options, identifiers=identifiers)
if warnings:
print("\nWarnings:")
for warning in warnings:
print(" " + warning)
for warning in warnings:
log.warning(warning)
print("\nHere we go!\n")
print("Here we go!\n")
def get_build_identifiers(
@@ -403,6 +401,16 @@ def get_build_identifiers(
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"
)
warnings.append(msg)
# warn about 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]
@@ -411,7 +419,7 @@ def detect_warnings(*, options: Options, identifiers: Iterable[str]) -> list[str
# Reminder: in an f-string, double braces means literal single brace
msg = (
f"{option_name}: '{{python}}' and '{{pip}}' are no longer needed, "
"and will be removed in a future release. Simply use 'python' or 'pip' instead."
"and will be removed in cibuildwheel 3. Simply use 'python' or 'pip' instead."
)
warnings.append(msg)
+1 -1
View File
@@ -8,7 +8,7 @@ else:
from typing import NotRequired, Self, assert_never
__all__ = (
"assert_never",
"NotRequired",
"Self",
"assert_never",
)
+5 -5
View File
@@ -37,6 +37,7 @@ class Architecture(Enum):
aarch64 = "aarch64"
ppc64le = "ppc64le"
s390x = "s390x"
armv7l = "armv7l"
# mac archs
universal2 = "universal2"
@@ -132,6 +133,7 @@ class Architecture(Enum):
Architecture.aarch64,
Architecture.ppc64le,
Architecture.s390x,
Architecture.armv7l,
},
"macos": {Architecture.x86_64, Architecture.arm64, Architecture.universal2},
"windows": {Architecture.x86, Architecture.AMD64, Architecture.ARM64},
@@ -140,17 +142,15 @@ class Architecture(Enum):
return all_archs_map[platform]
@staticmethod
# pylint: disable-next=inconsistent-return-statements
def bitness_archs(platform: PlatformName, bitness: Literal["64", "32"]) -> set[Architecture]:
archs_32 = {Architecture.i686, Architecture.x86}
archs_32 = {Architecture.i686, Architecture.x86, Architecture.armv7l}
auto_archs = Architecture.auto_archs(platform)
if bitness == "64":
return auto_archs - archs_32
elif bitness == "32":
if bitness == "32":
return auto_archs & archs_32
else:
assert_never(bitness)
assert_never(bitness)
def allowed_architectures_check(
+28 -5
View File
@@ -35,11 +35,14 @@ class NonPlatformWheelError(FatalError):
"""
Build failed because a pure Python wheel was generated.
If you intend to build a pure-Python wheel, you don't need cibuildwheel - use
`pip wheel -w DEST_DIR .` instead.
If you intend to build a pure-Python wheel, you don't need
cibuildwheel - use `pip wheel .`, `pipx run build --wheel`, `uv
build --wheel`, etc. instead. You only need cibuildwheel if you
have compiled (not Python) code in your wheels making them depend
on the platform.
If you expected a platform wheel, check your project configuration, or run
cibuildwheel with CIBW_BUILD_VERBOSITY=1 to view build logs.
If you expected a platform wheel, check your project configuration,
or run cibuildwheel with CIBW_BUILD_VERBOSITY=1 to view build logs.
"""
)
super().__init__(message)
@@ -61,4 +64,24 @@ class AlreadyBuiltWheelError(FatalError):
class OCIEngineTooOldError(FatalError):
return_code = 7
def __init__(self, message: str) -> None:
super().__init__(message)
self.return_code = 7
class RepairStepProducedNoWheelError(FatalError):
def __init__(self) -> None:
message = textwrap.dedent(
"""
Build failed because the repair step completed successfully but
did not produce a wheel.
Your `repair-wheel-command` is expected to place the repaired
wheel in the {dest_dir} directory. See the documentation for
example configurations:
https://cibuildwheel.pypa.io/en/stable/options/#repair-wheel-command
"""
)
super().__init__(message)
self.return_code = 8
+26 -14
View File
@@ -1,5 +1,6 @@
from __future__ import annotations
import contextlib
import subprocess
import sys
import textwrap
@@ -35,6 +36,7 @@ ARCHITECTURE_OCI_PLATFORM_MAP = {
Architecture.aarch64: OCIPlatform.ARM64,
Architecture.ppc64le: OCIPlatform.PPC64LE,
Architecture.s390x: OCIPlatform.S390X,
Architecture.armv7l: OCIPlatform.ARMV7,
}
@@ -132,26 +134,33 @@ def check_all_python_exist(
*, platform_configs: Iterable[PythonConfiguration], container: OCIContainer
) -> None:
exist = True
has_manylinux_interpreters = True
has_manylinux_interpreters = False
messages = []
try:
with contextlib.suppress(subprocess.CalledProcessError):
# use capture_output to keep quiet
container.call(["manylinux-interpreters", "--help"], capture_output=True)
except subprocess.CalledProcessError:
has_manylinux_interpreters = False
has_manylinux_interpreters = True
for config in platform_configs:
python_path = config.path / "bin" / "python"
try:
if has_manylinux_interpreters:
if has_manylinux_interpreters:
try:
container.call(["manylinux-interpreters", "ensure", config.path.name])
container.call(["test", "-x", python_path])
except subprocess.CalledProcessError:
messages.append(
f" '{python_path}' executable doesn't exist in image '{container.image}' to build '{config.identifier}'."
)
exist = False
except subprocess.CalledProcessError:
messages.append(
f" 'manylinux-interpreters ensure {config.path.name}' needed to build '{config.identifier}' failed in container running image '{container.image}'."
" Either the installation failed or this interpreter is not available in that image. Please check the logs."
)
exist = False
else:
try:
container.call(["test", "-x", python_path])
except subprocess.CalledProcessError:
messages.append(
f" '{python_path}' executable doesn't exist in image '{container.image}' to build '{config.identifier}'."
)
exist = False
if not exist:
message = "\n".join(messages)
raise errors.FatalError(message)
@@ -179,7 +188,7 @@ def build_in_container(
log.step("Running before_all...")
env = container.get_environment()
env["PATH"] = f'/opt/python/cp38-cp38/bin:{env["PATH"]}'
env["PATH"] = f'/opt/python/cp39-cp39/bin:{env["PATH"]}'
env["PIP_DISABLE_PIP_VERSION_CHECK"] = "1"
env["PIP_ROOT_USER_ACTION"] = "ignore"
env = before_all_options.environment.as_dictionary(
@@ -325,6 +334,9 @@ def build_in_container(
repaired_wheels = container.glob(repaired_wheel_dir, "*.whl")
if not repaired_wheels:
raise errors.RepairStepProducedNoWheelError()
for repaired_wheel in repaired_wheels:
if repaired_wheel.name in {wheel.name for wheel in built_wheels}:
raise errors.AlreadyBuiltWheelError(repaired_wheel.name)
@@ -345,7 +357,7 @@ def build_in_container(
venv_dir = testing_temp_dir / "venv"
if use_uv:
container.call(["uv", "venv", venv_dir], env=env)
container.call(["uv", "venv", venv_dir, "--python", python_bin / "python"], env=env)
else:
# Use embedded dependencies from virtualenv to ensure determinism
venv_args = ["--no-periodic-update", "--pip=embed"]
+3 -1
View File
@@ -23,11 +23,13 @@ PLATFORM_IDENTIFIER_DESCRIPTIONS: Final[dict[str, str]] = {
"manylinux_aarch64": "manylinux aarch64",
"manylinux_ppc64le": "manylinux ppc64le",
"manylinux_s390x": "manylinux s390x",
"manylinux_armv7l": "manylinux armv7l",
"musllinux_x86_64": "musllinux x86_64",
"musllinux_i686": "musllinux i686",
"musllinux_aarch64": "musllinux aarch64",
"musllinux_ppc64le": "musllinux ppc64le",
"musllinux_s390x": "manylinux s390x",
"musllinux_s390x": "musllinux s390x",
"musllinux_armv7l": "musllinux armv7l",
"win32": "Windows 32bit",
"win_amd64": "Windows 64bit",
"win_arm64": "Windows on ARM 64bit",
+34 -25
View File
@@ -1,6 +1,7 @@
from __future__ import annotations
import functools
import inspect
import os
import platform
import re
@@ -149,11 +150,15 @@ def install_cpython(tmp: Path, version: str, url: str, free_threading: bool) ->
if detect_ci_provider() is None:
# if running locally, we don't want to install CPython with sudo
# let the user know & provide a link to the installer
msg = (
f"Error: CPython {version} is not installed.\n"
"cibuildwheel will not perform system-wide installs when running outside of CI.\n"
f"To build locally, install CPython {version} on this machine, or, disable this version of Python using CIBW_SKIP=cp{version.replace('.', '')}-macosx_*\n"
f"\nDownload link: {url}"
msg = inspect.cleandoc(
f"""
Error: CPython {version} is not installed.
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_*
For portable builds, cibuildwheel needs the official builds from python.org.
Download link: {url}
"""
)
raise errors.FatalError(msg)
pkg_path = tmp / "Python.pkg"
@@ -193,6 +198,11 @@ def install_pypy(tmp: Path, url: str) -> Path:
return installation_path / "bin" / "pypy3"
def can_use_uv(python_configuration: PythonConfiguration) -> bool:
conditions = (Version(python_configuration.version) >= Version("3.8"),)
return all(conditions)
def setup_python(
tmp: Path,
python_configuration: PythonConfiguration,
@@ -200,13 +210,11 @@ def setup_python(
environment: ParsedEnvironment,
build_frontend: BuildFrontendName,
) -> tuple[Path, dict[str, str]]:
if build_frontend == "build[uv]" and Version(python_configuration.version) < Version("3.8"):
if build_frontend == "build[uv]" and not can_use_uv(python_configuration):
build_frontend = "build"
uv_path = find_uv()
use_uv = build_frontend == "build[uv]" and Version(python_configuration.version) >= Version(
"3.8"
)
use_uv = build_frontend == "build[uv]"
tmp.mkdir()
implementation_id = python_configuration.identifier.split("-")[0]
@@ -270,23 +278,23 @@ def setup_python(
# Apply our environment after pip is ready
env = environment.as_dictionary(prev_environment=env)
# check what pip version we're on
if not use_uv:
assert (venv_bin_path / "pip").exists()
call("which", "pip", env=env)
call("pip", "--version", env=env)
which_pip = call("which", "pip", env=env, capture_stdout=True).strip()
if which_pip != str(venv_bin_path / "pip"):
msg = "cibuildwheel: pip available on PATH doesn't match our installed instance. If you have modified PATH, ensure that you don't overwrite cibuildwheel's entry or insert pip above it."
raise errors.FatalError(msg)
# check what Python version we're on
call("which", "python", env=env)
call("python", "--version", env=env)
which_python = call("which", "python", env=env, capture_stdout=True).strip()
print(which_python)
if which_python != str(venv_bin_path / "python"):
msg = "cibuildwheel: python available on PATH doesn't match our installed instance. If you have modified PATH, ensure that you don't overwrite cibuildwheel's entry or insert python above it."
raise errors.FatalError(msg)
call("python", "--version", env=env)
# check what pip version we're on
if not use_uv:
assert (venv_bin_path / "pip").exists()
which_pip = call("which", "pip", env=env, capture_stdout=True).strip()
print(which_pip)
if which_pip != str(venv_bin_path / "pip"):
msg = "cibuildwheel: pip available on PATH doesn't match our installed instance. If you have modified PATH, ensure that you don't overwrite cibuildwheel's entry or insert pip above it."
raise errors.FatalError(msg)
call("pip", "--version", env=env)
config_is_arm64 = python_configuration.identifier.endswith("arm64")
config_is_universal2 = python_configuration.identifier.endswith("universal2")
@@ -415,9 +423,7 @@ def build(options: Options, tmp_path: Path) -> None:
for config in python_configurations:
build_options = options.build_options(config.identifier)
build_frontend = build_options.build_frontend or BuildFrontendConfig("pip")
use_uv = build_frontend.name == "build[uv]" and Version(config.version) >= Version(
"3.8"
)
use_uv = build_frontend.name == "build[uv]" and can_use_uv(config)
uv_path = find_uv()
if use_uv and uv_path is None:
msg = "uv not found"
@@ -545,7 +551,10 @@ def build(options: Options, tmp_path: Path) -> None:
else:
shutil.move(str(built_wheel), repaired_wheel_dir)
repaired_wheel = next(repaired_wheel_dir.glob("*.whl"))
try:
repaired_wheel = next(repaired_wheel_dir.glob("*.whl"))
except StopIteration:
raise errors.RepairStepProducedNoWheelError() from None
if repaired_wheel.name in {wheel.name for wheel in built_wheels}:
raise errors.AlreadyBuiltWheelError(repaired_wheel.name)
+87 -28
View File
@@ -5,8 +5,10 @@ import json
import os
import platform
import shlex
import shutil
import subprocess
import sys
import textwrap
import typing
import uuid
from collections.abc import Mapping, Sequence
@@ -16,14 +18,13 @@ from pathlib import Path, PurePath, PurePosixPath
from types import TracebackType
from typing import IO, Dict, Literal
from packaging.version import InvalidVersion, Version
from ._compat.typing import Self, assert_never
from .errors import OCIEngineTooOldError
from .logger import log
from .typing import PathOrStr, PopenBytes
from .util import (
CIProvider,
FlexibleVersion,
call,
detect_ci_provider,
parse_key_value_string,
@@ -37,6 +38,7 @@ ContainerEngineName = Literal["docker", "podman"]
class OCIPlatform(Enum):
i386 = "linux/386"
AMD64 = "linux/amd64"
ARMV7 = "linux/arm/v7"
ARM64 = "linux/arm64"
PPC64LE = "linux/ppc64le"
S390X = "linux/s390x"
@@ -102,25 +104,45 @@ def _check_engine_version(engine: OCIContainerEngineConfig) -> None:
version_string = call(engine.name, "version", "-f", "{{json .}}", capture_stdout=True)
version_info = json.loads(version_string.strip())
if engine.name == "docker":
# --platform support was introduced in 1.32 as experimental
# docker cp, as used by cibuildwheel, has been fixed in v24 => API 1.43, https://github.com/moby/moby/issues/38995
client_api_version = Version(version_info["Client"]["ApiVersion"])
engine_api_version = Version(version_info["Server"]["ApiVersion"])
version_supported = min(client_api_version, engine_api_version) >= Version("1.43")
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")
minimum_version_str = "20.10.0" # docker version
error_msg = textwrap.dedent(
f"""
Build failed because {engine.name} is too old.
cibuildwheel requires {engine.name}>={minimum_version_str} running API version {minimum_version}.
The API version found by cibuildwheel is {version}.
"""
)
elif engine.name == "podman":
client_api_version = Version(version_info["Client"]["APIVersion"])
# podman uses the same version string for "Version" & "ApiVersion"
client_version = FlexibleVersion(version_info["Client"]["Version"])
if "Server" in version_info:
engine_api_version = Version(version_info["Server"]["APIVersion"])
server_version = FlexibleVersion(version_info["Server"]["Version"])
else:
engine_api_version = client_api_version
server_version = client_version
# --platform support was introduced in v3
version_supported = min(client_api_version, engine_api_version) >= Version("3")
version = min(client_version, server_version)
minimum_version = FlexibleVersion("3")
error_msg = textwrap.dedent(
f"""
Build failed because {engine.name} is too old.
cibuildwheel requires {engine.name}>={minimum_version}.
The version found by cibuildwheel is {version}.
"""
)
else:
assert_never(engine.name)
if not version_supported:
raise OCIEngineTooOldError() from None
except (subprocess.CalledProcessError, KeyError, InvalidVersion) as e:
raise OCIEngineTooOldError() from e
if version < minimum_version:
raise OCIEngineTooOldError(error_msg) from None
except (subprocess.CalledProcessError, KeyError, ValueError) as e:
msg = f"Build failed because {engine.name} is too old or is not working properly."
raise OCIEngineTooOldError(msg) from e
class OCIContainer:
@@ -146,7 +168,7 @@ class OCIContainer:
... print(self.debug_info())
"""
UTILITY_PYTHON = "/opt/python/cp38-cp38/bin/python"
UTILITY_PYTHON = "/opt/python/cp39-cp39/bin/python"
process: PopenBytes
bash_stdin: IO[bytes]
@@ -169,6 +191,9 @@ class OCIContainer:
self.cwd = cwd
self.name: str | None = None
self.engine = engine
self.host_tar_format = ""
if sys.platform.startswith("darwin"):
self.host_tar_format = "--format gnutar"
def _get_platform_args(self, *, oci_platform: OCIPlatform | None = None) -> tuple[str, str]:
if oci_platform is None:
@@ -184,7 +209,11 @@ class OCIContainer:
"inspect",
self.image,
"--format",
"{{.Os}}/{{.Architecture}}",
(
"{{.Os}}/{{.Architecture}}/{{.Variant}}"
if len(oci_platform.value.split("/")) == 3
else "{{.Os}}/{{.Architecture}}"
),
capture_stdout=True,
).strip()
if image_platform == oci_platform.value:
@@ -211,7 +240,7 @@ class OCIContainer:
platform_args = self._get_platform_args()
simulate_32_bit = False
if self.oci_platform == OCIPlatform.i386:
if self.oci_platform in {OCIPlatform.i386, OCIPlatform.ARMV7}:
# If the architecture running the image is already the right one
# or the image entrypoint takes care of enforcing this, then we don't need to
# simulate this
@@ -222,13 +251,16 @@ class OCIContainer:
*run_cmd, *platform_args, self.image, *ctr_cmd, capture_stdout=True
).strip()
except subprocess.CalledProcessError:
# The image might have been built with amd64 architecture
# Let's try that
platform_args = self._get_platform_args(oci_platform=OCIPlatform.AMD64)
container_machine = call(
*run_cmd, *platform_args, self.image, *ctr_cmd, capture_stdout=True
).strip()
simulate_32_bit = container_machine != "i686"
if self.oci_platform == OCIPlatform.i386:
# The image might have been built with amd64 architecture
# Let's try that
platform_args = self._get_platform_args(oci_platform=OCIPlatform.AMD64)
container_machine = call(
*run_cmd, *platform_args, self.image, *ctr_cmd, capture_stdout=True
).strip()
else:
raise
simulate_32_bit = container_machine not in {"i686", "armv7l", "armv8l"}
shell_args = ["linux32", "/bin/bash"] if simulate_32_bit else ["/bin/bash"]
@@ -311,10 +343,37 @@ class OCIContainer:
def copy_into(self, from_path: Path, to_path: PurePath) -> None:
if from_path.is_dir():
self.call(["mkdir", "-p", to_path])
call(self.engine.name, "cp", f"{from_path}/.", f"{self.name}:{to_path}")
subprocess.run(
f"tar -c {self.host_tar_format} -f - . | {self.engine.name} exec -i {self.name} tar --no-same-owner -xC {shell_quote(to_path)} -f -",
shell=True,
check=True,
cwd=from_path,
)
else:
self.call(["mkdir", "-p", to_path.parent])
call(self.engine.name, "cp", from_path, f"{self.name}:{to_path}")
exec_process: subprocess.Popen[bytes]
with subprocess.Popen(
[
self.engine.name,
"exec",
"-i",
str(self.name),
"sh",
"-c",
f"cat > {shell_quote(to_path)}",
],
stdin=subprocess.PIPE,
) as exec_process:
assert exec_process.stdin
with open(from_path, "rb") as from_file:
shutil.copyfileobj(from_file, exec_process.stdin)
exec_process.stdin.close()
exec_process.wait()
if exec_process.returncode:
raise subprocess.CalledProcessError(
exec_process.returncode, exec_process.args, None, None
)
def copy_out(self, from_path: PurePath, to_path: Path) -> None:
# note: we assume from_path is a dir
+86 -21
View File
@@ -22,7 +22,7 @@ from .architecture import Architecture
from .environment import EnvironmentParseError, ParsedEnvironment, parse_environment
from .logger import log
from .oci_container import OCIContainerEngineConfig
from .projectfiles import get_requires_python_str
from .projectfiles import get_requires_python_str, resolve_dependency_groups
from .typing import PLATFORMS, PlatformName
from .util import (
MANYLINUX_ARCHS,
@@ -30,8 +30,10 @@ from .util import (
BuildFrontendConfig,
BuildSelector,
DependencyConstraints,
EnableGroups,
TestSelector,
format_safe,
read_python_configs,
resources_dir,
selector_matches,
strtobool,
@@ -92,6 +94,7 @@ class BuildOptions:
before_test: str | None
test_requires: list[str]
test_extras: str
test_groups: list[str]
build_verbosity: int
build_frontend: BuildFrontendConfig | None
config_settings: str
@@ -307,7 +310,6 @@ def _resolve_cascade(
return result
# pylint: disable-next=inconsistent-return-statements
def _apply_inherit_rule(
before: str | None, after: str, rule: InheritRule, option_format: OptionFormat | None
) -> str:
@@ -329,10 +331,10 @@ def _apply_inherit_rule(
if rule == InheritRule.APPEND:
return option_format.merge_values(before, after)
elif rule == InheritRule.PREPEND:
if rule == InheritRule.PREPEND:
return option_format.merge_values(after, before)
else:
assert_never(rule)
assert_never(rule)
def _stringify_setting(
@@ -512,6 +514,7 @@ class OptionsReader:
env_plat: bool = True,
option_format: OptionFormat | None = None,
ignore_empty: bool = False,
env_rule: InheritRule = InheritRule.NONE,
) -> str:
"""
Get and return the value for the named option from environment,
@@ -543,33 +546,44 @@ class OptionsReader:
(o.options.get(name), o.inherit.get(name, InheritRule.NONE))
for o in self.active_config_overrides
],
(self.env.get(envvar), InheritRule.NONE),
(self.env.get(plat_envvar) if env_plat else None, InheritRule.NONE),
(self.env.get(envvar), env_rule),
(self.env.get(plat_envvar) if env_plat else None, env_rule),
ignore_empty=ignore_empty,
option_format=option_format,
)
class Options:
pyproject_toml: dict[str, Any] | None
def __init__(
self,
platform: PlatformName,
command_line_arguments: CommandLineArguments,
env: Mapping[str, str],
read_config_file: bool = True,
defaults: bool = False,
):
self.platform = platform
self.command_line_arguments = command_line_arguments
self.env = env
self._defaults = defaults
self._image_warnings: set[str] = set()
self.reader = OptionsReader(
self.config_file_path if read_config_file else None,
None if defaults else self.config_file_path,
platform=platform,
env=env,
disallow=DISALLOWED_OPTIONS,
)
@property
self.package_dir = Path(command_line_arguments.package_dir)
try:
with self.package_dir.joinpath("pyproject.toml").open("rb") as f:
self.pyproject_toml = tomllib.load(f)
except FileNotFoundError:
self.pyproject_toml = None
@functools.cached_property
def config_file_path(self) -> Path | None:
args = self.command_line_arguments
@@ -585,10 +599,9 @@ class Options:
@functools.cached_property
def package_requires_python_str(self) -> str | None:
args = self.command_line_arguments
return get_requires_python_str(Path(args.package_dir))
return get_requires_python_str(self.package_dir, self.pyproject_toml)
@property
@functools.cached_property
def globals(self) -> GlobalOptions:
args = self.command_line_arguments
package_dir = args.package_dir
@@ -600,16 +613,34 @@ class Options:
skip_config = self.reader.get("skip", env_plat=False, option_format=ListFormat(sep=" "))
test_skip = self.reader.get("test-skip", env_plat=False, option_format=ListFormat(sep=" "))
allow_empty = args.allow_empty or strtobool(self.env.get("CIBW_ALLOW_EMPTY", "0"))
enable_groups = self.reader.get(
"enable", env_plat=False, option_format=ListFormat(sep=" "), env_rule=InheritRule.APPEND
)
enable = {EnableGroups(group) for group in enable_groups.split()}
free_threaded_support = strtobool(
self.reader.get("free-threaded-support", env_plat=False, ignore_empty=True)
)
allow_empty = args.allow_empty or strtobool(self.env.get("CIBW_ALLOW_EMPTY", "0"))
prerelease_pythons = args.prerelease_pythons or strtobool(
self.env.get("CIBW_PRERELEASE_PYTHONS", "0")
)
if free_threaded_support or prerelease_pythons:
msg = (
"free-threaded-support and prerelease-pythons should be specified by enable instead"
)
if enable:
raise OptionsReaderError(msg)
log.warning(msg)
if free_threaded_support:
enable.add(EnableGroups.CPythonFreeThreading)
if prerelease_pythons:
enable.add(EnableGroups.CPythonPrerelease)
# This is not supported in tool.cibuildwheel, as it comes from a standard location.
# Passing this in as an environment variable will override pyproject.toml, setup.cfg, or setup.py
requires_python_str: str | None = (
@@ -625,18 +656,30 @@ class Options:
build_config = args.only
skip_config = ""
architectures = Architecture.all_archs(self.platform)
prerelease_pythons = True
free_threaded_support = True
enable = set(EnableGroups)
build_selector = BuildSelector(
build_config=build_config,
skip_config=skip_config,
requires_python=requires_python,
prerelease_pythons=prerelease_pythons,
free_threaded_support=free_threaded_support,
enable=frozenset(
enable | {EnableGroups.PyPy}
), # For backwards compatibility, we are adding PyPy for now
)
test_selector = TestSelector(skip_config=test_skip)
all_configs = read_python_configs(self.platform)
all_pypy_ids = {
config["identifier"] for config in all_configs if config["identifier"].startswith("pp")
}
if (
not self._defaults
and EnableGroups.PyPy not in enable
and any(build_selector(build_id) for build_id in all_pypy_ids)
):
msg = "PyPy builds will be disabled by default in version 3. Enabling PyPy builds should be specified by enable"
log.warning(msg)
return GlobalOptions(
package_dir=package_dir,
output_dir=output_dir,
@@ -646,6 +689,20 @@ class Options:
allow_empty=allow_empty,
)
def _check_pinned_image(self, value: str, pinned_images: Mapping[str, str]) -> None:
if (
value in {"manylinux1", "manylinux2010", "manylinux_2_24", "musllinux_1_1"}
and value not in self._image_warnings
):
self._image_warnings.add(value)
msg = (
f"Deprecated image {value!r}. This value will not work"
" in a future version of cibuildwheel. Either upgrade to a supported"
" image or continue using the deprecated image by pinning directly"
f" to {pinned_images[value]!r}."
)
log.warning(msg)
def build_options(self, identifier: str | None) -> BuildOptions:
"""
Compute BuildOptions for a single run configuration.
@@ -673,6 +730,11 @@ class Options:
"test-requires", option_format=ListFormat(sep=" ")
).split()
test_extras = self.reader.get("test-extras", option_format=ListFormat(sep=","))
test_groups_str = self.reader.get("test-groups", option_format=ListFormat(sep=" "))
test_groups = [x for x in test_groups_str.split() if x]
test_requirements_from_groups = resolve_dependency_groups(
self.pyproject_toml, *test_groups
)
build_verbosity_str = self.reader.get("build-verbosity")
build_frontend_str = self.reader.get(
@@ -738,6 +800,7 @@ class Options:
# default to manylinux2014
image = pinned_images["manylinux2014"]
elif config_value in pinned_images:
self._check_pinned_image(config_value, pinned_images)
image = pinned_images[config_value]
else:
image = config_value
@@ -752,6 +815,7 @@ class Options:
if not config_value:
image = pinned_images["musllinux_1_2"]
elif config_value in pinned_images:
self._check_pinned_image(config_value, pinned_images)
image = pinned_images[config_value]
else:
image = config_value
@@ -772,8 +836,9 @@ class Options:
return BuildOptions(
globals=self.globals,
test_command=test_command,
test_requires=test_requires,
test_requires=[*test_requires, *test_requirements_from_groups],
test_extras=test_extras,
test_groups=test_groups,
before_test=before_test,
before_build=before_build,
before_all=before_all,
@@ -817,7 +882,7 @@ class Options:
platform=self.platform,
command_line_arguments=CommandLineArguments.defaults(),
env={},
read_config_file=False,
defaults=True,
)
def summary(self, identifiers: Iterable[str]) -> str:
+28 -7
View File
@@ -4,8 +4,9 @@ import ast
import configparser
import contextlib
from pathlib import Path
from typing import Any
from ._compat import tomllib
import dependency_groups
def get_parent(node: ast.AST | None, depth: int = 1) -> ast.AST | None:
@@ -84,15 +85,12 @@ def setup_py_python_requires(content: str) -> str | None:
return None
def get_requires_python_str(package_dir: Path) -> str | None:
def get_requires_python_str(package_dir: Path, pyproject_toml: dict[str, Any] | None) -> str | None:
"""Return the python requires string from the most canonical source available, or None"""
# Read in from pyproject.toml:project.requires-python
with contextlib.suppress(FileNotFoundError):
with (package_dir / "pyproject.toml").open("rb") as f1:
info = tomllib.load(f1)
with contextlib.suppress(KeyError, IndexError, TypeError):
return str(info["project"]["requires-python"])
with contextlib.suppress(KeyError, IndexError, TypeError):
return str((pyproject_toml or {})["project"]["requires-python"])
# Read in from setup.cfg:options.python_requires
config = configparser.ConfigParser()
@@ -106,3 +104,26 @@ def get_requires_python_str(package_dir: Path) -> str | None:
return setup_py_python_requires(f2.read())
return None
def resolve_dependency_groups(
pyproject_toml: dict[str, Any] | None, *groups: str
) -> tuple[str, ...]:
"""
Get the packages in dependency-groups for a package.
"""
if not groups:
return ()
if pyproject_toml is None:
msg = f"Didn't find a pyproject.toml, so can't read [dependency-groups] {groups!r} from it!"
raise FileNotFoundError(msg)
try:
dependency_groups_toml = pyproject_toml["dependency-groups"]
except KeyError:
msg = f"Didn't find [dependency-groups] in pyproject.toml, which is needed to resolve {groups!r}."
raise KeyError(msg) from None
return dependency_groups.resolve(dependency_groups_toml, *groups)
+24 -16
View File
@@ -41,6 +41,7 @@ class PythonConfiguration:
version: str
identifier: str
pyodide_version: str
pyodide_build_version: str
emscripten_version: str
node_version: str
@@ -65,10 +66,15 @@ def install_emscripten(tmp: Path, version: str) -> Path:
return emcc_path
def install_xbuildenv(env: dict[str, str], pyodide_version: str) -> str:
def install_xbuildenv(env: dict[str, str], pyodide_build_version: str, pyodide_version: str) -> str:
"""Install a particular Pyodide xbuildenv version and set a path to the Pyodide root."""
# Since pyodide-build was unvendored from Pyodide v0.27.0, the versions of pyodide-build are
# not guaranteed to match the versions of Pyodide or be in sync with them. Hence, we shall
# specify the pyodide-build version in the root path, which will set up the xbuildenv for
# the requested Pyodide version.
pyodide_root = (
CIBW_CACHE_PATH
/ f".pyodide-xbuildenv-{pyodide_version}/{pyodide_version}/xbuildenv/pyodide-root"
/ f".pyodide-xbuildenv-{pyodide_build_version}/{pyodide_version}/xbuildenv/pyodide-root"
)
with FileLock(CIBW_CACHE_PATH / "xbuildenv.lock"):
if pyodide_root.exists():
@@ -136,22 +142,22 @@ def setup_python(
env = environment.as_dictionary(prev_environment=env)
# check what pip version we're on
assert (venv_bin_path / "pip").exists()
call("which", "pip", env=env)
call("pip", "--version", env=env)
which_pip = call("which", "pip", env=env, capture_stdout=True).strip()
if which_pip != str(venv_bin_path / "pip"):
msg = "pip available on PATH doesn't match our venv instance. If you have modified PATH, ensure that you don't overwrite cibuildwheel's entry or insert pip above it."
raise errors.FatalError(msg)
# check what Python version we're on
call("which", "python", env=env)
call("python", "--version", env=env)
which_python = call("which", "python", env=env, capture_stdout=True).strip()
print(which_python)
if which_python != str(venv_bin_path / "python"):
msg = "python available on PATH doesn't match our venv instance. If you have modified PATH, ensure that you don't overwrite cibuildwheel's entry or insert python above it."
raise errors.FatalError(msg)
call("python", "--version", env=env)
# check what pip version we're on
assert (venv_bin_path / "pip").exists()
which_pip = call("which", "pip", env=env, capture_stdout=True).strip()
print(which_pip)
if which_pip != str(venv_bin_path / "pip"):
msg = "pip available on PATH doesn't match our venv instance. If you have modified PATH, ensure that you don't overwrite cibuildwheel's entry or insert pip above it."
raise errors.FatalError(msg)
call("pip", "--version", env=env)
log.step("Installing build tools...")
call(
@@ -165,13 +171,15 @@ def setup_python(
env=env,
)
log.step("Installing emscripten...")
log.step(f"Installing Emscripten version: {python_configuration.emscripten_version} ...")
emcc_path = install_emscripten(tmp, python_configuration.emscripten_version)
env["PATH"] = os.pathsep.join([str(emcc_path.parent), env["PATH"]])
log.step("Installing Pyodide xbuildenv...")
env["PYODIDE_ROOT"] = install_xbuildenv(env, python_configuration.pyodide_version)
log.step(f"Installing Pyodide xbuildenv version: {python_configuration.pyodide_version} ...")
env["PYODIDE_ROOT"] = install_xbuildenv(
env, python_configuration.pyodide_build_version, python_configuration.pyodide_version
)
return env
+46 -22
View File
@@ -22,6 +22,7 @@ python_configurations = [
{ identifier = "pp38-manylinux_x86_64", version = "3.8", path_str = "/opt/python/pp38-pypy38_pp73" },
{ identifier = "pp39-manylinux_x86_64", version = "3.9", path_str = "/opt/python/pp39-pypy39_pp73" },
{ 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 = "cp36-manylinux_aarch64", version = "3.6", path_str = "/opt/python/cp36-cp36m" },
{ identifier = "cp37-manylinux_aarch64", version = "3.7", path_str = "/opt/python/cp37-cp37m" },
{ identifier = "cp38-manylinux_aarch64", version = "3.8", path_str = "/opt/python/cp38-cp38" },
@@ -49,14 +50,25 @@ python_configurations = [
{ identifier = "cp312-manylinux_s390x", version = "3.12", path_str = "/opt/python/cp312-cp312" },
{ identifier = "cp313-manylinux_s390x", version = "3.13", path_str = "/opt/python/cp313-cp313" },
{ identifier = "cp313t-manylinux_s390x", version = "3.13", path_str = "/opt/python/cp313-cp313t" },
{ identifier = "cp36-manylinux_armv7l", version = "3.6", path_str = "/opt/python/cp36-cp36m" },
{ identifier = "cp37-manylinux_armv7l", version = "3.7", path_str = "/opt/python/cp37-cp37m" },
{ identifier = "cp38-manylinux_armv7l", version = "3.8", path_str = "/opt/python/cp38-cp38" },
{ identifier = "cp39-manylinux_armv7l", version = "3.9", path_str = "/opt/python/cp39-cp39" },
{ identifier = "cp310-manylinux_armv7l", version = "3.10", path_str = "/opt/python/cp310-cp310" },
{ identifier = "cp311-manylinux_armv7l", version = "3.11", path_str = "/opt/python/cp311-cp311" },
{ identifier = "cp312-manylinux_armv7l", version = "3.12", path_str = "/opt/python/cp312-cp312" },
{ identifier = "cp313-manylinux_armv7l", version = "3.13", path_str = "/opt/python/cp313-cp313" },
{ identifier = "cp313t-manylinux_armv7l", version = "3.13", path_str = "/opt/python/cp313-cp313t" },
{ identifier = "pp37-manylinux_aarch64", version = "3.7", path_str = "/opt/python/pp37-pypy37_pp73" },
{ identifier = "pp38-manylinux_aarch64", version = "3.8", path_str = "/opt/python/pp38-pypy38_pp73" },
{ identifier = "pp39-manylinux_aarch64", version = "3.9", path_str = "/opt/python/pp39-pypy39_pp73" },
{ 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 = "pp37-manylinux_i686", version = "3.7", path_str = "/opt/python/pp37-pypy37_pp73" },
{ 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" },
{ identifier = "pp311-manylinux_i686", version = "3.11", path_str = "/opt/python/pp311-pypy311_pp73" },
{ identifier = "cp36-musllinux_x86_64", version = "3.6", path_str = "/opt/python/cp36-cp36m" },
{ identifier = "cp37-musllinux_x86_64", version = "3.7", path_str = "/opt/python/cp37-cp37m" },
{ identifier = "cp38-musllinux_x86_64", version = "3.8", path_str = "/opt/python/cp38-cp38" },
@@ -102,6 +114,15 @@ python_configurations = [
{ identifier = "cp312-musllinux_s390x", version = "3.12", path_str = "/opt/python/cp312-cp312" },
{ identifier = "cp313-musllinux_s390x", version = "3.13", path_str = "/opt/python/cp313-cp313" },
{ identifier = "cp313t-musllinux_s390x", version = "3.13", path_str = "/opt/python/cp313-cp313t" },
{ identifier = "cp36-musllinux_armv7l", version = "3.6", path_str = "/opt/python/cp36-cp36m" },
{ identifier = "cp37-musllinux_armv7l", version = "3.7", path_str = "/opt/python/cp37-cp37m" },
{ identifier = "cp38-musllinux_armv7l", version = "3.8", path_str = "/opt/python/cp38-cp38" },
{ identifier = "cp39-musllinux_armv7l", version = "3.9", path_str = "/opt/python/cp39-cp39" },
{ identifier = "cp310-musllinux_armv7l", version = "3.10", path_str = "/opt/python/cp310-cp310" },
{ identifier = "cp311-musllinux_armv7l", version = "3.11", path_str = "/opt/python/cp311-cp311" },
{ identifier = "cp312-musllinux_armv7l", version = "3.12", path_str = "/opt/python/cp312-cp312" },
{ identifier = "cp313-musllinux_armv7l", version = "3.13", path_str = "/opt/python/cp313-cp313" },
{ identifier = "cp313t-musllinux_armv7l", version = "3.13", path_str = "/opt/python/cp313-cp313t" },
]
[macos]
@@ -120,22 +141,24 @@ python_configurations = [
{ identifier = "cp311-macosx_x86_64", version = "3.11", url = "https://www.python.org/ftp/python/3.11.9/python-3.11.9-macos11.pkg" },
{ identifier = "cp311-macosx_arm64", version = "3.11", url = "https://www.python.org/ftp/python/3.11.9/python-3.11.9-macos11.pkg" },
{ identifier = "cp311-macosx_universal2", version = "3.11", url = "https://www.python.org/ftp/python/3.11.9/python-3.11.9-macos11.pkg" },
{ identifier = "cp312-macosx_x86_64", version = "3.12", url = "https://www.python.org/ftp/python/3.12.6/python-3.12.6-macos11.pkg" },
{ identifier = "cp312-macosx_arm64", version = "3.12", url = "https://www.python.org/ftp/python/3.12.6/python-3.12.6-macos11.pkg" },
{ identifier = "cp312-macosx_universal2", version = "3.12", url = "https://www.python.org/ftp/python/3.12.6/python-3.12.6-macos11.pkg" },
{ identifier = "cp313-macosx_x86_64", version = "3.13", url = "https://www.python.org/ftp/python/3.13.0/python-3.13.0rc2-macos11.pkg" },
{ identifier = "cp313-macosx_arm64", version = "3.13", url = "https://www.python.org/ftp/python/3.13.0/python-3.13.0rc2-macos11.pkg" },
{ identifier = "cp313-macosx_universal2", version = "3.13", url = "https://www.python.org/ftp/python/3.13.0/python-3.13.0rc2-macos11.pkg" },
{ identifier = "cp313t-macosx_x86_64", version = "3.13", url = "https://www.python.org/ftp/python/3.13.0/python-3.13.0rc2-macos11.pkg" },
{ identifier = "cp313t-macosx_arm64", version = "3.13", url = "https://www.python.org/ftp/python/3.13.0/python-3.13.0rc2-macos11.pkg" },
{ identifier = "cp313t-macosx_universal2", version = "3.13", url = "https://www.python.org/ftp/python/3.13.0/python-3.13.0rc2-macos11.pkg" },
{ identifier = "cp312-macosx_x86_64", version = "3.12", url = "https://www.python.org/ftp/python/3.12.9/python-3.12.9-macos11.pkg" },
{ identifier = "cp312-macosx_arm64", version = "3.12", url = "https://www.python.org/ftp/python/3.12.9/python-3.12.9-macos11.pkg" },
{ identifier = "cp312-macosx_universal2", version = "3.12", url = "https://www.python.org/ftp/python/3.12.9/python-3.12.9-macos11.pkg" },
{ identifier = "cp313-macosx_x86_64", version = "3.13", url = "https://www.python.org/ftp/python/3.13.2/python-3.13.2-macos11.pkg" },
{ identifier = "cp313-macosx_arm64", version = "3.13", url = "https://www.python.org/ftp/python/3.13.2/python-3.13.2-macos11.pkg" },
{ identifier = "cp313-macosx_universal2", version = "3.13", url = "https://www.python.org/ftp/python/3.13.2/python-3.13.2-macos11.pkg" },
{ identifier = "cp313t-macosx_x86_64", version = "3.13", url = "https://www.python.org/ftp/python/3.13.2/python-3.13.2-macos11.pkg" },
{ identifier = "cp313t-macosx_arm64", version = "3.13", url = "https://www.python.org/ftp/python/3.13.2/python-3.13.2-macos11.pkg" },
{ identifier = "cp313t-macosx_universal2", version = "3.13", url = "https://www.python.org/ftp/python/3.13.2/python-3.13.2-macos11.pkg" },
{ identifier = "pp37-macosx_x86_64", version = "3.7", url = "https://downloads.python.org/pypy/pypy3.7-v7.3.9-osx64.tar.bz2" },
{ identifier = "pp38-macosx_x86_64", version = "3.8", url = "https://downloads.python.org/pypy/pypy3.8-v7.3.11-macos_x86_64.tar.bz2" },
{ identifier = "pp38-macosx_arm64", version = "3.8", url = "https://downloads.python.org/pypy/pypy3.8-v7.3.11-macos_arm64.tar.bz2" },
{ identifier = "pp39-macosx_x86_64", version = "3.9", url = "https://downloads.python.org/pypy/pypy3.9-v7.3.16-macos_x86_64.tar.bz2" },
{ identifier = "pp39-macosx_arm64", version = "3.9", url = "https://downloads.python.org/pypy/pypy3.9-v7.3.16-macos_arm64.tar.bz2" },
{ identifier = "pp310-macosx_x86_64", version = "3.10", url = "https://downloads.python.org/pypy/pypy3.10-v7.3.17-macos_x86_64.tar.bz2" },
{ identifier = "pp310-macosx_arm64", version = "3.10", url = "https://downloads.python.org/pypy/pypy3.10-v7.3.17-macos_arm64.tar.bz2" },
{ identifier = "pp310-macosx_x86_64", version = "3.10", url = "https://downloads.python.org/pypy/pypy3.10-v7.3.19-macos_x86_64.tar.bz2" },
{ identifier = "pp310-macosx_arm64", version = "3.10", url = "https://downloads.python.org/pypy/pypy3.10-v7.3.19-macos_arm64.tar.bz2" },
{ identifier = "pp311-macosx_x86_64", version = "3.11", url = "https://downloads.python.org/pypy/pypy3.11-v7.3.19-macos_x86_64.tar.bz2" },
{ identifier = "pp311-macosx_arm64", version = "3.11", url = "https://downloads.python.org/pypy/pypy3.11-v7.3.19-macos_arm64.tar.bz2" },
]
[windows]
@@ -152,25 +175,26 @@ python_configurations = [
{ 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.6", arch = "32" },
{ identifier = "cp312-win_amd64", version = "3.12.6", arch = "64" },
{ identifier = "cp313-win32", version = "3.13.0-rc2", arch = "32" },
{ identifier = "cp313t-win32", version = "3.13.0-rc2", arch = "32" },
{ identifier = "cp313-win_amd64", version = "3.13.0-rc2", arch = "64" },
{ identifier = "cp313t-win_amd64", version = "3.13.0-rc2", arch = "64" },
{ identifier = "cp312-win32", version = "3.12.9", arch = "32" },
{ identifier = "cp312-win_amd64", version = "3.12.9", arch = "64" },
{ identifier = "cp313-win32", version = "3.13.2", arch = "32" },
{ identifier = "cp313t-win32", version = "3.13.2", arch = "32" },
{ identifier = "cp313-win_amd64", version = "3.13.2", arch = "64" },
{ identifier = "cp313t-win_amd64", version = "3.13.2", 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.6", arch = "ARM64" },
{ identifier = "cp313-win_arm64", version = "3.13.0-rc2", arch = "ARM64" },
{ identifier = "cp313t-win_arm64", version = "3.13.0-rc2", arch = "ARM64" },
{ identifier = "cp312-win_arm64", version = "3.12.9", arch = "ARM64" },
{ identifier = "cp313-win_arm64", version = "3.13.2", arch = "ARM64" },
{ identifier = "cp313t-win_arm64", version = "3.13.2", arch = "ARM64" },
{ identifier = "pp37-win_amd64", version = "3.7", arch = "64", url = "https://downloads.python.org/pypy/pypy3.7-v7.3.9-win64.zip" },
{ 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.17-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.19-win64.zip" },
]
[pyodide]
python_configurations = [
{ identifier = "cp312-pyodide_wasm32", version = "3.12.1", pyodide_version = "0.26.1", emscripten_version = "3.1.58", node_version = "v20" },
{ identifier = "cp312-pyodide_wasm32", version = "3.12", pyodide_version = "0.27.0", pyodide_build_version = "0.29.2", emscripten_version = "3.1.58", node_version = "v20" },
]
@@ -10,7 +10,16 @@
],
"default": "none",
"description": "How to inherit the parent's value."
}
},
"enable": {
"enum": [
"cpython-eol",
"cpython-freethreading",
"cpython-prerelease",
"pypy-eol"
]
},
"description": "A Python version or flavor to enable."
},
"additionalProperties": false,
"description": "cibuildwheel's settings.",
@@ -228,6 +237,21 @@
"type": "string",
"title": "CIBW_DEPENDENCY_VERSIONS"
},
"enable": {
"description": "Enable or disable certain builds.",
"oneOf": [
{
"$ref": "#/$defs/enable"
},
{
"type": "array",
"items": {
"$ref": "#/$defs/enable"
}
}
],
"title": "CIBW_ENABLE"
},
"environment": {
"description": "Set environment variables needed during the build.",
"oneOf": [
@@ -272,6 +296,11 @@
"description": "Specify alternative manylinux / musllinux container images",
"title": "CIBW_MANYLINUX_AARCH64_IMAGE"
},
"manylinux-armv7l-image": {
"type": "string",
"description": "Specify alternative manylinux / musllinux container images",
"title": "CIBW_MANYLINUX_ARMV7L_IMAGE"
},
"manylinux-i686-image": {
"type": "string",
"description": "Specify alternative manylinux / musllinux container images",
@@ -312,6 +341,11 @@
"description": "Specify alternative manylinux / musllinux container images",
"title": "CIBW_MUSLLINUX_AARCH64_IMAGE"
},
"musllinux-armv7l-image": {
"type": "string",
"description": "Specify alternative manylinux / musllinux container images",
"title": "CIBW_MUSLLINUX_ARMV7L_IMAGE"
},
"musllinux-i686-image": {
"type": "string",
"description": "Specify alternative manylinux / musllinux container images",
@@ -392,6 +426,21 @@
],
"title": "CIBW_TEST_EXTRAS"
},
"test-groups": {
"description": "Install extra groups when testing",
"oneOf": [
{
"type": "string"
},
{
"type": "array",
"items": {
"type": "string"
}
}
],
"title": "CIBW_TEST_GROUPS"
},
"test-requires": {
"description": "Install Python dependencies before running the tests",
"oneOf": [
@@ -518,6 +567,9 @@
"manylinux-aarch64-image": {
"$ref": "#/properties/manylinux-aarch64-image"
},
"manylinux-armv7l-image": {
"$ref": "#/properties/manylinux-armv7l-image"
},
"manylinux-i686-image": {
"$ref": "#/properties/manylinux-i686-image"
},
@@ -542,6 +594,9 @@
"musllinux-aarch64-image": {
"$ref": "#/properties/musllinux-aarch64-image"
},
"musllinux-armv7l-image": {
"$ref": "#/properties/musllinux-armv7l-image"
},
"musllinux-i686-image": {
"$ref": "#/properties/musllinux-i686-image"
},
@@ -563,6 +618,9 @@
"test-extras": {
"$ref": "#/properties/test-extras"
},
"test-groups": {
"$ref": "#/properties/test-groups"
},
"test-requires": {
"$ref": "#/properties/test-requires"
}
@@ -606,6 +664,9 @@
"manylinux-aarch64-image": {
"$ref": "#/properties/manylinux-aarch64-image"
},
"manylinux-armv7l-image": {
"$ref": "#/properties/manylinux-armv7l-image"
},
"manylinux-i686-image": {
"$ref": "#/properties/manylinux-i686-image"
},
@@ -630,6 +691,9 @@
"musllinux-aarch64-image": {
"$ref": "#/properties/musllinux-aarch64-image"
},
"musllinux-armv7l-image": {
"$ref": "#/properties/musllinux-armv7l-image"
},
"musllinux-i686-image": {
"$ref": "#/properties/musllinux-i686-image"
},
@@ -664,6 +728,9 @@
"test-extras": {
"$ref": "#/properties/test-extras"
},
"test-groups": {
"$ref": "#/properties/test-groups"
},
"test-requires": {
"$ref": "#/properties/test-requires"
}
@@ -709,6 +776,9 @@
"test-extras": {
"$ref": "#/properties/test-extras"
},
"test-groups": {
"$ref": "#/properties/test-groups"
},
"test-requires": {
"$ref": "#/properties/test-requires"
}
@@ -767,6 +837,9 @@
"test-extras": {
"$ref": "#/properties/test-extras"
},
"test-groups": {
"$ref": "#/properties/test-groups"
},
"test-requires": {
"$ref": "#/properties/test-requires"
}
@@ -812,6 +885,9 @@
"test-extras": {
"$ref": "#/properties/test-extras"
},
"test-groups": {
"$ref": "#/properties/test-groups"
},
"test-requires": {
"$ref": "#/properties/test-requires"
}
@@ -2,124 +2,111 @@
# nox -s update_constraints
annotated-types==0.7.0
# via pydantic
anyio==4.4.0
anyio==4.9.0
# via httpx
auditwheel-emscripten==0.0.16
# via pyodide-build
build==1.2.2
build==1.2.2.post1
# via
# -r .nox/update_constraints/tmp/constraints-pyodide.in
# pyodide-build
certifi==2024.8.30
certifi==2025.1.31
# via
# httpcore
# httpx
# requests
charset-normalizer==3.3.2
charset-normalizer==3.4.1
# via requests
click==8.1.7
click==8.1.8
# via typer
cloudpickle==3.0.0
# via loky
cmake==3.30.3
cmake==3.31.6
# via pyodide-build
distlib==0.3.8
distlib==0.3.9
# via virtualenv
filelock==3.16.0
filelock==3.18.0
# via virtualenv
h11==0.14.0
# via httpcore
httpcore==1.0.5
httpcore==1.0.7
# via httpx
httpx==0.27.2
httpx==0.28.1
# via unearth
idna==3.8
idna==3.10
# via
# anyio
# httpx
# requests
leb128==1.0.8
# via auditwheel-emscripten
loky==3.4.1
# via pyodide-build
markdown-it-py==3.0.0
# via rich
mdurl==0.1.2
# via markdown-it-py
packaging==24.1
packaging==24.2
# via
# auditwheel-emscripten
# build
# pyodide-build
# unearth
pip==24.2
pip==25.0.1
# via -r .nox/update_constraints/tmp/constraints-pyodide.in
platformdirs==4.3.2
platformdirs==4.3.7
# via virtualenv
pydantic==2.9.0
pydantic==2.10.6
# via
# pyodide-build
# pyodide-lock
pydantic-core==2.23.2
pydantic-core==2.27.2
# via pydantic
pygments==2.18.0
pygments==2.19.1
# via rich
pyodide-build==0.26.1
pyodide-build==0.29.2
# via -r .nox/update_constraints/tmp/constraints-pyodide.in
pyodide-cli==0.2.4
# via
# auditwheel-emscripten
# pyodide-build
pyodide-lock==0.1.0a6
pyodide-lock==0.1.0a7
# via pyodide-build
pyproject-hooks==1.1.0
pyproject-hooks==1.2.0
# via build
pyyaml==6.0.2
# via pyodide-build
requests==2.32.3
# via pyodide-build
resolvelib==1.0.1
resolvelib==1.1.0
# via pyodide-build
rich==13.8.0
rich==13.9.4
# via
# pyodide-build
# pyodide-cli
# typer
ruamel-yaml==0.18.6
ruamel-yaml==0.18.10
# via pyodide-build
ruamel-yaml-clib==0.2.8
ruamel-yaml-clib==0.2.12
# via ruamel-yaml
shellingham==1.5.4
# via typer
sniffio==1.3.1
# via
# anyio
# httpx
typer==0.12.5
# via anyio
typer==0.15.2
# via
# auditwheel-emscripten
# pyodide-build
# pyodide-cli
types-requests==2.32.0.20240907
# via pyodide-build
typing-extensions==4.12.2
# via
# anyio
# pydantic
# pydantic-core
# typer
tzdata==2024.1
# via pydantic
unearth==0.17.2
unearth==0.17.3
# via pyodide-build
urllib3==2.2.2
# via
# requests
# types-requests
virtualenv==20.26.4
urllib3==2.3.0
# via requests
virtualenv==20.29.3
# via
# build
# pyodide-build
wheel==0.44.0
wheel==0.45.1
# via
# auditwheel-emscripten
# pyodide-build
@@ -2,33 +2,33 @@
# nox -s update_constraints
altgraph==0.17.4
# via macholib
build==1.2.2
build==1.2.2.post1
# via -r cibuildwheel/resources/constraints.in
delocate==0.12.0
delocate==0.13.0
# via -r cibuildwheel/resources/constraints.in
distlib==0.3.8
distlib==0.3.9
# via virtualenv
filelock==3.16.0
filelock==3.18.0
# via virtualenv
importlib-metadata==8.4.0
importlib-metadata==8.6.1
# via build
macholib==1.16.3
# via delocate
packaging==24.1
packaging==24.2
# via
# build
# delocate
pip==24.2
pip==25.0.1
# via -r cibuildwheel/resources/constraints.in
platformdirs==4.3.2
platformdirs==4.3.7
# via virtualenv
pyproject-hooks==1.1.0
pyproject-hooks==1.2.0
# via build
tomli==2.0.1
tomli==2.2.1
# via build
typing-extensions==4.12.2
# via delocate
virtualenv==20.26.4
virtualenv==20.29.3
# via -r cibuildwheel/resources/constraints.in
zipp==3.20.1
zipp==3.21.0
# via importlib-metadata
@@ -2,27 +2,27 @@
# nox -s update_constraints
altgraph==0.17.4
# via macholib
build==1.2.2
build==1.2.2.post1
# via -r cibuildwheel/resources/constraints.in
delocate==0.12.0
delocate==0.13.0
# via -r cibuildwheel/resources/constraints.in
distlib==0.3.8
distlib==0.3.9
# via virtualenv
filelock==3.16.0
filelock==3.18.0
# via virtualenv
macholib==1.16.3
# via delocate
packaging==24.1
packaging==24.2
# via
# build
# delocate
pip==24.2
pip==25.0.1
# via -r cibuildwheel/resources/constraints.in
platformdirs==4.3.2
platformdirs==4.3.7
# via virtualenv
pyproject-hooks==1.1.0
pyproject-hooks==1.2.0
# via build
typing-extensions==4.12.2
# via delocate
virtualenv==20.26.4
virtualenv==20.29.3
# via -r cibuildwheel/resources/constraints.in
@@ -2,27 +2,27 @@
# nox -s update_constraints
altgraph==0.17.4
# via macholib
build==1.2.2
build==1.2.2.post1
# via -r cibuildwheel/resources/constraints.in
delocate==0.12.0
delocate==0.13.0
# via -r cibuildwheel/resources/constraints.in
distlib==0.3.8
distlib==0.3.9
# via virtualenv
filelock==3.16.0
filelock==3.18.0
# via virtualenv
macholib==1.16.3
# via delocate
packaging==24.1
packaging==24.2
# via
# build
# delocate
pip==24.2
pip==25.0.1
# via -r cibuildwheel/resources/constraints.in
platformdirs==4.3.2
platformdirs==4.3.7
# via virtualenv
pyproject-hooks==1.1.0
pyproject-hooks==1.2.0
# via build
typing-extensions==4.12.2
# via delocate
virtualenv==20.26.4
virtualenv==20.29.3
# via -r cibuildwheel/resources/constraints.in
@@ -2,27 +2,27 @@
# nox -s update_constraints
altgraph==0.17.4
# via macholib
build==1.2.2
build==1.2.2.post1
# via -r cibuildwheel/resources/constraints.in
delocate==0.12.0
delocate==0.13.0
# via -r cibuildwheel/resources/constraints.in
distlib==0.3.8
distlib==0.3.9
# via virtualenv
filelock==3.16.0
filelock==3.18.0
# via virtualenv
macholib==1.16.3
# via delocate
packaging==24.1
packaging==24.2
# via
# build
# delocate
pip==24.2
pip==25.0.1
# via -r cibuildwheel/resources/constraints.in
platformdirs==4.3.2
platformdirs==4.3.7
# via virtualenv
pyproject-hooks==1.1.0
pyproject-hooks==1.2.0
# via build
typing-extensions==4.12.2
# via delocate
virtualenv==20.26.4
virtualenv==20.29.3
# via -r cibuildwheel/resources/constraints.in
@@ -6,7 +6,7 @@ build==1.1.1
# via -r cibuildwheel/resources/constraints.in
delocate==0.12.0
# via -r cibuildwheel/resources/constraints.in
distlib==0.3.8
distlib==0.3.9
# via virtualenv
filelock==3.12.2
# via virtualenv
@@ -24,7 +24,7 @@ pip==24.0
# via -r cibuildwheel/resources/constraints.in
platformdirs==4.0.0
# via virtualenv
pyproject-hooks==1.1.0
pyproject-hooks==1.2.0
# via build
tomli==2.0.1
# via build
@@ -33,7 +33,7 @@ typing-extensions==4.7.1
# delocate
# importlib-metadata
# platformdirs
virtualenv==20.26.4
virtualenv==20.26.6
# via -r cibuildwheel/resources/constraints.in
zipp==3.15.0
# via importlib-metadata
+11 -11
View File
@@ -2,33 +2,33 @@
# nox -s update_constraints
altgraph==0.17.4
# via macholib
build==1.2.2
build==1.2.2.post1
# via -r cibuildwheel/resources/constraints.in
delocate==0.12.0
# via -r cibuildwheel/resources/constraints.in
distlib==0.3.8
distlib==0.3.9
# via virtualenv
filelock==3.16.0
filelock==3.16.1
# via virtualenv
importlib-metadata==8.4.0
importlib-metadata==8.5.0
# via build
macholib==1.16.3
# via delocate
packaging==24.1
packaging==24.2
# via
# build
# delocate
pip==24.2
pip==25.0.1
# via -r cibuildwheel/resources/constraints.in
platformdirs==4.3.2
platformdirs==4.3.6
# via virtualenv
pyproject-hooks==1.1.0
pyproject-hooks==1.2.0
# via build
tomli==2.0.1
tomli==2.2.1
# via build
typing-extensions==4.12.2
# via delocate
virtualenv==20.26.4
virtualenv==20.29.3
# via -r cibuildwheel/resources/constraints.in
zipp==3.20.1
zipp==3.20.2
# via importlib-metadata
+12 -12
View File
@@ -2,33 +2,33 @@
# nox -s update_constraints
altgraph==0.17.4
# via macholib
build==1.2.2
build==1.2.2.post1
# via -r cibuildwheel/resources/constraints.in
delocate==0.12.0
delocate==0.13.0
# via -r cibuildwheel/resources/constraints.in
distlib==0.3.8
distlib==0.3.9
# via virtualenv
filelock==3.16.0
filelock==3.18.0
# via virtualenv
importlib-metadata==8.4.0
importlib-metadata==8.6.1
# via build
macholib==1.16.3
# via delocate
packaging==24.1
packaging==24.2
# via
# build
# delocate
pip==24.2
pip==25.0.1
# via -r cibuildwheel/resources/constraints.in
platformdirs==4.3.2
platformdirs==4.3.7
# via virtualenv
pyproject-hooks==1.1.0
pyproject-hooks==1.2.0
# via build
tomli==2.0.1
tomli==2.2.1
# via build
typing-extensions==4.12.2
# via delocate
virtualenv==20.26.4
virtualenv==20.29.3
# via -r cibuildwheel/resources/constraints.in
zipp==3.20.1
zipp==3.21.0
# via importlib-metadata
+9 -9
View File
@@ -2,27 +2,27 @@
# nox -s update_constraints
altgraph==0.17.4
# via macholib
build==1.2.2
build==1.2.2.post1
# via -r cibuildwheel/resources/constraints.in
delocate==0.12.0
delocate==0.13.0
# via -r cibuildwheel/resources/constraints.in
distlib==0.3.8
distlib==0.3.9
# via virtualenv
filelock==3.16.0
filelock==3.18.0
# via virtualenv
macholib==1.16.3
# via delocate
packaging==24.1
packaging==24.2
# via
# build
# delocate
pip==24.2
pip==25.0.1
# via -r cibuildwheel/resources/constraints.in
platformdirs==4.3.2
platformdirs==4.3.7
# via virtualenv
pyproject-hooks==1.1.0
pyproject-hooks==1.2.0
# via build
typing-extensions==4.12.2
# via delocate
virtualenv==20.26.4
virtualenv==20.29.3
# via -r cibuildwheel/resources/constraints.in
+4
View File
@@ -3,6 +3,7 @@ build = "*"
skip = ""
test-skip = ""
free-threaded-support = false
enable = []
archs = ["auto"]
build-frontend = "default"
@@ -20,6 +21,7 @@ test-command = ""
before-test = ""
test-requires = []
test-extras = []
test-groups = []
container-engine = "docker"
@@ -28,6 +30,7 @@ manylinux-i686-image = "manylinux2014"
manylinux-aarch64-image = "manylinux2014"
manylinux-ppc64le-image = "manylinux2014"
manylinux-s390x-image = "manylinux2014"
manylinux-armv7l-image = "manylinux_2_31"
manylinux-pypy_x86_64-image = "manylinux2014"
manylinux-pypy_i686-image = "manylinux2014"
manylinux-pypy_aarch64-image = "manylinux2014"
@@ -37,6 +40,7 @@ musllinux-i686-image = "musllinux_1_2"
musllinux-aarch64-image = "musllinux_1_2"
musllinux-ppc64le-image = "musllinux_1_2"
musllinux-s390x-image = "musllinux_1_2"
musllinux-armv7l-image = "musllinux_1_2"
[tool.cibuildwheel.linux]
+2 -1
View File
@@ -1,2 +1,3 @@
url = "https://nodejs.org/dist/"
v20 = "v20.17.0"
v22 = "v22.14.0"
v20 = "v20.19.0"
+28 -24
View File
@@ -1,54 +1,58 @@
[x86_64]
manylinux1 = quay.io/pypa/manylinux1_x86_64:2024-04-29-76807b8
manylinux2010 = quay.io/pypa/manylinux2010_x86_64:2022-08-05-4535177
manylinux2014 = quay.io/pypa/manylinux2014_x86_64:2024.09.09-0
manylinux2014 = quay.io/pypa/manylinux2014_x86_64:2025.03.23-1
manylinux_2_24 = quay.io/pypa/manylinux_2_24_x86_64:2022-12-26-0d38463
manylinux_2_28 = quay.io/pypa/manylinux_2_28_x86_64:2024.09.09-0
musllinux_1_1 = quay.io/pypa/musllinux_1_1_x86_64:2024.09.09-0
musllinux_1_2 = quay.io/pypa/musllinux_1_2_x86_64:2024.09.09-0
manylinux_2_28 = quay.io/pypa/manylinux_2_28_x86_64:2025.03.23-1
musllinux_1_1 = quay.io/pypa/musllinux_1_1_x86_64:2024.10.26-1
musllinux_1_2 = quay.io/pypa/musllinux_1_2_x86_64:2025.03.23-1
[i686]
manylinux1 = quay.io/pypa/manylinux1_i686:2024-04-29-76807b8
manylinux2010 = quay.io/pypa/manylinux2010_i686:2022-08-05-4535177
manylinux2014 = quay.io/pypa/manylinux2014_i686:2024.09.09-0
manylinux2014 = quay.io/pypa/manylinux2014_i686:2025.03.23-1
manylinux_2_24 = quay.io/pypa/manylinux_2_24_i686:2022-12-26-0d38463
musllinux_1_1 = quay.io/pypa/musllinux_1_1_i686:2024.09.09-0
musllinux_1_2 = quay.io/pypa/musllinux_1_2_i686:2024.09.09-0
musllinux_1_1 = quay.io/pypa/musllinux_1_1_i686:2024.10.26-1
musllinux_1_2 = quay.io/pypa/musllinux_1_2_i686:2025.03.23-1
[pypy_x86_64]
manylinux2010 = quay.io/pypa/manylinux2010_x86_64:2022-08-05-4535177
manylinux2014 = quay.io/pypa/manylinux2014_x86_64:2024.09.09-0
manylinux2014 = quay.io/pypa/manylinux2014_x86_64:2025.03.23-1
manylinux_2_24 = quay.io/pypa/manylinux_2_24_x86_64:2022-12-26-0d38463
manylinux_2_28 = quay.io/pypa/manylinux_2_28_x86_64:2024.09.09-0
manylinux_2_28 = quay.io/pypa/manylinux_2_28_x86_64:2025.03.23-1
[pypy_i686]
manylinux2010 = quay.io/pypa/manylinux2010_i686:2022-08-05-4535177
manylinux2014 = quay.io/pypa/manylinux2014_i686:2024.09.09-0
manylinux2014 = quay.io/pypa/manylinux2014_i686:2025.03.23-1
manylinux_2_24 = quay.io/pypa/manylinux_2_24_i686:2022-12-26-0d38463
[aarch64]
manylinux2014 = quay.io/pypa/manylinux2014_aarch64:2024.09.09-0
manylinux2014 = quay.io/pypa/manylinux2014_aarch64:2025.03.23-1
manylinux_2_24 = quay.io/pypa/manylinux_2_24_aarch64:2022-12-26-0d38463
manylinux_2_28 = quay.io/pypa/manylinux_2_28_aarch64:2024.09.09-0
musllinux_1_1 = quay.io/pypa/musllinux_1_1_aarch64:2024.09.09-0
musllinux_1_2 = quay.io/pypa/musllinux_1_2_aarch64:2024.09.09-0
manylinux_2_28 = quay.io/pypa/manylinux_2_28_aarch64:2025.03.23-1
musllinux_1_1 = quay.io/pypa/musllinux_1_1_aarch64:2024.10.26-1
musllinux_1_2 = quay.io/pypa/musllinux_1_2_aarch64:2025.03.23-1
[ppc64le]
manylinux2014 = quay.io/pypa/manylinux2014_ppc64le:2024.09.09-0
manylinux2014 = quay.io/pypa/manylinux2014_ppc64le:2025.03.23-1
manylinux_2_24 = quay.io/pypa/manylinux_2_24_ppc64le:2022-12-26-0d38463
manylinux_2_28 = quay.io/pypa/manylinux_2_28_ppc64le:2024.09.09-0
musllinux_1_1 = quay.io/pypa/musllinux_1_1_ppc64le:2024.09.09-0
musllinux_1_2 = quay.io/pypa/musllinux_1_2_ppc64le:2024.09.09-0
manylinux_2_28 = quay.io/pypa/manylinux_2_28_ppc64le:2025.03.23-1
musllinux_1_1 = quay.io/pypa/musllinux_1_1_ppc64le:2024.10.26-1
musllinux_1_2 = quay.io/pypa/musllinux_1_2_ppc64le:2025.03.23-1
[s390x]
manylinux2014 = quay.io/pypa/manylinux2014_s390x:2024.09.09-0
manylinux2014 = quay.io/pypa/manylinux2014_s390x:2025.03.23-1
manylinux_2_24 = quay.io/pypa/manylinux_2_24_s390x:2022-12-26-0d38463
manylinux_2_28 = quay.io/pypa/manylinux_2_28_s390x:2024.09.09-0
musllinux_1_1 = quay.io/pypa/musllinux_1_1_s390x:2024.09.09-0
musllinux_1_2 = quay.io/pypa/musllinux_1_2_s390x:2024.09.09-0
manylinux_2_28 = quay.io/pypa/manylinux_2_28_s390x:2025.03.23-1
musllinux_1_1 = quay.io/pypa/musllinux_1_1_s390x:2024.10.26-1
musllinux_1_2 = quay.io/pypa/musllinux_1_2_s390x:2025.03.23-1
[pypy_aarch64]
manylinux2014 = quay.io/pypa/manylinux2014_aarch64:2024.09.09-0
manylinux2014 = quay.io/pypa/manylinux2014_aarch64:2025.03.23-1
manylinux_2_24 = quay.io/pypa/manylinux_2_24_aarch64:2022-12-26-0d38463
manylinux_2_28 = quay.io/pypa/manylinux_2_28_aarch64:2024.09.09-0
manylinux_2_28 = quay.io/pypa/manylinux_2_28_aarch64:2025.03.23-1
[armv7l]
manylinux_2_31 = quay.io/pypa/manylinux_2_31_armv7l:2025.03.23-1
musllinux_1_2 = quay.io/pypa/musllinux_1_2_armv7l:2025.03.23-1
+1 -1
View File
@@ -1,2 +1,2 @@
py36 = { version = "20.21.1", url = "https://github.com/pypa/get-virtualenv/blob/20.21.1/public/virtualenv.pyz?raw=true" }
default = { version = "20.26.4", url = "https://github.com/pypa/get-virtualenv/blob/20.26.4/public/virtualenv.pyz?raw=true" }
default = { version = "20.29.3", url = "https://github.com/pypa/get-virtualenv/blob/20.29.3/public/virtualenv.pyz?raw=true" }
-1
View File
@@ -9,7 +9,6 @@ __all__ = (
"PLATFORMS",
"PathOrStr",
"PlatformName",
"PLATFORMS",
"PopenBytes",
)
+104 -20
View File
@@ -1,6 +1,7 @@
from __future__ import annotations
import contextlib
import enum
import fnmatch
import itertools
import os
@@ -19,11 +20,11 @@ from collections import defaultdict
from collections.abc import Generator, Iterable, Mapping, MutableMapping, Sequence
from dataclasses import dataclass
from enum import Enum
from functools import lru_cache
from functools import lru_cache, total_ordering
from pathlib import Path, PurePath
from tempfile import TemporaryDirectory
from time import sleep
from typing import Any, ClassVar, Final, Literal, TextIO, TypeVar
from typing import Any, Final, Literal, TextIO, TypeVar
from zipfile import ZipFile
import bracex
@@ -37,10 +38,12 @@ from platformdirs import user_cache_path
from ._compat import tomllib
from .architecture import Architecture
from .errors import FatalError
from .typing import PathOrStr, PlatformName
__all__ = [
"MANYLINUX_ARCHS",
"EnableGroups",
"call",
"chdir",
"combine_constraints",
@@ -66,6 +69,16 @@ free_thread_enable_313: Final[Path] = resources_dir / "free-threaded-enable-313.
test_fail_cwd_file: Final[Path] = resources_dir / "testing_temp_dir_file.py"
class EnableGroups(enum.Enum):
"""
Groups of build selectors that are not enabled by default.
"""
CPythonFreeThreading = "cpython-freethreading"
CPythonPrerelease = "cpython-prerelease"
PyPy = "pypy"
MANYLINUX_ARCHS: Final[tuple[str, ...]] = (
"x86_64",
"i686",
@@ -73,6 +86,7 @@ MANYLINUX_ARCHS: Final[tuple[str, ...]] = (
"aarch64",
"ppc64le",
"s390x",
"armv7l",
"pypy_aarch64",
"pypy_i686",
)
@@ -83,6 +97,7 @@ MUSLLINUX_ARCHS: Final[tuple[str, ...]] = (
"aarch64",
"ppc64le",
"s390x",
"armv7l",
)
DEFAULT_CIBW_CACHE_PATH: Final[Path] = user_cache_path(appname="cibuildwheel", appauthor="pypa")
@@ -126,13 +141,32 @@ def call(
args_ = [str(arg) for arg in args]
# print the command executing for the logs
print("+ " + " ".join(shlex.quote(a) for a in args_))
kwargs: dict[str, Any] = {}
if capture_stdout:
kwargs["universal_newlines"] = True
kwargs["stdout"] = subprocess.PIPE
result = subprocess.run(args_, check=True, shell=IS_WIN, env=env, cwd=cwd, **kwargs)
# workaround platform behaviour differences outlined
# in https://github.com/python/cpython/issues/52803
path_env = env if env is not None else os.environ
path = path_env.get("PATH", None)
executable = shutil.which(args_[0], path=path)
if executable is None:
msg = f"Couldn't find {args_[0]!r} in PATH {path!r}"
raise FatalError(msg)
args_[0] = executable
try:
result = subprocess.run(
args_,
check=True,
shell=IS_WIN,
env=env,
cwd=cwd,
capture_output=capture_stdout,
text=capture_stdout,
)
except subprocess.CalledProcessError as e:
if capture_stdout:
sys.stderr.write(e.stderr)
raise
if not capture_stdout:
return None
sys.stderr.write(result.stderr)
return typing.cast(str, result.stdout)
@@ -246,12 +280,7 @@ class BuildSelector:
build_config: str
skip_config: str
requires_python: SpecifierSet | None = None
# a pattern that skips prerelease versions, when include_prereleases is False.
PRERELEASE_SKIP: ClassVar[str] = ""
prerelease_pythons: bool = False
free_threaded_support: bool = False
enable: frozenset[EnableGroups] = frozenset()
def __call__(self, build_id: str) -> bool:
# Filter build selectors by python_requires if set
@@ -265,12 +294,16 @@ class BuildSelector:
if not self.requires_python.contains(version):
return False
# filter out the prerelease pythons if self.prerelease_pythons is False
if not self.prerelease_pythons and selector_matches(self.PRERELEASE_SKIP, build_id):
# filter out groups that are not enabled
if EnableGroups.CPythonFreeThreading not in self.enable and selector_matches(
"cp3??t-*", build_id
):
return False
# filter out free threaded pythons if self.free_threaded_support is False
if not self.free_threaded_support and selector_matches("*t-*", build_id):
if EnableGroups.CPythonPrerelease not in self.enable and selector_matches(
"cp314*", build_id
):
return False
if EnableGroups.PyPy not in self.enable and selector_matches("pp*", build_id):
return False
should_build = selector_matches(self.build_config, build_id)
@@ -283,8 +316,7 @@ class BuildSelector:
"build_config": self.build_config,
"skip_config": self.skip_config,
"requires_python": str(self.requires_python),
"prerelease_pythons": self.prerelease_pythons,
"free_threaded_support": self.free_threaded_support,
"enable": sorted(group.value for group in self.enable),
}
@@ -673,6 +705,10 @@ def virtualenv(
dependency_constraint_flags are ignored since nothing is installed in the
venv. Otherwise, pip is installed, and setuptools + wheel if Python < 3.12.
"""
# virtualenv may fail if this is a symlink.
python = python.resolve()
assert python.exists()
if use_uv:
@@ -899,3 +935,51 @@ def combine_constraints(
env["UV_CONSTRAINT"] = env["PIP_CONSTRAINT"] = " ".join(
c for c in [our_constraints, user_constraints] if c
)
@total_ordering
class FlexibleVersion:
version_str: str
version_parts: tuple[int, ...]
suffix: str
def __init__(self, version_str: str) -> None:
self.version_str = version_str
# Split into numeric parts and the optional suffix
match = re.match(r"^[v]?(\d+(\.\d+)*)(.*)$", version_str)
if not match:
msg = f"Invalid version string: {version_str}"
raise ValueError(msg)
version_part, _, suffix = match.groups()
# Convert numeric version part into a tuple of integers
self.version_parts = tuple(map(int, version_part.split(".")))
self.suffix = suffix.strip() if suffix else ""
# Normalize by removing trailing zeros
self.version_parts = self._remove_trailing_zeros(self.version_parts)
def _remove_trailing_zeros(self, parts: tuple[int, ...]) -> tuple[int, ...]:
# Remove trailing zeros for accurate comparisons
# without this, "3.0" would be considered greater than "3"
while parts and parts[-1] == 0:
parts = parts[:-1]
return parts
def __eq__(self, other: object) -> bool:
if not isinstance(other, FlexibleVersion):
raise NotImplementedError()
return (self.version_parts, self.suffix) == (other.version_parts, other.suffix)
def __lt__(self, other: object) -> bool:
if not isinstance(other, FlexibleVersion):
raise NotImplementedError()
return (self.version_parts, self.suffix) < (other.version_parts, other.suffix)
def __repr__(self) -> str:
return f"FlexibleVersion('{self.version_str}')"
def __str__(self) -> str:
return self.version_str
+21 -15
View File
@@ -225,6 +225,14 @@ def setup_rust_cross_compile(
)
def can_use_uv(python_configuration: PythonConfiguration) -> bool:
conditions = (
Version(python_configuration.version) >= Version("3.8"),
not python_configuration.identifier.startswith("pp38-"),
)
return all(conditions)
def setup_python(
tmp: Path,
python_configuration: PythonConfiguration,
@@ -254,11 +262,10 @@ def setup_python(
raise ValueError(msg)
assert base_python.exists()
use_uv = (
build_frontend == "build[uv]"
and Version(python_configuration.version) >= Version("3.8")
and not python_configuration.identifier.startswith("pp38-")
)
if build_frontend == "build[uv]" and not can_use_uv(python_configuration):
build_frontend = "build"
use_uv = build_frontend == "build[uv]"
uv_path = find_uv()
log.step("Setting up build environment...")
@@ -295,22 +302,22 @@ def setup_python(
env = environment.as_dictionary(prev_environment=env)
# check what Python version we're on
call("where", "python", env=env)
call("python", "--version", env=env)
call("python", "-c", "\"import struct; print(struct.calcsize('P') * 8)\"", env=env)
where_python = call("where", "python", env=env, capture_stdout=True).splitlines()[0].strip()
print(where_python)
if where_python != str(venv_path / "Scripts" / "python.exe"):
msg = "python available on PATH doesn't match our installed instance. If you have modified PATH, ensure that you don't overwrite cibuildwheel's entry or insert python above it."
raise errors.FatalError(msg)
call("python", "--version", env=env)
call("python", "-c", "\"import struct; print(struct.calcsize('P') * 8)\"", env=env)
# check what pip version we're on
if not use_uv:
assert (venv_path / "Scripts" / "pip.exe").exists()
where_pip = call("where", "pip", env=env, capture_stdout=True).splitlines()[0].strip()
print(where_pip)
if where_pip.strip() != str(venv_path / "Scripts" / "pip.exe"):
msg = "pip available on PATH doesn't match our installed instance. If you have modified PATH, ensure that you don't overwrite cibuildwheel's entry or insert pip above it."
raise errors.FatalError(msg)
call("pip", "--version", env=env)
log.step("Installing build tools...")
@@ -368,11 +375,7 @@ def build(options: Options, tmp_path: Path) -> None:
for config in python_configurations:
build_options = options.build_options(config.identifier)
build_frontend = build_options.build_frontend or BuildFrontendConfig("pip")
use_uv = (
build_frontend.name == "build[uv]"
and Version(config.version) >= Version("3.8")
and not config.identifier.startswith("pp38-")
)
use_uv = build_frontend.name == "build[uv]" and can_use_uv(config)
log.build_start(config.identifier)
identifier_tmp_dir = tmp_path / config.identifier
@@ -487,7 +490,10 @@ def build(options: Options, tmp_path: Path) -> None:
else:
shutil.move(str(built_wheel), repaired_wheel_dir)
repaired_wheel = next(repaired_wheel_dir.glob("*.whl"))
try:
repaired_wheel = next(repaired_wheel_dir.glob("*.whl"))
except StopIteration:
raise errors.RepairStepProducedNoWheelError() from None
if repaired_wheel.name in {wheel.name for wheel in built_wheels}:
raise errors.AlreadyBuiltWheelError(repaired_wheel.name)
+69
View File
@@ -4,6 +4,75 @@ title: Changelog
# Changelog
### v2.23.2
_24 March 2025_
- 🐛 Workaround an issue with pyodide builds when running cibuildwheel with a Python that was installed via UV (#2328 via #2331)
- 🛠 Dependency updates, including a manylinux update that fixes an ['undefined symbol' error](https://github.com/pypa/manylinux/issues/1760) in gcc-toolset (#2334)
### v2.23.1
_15 March 2025_
- ⚠️ Added warnings when the shorthand values `manylinux1`, `manylinux2010`, `manylinux_2_24`, and `musllinux_1_1` are used to specify the images in linux builds. The shorthand to these (unmaintainted) images will be removed in v3.0. If you want to keep using these images, explicitly opt-in using the full image URL, which can be found in [this file](https://github.com/pypa/cibuildwheel/blob/v2.23.1/cibuildwheel/resources/pinned_docker_images.cfg). (#2312)
- 🛠 Dependency updates, including a manylinux update which fixes an [issue with rustup](https://github.com/pypa/cibuildwheel/issues/2303). (#2315)
### v2.23.0
_1 March 2025_
- ✨ Adds official support for the new GitHub Actions Arm runners. In fact these worked out-of-the-box, now we include them in our tests and example configs. (#2135 via #2281)
- ✨ Adds support for building PyPy 3.11 wheels (#2268 via #2281)
- 🛠 Adopts the beta pypa/manylinux image for armv7l builds (#2269 via #2281)
- 🛠 Dependency updates, including Pyodide 0.27 (#2117 and #2281)
### v2.22.0
_23 November 2024_
- 🌟 Added a new `CIBW_ENABLE`/`enable` feature that replaces `CIBW_FREETHREADED_SUPPORT`/`free-threaded-support` and `CIBW_PRERELEASE_PYTHONS` with a system that supports both. In cibuildwheel 3, this will also include a PyPy setting and the deprecated options will be removed. (#2048)
- 🌟 [Dependency groups](https://peps.python.org/pep-0735/) are now supported for tests. Use `CIBW_TEST_GROUPS`/`test-groups` to specify groups in `[dependency-groups]` for testing. (#2063)
- 🌟 Support for the experimental Ubuntu-based ARMv7l manylinux image (#2052)
- ✨ Show a warning when cibuildwheel is run from Python 3.10 or older; cibuildwheel 3.0 will require Python 3.11 or newer as host (#2050)
- 🐛 Fix issue with stderr interfering with checking the docker version (#2074)
- 🛠 Python 3.9 is now used in `CIBW_BEFORE_ALL`/`before-all` on linux, replacing 3.8, which is now EoL (#2043)
- 🛠 Error messages for producing a pure-Python wheel are slightly more informative (#2044)
- 🛠 Better error when `uname -m` fails on ARM (#2049)
- 🛠 Better error when repair fails and docs for abi3audit on Windows (#2058)
- 🛠 Better error when `manylinux-interpreters ensure` fails (#2066)
- 🛠 Update Pyodide to 0.26.4, and adapt to the unbundled pyodide-build (now 0.29) (#2090)
- 🛠 Now cibuildwheel uses dependency-groups for development dependencies (#2064, #2085)
- 📚 Docs updates and tidy ups (#2061, #2067, #2072)
### v2.21.3
_9 October 2024_
- 🛠 Update CPython 3.13 to 3.13.0 final release (#2032)
- 📚 Docs updates and tidy ups (#2035)
### v2.21.2
_2 October 2024_
- ✨ Adds support for building 32-bit armv7l wheels on musllinux. On a Linux system with emulation set up, set [CIBW_ARCHS](https://cibuildwheel.pypa.io/en/stable/options/#archs) to `armv7l` on Linux to try it out if you're interested! (#2017)
- 🐛 Fix Linux Podman builds on some systems (#2016)
- ✨ Adds official support for running on Python 3.13 (#2026)
- 🛠 Update CPython 3.13 to 3.13.0rc3 (#2029)
Note: the default [manylinux image](https://cibuildwheel.pypa.io/en/stable/options/#linux-image) is **scheduled to change** from `manylinux2014` to `manylinux_2_28` in a cibuildwheel release on or after **6th May 2025** - you can set the value now to avoid getting upgraded if you want. (#1992)
### v2.21.1
_16 September 2024_
- 🐛 Fix a bug in the Linux build, where files copied to the container would have invalid ownership permissions (#2007)
- 🐛 Fix a bug on Windows where cibuildwheel would call upon `uv` to install dependencies for versions of CPython that it does not support (#2005)
- 🐛 Fix a bug where `uv 0.4.10` would not use the right Python when testing on Linux. (#2008)
- 🛠 Bump our documentation pins, fixes an issue with a missing package (#2011)
### v2.21.0
_13 September 2024_
+28 -10
View File
@@ -17,11 +17,11 @@ Everyone contributing to the cibuildwheel project is expected to follow the [PSF
- `cibuildwheel` should wrap the complexity of wheel building.
- The user interface to `cibuildwheel` is the build script (e.g. `.travis.yml`). Feature additions should not increase the complexity of this script.
- Options should be environment variables (these lend themselves better to YML config files). They should be prefixed with `CIBW_`.
- Options should be generalise to all platforms. If platform-specific options are required, they should be namespaced e.g. `CIBW_TEST_COMMAND_MACOS`
- Options should be generalised to all platforms. If platform-specific options are required, they should be namespaced e.g. `CIBW_TEST_COMMAND_MACOS`
Other notes:
- The platforms are very similar, until they're not. I'd rather have straight-forward code than totally DRY code, so let's keep airy platform abstractions to a minimum.
- The platforms are very similar, until they're not. I'd rather have straightforward code than totally DRY code, so let's keep airy platform abstractions to a minimum.
- I might want to break the options into a shared config file one day, so that config is more easily shared. That has motivated some of the design decisions.
### cibuildwheel's relationship with build errors
@@ -82,14 +82,11 @@ A few notes-
- Running the macOS integration tests requires _system installs_ of Python from python.org for all the versions that are tested. We won't attempt to install these when running locally, but you can do so manually using the URL in the error message that is printed when the install is not found.
#### Making a venv
#### Running pytest directly
More advanced users might prefer to invoke pytest directly-
More advanced users might prefer to invoke pytest directly. Set up a [dev environment](#setting-up-a-dev-environment), then,
```bash
python3 -m venv .venv
source .venv/bin/activate
pip install -e .[dev]
# run the unit tests
pytest unit_test
# run the whole integration test suite
@@ -102,7 +99,7 @@ CIBW_PLATFORM=linux pytest test -k test_build_frontend_args
### Linting, docs
Most developer tasks have a nox interface. This allows you to very simply run tasks without worrying about setting up a development environment (as shown below). This is a slower than setting up a development environment and reusing it, but has the (important) benefit of being highly reproducible; an earlier run does not affect a current run, or anything else on your machine.
Most developer tasks have a nox interface. This allows you to very simply run tasks without worrying about setting up a development environment (as shown below). This is slower than setting up a development environment and reusing it, but has the (important) benefit of being highly reproducible; an earlier run does not affect a current run, or anything else on your machine.
You can see a list of sessions by typing `nox -l`; here are a few common ones:
@@ -113,12 +110,33 @@ nox -s docs # Build and serve the documentation
nox -s build # Make SDist and wheel
```
More advanced users can run the update scripts. `update_pins` should work directly, but `update_constraints` needs all versions of Python installed. If you don't want to do that locally, a fast way to run it to use docker to run nox:
More advanced users can run the update scripts:
```console
docker run --rm -itv $PWD:/src -w /src quay.io/pypa/manylinux_2_24_x86_64:latest pipx run nox -s update_constraints
nox -s update_constraints # update all constraints files in cibuildwheel/resources
nox -s update_pins # update tools, python interpreters & docker images used by cibuildwheel
```
### Setting up a dev environment
A dev environment isn't required for any of the `nox` tasks above. However, a dev environment is still useful, to be able to point an editor at, and a few other jobs.
cibuildwheel uses dependency groups. Set up a dev environment with UV by doing
```bash
uv sync
```
Or, if you're not using `uv`, you can do:
```bash
python3 -m venv .venv
source .venv/bin/activate
pipx run dependency-groups dev | xargs pip install -e.
```
Your virtualenv is at `.venv`.
## Maintainer notes
### Testing sample configs
+2 -3
View File
@@ -8,7 +8,7 @@ Building Python wheels with modern C++ standards (C++11 and later) requires a fe
## manylinux1 and C++14
The old `manylinux1` image (based on CentOS 5) contains a version of GCC and libstdc++ that only supports C++11 and earlier standards. There are however ways to compile wheels with the C++14 standard (and later): https://github.com/pypa/manylinux/issues/118
The past end-of-life `manylinux1` image (based on CentOS 5) contains a version of GCC and libstdc++ that only supports C++11 and earlier standards. There are however ways to compile wheels with the C++14 standard (and later): https://github.com/pypa/manylinux/issues/118
`manylinux2010` and `manylinux2014` are newer and support all C++ standards (up to C++17).
@@ -18,9 +18,8 @@ OS X/macOS allows you to specify a so-called "deployment target" version that wi
However, to enable modern C++ standards, the deployment target needs to be set high enough (since older OS X/macOS versions did not have the necessary modern C++ standard library).
To get C++11 and C++14 support, `MACOSX_DEPLOYMENT_TARGET` needs to be set to (at least) `"10.9"`. By default, `cibuildwheel` already does this, building 64-bit-only wheels for macOS 10.9 and later.
To get C++17 support, Xcode 9.3+ is needed, requiring at least macOS 10.13 on the build machine. To use C++17 library features and link against the C++ runtime library, set `MACOSX_DEPLOYMENT_TARGET` to `"10.13"` or `"10.14"` (or higher) - macOS 10.13 offers partial C++17 support (e.g., the filesystem header is in experimental, offering `#include <experimental/filesystem>` instead of `#include <filesystem>`); macOS 10.14 has full C++17 support.
To get C++17 support, Xcode 9.3+ is needed, requiring at least macOS 10.13 on the build machine. To use C++17 library features and link against the C++ runtime library, set `MACOSX_DEPLOYMENT_TARGET` to `"10.13"` or `"10.14"` (or higher) - macOS 10.13 offers partial C++17 support (e.g., the filesystem header is in experimental, offering `#include <experimental/filesystem>` instead of `#include <filesystem>`); macOS 10.14 has full C++17 support. CPython 3.12+ require 10.13+ anyway.
However, if only C++17 compiler and standard template library (STL) features are used (not needing a C++17 runtime) it might be possible to set `MACOSX_DEPLOYMENT_TARGET` to a lower value, such as `"10.9"`. To find out if this is the case, try compiling and running with a lower `MACOSX_DEPLOYMENT_TARGET`: if C++17 features are used that require a more recent deployment target, building the wheel should fail.
+1 -1
View File
@@ -86,7 +86,7 @@ This requires setting this GitHub workflow in your project's PyPI settings (for
You should use Dependabot to keep the publish action up to date. In the above
example, the same name (the default, "artifact" is used for all upload-artifact
runs, so we can just download all of the in one step into a common directory.
runs, so we can just download all of them in one step into a common directory.
See
[`examples/github-deploy.yml`](https://github.com/pypa/cibuildwheel/blob/main/examples/github-deploy.yml)
+10
View File
@@ -258,6 +258,16 @@ h1, h2, h3, h4, h5, h6 {
font-size: 80%;
}
.rst-content table.docutils td code,
.rst-content table.docutils th code,
.rst-content table.field-list td code,
.rst-content table.field-list th code,
.wy-table td code,
.wy-table th code {
/* table elements are already made smaller, the code styling on top of that makes the text too small */
font-size: 82.5%;
}
/* expand all the toctree entries */
.wy-menu-vertical .toctree-l1.current .toctree-l2>ul,
+6 -6
View File
@@ -10,7 +10,7 @@ title: Tips and tricks
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 `manylinux2010` or `manylinux2014`, `apt-get` for `manylinux_2_24`, `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 `manylinux2010` or `manylinux2014`, `apt-get` for `manylinux_2_24`/`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.
`cibuildwheel` supports this by providing the [`CIBW_ENVIRONMENT`](options.md#environment) and [`CIBW_BEFORE_ALL`](options.md#before-all) options to setup the build environment inside the running container.
@@ -133,7 +133,7 @@ myextension = Extension(
### Automatic updates using Dependabot {: #automatic-updates}
Selecting a moving target (like the latest release) is generally a bad idea in CI. If something breaks, you can't tell whether it was your code or an upstream update that caused the breakage, and in a worse-case scenario, it could occur during a release.
Selecting a moving target (like the latest release) is generally a bad idea in CI. If something breaks, you can't tell whether it was your code or an upstream update that caused the breakage, and in a worst-case scenario, it could occur during a release.
There are two suggested methods for keeping cibuildwheel up to date that instead involve scheduled pull requests using GitHub's Dependabot.
@@ -142,7 +142,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@v2.21.0
uses: pypa/cibuildwheel@v2.23.2
```
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.
@@ -164,7 +164,7 @@ The second option, and the only one that supports other CI systems, is using a `
```bash
# requirements-cibw.txt
cibuildwheel==2.21.0
cibuildwheel==2.23.2
```
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:
@@ -184,7 +184,7 @@ This will also try to update other pins in all requirement files, so be sure you
### Alternatives to cibuildwheel options {: #cibw-options-alternatives}
cibuildwheel provides lots of opportunities to configure the build
environment. However, you might consider adding this build configuration into
environment. However, you might consider adding this build configuration into
the package itself - in general, this is preferred, because users of your
package 'sdist' will also benefit.
@@ -328,7 +328,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==2.21.0 --output-dir wheelhouse
pipx run cibuildwheel==2.23.2 --output-dir wheelhouse
pipx run twine upload wheelhouse/*.whl
```
+1 -1
View File
@@ -9,7 +9,7 @@ from typing import Any
def define_env(env: Any) -> None:
"Hook function for mkdocs-macros"
@env.macro
@env.macro # type: ignore[misc]
def subprocess_run(*args: str) -> str:
"Run a subprocess and return the stdout"
env = os.environ.copy()
+167 -98
View File
@@ -288,25 +288,36 @@ When setting the options, you can use shell-style globbing syntax, as per [fnmat
<div class="build-id-table-marker"></div>
| | macOS | Windows | Linux Intel | Linux Other |
|---------------|------------------------------------------------------------------------|-----------------------------------------------------|-----------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Python 3.6 | cp36-macosx_x86_64 | cp36-win_amd64<br/>cp36-win32 | cp36-manylinux_x86_64<br/>cp36-manylinux_i686<br/>cp36-musllinux_x86_64<br/>cp36-musllinux_i686 | cp36-manylinux_aarch64<br/>cp36-manylinux_ppc64le<br/>cp36-manylinux_s390x<br/>cp36-musllinux_aarch64<br/>cp36-musllinux_ppc64le<br/>cp36-musllinux_s390x |
| Python 3.7 | cp37-macosx_x86_64 | cp37-win_amd64<br/>cp37-win32 | cp37-manylinux_x86_64<br/>cp37-manylinux_i686<br/>cp37-musllinux_x86_64<br/>cp37-musllinux_i686 | cp37-manylinux_aarch64<br/>cp37-manylinux_ppc64le<br/>cp37-manylinux_s390x<br/>cp37-musllinux_aarch64<br/>cp37-musllinux_ppc64le<br/>cp37-musllinux_s390x |
| Python 3.8 | cp38-macosx_x86_64<br/>cp38-macosx_universal2<br/>cp38-macosx_arm64 | cp38-win_amd64<br/>cp38-win32 | cp38-manylinux_x86_64<br/>cp38-manylinux_i686<br/>cp38-musllinux_x86_64<br/>cp38-musllinux_i686 | cp38-manylinux_aarch64<br/>cp38-manylinux_ppc64le<br/>cp38-manylinux_s390x<br/>cp38-musllinux_aarch64<br/>cp38-musllinux_ppc64le<br/>cp38-musllinux_s390x |
| Python 3.9 | cp39-macosx_x86_64<br/>cp39-macosx_universal2<br/>cp39-macosx_arm64 | cp39-win_amd64<br/>cp39-win32<br/>cp39-win_arm64 | cp39-manylinux_x86_64<br/>cp39-manylinux_i686<br/>cp39-musllinux_x86_64<br/>cp39-musllinux_i686 | cp39-manylinux_aarch64<br/>cp39-manylinux_ppc64le<br/>cp39-manylinux_s390x<br/>cp39-musllinux_aarch64<br/>cp39-musllinux_ppc64le<br/>cp39-musllinux_s390x |
| 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-musllinux_aarch64<br/>cp310-musllinux_ppc64le<br/>cp310-musllinux_s390x |
| 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-musllinux_aarch64<br/>cp311-musllinux_ppc64le<br/>cp311-musllinux_s390x |
| 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-musllinux_aarch64<br/>cp312-musllinux_ppc64le<br/>cp312-musllinux_s390x |
| 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-musllinux_aarch64<br/>cp313-musllinux_ppc64le<br/>cp313-musllinux_s390x |
| PyPy3.7 v7.3 | pp37-macosx_x86_64 | pp37-win_amd64 | pp37-manylinux_x86_64<br/>pp37-manylinux_i686 | pp37-manylinux_aarch64 |
| 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 |
| | macOS | Windows | Linux Intel | Linux Other |
|---------------|------------------------------------------------------------------------|-----------------------------------------------------|-----------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Python 3.6 | cp36-macosx_x86_64 | cp36-win_amd64<br/>cp36-win32 | cp36-manylinux_x86_64<br/>cp36-manylinux_i686<br/>cp36-musllinux_x86_64<br/>cp36-musllinux_i686 | cp36-manylinux_aarch64<br/>cp36-manylinux_ppc64le<br/>cp36-manylinux_s390x<br/>cp36-manylinux_armv7l<br/>cp36-musllinux_aarch64<br/>cp36-musllinux_ppc64le<br/>cp36-musllinux_s390x<br/>cp36-musllinux_armv7l |
| Python 3.7 | cp37-macosx_x86_64 | cp37-win_amd64<br/>cp37-win32 | cp37-manylinux_x86_64<br/>cp37-manylinux_i686<br/>cp37-musllinux_x86_64<br/>cp37-musllinux_i686 | cp37-manylinux_aarch64<br/>cp37-manylinux_ppc64le<br/>cp37-manylinux_s390x<br/>cp37-manylinux_armv7l<br/>cp37-musllinux_aarch64<br/>cp37-musllinux_ppc64le<br/>cp37-musllinux_s390x<br/>cp37-musllinux_armv7l |
| Python 3.8 | cp38-macosx_x86_64<br/>cp38-macosx_universal2<br/>cp38-macosx_arm64 | cp38-win_amd64<br/>cp38-win32 | cp38-manylinux_x86_64<br/>cp38-manylinux_i686<br/>cp38-musllinux_x86_64<br/>cp38-musllinux_i686 | cp38-manylinux_aarch64<br/>cp38-manylinux_ppc64le<br/>cp38-manylinux_s390x<br/>cp38-manylinux_armv7l<br/>cp38-musllinux_aarch64<br/>cp38-musllinux_ppc64le<br/>cp38-musllinux_s390x<br/>cp38-musllinux_armv7l |
| Python 3.9 | cp39-macosx_x86_64<br/>cp39-macosx_universal2<br/>cp39-macosx_arm64 | cp39-win_amd64<br/>cp39-win32<br/>cp39-win_arm64 | cp39-manylinux_x86_64<br/>cp39-manylinux_i686<br/>cp39-musllinux_x86_64<br/>cp39-musllinux_i686 | cp39-manylinux_aarch64<br/>cp39-manylinux_ppc64le<br/>cp39-manylinux_s390x<br/>cp39-manylinux_armv7l<br/>cp39-musllinux_aarch64<br/>cp39-musllinux_ppc64le<br/>cp39-musllinux_s390x<br/>cp39-musllinux_armv7l |
| 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-musllinux_aarch64<br/>cp310-musllinux_ppc64le<br/>cp310-musllinux_s390x<br/>cp310-musllinux_armv7l |
| 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-musllinux_aarch64<br/>cp311-musllinux_ppc64le<br/>cp311-musllinux_s390x<br/>cp311-musllinux_armv7l |
| 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-musllinux_armv7l<br/>cp312-musllinux_ppc64le<br/>cp312-musllinux_s390x<br/>cp312-musllinux_armv7l |
| 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-musllinux_aarch64<br/>cp313-musllinux_ppc64le<br/>cp313-musllinux_s390x<br/>cp313-musllinux_armv7l |
| PyPy3.7 v7.3 | pp37-macosx_x86_64 | pp37-win_amd64 | pp37-manylinux_x86_64<br/>pp37-manylinux_i686 | pp37-manylinux_aarch64 |
| 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 |
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).
For CPython, the minimally supported macOS version is 10.9; for PyPy 3.7, macOS 10.13 or higher is required.
The lowest value you can set `MACOSX_DEPLOYMENT_TARGET` is as follows:
| Arch | Python version range | Minimum target |
|-------|----------------------|----------------|
| Intel | CPython 3.6-3.11 | 10.9 |
| Intel | CPython 3.12+ | 10.13 |
| AS | CPython or PyPy | 11 |
| Intel | PyPy 3.7-3.8 | 10.13 |
| Intel | PyPy 3.9+ | 10.15 |
If you set the value lower, cibuildwheel will cap it to the lowest supported value for each target as needed.
Windows arm64 platform support is experimental.
@@ -412,52 +423,6 @@ See the [cibuildwheel 1 documentation](https://cibuildwheel.pypa.io/en/1.x/) for
}
</style>
### `CIBW_FREE_THREADED_SUPPORT` {: #free-threaded-support}
> Choose whether free-threaded variants should be built
[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.
Building for free-threaded variants is disabled by default.
Building can be enabled by setting this option to `true`. The free-threaded compatible wheels will be built in addition to the standard wheels.
This option doesn't support overrides.
If you need to enable/disable it per platform or python version, set this option to `true` and use [`CIBW_BUILD`](#build-skip)/[`CIBW_SKIP`](#build-skip) options to filter the builds.
The build identifiers for those variants have a `t` suffix in their `python_tag` (e.g. `cp313t-manylinux_x86_64`)
!!! note
This feature is experimental: [Whats New In Python 3.13](https://docs.python.org/3.13/whatsnew/3.13.html#free-threaded-cpython)
#### Examples
!!! tab examples "Environment variables"
```yaml
# Enable free-threaded support
CIBW_FREE_THREADED_SUPPORT: 1
# Skip building free-threaded compatible wheels on Windows
CIBW_FREE_THREADED_SUPPORT: 1
CIBW_SKIP: *t-win*
```
It is generally recommended to use `free-threaded-support` in a config file as you can statically declare that you
support free-threaded builds.
!!! tab examples "pyproject.toml"
```toml
[tool.cibuildwheel]
# Enable free-threaded support
free-threaded-support = true
# Skip building free-threaded compatible wheels on Windows
free-threaded-support = true
skip = "*t-win*"
```
### `CIBW_ARCHS` {: #archs}
> Change the architectures built on your machine by default.
@@ -475,7 +440,7 @@ machine, provided the cross-compiling tools are installed.
Options:
- Linux: `x86_64` `i686` `aarch64` `ppc64le` `s390x`
- Linux: `x86_64` `i686` `aarch64` `ppc64le` `s390x` `armv7l`
- macOS: `x86_64` `arm64` `universal2`
- Windows: `AMD64` `x86` `ARM64`
- Pyodide: `wasm32`
@@ -593,24 +558,53 @@ the package is compatible with all versions of Python that it can build.
CIBW_PROJECT_REQUIRES_PYTHON: ">=3.6"
```
### `CIBW_PRERELEASE_PYTHONS` {: #prerelease-pythons}
> Enable building with pre-release versions of Python if available
### `CIBW_ENABLE` {: #enable}
> Enable building with extra categories of selectors present.
This option lets you opt-in to non-default builds, like pre-releases and
free-threaded Python. These are not included by default to give a nice default
for new users, but can be added to the selectors available here. The allowed
values are:
- `cypython-prerelease`: Enables beta versions of Pythons if any are available
(May-July, approximately). For backward compatibility, `CIBW_PRERELEASE_PYTHONS`
is also supported until cibuildwheel 3.
- `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 while they are experimental.
The build identifiers for those variants have a `t` suffix in their
`python_tag` (e.g. `cp313t-manylinux_x86_64`). For backward compatibility,
`CIBW_FREE_THREADED_SUPPORT` is also supported until cibuildwheel 3.
- `pypy`: Enable PyPy. For backward compatibility, this is always enabled until
cibuildwheel 3 is released.
During the beta period, when new versions of Python are being tested,
cibuildwheel will often gain early support for beta releases. If you would
like to test wheel building with these versions, you can enable this flag.
!!! caution
This option is provided for testing purposes only. It is not
recommended to distribute wheels built when `CIBW_PRERELEASE_PYTHONS` is
set, such as uploading to PyPI. Please _do not_ upload these wheels to
PyPI, as they are not guaranteed to work with the final Python release.
Once Python is ABI stable and enters the release candidate phase, that
version of Python will become available without this flag.
`cpython-prerelease` is provided for testing purposes only. It is not
recommended to distribute wheels built with beta releases, such as
uploading to PyPI. Please _do not_ upload these wheels to PyPI, as they are
not guaranteed to work with the final Python release. Once Python is ABI
stable and enters the release candidate phase, that version of Python will
become available without this flag.
Default: Off (0) if Python is available in beta phase. No effect otherwise.
!!! note
Free threading is experimental: [Whats New In Python 3.13](https://docs.python.org/3.13/whatsnew/3.13.html#free-threaded-cpython)
Default: empty (`pypy` is always injected).
This option doesn't support overrides or platform specific variants; it is
intended as a way to acknowledge that a project is aware that these extra
selectors exist. If you need to enable/disable it per platform or python
version, set this option to `true` and use
[`CIBW_BUILD`](#build-skip)/[`CIBW_SKIP`](#build-skip) options to filter the
builds.
Unlike all other cibuildwheel options, the environment variable setting will
only add to the TOML config; you can't remove an enable by setting an empty or
partial list in environment variables; use `CIBW_SKIP` instead.
This option can also be set using the [command-line option](#command-line) `--prerelease-pythons`. This option is not available in the `pyproject.toml` config.
#### Examples
@@ -618,9 +612,38 @@ This option can also be set using the [command-line option](#command-line) `--pr
```yaml
# Include latest Python beta
CIBW_PRERELEASE_PYTHONS: True
CIBW_ENABLE: cpython-prerelease
# Include free-threaded support
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*
```
It is generally recommended to use `cpython-freethreading` in a config
file as you can statically declare that you support free-threaded builds.
!!! tab examples "pyproject.toml"
```toml
[tool.cibuildwheel]
# Enable free-threaded support
enable = ["cpython-freethreading"]
# Skip building free-threaded compatible wheels on Windows
enable = ["cpython-freethreading"]
skip = "*t-win*"
```
It is generally not recommended to use `cpython-prerelease` in a config file,
as it's intended for testing pre-releases for a 2-3 month period only.
### `CIBW_ALLOW_EMPTY` {: #allow-empty}
> Suppress the error code if no wheels match the specified build identifiers
@@ -953,9 +976,9 @@ Platform-specific environment variables also available:<br/>
In configuration files, you can use a TOML array, and each line will be run sequentially - joined with `&&`.
Note that manylinux_2_24 builds occur inside a Debian9 docker, where
Note that manylinux_2_24/manylinux_2_31 builds occur inside a debian derivative docker container, where
manylinux2010 and manylinux2014 builds occur inside a CentOS one. So for
`manylinux_2_24` the `CIBW_BEFORE_ALL_LINUX` command must use `apt-get -y`
`manylinux_2_24`/`manylinux_2_31` the `CIBW_BEFORE_ALL_LINUX` command must use `apt-get -y`
instead.
### `CIBW_BEFORE_BUILD` {: #before-build}
@@ -1110,6 +1133,7 @@ Platform-specific environment variables are also available:<br/>
delocate-wheel --require-archs {delocate_archs} -w {dest_dir} -v {wheel} &&
pipx run abi3audit --strict --report {wheel}
CIBW_REPAIR_WHEEL_COMMAND_WINDOWS: >
copy {wheel} {dest_dir} &&
pipx run abi3audit --strict --report {wheel}
```
@@ -1148,7 +1172,10 @@ Platform-specific environment variables are also available:<br/>
"pipx run abi3audit --strict --report {wheel}",
]
[tool.cibuildwheel.windows]
repair-wheel-command = "pipx run abi3audit --strict --report {wheel}"
repair-wheel-command = [
"copy {wheel} {dest_dir}",
"pipx run abi3audit --strict --report {wheel}",
]
```
In configuration mode, you can use an inline array, and the items will be joined with `&&`.
@@ -1157,28 +1184,36 @@ Platform-specific environment variables are also available:<br/>
<div class="link-target" id="manylinux-image"></div>
### `CIBW_MANYLINUX_*_IMAGE`, `CIBW_MUSLLINUX_*_IMAGE` {: #linux-image}
> Specify alternative manylinux / musllinux container images
The available options are (default value):
> Specify manylinux / musllinux container images
- `CIBW_MANYLINUX_X86_64_IMAGE` ([`quay.io/pypa/manylinux2014_x86_64`](https://quay.io/pypa/manylinux2014_x86_64))
- `CIBW_MANYLINUX_I686_IMAGE` ([`quay.io/pypa/manylinux2014_i686`](https://quay.io/pypa/manylinux2014_i686))
- `CIBW_MANYLINUX_PYPY_X86_64_IMAGE` ([`quay.io/pypa/manylinux2014_x86_64`](https://quay.io/pypa/manylinux2014_x86_64))
- `CIBW_MANYLINUX_AARCH64_IMAGE` ([`quay.io/pypa/manylinux2014_aarch64`](https://quay.io/pypa/manylinux2014_aarch64))
- `CIBW_MANYLINUX_PPC64LE_IMAGE` ([`quay.io/pypa/manylinux2014_ppc64le`](https://quay.io/pypa/manylinux2014_ppc64le))
- `CIBW_MANYLINUX_S390X_IMAGE` ([`quay.io/pypa/manylinux2014_s390x`](https://quay.io/pypa/manylinux2014_s390x))
- `CIBW_MANYLINUX_PYPY_AARCH64_IMAGE` ([`quay.io/pypa/manylinux2014_aarch64`](https://quay.io/pypa/manylinux2014_aarch64))
- `CIBW_MANYLINUX_PYPY_I686_IMAGE` ([`quay.io/pypa/manylinux2014_i686`](https://quay.io/pypa/manylinux2014_i686))
- `CIBW_MUSLLINUX_X86_64_IMAGE` ([`quay.io/pypa/musllinux_1_2_x86_64`](https://quay.io/pypa/musllinux_1_2_x86_64))
- `CIBW_MUSLLINUX_I686_IMAGE` ([`quay.io/pypa/musllinux_1_2_i686`](https://quay.io/pypa/musllinux_1_2_i686))
- `CIBW_MUSLLINUX_AARCH64_IMAGE` ([`quay.io/pypa/musllinux_1_2_aarch64`](https://quay.io/pypa/musllinux_1_2_aarch64))
- `CIBW_MUSLLINUX_PPC64LE_IMAGE` ([`quay.io/pypa/musllinux_1_2_ppc64le`](https://quay.io/pypa/musllinux_1_2_ppc64le))
- `CIBW_MUSLLINUX_S390X_IMAGE` ([`quay.io/pypa/musllinux_1_2_s390x`](https://quay.io/pypa/musllinux_1_2_s390x))
The available options are:
Set an alternative Docker image to be used for building [manylinux / musllinux](https://github.com/pypa/manylinux) wheels.
| Option | Default | Future default* |
|-----------------------------------|----------------------------------------------------------------|-----------------------------------------------------------------|
| CIBW_MANYLINUX_X86_64_IMAGE | [`manylinux2014`](https://quay.io/pypa/manylinux2014_x86_64) | [`manylinux_2_28`](https://quay.io/pypa/manylinux_2_28_x86_64) |
| CIBW_MANYLINUX_I686_IMAGE | [`manylinux2014`](https://quay.io/pypa/manylinux2014_i686) | |
| CIBW_MANYLINUX_PYPY_X86_64_IMAGE | [`manylinux2014`](https://quay.io/pypa/manylinux2014_x86_64) | [`manylinux_2_28`](https://quay.io/pypa/manylinux_2_28_x86_64) |
| CIBW_MANYLINUX_AARCH64_IMAGE | [`manylinux2014`](https://quay.io/pypa/manylinux2014_aarch64) | [`manylinux_2_28`](https://quay.io/pypa/manylinux_2_28_aarch64) |
| CIBW_MANYLINUX_PPC64LE_IMAGE | [`manylinux2014`](https://quay.io/pypa/manylinux2014_ppc64le) | [`manylinux_2_28`](https://quay.io/pypa/manylinux_2_28_ppc64le) |
| CIBW_MANYLINUX_S390X_IMAGE | [`manylinux2014`](https://quay.io/pypa/manylinux2014_s390x) | [`manylinux_2_28`](https://quay.io/pypa/manylinux_2_28_s390x) |
| CIBW_MANYLINUX_ARMV7L_IMAGE | [`manylinux_2_31`](https://quay.io/pypa/manylinux_2_31_armv7l) | |
| CIBW_MANYLINUX_PYPY_AARCH64_IMAGE | [`manylinux2014`](https://quay.io/pypa/manylinux2014_aarch64) | [`manylinux_2_28`](https://quay.io/pypa/manylinux_2_28_aarch64) |
| CIBW_MANYLINUX_PYPY_I686_IMAGE | [`manylinux2014`](https://quay.io/pypa/manylinux2014_i686) | |
| CIBW_MUSLLINUX_X86_64_IMAGE | [`musllinux_1_2`](https://quay.io/pypa/musllinux_1_2_x86_64) | |
| CIBW_MUSLLINUX_I686_IMAGE | [`musllinux_1_2`](https://quay.io/pypa/musllinux_1_2_i686) | |
| CIBW_MUSLLINUX_AARCH64_IMAGE | [`musllinux_1_2`](https://quay.io/pypa/musllinux_1_2_aarch64) | |
| CIBW_MUSLLINUX_PPC64LE_IMAGE | [`musllinux_1_2`](https://quay.io/pypa/musllinux_1_2_ppc64le) | |
| CIBW_MUSLLINUX_S390X_IMAGE | [`musllinux_1_2`](https://quay.io/pypa/musllinux_1_2_s390x) | |
| CIBW_MUSLLINUX_ARMV7L_IMAGE | [`musllinux_1_2`](https://quay.io/pypa/musllinux_1_2_armv7l) | |
For `CIBW_MANYLINUX_*_IMAGE`, the value of this option can either be set to `manylinux1`, `manylinux2010`, `manylinux2014`, `manylinux_2_24` or `manylinux_2_28` 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 PyPy, the `manylinux1` image is not available. For architectures other
<small>* The default is scheduled to change in a cibuildwheel release on or after 6th May 2025 - if you don't want the new default, you should set the value to `manylinux2014`.</small>
Set the Docker image to be used for building [manylinux / musllinux](https://github.com/pypa/manylinux) wheels.
For `CIBW_MANYLINUX_*_IMAGE`, except `CIBW_MANYLINUX_ARMV7L_IMAGE`, the value of this option can either be set to `manylinux1`, `manylinux2010`, `manylinux2014`, `manylinux_2_24` or `manylinux_2_28` 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 PyPy, the `manylinux1` image is not available. For architectures other
than x86 (x86\_64 and i686) `manylinux2014`, `manylinux_2_24` or `manylinux_2_28` must be used, because the first version of the manylinux specification that supports additional architectures is `manylinux2014`. `manylinux_2_28` is not supported for `i686` architecture.
For `CIBW_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 `CIBW_MUSLLINUX_*_IMAGE`, the value of this option can either be set to `musllinux_1_1` or `musllinux_1_2` to use a pinned version of the [official musllinux images](https://github.com/pypa/musllinux). Alternatively, set these options to any other valid Docker image name.
@@ -1584,6 +1619,40 @@ Platform-specific environment variables are also available:<br/>
In configuration files, you can use an inline array, and the items will be joined with a comma.
### `CIBW_TEST_GROUPS` {: #test-groups}
> Specify test dependencies from your project's `dependency-groups`
List of
[dependency-groups](https://peps.python.org/pep-0735)
that should be included when installing the wheel prior to running the
tests. This can be used to avoid having to redefine test dependencies in
`CIBW_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`
#### Examples
!!! tab examples "Environment variables"
```yaml
# Will cause the wheel to be installed with these groups of dependencies
CIBW_TEST_GROUPS: "test qt"
```
Separate multiple items with a space.
!!! tab examples "pyproject.toml"
```toml
[tool.cibuildwheel]
# Will cause the wheel to be installed with these groups of dependencies
test-groups = ["test", "qt"]
```
In configuration files, you can use an inline array, and the items will be joined with a space.
### `CIBW_TEST_SKIP` {: #test-skip}
> Skip running tests on some builds
@@ -1599,7 +1668,7 @@ This option is not supported in the overrides section in `pyproject.toml`.
```yaml
# Will avoid testing on emulated architectures
CIBW_TEST_SKIP: "*-*linux_{aarch64,ppc64le,s390x}"
CIBW_TEST_SKIP: "*-*linux_{aarch64,ppc64le,s390x,armv7l}"
# Skip trying to test arm64 builds on Intel Macs
CIBW_TEST_SKIP: "*-macosx_arm64 *-macosx_universal2:arm64"
@@ -1610,7 +1679,7 @@ This option is not supported in the overrides section in `pyproject.toml`.
```toml
[tool.cibuildwheel]
# Will avoid testing on emulated architectures
test-skip = "*-*linux_{aarch64,ppc64le,s390x}"
test-skip = "*-*linux_{aarch64,ppc64le,s390x,armv7l}"
# Skip trying to test arm64 builds on Intel Macs
test-skip = "*-macosx_arm64 *-macosx_universal2:arm64"
+2 -2
View File
@@ -161,7 +161,7 @@ To build Linux, Mac, and Windows wheels using GitHub Actions, create a `.github/
- uses: actions/checkout@v4
- name: Build wheels
run: pipx run cibuildwheel==2.21.0
run: pipx run cibuildwheel==2.23.2
- uses: actions/upload-artifact@v4
with:
@@ -198,7 +198,7 @@ To build Linux, Mac, and Windows wheels using GitHub Actions, create a `.github/
- uses: actions/setup-python@v5
- name: Install cibuildwheel
run: python -m pip install cibuildwheel==2.21.0
run: python -m pip install cibuildwheel==2.23.2
- name: Build wheels
run: python -m cibuildwheel --output-dir wheelhouse
+24 -24
View File
@@ -18,8 +18,8 @@ title: Working examples
| [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. |
| [MyPy][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | The compiled version of MyPy using MyPyC. |
| [Kivy][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Open source UI framework written in Python, running on Windows, Linux, macOS, Android and iOS |
| [MemRay][] | ![github icon][] | ![linux icon][] | Memray is a memory profiler for Python |
| [Triton][] | ![github icon][] | ![linux icon][] | Self hosted runners |
| [MemRay][] | ![github icon][] | ![linux icon][] | Memray is a memory profiler for Python |
| [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 |
@@ -32,18 +32,18 @@ title: Working examples
| [twisted-iocpsupport][] | ![github icon][] | ![windows icon][] | A submodule of Twisted that hooks into native C APIs using Cython. |
| [PyOxidizer][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | A modern Python application packaging and distribution tool |
| [cvxpy][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | A Python-embedded modeling language for convex optimization problems. |
| [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. |
| [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 |
| [UltraJSON][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Ultra fast JSON decoder and encoder written in C with Python bindings |
| [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. |
| [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 |
| [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. |
| [Implicit][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Includes GPU support for linux wheels |
| [vispy][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Main repository for Vispy |
| [tinyobjloader][] | ![azurepipelines icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Tiny but powerful single file wavefront obj loader |
| [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. |
| [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 |
| [coverage.py][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | The coverage tool for Python |
| [PyCryptodome][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | A self-contained cryptographic library for Python |
| [Line Profiler][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Line-by-line profiling for Python |
@@ -78,32 +78,32 @@ title: Working examples
| [python-rapidjson][] | ![travisci icon][] ![gitlab icon][] ![appveyor 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 |
| [python-snappy][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Python bindings for the snappy google library |
| [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. |
| [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. |
| [cyvcf2][] | ![github icon][] | ![apple icon][] ![linux icon][] | cython + htslib == fast VCF and BCF processing |
| [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. |
| [jq.py][] | ![travisci icon][] | ![apple icon][] ![linux icon][] | Python bindings for jq |
| [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. |
| [iminuit][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Jupyter-friendly Python interface for C++ MINUIT2 |
| [Tokenizer][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Fast and customizable text tokenization library with BPE and SentencePiece support |
| [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 |
| [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. |
| [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 |
| [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. |
| [power-grid-model][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Python/C++ library for distribution power system analysis |
| [Python-WebRTC][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | a Python extension that provides bindings to WebRTC M92 |
| [boost-histogram][] | ![github icon][] ![travisci icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Supports full range of wheels, including PyPy and alternate archs. |
| [pybase64][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Fast Base64 encoding/decoding in Python |
| [Python-WebRTC][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | a Python extension that provides bindings to WebRTC M92 |
| [Confluent client for Kafka][] | ![travisci icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | setup in `tools/wheels/build-wheels.bat` |
| [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. |
| [fathon][] | ![travisci icon][] | ![apple icon][] ![linux icon][] | python package for DFA (Detrended Fluctuation Analysis) and related algorithms |
| [Arbor][] | ![github icon][] | ![apple icon][] ![linux icon][] | Arbor is a multi-compartment neuron simulation library; compatible with next-generation accelerators; best-practices applied to research software; focused on community-driven development. Includes a [small script](https://github.com/arbor-sim/arbor/blob/master/scripts/patchwheel.py) patching `rpath` in bundled libraries. |
| [pybind11 scikit_build_example][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | An example combining scikit-build and pybind11 |
| [Arbor][] | ![github icon][] | ![apple icon][] ![linux icon][] | Arbor is a multi-compartment neuron simulation library; compatible with next-generation accelerators; best-practices applied to research software; focused on community-driven development. Includes a [small script](https://github.com/arbor-sim/arbor/blob/master/scripts/patchwheel.py) patching `rpath` in bundled libraries. |
| [polaroid][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Full range of wheels for setuptools rust, with auto release and PyPI deploy. |
| [clang-format][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Scikit-build wrapper around LLVM's CMake, all platforms, generic wheels. |
| [etebase-py][] | ![travisci icon][] | ![linux icon][] | Python bindings to a Rust library using `setuptools-rust`, and `sccache` for improved speed. |
| [Confluent client for Kafka][] | ![travisci icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | setup in `tools/wheels/build-wheels.bat` |
| [cf-units][] | ![github icon][] | ![apple icon][] ![linux icon][] | Units of measure as required by the Climate and Forecast (CF) Metadata Conventions |
| [ninja][] | ![github icon][] ![travisci icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Multitagged binary builds for all supported platforms, using cibw 2 config configuration. |
| [numpythia][] | ![github icon][] | ![apple icon][] ![linux icon][] | The interface between PYTHIA and NumPy |
@@ -128,8 +128,8 @@ title: Working examples
[Prophet]: https://github.com/facebook/prophet
[MyPy]: https://github.com/mypyc/mypy_mypyc-wheels
[Kivy]: https://github.com/kivy/kivy
[MemRay]: https://github.com/bloomberg/memray
[Triton]: https://github.com/openai/triton
[MemRay]: https://github.com/bloomberg/memray
[uvloop]: https://github.com/MagicStack/uvloop
[psutil]: https://github.com/giampaolo/psutil
[Google Benchmark]: https://github.com/google/benchmark
@@ -142,18 +142,18 @@ title: Working examples
[twisted-iocpsupport]: https://github.com/twisted/twisted-iocpsupport
[PyOxidizer]: https://github.com/indygreg/PyOxidizer
[cvxpy]: https://github.com/cvxpy/cvxpy
[websockets]: https://github.com/python-websockets/websockets
[pedalboard]: https://github.com/spotify/pedalboard
[websockets]: https://github.com/python-websockets/websockets
[River]: https://github.com/online-ml/river
[UltraJSON]: https://github.com/ultrajson/ultrajson
[OpenSpiel]: https://github.com/google-deepmind/open_spiel
[aiortc]: https://github.com/aiortc/aiortc
[OpenSpiel]: https://github.com/google-deepmind/open_spiel
[Dependency Injector]: https://github.com/ets-labs/python-dependency-injector
[pyzmq]: https://github.com/zeromq/pyzmq
[Implicit]: https://github.com/benfred/implicit
[vispy]: https://github.com/vispy/vispy
[tinyobjloader]: https://github.com/tinyobjloader/tinyobjloader
[CTranslate2]: https://github.com/OpenNMT/CTranslate2
[tinyobjloader]: https://github.com/tinyobjloader/tinyobjloader
[vispy]: https://github.com/vispy/vispy
[coverage.py]: https://github.com/nedbat/coveragepy
[PyCryptodome]: https://github.com/Legrandin/pycryptodome
[Line Profiler]: https://github.com/pyutils/line_profiler
@@ -188,32 +188,32 @@ title: Working examples
[python-rapidjson]: https://github.com/python-rapidjson/python-rapidjson
[pybind11 python_example]: https://github.com/pybind/python_example
[python-snappy]: https://github.com/intake/python-snappy
[abess]: https://github.com/abess-team/abess
[sourmash]: https://github.com/sourmash-bio/sourmash
[abess]: https://github.com/abess-team/abess
[cyvcf2]: https://github.com/brentp/cyvcf2
[matrixprofile]: https://github.com/matrix-profile-foundation/matrixprofile
[jq.py]: https://github.com/mwilliamson/jq.py
[matrixprofile]: https://github.com/matrix-profile-foundation/matrixprofile
[iminuit]: https://github.com/scikit-hep/iminuit
[Tokenizer]: https://github.com/OpenNMT/Tokenizer
[keyvi]: https://github.com/KeyviDev/keyvi
[PyGLM]: https://github.com/Zuzu-Typ/PyGLM
[pillow-heif]: https://github.com/bigcat88/pillow_heif
[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
[bx-python]: https://github.com/bxlab/bx-python
[boost-histogram]: https://github.com/scikit-hep/boost-histogram
[power-grid-model]: https://github.com/PowerGridModel/power-grid-model
[Python-WebRTC]: https://github.com/MarshalX/python-webrtc
[boost-histogram]: https://github.com/scikit-hep/boost-histogram
[pybase64]: https://github.com/mayeut/pybase64
[Python-WebRTC]: https://github.com/MarshalX/python-webrtc
[Confluent client for Kafka]: https://github.com/confluentinc/confluent-kafka-python
[Imagecodecs (fork)]: https://github.com/czaki/imagecodecs_build
[fathon]: https://github.com/stfbnc/fathon
[Arbor]: https://github.com/arbor-sim/arbor
[pybind11 scikit_build_example]: https://github.com/pybind/scikit_build_example
[Arbor]: https://github.com/arbor-sim/arbor
[polaroid]: https://github.com/daggy1234/polaroid
[clang-format]: https://github.com/ssciwr/clang-format-wheel
[etebase-py]: https://github.com/etesync/etebase-py
[Confluent client for Kafka]: https://github.com/confluentinc/confluent-kafka-python
[cf-units]: https://github.com/SciTools/cf-units
[ninja]: https://github.com/scikit-build/ninja-python-distributions
[numpythia]: https://github.com/scikit-hep/numpythia
+1 -1
View File
@@ -9,7 +9,7 @@ environment:
stack: python 3.12
install: python -m pip install cibuildwheel==2.21.0
install: python -m pip install cibuildwheel==2.23.2
build_script: python -m cibuildwheel --output-dir wheelhouse
+4 -4
View File
@@ -6,7 +6,7 @@ jobs:
- bash: |
set -o errexit
python3 -m pip install --upgrade pip
pip3 install cibuildwheel==2.21.0
pip3 install cibuildwheel==2.23.2
displayName: Install dependencies
- bash: cibuildwheel --output-dir wheelhouse .
displayName: Build wheels
@@ -14,13 +14,13 @@ jobs:
inputs: {pathtoPublish: 'wheelhouse'}
- job: macos
pool: {vmImage: 'macOS-12'}
pool: {vmImage: 'macOS-13'}
steps:
- task: UsePythonVersion@0
- bash: |
set -o errexit
python3 -m pip install --upgrade pip
python3 -m pip install cibuildwheel==2.21.0
python3 -m pip install cibuildwheel==2.23.2
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==2.21.0
pip install cibuildwheel==2.23.2
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==2.21.0
python3 -m pip install --user cibuildwheel==2.23.2
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==2.21.0
python3 -m pip install --user cibuildwheel==2.23.2
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==2.21.0
pip3 install cibuildwheel==2.23.2
cibuildwheel --output-dir wheelhouse
- store_artifacts:
path: wheelhouse/
+2 -2
View File
@@ -1,6 +1,6 @@
build_and_store_wheels: &BUILD_AND_STORE_WHEELS
install_cibuildwheel_script:
- python -m pip install cibuildwheel==2.21.0
- python -m pip install cibuildwheel==2.23.2
run_cibuildwheel_script:
- cibuildwheel
wheels_artifacts:
@@ -10,7 +10,7 @@ build_and_store_wheels: &BUILD_AND_STORE_WHEELS
macos_task:
name: Build macOS x86_64 and arm64 wheels.
macos_instance:
image: ghcr.io/cirruslabs/macos-sonoma-xcode
image: ghcr.io/cirruslabs/macos-runner:sonoma
env:
VENV_ROOT: ${HOME}/venv-cibuildwheel
PATH: ${VENV_ROOT}/bin:${PATH}
+2 -2
View File
@@ -1,6 +1,6 @@
build_and_store_wheels: &BUILD_AND_STORE_WHEELS
install_cibuildwheel_script:
- python -m pip install cibuildwheel==2.21.0
- python -m pip install cibuildwheel==2.23.2
run_cibuildwheel_script:
- cibuildwheel
wheels_artifacts:
@@ -60,7 +60,7 @@ windows_x86_task:
macos_arm64_task:
name: Build macOS arm64 wheels.
macos_instance:
image: ghcr.io/cirruslabs/macos-sonoma-xcode
image: ghcr.io/cirruslabs/macos-runner:sonoma
env:
VENV_ROOT: ${HOME}/venv-cibuildwheel
PATH: ${VENV_ROOT}/bin:${PATH}
+2 -2
View File
@@ -17,13 +17,13 @@ jobs:
strategy:
matrix:
# macos-13 is an intel runner, macos-14 is apple silicon
os: [ubuntu-latest, windows-latest, macos-13, macos-14]
os: [ubuntu-latest, ubuntu-24.04-arm, windows-latest, macos-13, macos-14]
steps:
- uses: actions/checkout@v4
- name: Build wheels
uses: pypa/cibuildwheel@v2.21.0
uses: pypa/cibuildwheel@v2.23.2
- uses: actions/upload-artifact@v4
with:
+2 -2
View File
@@ -9,13 +9,13 @@ jobs:
strategy:
matrix:
# macos-13 is an intel runner, macos-14 is apple silicon
os: [ubuntu-latest, windows-latest, macos-13, macos-14]
os: [ubuntu-latest, ubuntu-24.04-arm, windows-latest, macos-13, macos-14]
steps:
- uses: actions/checkout@v4
- name: Build wheels
uses: pypa/cibuildwheel@v2.21.0
uses: pypa/cibuildwheel@v2.23.2
# env:
# CIBW_SOME_OPTION: value
# ...
+10 -6
View File
@@ -9,23 +9,27 @@ jobs:
strategy:
matrix:
# macos-13 is an intel runner, macos-14 is apple silicon
os: [ubuntu-latest, windows-latest, macos-13, macos-14]
os: [ubuntu-latest, ubuntu-24.04-arm, windows-latest, macos-13, macos-14]
steps:
- uses: actions/checkout@v4
- name: Set up QEMU
if: runner.os == 'Linux'
if: runner.os == 'Linux' && runner.arch == 'X64'
uses: docker/setup-qemu-action@v3
with:
platforms: all
- name: Build wheels
uses: pypa/cibuildwheel@v2.21.0
uses: pypa/cibuildwheel@v2.23.2
env:
# configure cibuildwheel to build native archs ('auto'), and some
# emulated ones
CIBW_ARCHS_LINUX: auto aarch64 ppc64le s390x
# configure cibuildwheel on Linux to build native archs ('auto'),
# and to split the remaining architectures between the x86_64 and
# ARM runners
# armv7l can be built without QEMU on GitHub Actions ARM runners but that's
# not the case on all ARM64 hardware hence 'auto armv7l' for native archs
# on the GHA ARM64 runner
CIBW_ARCHS_LINUX: ${{ runner.arch == 'X64' && 'auto ppc64le s390x' || 'auto armv7l' }}
- uses: actions/upload-artifact@v4
with:
+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==2.21.0
- python -m pip install cibuildwheel==2.23.2
- cibuildwheel --output-dir wheelhouse
artifacts:
paths:
@@ -23,7 +23,7 @@ windows:
before_script:
- choco install python -y --version 3.12.4
- choco install git.install -y
- py -m pip install cibuildwheel==2.21.0
- py -m pip install cibuildwheel==2.23.2
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==2.21.0
- python3 -m pip install cibuildwheel==2.23.2
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==2.21.0
- python -m pip install cibuildwheel==2.23.2
# 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==2.21.0
- python3 -m pip install cibuildwheel==2.23.2
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==2.21.0
- python3 -m pip install cibuildwheel==2.23.2
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==2.21.0 twine
install: python3 -m pip install cibuildwheel==2.23.2 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==2.21.0 twine
install: python3 -m pip install cibuildwheel==2.23.2 twine
script: python3 -m cibuildwheel --output-dir wheelhouse
after_success: python3 -m twine upload --skip-existing wheelhouse/*.whl
+9 -5
View File
@@ -21,12 +21,16 @@ def install_and_run(session: nox.Session, script: str, *args: str, **kwargs: Any
return session.run("python", script, *args, **kwargs)
def dep_group(group: str) -> list[str]:
return nox.project.load_toml("pyproject.toml")["dependency-groups"][group] # type: ignore[no-any-return]
@nox.session
def tests(session: nox.Session) -> None:
"""
Run the unit and regular tests.
"""
session.install("-e.[test]")
session.install("-e.", *dep_group("test"))
if session.posargs:
session.run("pytest", *session.posargs)
else:
@@ -102,10 +106,10 @@ def update_constraints(session: nox.Session) -> None:
pyodides = build_platforms["pyodide"]["python_configurations"]
for pyodide in pyodides:
python_version = ".".join(pyodide["version"].split(".")[:2])
pyodide_version = pyodide["pyodide_version"]
pyodide_build_version = pyodide["pyodide_build_version"]
output_file = resources / f"constraints-pyodide{python_version.replace('.', '')}.txt"
tmp_file = Path(session.create_tmp()) / "constraints-pyodide.in"
tmp_file.write_text(f"pip\nbuild[virtualenv]\npyodide-build=={pyodide_version}")
tmp_file.write_text(f"pip\nbuild[virtualenv]\npyodide-build=={pyodide_build_version}")
session.run(
"uv",
"pip",
@@ -123,7 +127,7 @@ def update_pins(session: nox.Session) -> None:
"""
Update the python, docker and virtualenv pins version inplace.
"""
session.install("-e.[bin]")
session.install("-e.", *dep_group("bin"))
session.run("python", "bin/update_pythons.py", "--force")
session.run("python", "bin/update_docker.py")
session.run("python", "bin/update_virtualenv.py", "--force")
@@ -166,7 +170,7 @@ def docs(session: nox.Session) -> None:
"""
Build the docs. Will serve unless --non-interactive
"""
session.install("-e.[docs]")
session.install("-e.", *dep_group("docs"))
session.run("mkdocs", "serve" if session.interactive else "build", "--strict", *session.posargs)
+43 -47
View File
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
[project]
name = "cibuildwheel"
version = "2.21.0"
version = "2.23.2"
description = "Build Python wheels on CI with minimal configuration."
readme = "README.md"
license = "BSD-2-Clause"
@@ -35,6 +35,7 @@ classifiers = [
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: Implementation :: CPython",
"Topic :: Software Development :: Build Tools",
]
@@ -42,6 +43,7 @@ dependencies = [
"bashlex!=0.13",
"bracex",
"certifi",
"dependency-groups>=1.2",
"filelock",
"packaging>=20.9",
"platformdirs",
@@ -50,35 +52,6 @@ dependencies = [
]
[project.optional-dependencies]
bin = [
"click",
"packaging>=21.0",
"pip-tools",
"pygithub",
"pyyaml",
"requests",
"rich>=9.6",
]
dev = [
"cibuildwheel[test,bin]",
]
docs = [
"jinja2>=3.1.2",
"mkdocs-include-markdown-plugin==2.8.0",
"mkdocs-macros-plugin",
"mkdocs==1.3.1",
"pymdown-extensions",
]
test = [
"build",
"jinja2",
"pytest-timeout",
"pytest-xdist",
"pytest>=6",
"setuptools",
"tomli_w",
"validate-pyproject",
]
uv = ["uv"]
[project.scripts]
@@ -92,6 +65,40 @@ Changelog = "https://github.com/pypa/cibuildwheel#changelog"
Documentation = "https://cibuildwheel.pypa.io"
Homepage = "https://github.com/pypa/cibuildwheel"
[dependency-groups]
bin = [
"click",
"packaging>=21.0",
"pip-tools",
"pygithub",
"pyyaml",
"requests",
"rich>=9.6",
]
docs = [
"jinja2>=3.1.2",
"mkdocs-include-markdown-plugin==6.2.2",
"mkdocs-macros-plugin",
"mkdocs==1.6.1",
"pymdown-extensions",
]
test = [
"build",
"jinja2",
"pytest-timeout",
"pytest-xdist",
"pytest>=6",
"setuptools",
"tomli_w",
"validate-pyproject",
]
dev = [
{include-group = "bin"},
{include-group = "docs"},
{include-group = "test"},
]
[tool.pytest.ini_options]
minversion = "6.0"
addopts = ["-ra", "--showlocals", "--strict-markers", "--strict-config"]
@@ -112,33 +119,20 @@ files = [
]
warn_unused_configs = true
warn_redundant_casts = true
no_implicit_reexport = true
strict_equality = true
warn_unused_ignores = true
check_untyped_defs = true
disallow_subclassing_any = true
disallow_any_generics = true
warn_return_any = true
no_implicit_optional = true
strict = true
disallow_untyped_defs = false
enable_error_code = ["ignore-without-code", "redundant-expr", "truthy-bool"]
warn_unreachable = true
warn_unreachable = false
[[tool.mypy.overrides]]
module = "cibuildwheel.*"
disallow_untyped_defs = true
disallow_untyped_calls = true
disallow_incomplete_defs = true
disallow_untyped_decorators = true
[[tool.mypy.overrides]]
module = [
"setuptools",
"setuptools._distutils", # needed even if only directly import setuptools._distutils.util
"setuptools._distutils.util",
"pytest", # ignored in pre-commit to speed up check
"bashlex",
"bashlex.*",
"importlib_resources",
@@ -213,7 +207,6 @@ ignore = [
"PLR", # Design related pylint codes
"E501", # Line too long
"RET504", "RET505", "RET508", # else after control flow
"PT004", # Rename suggested for returnless fixtures
"PT007", # False positive
"PYI025", # Set as AbstractSet
"ISC001", # Conflicts with formatter
@@ -239,3 +232,6 @@ flake8-unused-arguments.ignore-variadic-names = true
[tool.repo-review]
ignore = ["PC170", "PP303"]
[tool.check-wheel-contents]
ignore = ["W002"] # requirements-*.txt are allowed to be duplicates of one another
-1
View File
@@ -1 +0,0 @@
-e .[dev,docs]
+1 -1
View File
@@ -11,7 +11,7 @@ from cibuildwheel.util import detect_ci_provider, find_uv
from .utils import EMULATED_ARCHS, platform
def pytest_addoption(parser) -> None:
def pytest_addoption(parser: pytest.Parser) -> None:
parser.addoption(
"--run-emulation",
action="store",
+4 -15
View File
@@ -18,27 +18,16 @@ limited_api_project = test_projects.new_c_project(
IS_CPYTHON = sys.implementation.name == "cpython"
Py_GIL_DISABLED = sysconfig.get_config_var("Py_GIL_DISABLED")
CAN_USE_ABI3 = IS_CPYTHON and not Py_GIL_DISABLED
cmdclass = {}
setup_options = {}
extension_kwargs = {}
if CAN_USE_ABI3 and sys.version_info[:2] >= (3, 10):
from wheel.bdist_wheel import bdist_wheel as _bdist_wheel
class bdist_wheel_abi3(_bdist_wheel):
def finalize_options(self):
_bdist_wheel.finalize_options(self)
self.root_is_pure = False
def get_tag(self):
python, abi, plat = _bdist_wheel.get_tag(self)
return python, "abi3", plat
cmdclass["bdist_wheel"] = bdist_wheel_abi3
extension_kwargs["define_macros"] = [("Py_LIMITED_API", "0x030A0000")]
extension_kwargs["py_limited_api"] = True
setup_options = {"bdist_wheel": {"py_limited_api": "cp310"}}
"""
),
setup_py_extension_args_add="**extension_kwargs",
setup_py_setup_args_add="cmdclass=cmdclass",
setup_py_setup_args_add="options=setup_options",
)
limited_api_project.files["pyproject.toml"] = pyproject_toml
@@ -65,7 +54,7 @@ def test_abi3(tmp_path):
if utils.platform == "pyodide":
# there's only 1 possible configuration for pyodide, the single_python_tag one
expected_wheels = [
w.replace(f"{single_python_tag}-{single_python_tag}", f"{single_python_tag}-abi3")
w.replace(f"{single_python_tag}-{single_python_tag}", "cp310-abi3")
for w in expected_wheels
]
else:
+4 -4
View File
@@ -33,10 +33,9 @@ def test(tmp_path, capfd):
basic_project.generate(project_dir)
num_builds = len(utils.cibuildwheel_get_build_identifiers(project_dir))
if num_builds > 1:
expectation = pytest.raises(subprocess.CalledProcessError)
else:
expectation = does_not_raise()
expectation = (
pytest.raises(subprocess.CalledProcessError) if num_builds > 1 else does_not_raise()
)
with expectation as exc_info:
result = utils.cibuildwheel_run(
@@ -48,6 +47,7 @@ def test(tmp_path, capfd):
captured = capfd.readouterr()
if num_builds > 1:
assert exc_info is not None
assert "Build failed because a wheel named" in captured.err
assert exc_info.value.returncode == 6
else:
+3 -2
View File
@@ -3,6 +3,7 @@ from __future__ import annotations
import platform
import re
import textwrap
from pathlib import Path
import pytest
@@ -46,8 +47,8 @@ build-backend = "setuptools.build_meta"
VERSION_REGEX = r"([\w-]+)==([^\s]+)"
def get_versions_from_constraint_file(constraint_file):
constraint_file_text = constraint_file.read_text(encoding="utf8")
def get_versions_from_constraint_file(constraint_file: Path) -> dict[str, str]:
constraint_file_text = constraint_file.read_text(encoding="utf-8")
return dict(re.findall(VERSION_REGEX, constraint_file_text))
+1 -1
View File
@@ -20,7 +20,7 @@ from pyodide.code import run_js
def check_node():
# cibuildwheel adds a pinned node version to the PATH
# check it's in the PATH then, check it's the one that runs pyoodide
# check it's in the PATH then, check it's the one that runs Pyodide
cibw_cache_path = Path(sys.argv[1]).resolve(strict=True)
# find the node executable in PATH
node = shutil.which("node")
+6 -1
View File
@@ -4,6 +4,7 @@ import os
import subprocess
import sys
import textwrap
from collections.abc import Mapping
from pathlib import Path
from tempfile import TemporaryDirectory
@@ -28,7 +29,11 @@ def make_sdist(project: TestProject, working_dir: Path) -> Path:
return next(sdist_dir.glob("*.tar.gz"))
def cibuildwheel_from_sdist_run(sdist_path, add_env=None, config_file=None):
def cibuildwheel_from_sdist_run(
sdist_path: Path | str,
add_env: Mapping[str, str] | None = None,
config_file: str | None = None,
) -> list[str]:
env = os.environ.copy()
if add_env:
+1 -1
View File
@@ -8,7 +8,7 @@ from argparse import ArgumentParser
from pathlib import Path
def main():
def main() -> None:
parser = ArgumentParser(
prog="python -m test.test_projects", description="Generate a test project to check it out"
)
+3 -3
View File
@@ -22,11 +22,11 @@ class TestProject:
files: FilesDict
template_context: TemplateContext
def __init__(self):
def __init__(self) -> None:
self.files = {}
self.template_context = {}
def generate(self, path: Path):
def generate(self, path: Path) -> None:
for filename, content in self.files.items():
file_path = path / filename
file_path.parent.mkdir(parents=True, exist_ok=True)
@@ -37,7 +37,7 @@ class TestProject:
f.write(content)
def copy(self):
def copy(self) -> TestProject:
other = TestProject()
other.files = self.files.copy()
other.template_context = self.template_context.copy()
+7 -7
View File
@@ -78,13 +78,13 @@ version = 0.1.0
def new_c_project(
*,
spam_c_top_level_add="",
spam_c_function_add="",
setup_py_add="",
setup_py_extension_args_add="",
setup_py_setup_args_add="",
setup_cfg_add="",
):
spam_c_top_level_add: str = "",
spam_c_function_add: str = "",
setup_py_add: str = "",
setup_py_extension_args_add: str = "",
setup_py_setup_args_add: str = "",
setup_cfg_add: str = "",
) -> TestProject:
project = TestProject()
project.files.update(
+34 -1
View File
@@ -1,5 +1,6 @@
from __future__ import annotations
import inspect
import os
import subprocess
import textwrap
@@ -114,6 +115,38 @@ def test_extras_require(tmp_path):
assert set(actual_wheels) == set(expected_wheels)
def test_dependency_groups(tmp_path):
group_project = project_with_a_test.copy()
group_project.files["pyproject.toml"] = inspect.cleandoc("""
[build-system]
requires = ["setuptools"]
build-backend = "setuptools.build_meta"
[dependency-groups]
dev = ["pytest"]
""")
project_dir = tmp_path / "project"
group_project.generate(project_dir)
# build and test the wheels
actual_wheels = utils.cibuildwheel_run(
project_dir,
add_env={
"CIBW_TEST_GROUPS": "dev",
# 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",
"CIBW_TEST_COMMAND_WINDOWS": "COLOR 00 || pytest {project}/test",
},
single_python=True,
)
# also check that we got the right wheels
expected_wheels = utils.expected_wheels("spam", "0.1.0", single_python=True)
assert set(actual_wheels) == set(expected_wheels)
project_with_a_failing_test = test_projects.new_c_project()
project_with_a_failing_test.files["test/spam_test.py"] = r"""
from unittest import TestCase
@@ -155,7 +188,7 @@ def test_failing_test(tmp_path):
@pytest.mark.parametrize("test_runner", ["pytest", "unittest"])
def test_bare_pytest_invocation(
tmp_path: Path, capfd: pytest.CaptureFixture[str], test_runner: str
):
) -> None:
"""Check that if a user runs pytest in the the test cwd, it raises a helpful error"""
project_dir = tmp_path / "project"
output_dir = tmp_path / "output"
+1 -1
View File
@@ -11,7 +11,7 @@ from . import test_projects, utils
basic_project = test_projects.new_c_project()
def skip_if_no_msvc(arm64=False):
def skip_if_no_msvc(arm64: bool = False) -> None:
programfiles = os.getenv("PROGRAMFILES(X86)", "") or os.getenv("PROGRAMFILES", "")
if not programfiles:
pytest.skip("Requires %PROGRAMFILES(X86)% variable to be set")
+34 -26
View File
@@ -10,8 +10,10 @@ import os
import platform as pm
import subprocess
import sys
from collections.abc import Mapping, Sequence
from pathlib import Path
from tempfile import TemporaryDirectory
from typing import Final
from typing import Any, Final
import pytest
@@ -37,7 +39,9 @@ else:
raise Exception(msg)
def cibuildwheel_get_build_identifiers(project_path, env=None, *, prerelease_pythons=False):
def cibuildwheel_get_build_identifiers(
project_path: Path, env: dict[str, str] | None = None, *, prerelease_pythons: bool = False
) -> list[str]:
"""
Returns the list of build identifiers that cibuildwheel will try to build
for the current platform.
@@ -75,14 +79,14 @@ def _update_pip_cache_dir(env: dict[str, str]) -> None:
def cibuildwheel_run(
project_path,
package_dir=".",
env=None,
add_env=None,
output_dir=None,
add_args=None,
single_python=False,
):
project_path: str | Path,
package_dir: str | Path = ".",
env: dict[str, str] | None = None,
add_env: Mapping[str, str] | None = None,
output_dir: Path | None = None,
add_args: Sequence[str] | None = None,
single_python: bool = False,
) -> list[str]:
"""
Runs cibuildwheel as a subprocess, building the project at project_path.
@@ -144,17 +148,17 @@ def _floor_macosx(*args: str) -> str:
def expected_wheels(
package_name,
package_version,
manylinux_versions=None,
musllinux_versions=None,
macosx_deployment_target="10.9",
machine_arch=None,
python_abi_tags=None,
include_universal2=False,
single_python=False,
single_arch=False,
):
package_name: str,
package_version: str,
manylinux_versions: list[str] | None = None,
musllinux_versions: list[str] | None = None,
macosx_deployment_target: str = "10.9",
machine_arch: str | None = None,
python_abi_tags: list[str] | None = None,
include_universal2: bool = False,
single_python: bool = False,
single_arch: bool = False,
) -> list[str]:
"""
Returns a list of expected wheels from a run of cibuildwheel.
"""
@@ -170,7 +174,9 @@ def expected_wheels(
machine_arch = "aarch64"
if manylinux_versions is None:
if machine_arch == "x86_64":
if machine_arch == "armv7l":
manylinux_versions = ["manylinux_2_17", "manylinux2014", "manylinux_2_31"]
elif machine_arch == "x86_64":
manylinux_versions = [
"manylinux_2_5",
"manylinux1",
@@ -204,6 +210,7 @@ def expected_wheels(
"pp38-pypy38_pp73",
"pp39-pypy39_pp73",
"pp310-pypy310_pp73",
"pp311-pypy311_pp73",
]
if platform == "macos" and machine_arch == "arm64":
@@ -219,6 +226,7 @@ def expected_wheels(
"pp38-pypy38_pp73",
"pp39-pypy39_pp73",
"pp310-pypy310_pp73",
"pp311-pypy311_pp73",
]
if single_python:
@@ -305,7 +313,7 @@ def expected_wheels(
return wheels
def get_macos_version():
def get_macos_version() -> tuple[int, int]:
"""
Returns the macOS major/minor version, as a tuple, e.g. (10, 15) or (11, 0)
@@ -314,10 +322,10 @@ def get_macos_version():
(11, 2) <= (11, 0) != True
"""
version_str, _, _ = pm.mac_ver()
return tuple(map(int, version_str.split(".")[:2]))
return tuple(map(int, version_str.split(".")[:2])) # type: ignore[return-value]
def skip_if_pyodide(reason: str):
def skip_if_pyodide(reason: str) -> Any:
return pytest.mark.skipif(platform == "pyodide", reason=reason)
@@ -328,7 +336,7 @@ def invoke_pytest() -> str:
return "pytest"
def arch_name_for_linux(arch: str):
def arch_name_for_linux(arch: str) -> str:
"""
Archs have different names on different platforms, but it's useful to be
able to run linux tests on dev machines. This function translates between
+16 -9
View File
@@ -2,11 +2,13 @@ from __future__ import annotations
from packaging.specifiers import SpecifierSet
from cibuildwheel.util import BuildSelector
from cibuildwheel.util import BuildSelector, EnableGroups
def test_build():
build_selector = BuildSelector(build_config="cp3*-* *-manylinux*", skip_config="")
build_selector = BuildSelector(
build_config="cp3*-* *-manylinux*", skip_config="", enable=frozenset([EnableGroups.PyPy])
)
assert build_selector("cp36-manylinux_x86_64")
assert build_selector("cp37-manylinux_x86_64")
@@ -43,7 +45,7 @@ def test_build_filter_pre():
build_selector = BuildSelector(
build_config="cp3*-* *-manylinux*",
skip_config="",
prerelease_pythons=True,
enable=frozenset([EnableGroups.CPythonPrerelease, EnableGroups.PyPy]),
)
assert build_selector("cp37-manylinux_x86_64")
@@ -55,7 +57,9 @@ def test_build_filter_pre():
def test_skip():
build_selector = BuildSelector(
build_config="*", skip_config="pp36-* cp3?-manylinux_i686 cp36-win* *-win32"
build_config="*",
skip_config="pp36-* cp3?-manylinux_i686 cp36-win* *-win32",
enable=frozenset([EnableGroups.PyPy]),
)
assert not build_selector("pp36-manylinux_x86_64")
@@ -79,7 +83,9 @@ def test_skip():
def test_build_and_skip():
build_selector = BuildSelector(
build_config="cp36-* cp37-macosx* *-manylinux*", skip_config="pp37-* cp37-manylinux_i686"
build_config="cp36-* cp37-macosx* *-manylinux*",
skip_config="pp37-* cp37-manylinux_i686",
enable=frozenset([EnableGroups.PyPy]),
)
assert not build_selector("pp37-manylinux_x86_64")
@@ -110,7 +116,10 @@ def test_build_braces():
def test_build_limited_python():
build_selector = BuildSelector(
build_config="*", skip_config="", requires_python=SpecifierSet(">=3.7")
build_config="*",
skip_config="",
requires_python=SpecifierSet(">=3.7"),
enable=frozenset([EnableGroups.PyPy]),
)
assert not build_selector("cp36-manylinux_x86_64")
@@ -146,9 +155,7 @@ def test_build_limited_python_patch():
def test_build_free_threaded_python():
build_selector = BuildSelector(
build_config="*", skip_config="", prerelease_pythons=True, free_threaded_support=True
)
build_selector = BuildSelector(build_config="*", skip_config="", enable=frozenset(EnableGroups))
assert build_selector("cp313t-manylinux_x86_64")
+6 -4
View File
@@ -4,12 +4,14 @@ import textwrap
from pathlib import Path
from pprint import pprint
import pytest
import cibuildwheel.linux
from cibuildwheel.oci_container import OCIContainerEngineConfig
from cibuildwheel.options import CommandLineArguments, Options
def test_linux_container_split(tmp_path: Path, monkeypatch):
def test_linux_container_split(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
"""
Tests splitting linux builds by container image, container engine, and before_all
"""
@@ -53,13 +55,13 @@ def test_linux_container_split(tmp_path: Path, monkeypatch):
build_steps = list(cibuildwheel.linux.get_build_steps(options, python_configurations))
# helper functions to extract test info
def identifiers(step):
def identifiers(step: cibuildwheel.linux.BuildStep) -> list[str]:
return [c.identifier for c in step.platform_configs]
def before_alls(step):
def before_alls(step: cibuildwheel.linux.BuildStep) -> list[str]:
return [options.build_options(c.identifier).before_all for c in step.platform_configs]
def container_engines(step):
def container_engines(step: cibuildwheel.linux.BuildStep) -> list[OCIContainerEngineConfig]:
return [options.build_options(c.identifier).container_engine for c in step.platform_configs]
pprint(build_steps)
+4 -4
View File
@@ -12,12 +12,12 @@ from cibuildwheel import linux, macos, util, windows
class ArgsInterceptor:
def __init__(self):
def __init__(self) -> None:
self.call_count = 0
self.args = None
self.kwargs = None
self.args: tuple[object, ...] | None = None
self.kwargs: dict[str, object] | None = None
def __call__(self, *args, **kwargs):
def __call__(self, *args: object, **kwargs: object) -> None:
self.call_count += 1
self.args = args
self.kwargs = kwargs
+2 -2
View File
@@ -119,7 +119,7 @@ def test_manylinux_images(
assert build_options.manylinux_images is None
def get_default_repair_command(platform):
def get_default_repair_command(platform: str) -> str:
if platform == "linux":
return "auditwheel repair -w {dest_dir} {wheel}"
elif platform == "macos":
@@ -270,7 +270,7 @@ def test_config_settings(platform_specific, platform, intercepted_build_args, mo
config_settings = 'setting=value setting=value2 other="something else"'
if platform_specific:
monkeypatch.setenv("CIBW_CONFIG_SETTINGS_" + platform.upper(), config_settings)
monkeypatch.setenv("CIBW_CONFIG_SETTIGNS", "a=b")
monkeypatch.setenv("CIBW_CONFIG_SETTINGS", "a=b")
else:
monkeypatch.setenv("CIBW_CONFIG_SETTINGS", config_settings)
+3 -1
View File
@@ -6,6 +6,7 @@ import pytest
from cibuildwheel.__main__ import main
from cibuildwheel.architecture import Architecture
from cibuildwheel.util import EnableGroups
from ..conftest import MOCK_PACKAGE_DIR
@@ -179,6 +180,7 @@ def test_archs_platform_all(platform, intercepted_build_args, monkeypatch):
Architecture.aarch64,
Architecture.ppc64le,
Architecture.s390x,
Architecture.armv7l,
}
elif platform == "windows":
assert options.globals.architectures == {
@@ -215,7 +217,7 @@ def test_only_argument(intercepted_build_args, monkeypatch, only, plat):
assert options.globals.build_selector.skip_config == ""
assert options.platform == plat
assert options.globals.architectures == Architecture.all_archs(plat)
assert options.globals.build_selector.prerelease_pythons is True
assert EnableGroups.PyPy in options.globals.build_selector.enable
@pytest.mark.parametrize("only", ("cp311-manylxinux_x86_64", "some_linux_thing"))
+160 -39
View File
@@ -8,13 +8,22 @@ import shutil
import subprocess
import sys
import textwrap
import time
from contextlib import nullcontext
from pathlib import Path, PurePath, PurePosixPath
import pytest
import tomli_w
import cibuildwheel.oci_container
from cibuildwheel.environment import EnvironmentAssignmentBash
from cibuildwheel.oci_container import OCIContainer, OCIContainerEngineConfig, OCIPlatform
from cibuildwheel.errors import OCIEngineTooOldError
from cibuildwheel.oci_container import (
OCIContainer,
OCIContainerEngineConfig,
OCIPlatform,
_check_engine_version,
)
from cibuildwheel.util import CIProvider, detect_ci_provider
# Test utilities
@@ -130,14 +139,28 @@ def test_cwd(container_engine):
assert container.call(["pwd"], capture_output=True, cwd="/opt") == "/opt\n"
@pytest.mark.skipif(
pm == "s390x" and detect_ci_provider() == CIProvider.travis_ci,
reason="test is flaky on this platform, see https://github.com/pypa/cibuildwheel/pull/1961#issuecomment-2334678966",
)
def test_container_removed(container_engine):
# test is flaky on some platforms, implement retry for 5 second
timeout = 50 # * 100 ms = 5s
with OCIContainer(
engine=container_engine, image=DEFAULT_IMAGE, oci_platform=DEFAULT_OCI_PLATFORM
) as container:
assert container.name is not None
container_name = container.name
for _ in range(timeout):
docker_containers_listing = subprocess.run(
f"{container.engine.name} container ls",
shell=True,
check=True,
stdout=subprocess.PIPE,
text=True,
).stdout
if container_name in docker_containers_listing:
break
time.sleep(0.1)
assert container_name in docker_containers_listing
for _ in range(timeout):
docker_containers_listing = subprocess.run(
f"{container.engine.name} container ls",
shell=True,
@@ -145,18 +168,10 @@ def test_container_removed(container_engine):
stdout=subprocess.PIPE,
text=True,
).stdout
assert container.name is not None
assert container.name in docker_containers_listing
old_container_name = container.name
docker_containers_listing = subprocess.run(
f"{container.engine.name} container ls",
shell=True,
check=True,
stdout=subprocess.PIPE,
text=True,
).stdout
assert old_container_name not in docker_containers_listing
if container_name not in docker_containers_listing:
break
time.sleep(0.1)
assert container_name not in docker_containers_listing
def test_large_environment(container_engine):
@@ -231,7 +246,7 @@ def test_binary_output(container_engine):
assert output == binary_data_string
def test_file_operation(tmp_path: Path, container_engine):
def test_file_operation(tmp_path: Path, container_engine: OCIContainerEngineConfig) -> None:
with OCIContainer(
engine=container_engine, image=DEFAULT_IMAGE, oci_platform=DEFAULT_OCI_PLATFORM
) as container:
@@ -244,11 +259,14 @@ def test_file_operation(tmp_path: Path, container_engine):
container.copy_into(original_test_file, dst_file)
owner = container.call(["stat", "-c", "%u:%g", dst_file], capture_output=True).strip()
assert owner == "0:0"
output = container.call(["cat", dst_file], capture_output=True)
assert test_binary_data == bytes(output, encoding="utf8", errors="surrogateescape")
def test_dir_operations(tmp_path: Path, container_engine):
def test_dir_operations(tmp_path: Path, container_engine: OCIContainerEngineConfig) -> None:
with OCIContainer(
engine=container_engine, image=DEFAULT_IMAGE, oci_platform=DEFAULT_OCI_PLATFORM
) as container:
@@ -266,6 +284,12 @@ def test_dir_operations(tmp_path: Path, container_engine):
dst_file = dst_dir / "test.dat"
container.copy_into(test_dir, dst_dir)
owner = container.call(["stat", "-c", "%u:%g", dst_dir], capture_output=True).strip()
assert owner == "0:0"
owner = container.call(["stat", "-c", "%u:%g", dst_file], capture_output=True).strip()
assert owner == "0:0"
output = container.call(["cat", dst_file], capture_output=True)
assert test_binary_data == bytes(output, encoding="utf8", errors="surrogateescape")
@@ -276,10 +300,15 @@ def test_dir_operations(tmp_path: Path, container_engine):
new_test_dir = tmp_path / "test_dir_new"
container.copy_out(dst_dir, new_test_dir)
assert os.getuid() == new_test_dir.stat().st_uid
assert os.getgid() == new_test_dir.stat().st_gid
assert os.getuid() == (new_test_dir / "test.dat").stat().st_uid
assert os.getgid() == (new_test_dir / "test.dat").stat().st_gid
assert test_binary_data == (new_test_dir / "test.dat").read_bytes()
def test_environment_executor(container_engine):
def test_environment_executor(container_engine: OCIContainerEngineConfig) -> None:
with OCIContainer(
engine=container_engine, image=DEFAULT_IMAGE, oci_platform=DEFAULT_OCI_PLATFORM
) as container:
@@ -287,7 +316,9 @@ def test_environment_executor(container_engine):
assert assignment.evaluated_value({}, container.environment_executor) == "42"
def test_podman_vfs(tmp_path: Path, monkeypatch, container_engine):
def test_podman_vfs(
tmp_path: Path, monkeypatch: pytest.MonkeyPatch, container_engine: OCIContainerEngineConfig
) -> None:
if container_engine.name != "podman":
pytest.skip("only runs with podman")
if sys.platform.startswith("darwin"):
@@ -369,7 +400,7 @@ def test_podman_vfs(tmp_path: Path, monkeypatch, container_engine):
subprocess.run(["podman", "unshare", "rm", "-rf", vfs_path], check=True)
def test_create_args_volume(tmp_path: Path, container_engine):
def test_create_args_volume(tmp_path: Path, container_engine: OCIContainerEngineConfig) -> None:
if container_engine.name != "docker":
pytest.skip("only runs with docker")
@@ -491,7 +522,12 @@ def test_enforce_32_bit(container_engine):
("{name}; disable_host_mount: true", False),
],
)
def test_disable_host_mount(tmp_path: Path, container_engine, config, should_have_host_mount):
def test_disable_host_mount(
tmp_path: Path,
container_engine: OCIContainerEngineConfig,
config: str,
should_have_host_mount: bool,
) -> None:
if detect_ci_provider() in {CIProvider.circle_ci, CIProvider.gitlab}:
pytest.skip("Skipping test because docker on this platform does not support host mounts")
if sys.platform.startswith("darwin"):
@@ -513,16 +549,35 @@ def test_disable_host_mount(tmp_path: Path, container_engine, config, should_hav
container.call(["cat", host_mount_path], capture_output=True)
def test_local_image(container_engine):
local_image = f"cibw_test_{container_engine.name}_local:latest"
@pytest.mark.parametrize("platform", list(OCIPlatform))
def test_local_image(
container_engine: OCIContainerEngineConfig, platform: OCIPlatform, tmp_path: Path
) -> None:
if (
detect_ci_provider() in {CIProvider.travis_ci}
and pm in {"s390x", "ppc64le"}
and platform != DEFAULT_OCI_PLATFORM
):
pytest.skip("Skipping test because docker on this platform does not support QEMU")
if container_engine.name == "podman" and platform == OCIPlatform.ARMV7:
# both GHA & local macOS arm64 podman desktop are failing
pytest.xfail("podman fails with armv7l images")
remote_image = "debian:12-slim"
platform_name = platform.value.replace("/", "_")
local_image = f"cibw_{container_engine.name}_{platform_name}_local:latest"
dockerfile = tmp_path / "Dockerfile"
dockerfile.write_text(f"FROM {remote_image}")
subprocess.run(
[container_engine.name, "pull", f"--platform={DEFAULT_OCI_PLATFORM.value}", DEFAULT_IMAGE],
[container_engine.name, "pull", f"--platform={platform.value}", remote_image],
check=True,
)
subprocess.run([container_engine.name, "image", "tag", DEFAULT_IMAGE, local_image], check=True)
with OCIContainer(
engine=container_engine, image=local_image, oci_platform=DEFAULT_OCI_PLATFORM
):
subprocess.run(
[container_engine.name, "build", f"--platform={platform.value}", "-t", local_image, "."],
check=True,
cwd=tmp_path,
)
with OCIContainer(engine=container_engine, image=local_image, oci_platform=platform):
pass
@@ -534,24 +589,90 @@ def test_multiarch_image(container_engine, platform):
and platform != DEFAULT_OCI_PLATFORM
):
pytest.skip("Skipping test because docker on this platform does not support QEMU")
if container_engine.name == "podman" and platform == OCIPlatform.ARMV7:
# both GHA & local macOS arm64 podman desktop are failing
pytest.xfail("podman fails with armv7l images")
with OCIContainer(
engine=container_engine, image="debian:12-slim", oci_platform=platform
) as container:
output = container.call(["uname", "-m"], capture_output=True)
output_map = {
OCIPlatform.i386: "i686",
OCIPlatform.AMD64: "x86_64",
OCIPlatform.ARM64: "aarch64",
OCIPlatform.PPC64LE: "ppc64le",
OCIPlatform.S390X: "s390x",
output_map_kernel = {
OCIPlatform.i386: ("i686",),
OCIPlatform.AMD64: ("x86_64",),
OCIPlatform.ARMV7: ("armv7l", "armv8l"),
OCIPlatform.ARM64: ("aarch64",),
OCIPlatform.PPC64LE: ("ppc64le",),
OCIPlatform.S390X: ("s390x",),
}
assert output_map[platform] == output.strip()
assert output.strip() in output_map_kernel[platform]
output = container.call(["dpkg", "--print-architecture"], capture_output=True)
output_map = {
output_map_dpkg = {
OCIPlatform.i386: "i386",
OCIPlatform.AMD64: "amd64",
OCIPlatform.ARMV7: "armhf",
OCIPlatform.ARM64: "arm64",
OCIPlatform.PPC64LE: "ppc64el",
OCIPlatform.S390X: "s390x",
}
assert output_map[platform] == output.strip()
assert output_map_dpkg[platform] == output.strip()
@pytest.mark.parametrize(
("engine_name", "version", "context"),
[
(
"docker",
None, # 17.12.1-ce does supports "docker version --format '{{json . }}'" so a version before that
pytest.raises(OCIEngineTooOldError),
),
(
"docker",
'{"Client":{"Version":"19.03.15","ApiVersion": "1.40"},"Server":{"ApiVersion": "1.40"}}',
pytest.raises(OCIEngineTooOldError),
),
(
"docker",
'{"Client":{"Version":"20.10.0","ApiVersion":"1.41"},"Server":{"ApiVersion":"1.41"}}',
nullcontext(),
),
(
"docker",
'{"Client":{"Version":"24.0.0","ApiVersion":"1.43"},"Server":{"ApiVersion":"1.43"}}',
nullcontext(),
),
(
"docker",
'{"Client":{"ApiVersion":"1.43"},"Server":{"ApiVersion":"1.30"}}',
pytest.raises(OCIEngineTooOldError),
),
(
"docker",
'{"Client":{"ApiVersion":"1.30"},"Server":{"ApiVersion":"1.43"}}',
pytest.raises(OCIEngineTooOldError),
),
("podman", '{"Client":{"Version":"5.2.0"},"Server":{"Version":"5.1.2"}}', nullcontext()),
("podman", '{"Client":{"Version":"4.9.4-rhel"}}', nullcontext()),
(
"podman",
'{"Client":{"Version":"5.2.0"},"Server":{"Version":"2.1.2"}}',
pytest.raises(OCIEngineTooOldError),
),
(
"podman",
'{"Client":{"Version":"2.2.0"},"Server":{"Version":"5.1.2"}}',
pytest.raises(OCIEngineTooOldError),
),
("podman", '{"Client":{"Version":"3.0~rc1-rhel"}}', nullcontext()),
("podman", '{"Client":{"Version":"2.1.0~rc1"}}', pytest.raises(OCIEngineTooOldError)),
],
)
def test_engine_version(engine_name, version, context, monkeypatch):
def mockcall(*args, **kwargs):
if version is None:
raise subprocess.CalledProcessError(1, " ".join(str(arg) for arg in args))
return version
monkeypatch.setattr(cibuildwheel.oci_container, "call", mockcall)
engine = OCIContainerEngineConfig.from_config_string(engine_name)
with context:
_check_engine_version(engine)
+3 -2
View File
@@ -27,6 +27,7 @@ ALL_IDS = {
"pp38",
"pp39",
"pp310",
"pp311",
}
@@ -158,7 +159,7 @@ before-all = "true"
assert identifiers == {
f"{x}-manylinux_x86_64"
for x in ALL_IDS
- {"cp36", "cp310", "cp311", "cp312", "cp313", "pp37", "pp38", "pp39", "pp310"}
- {"cp36", "cp310", "cp311", "cp312", "cp313", "pp37", "pp38", "pp39", "pp310", "pp311"}
}
assert kwargs["options"].build_options("cp37-manylinux_x86_64").before_all == ""
@@ -169,7 +170,7 @@ before-all = "true"
identifiers = {x.identifier for x in kwargs["platform_configs"]}
assert identifiers == {
f"{x}-manylinux_x86_64"
for x in ["cp310", "cp311", "cp312", "cp313", "pp37", "pp38", "pp39", "pp310"]
for x in ["cp310", "cp311", "cp312", "cp313", "pp37", "pp38", "pp39", "pp310", "pp311"]
}
kwargs = build_in_container.call_args_list[3][1]
+51 -8
View File
@@ -15,6 +15,7 @@ from cibuildwheel.options import (
Options,
_get_pinned_container_images,
)
from cibuildwheel.util import EnableGroups
PYPROJECT_1 = """
[tool.cibuildwheel]
@@ -178,7 +179,7 @@ def test_toml_environment_evil(tmp_path, env_var_value):
(r'TEST_VAR="before\\$after"', "before$after"),
],
)
def test_toml_environment_quoting(tmp_path: Path, toml_assignment, result_value):
def test_toml_environment_quoting(tmp_path: Path, toml_assignment: str, result_value: str) -> None:
args = CommandLineArguments.defaults()
args.package_dir = tmp_path
@@ -255,8 +256,12 @@ def test_toml_environment_quoting(tmp_path: Path, toml_assignment, result_value)
],
)
def test_container_engine_option(
tmp_path: Path, toml_assignment, result_name, result_create_args, result_disable_host_mount
):
tmp_path: Path,
toml_assignment: str,
result_name: str,
result_create_args: tuple[str, ...],
result_disable_host_mount: bool,
) -> None:
args = CommandLineArguments.defaults()
args.package_dir = tmp_path
@@ -326,7 +331,9 @@ def test_environment_pass_references():
),
],
)
def test_build_frontend_option(tmp_path: Path, toml_assignment, result_name, result_args):
def test_build_frontend_option(
tmp_path: Path, toml_assignment: str, result_name: str, result_args: list[str]
) -> None:
args = CommandLineArguments.defaults()
args.package_dir = tmp_path
@@ -350,7 +357,7 @@ def test_build_frontend_option(tmp_path: Path, toml_assignment, result_name, res
assert parsed_build_frontend is None
def test_override_inherit_environment(tmp_path: Path):
def test_override_inherit_environment(tmp_path: Path) -> None:
args = CommandLineArguments.defaults()
args.package_dir = tmp_path
@@ -385,7 +392,7 @@ def test_override_inherit_environment(tmp_path: Path):
}
def test_override_inherit_environment_with_references(tmp_path: Path):
def test_override_inherit_environment_with_references(tmp_path: Path) -> None:
args = CommandLineArguments.defaults()
args.package_dir = tmp_path
@@ -434,7 +441,7 @@ def test_override_inherit_environment_with_references(tmp_path: Path):
)
def test_free_threaded_support(
tmp_path: Path, toml_assignment: str, env: dict[str, str], expected_result: bool
):
) -> None:
args = CommandLineArguments.defaults()
args.package_dir = tmp_path
@@ -448,4 +455,40 @@ def test_free_threaded_support(
)
)
options = Options(platform="linux", command_line_arguments=args, env=env)
assert options.globals.build_selector.free_threaded_support is expected_result
if expected_result:
assert EnableGroups.CPythonFreeThreading in options.globals.build_selector.enable
else:
assert EnableGroups.CPythonFreeThreading not in options.globals.build_selector.enable
@pytest.mark.parametrize(
("image", "deprecated"),
[
("manylinux1", True),
("manylinux2010", True),
("manylinux2014", False),
("manylinux_2_24", True),
("manylinux_2_28", False),
("manylinux_2_34", False),
("musllinux_1_1", True),
("musllinux_1_2", False),
],
)
def test_deprecated_image(image: str, deprecated: bool, capsys: pytest.CaptureFixture[str]) -> None:
args = CommandLineArguments.defaults()
env = {
"CIBW_ARCHS": "x86_64",
"CIBW_MANYLINUX_X86_64_IMAGE": image if image.startswith("manylinux") else "",
"CIBW_MUSLLINUX_X86_64_IMAGE": image if image.startswith("musllinux") else "",
}
options = Options(platform="linux", command_line_arguments=args, env=env)
bo = options.build_options(None)
images = bo.manylinux_images if image.startswith("manylinux") else bo.musllinux_images
assert images is not None
resolved_image = images["x86_64"]
captured = capsys.readouterr()
if deprecated:
assert f"Deprecated image {image!r}" in captured.err
assert f"{resolved_image!r}" in captured.err
else:
assert "Deprecated image" not in captured.err
+8
View File
@@ -22,6 +22,7 @@ environment = {THING = "OTHER", FOO="BAR"}
test-command = "pyproject"
test-requires = "something"
test-extras = ["one", "two"]
test-groups = ["three", "four"]
manylinux-x86_64-image = "manylinux1"
@@ -60,6 +61,7 @@ def test_simple_settings(tmp_path, platform, fname):
== 'THING="OTHER" FOO="BAR"'
)
assert options_reader.get("test-extras", option_format=ListFormat(",")) == "one,two"
assert options_reader.get("test-groups", option_format=ListFormat(" ")) == "three four"
assert options_reader.get("manylinux-x86_64-image") == "manylinux1"
assert options_reader.get("manylinux-i686-image") == "manylinux2014"
@@ -85,7 +87,9 @@ def test_envvar_override(tmp_path, platform):
"CIBW_MANYLINUX_X86_64_IMAGE": "manylinux_2_24",
"CIBW_TEST_COMMAND": "mytest",
"CIBW_TEST_REQUIRES": "docs",
"CIBW_TEST_GROUPS": "mgroup two",
"CIBW_TEST_REQUIRES_LINUX": "scod",
"CIBW_TEST_GROUPS_LINUX": "lgroup",
},
)
@@ -99,6 +103,10 @@ def test_envvar_override(tmp_path, platform):
options_reader.get("test-requires", option_format=ListFormat(" "))
== {"windows": "docs", "macos": "docs", "linux": "scod"}[platform]
)
assert (
options_reader.get("test-groups", option_format=ListFormat(" "))
== {"windows": "mgroup two", "macos": "mgroup two", "linux": "lgroup"}[platform]
)
assert options_reader.get("test-command") == "mytest"
+42 -13
View File
@@ -2,7 +2,14 @@ from __future__ import annotations
from textwrap import dedent
from cibuildwheel.projectfiles import get_requires_python_str, setup_py_python_requires
import pytest
from cibuildwheel._compat import tomllib
from cibuildwheel.projectfiles import (
get_requires_python_str,
resolve_dependency_groups,
setup_py_python_requires,
)
def test_read_setup_py_simple(tmp_path):
@@ -23,7 +30,7 @@ def test_read_setup_py_simple(tmp_path):
)
assert setup_py_python_requires(tmp_path.joinpath("setup.py").read_text()) == "1.23"
assert get_requires_python_str(tmp_path) == "1.23"
assert get_requires_python_str(tmp_path, {}) == "1.23"
def test_read_setup_py_if_main(tmp_path):
@@ -45,7 +52,7 @@ def test_read_setup_py_if_main(tmp_path):
)
assert setup_py_python_requires(tmp_path.joinpath("setup.py").read_text()) == "1.23"
assert get_requires_python_str(tmp_path) == "1.23"
assert get_requires_python_str(tmp_path, {}) == "1.23"
def test_read_setup_py_if_main_reversed(tmp_path):
@@ -67,7 +74,7 @@ def test_read_setup_py_if_main_reversed(tmp_path):
)
assert setup_py_python_requires(tmp_path.joinpath("setup.py").read_text()) == "1.23"
assert get_requires_python_str(tmp_path) == "1.23"
assert get_requires_python_str(tmp_path, {}) == "1.23"
def test_read_setup_py_if_invalid(tmp_path):
@@ -89,7 +96,7 @@ def test_read_setup_py_if_invalid(tmp_path):
)
assert not setup_py_python_requires(tmp_path.joinpath("setup.py").read_text())
assert not get_requires_python_str(tmp_path)
assert not get_requires_python_str(tmp_path, {})
def test_read_setup_py_full(tmp_path):
@@ -115,7 +122,7 @@ def test_read_setup_py_full(tmp_path):
assert (
setup_py_python_requires(tmp_path.joinpath("setup.py").read_text(encoding="utf8")) == "1.24"
)
assert get_requires_python_str(tmp_path) == "1.24"
assert get_requires_python_str(tmp_path, {}) == "1.24"
def test_read_setup_py_assign(tmp_path):
@@ -138,7 +145,7 @@ def test_read_setup_py_assign(tmp_path):
)
assert setup_py_python_requires(tmp_path.joinpath("setup.py").read_text()) is None
assert get_requires_python_str(tmp_path) is None
assert get_requires_python_str(tmp_path, {}) is None
def test_read_setup_py_None(tmp_path):
@@ -161,7 +168,7 @@ def test_read_setup_py_None(tmp_path):
)
assert setup_py_python_requires(tmp_path.joinpath("setup.py").read_text()) is None
assert get_requires_python_str(tmp_path) is None
assert get_requires_python_str(tmp_path, {}) is None
def test_read_setup_py_empty(tmp_path):
@@ -183,7 +190,7 @@ def test_read_setup_py_empty(tmp_path):
)
assert setup_py_python_requires(tmp_path.joinpath("setup.py").read_text()) is None
assert get_requires_python_str(tmp_path) is None
assert get_requires_python_str(tmp_path, {}) is None
def test_read_setup_cfg(tmp_path):
@@ -199,7 +206,7 @@ def test_read_setup_cfg(tmp_path):
)
)
assert get_requires_python_str(tmp_path) == "1.234"
assert get_requires_python_str(tmp_path, {}) == "1.234"
def test_read_setup_cfg_empty(tmp_path):
@@ -215,7 +222,7 @@ def test_read_setup_cfg_empty(tmp_path):
)
)
assert get_requires_python_str(tmp_path) is None
assert get_requires_python_str(tmp_path, {}) is None
def test_read_pyproject_toml(tmp_path):
@@ -231,8 +238,10 @@ def test_read_pyproject_toml(tmp_path):
"""
)
)
with open(tmp_path / "pyproject.toml", "rb") as f:
pyproject_toml = tomllib.load(f)
assert get_requires_python_str(tmp_path) == "1.654"
assert get_requires_python_str(tmp_path, pyproject_toml) == "1.654"
def test_read_pyproject_toml_empty(tmp_path):
@@ -245,5 +254,25 @@ def test_read_pyproject_toml_empty(tmp_path):
"""
)
)
with open(tmp_path / "pyproject.toml", "rb") as f:
pyproject_toml = tomllib.load(f)
assert get_requires_python_str(tmp_path) is None
assert get_requires_python_str(tmp_path, pyproject_toml) is None
def test_read_dep_groups():
pyproject_toml = {"dependency-groups": {"group1": ["pkg1", "pkg2"], "group2": ["pkg3"]}}
assert resolve_dependency_groups(pyproject_toml) == ()
assert resolve_dependency_groups(pyproject_toml, "group1") == ("pkg1", "pkg2")
assert resolve_dependency_groups(pyproject_toml, "group2") == ("pkg3",)
assert resolve_dependency_groups(pyproject_toml, "group1", "group2") == ("pkg1", "pkg2", "pkg3")
def test_dep_group_no_file_error():
with pytest.raises(FileNotFoundError, match="pyproject.toml"):
resolve_dependency_groups(None, "test")
def test_dep_group_no_section_error():
with pytest.raises(KeyError, match="pyproject.toml"):
resolve_dependency_groups({}, "test")
+17 -2
View File
@@ -6,6 +6,7 @@ from pathlib import PurePath
import pytest
from cibuildwheel.util import (
FlexibleVersion,
find_compatible_wheel,
fix_ansi_codes_for_github_actions,
format_safe,
@@ -75,7 +76,7 @@ def test_prepare_command():
("foo-0.1-py38-none-win_amd64.whl", "pp310-win_amd64"),
],
)
def test_find_compatible_wheel_found(wheel: str, identifier: str):
def test_find_compatible_wheel_found(wheel: str, identifier: str) -> None:
wheel_ = PurePath(wheel)
found = find_compatible_wheel([wheel_], identifier)
assert found is wheel_
@@ -95,7 +96,7 @@ def test_find_compatible_wheel_found(wheel: str, identifier: str):
("foo-0.1-cp38-cp38-win_amd64.whl", "cp310-win_amd64"),
],
)
def test_find_compatible_wheel_not_found(wheel: str, identifier: str):
def test_find_compatible_wheel_not_found(wheel: str, identifier: str) -> None:
assert find_compatible_wheel([PurePath(wheel)], identifier) is None
@@ -206,3 +207,17 @@ def test_parse_key_value_string():
"name": ["docker"],
"create_args": [],
}
def test_flexible_version_comparisons():
assert FlexibleVersion("2.0") == FlexibleVersion("2")
assert FlexibleVersion("2.0") < FlexibleVersion("2.1")
assert FlexibleVersion("2.1") > FlexibleVersion("2")
assert FlexibleVersion("1.9.9") < FlexibleVersion("2.0")
assert FlexibleVersion("1.10") > FlexibleVersion("1.9.9")
assert FlexibleVersion("3.0.1") > FlexibleVersion("3.0")
assert FlexibleVersion("3.0") < FlexibleVersion("3.0.1")
# Suffix should not affect comparisons
assert FlexibleVersion("1.0.1-rhel") > FlexibleVersion("1.0")
assert FlexibleVersion("1.0.1-rhel") < FlexibleVersion("1.1")
assert FlexibleVersion("1.0.1") == FlexibleVersion("v1.0.1")
+1 -1
View File
@@ -45,7 +45,7 @@ def test_validate_container_engine():
@pytest.mark.parametrize("platform", ["macos", "windows"])
def test_validate_bad_container_engine(platform: str):
def test_validate_bad_container_engine(platform: str) -> None:
"""
container-engine is not a valid option for macos or windows
"""
+1 -1
View File
@@ -27,7 +27,7 @@ def test_no_printout_on_error(tmp_path, capsys):
tmp_path.joinpath("example.1").touch()
raise RuntimeError()
captured = capsys.readouterr() # type: ignore[unreachable]
captured = capsys.readouterr()
assert captured.err == ""
assert "example.0" not in captured.out