Compare commits

...
44 Commits
Author SHA1 Message Date
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
Joe Rickerby 79b0dd3287 Bump version: v2.21.0 2024-09-13 16:42:42 +01:00
Matthieu Darbois 0787a44d99 fix: enforce minimum version of docker/podman (#1961)
* fix: enforce minimum version of docker/podman

This allows to always pass `--platform` to the OCI engine
thus fixing issues with multiarch images.

* Allow older versions with warnings

* Upgrade docker on Travis CI

* fix: use `docker cp` instead of `tar`

* Enforce docker>=24.0

* move log to include container.copy_into

* fix: travis-ci, only update docker on aarch64

* skip test_multiarch_image on s390x / ppc64le

* skip flaky test

* chore: only install test deps on Travis CI

* fix: do not try to pull images tagged `cibw_local`

* use "--pull=never" for local images

* Use docker image inspect to check if an image needs to be pulled
2024-09-12 15:32:43 -04:00
cibuildwheel-bot[bot]cibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com>mayeut
fd11286290 [Bot] Update dependencies (#1998)
* Update dependencies

* fix: set minimal deployment target to macOS 10.13 with CPython 3.12

---------

Co-authored-by: cibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com>
Co-authored-by: mayeut <mayeut@users.noreply.github.com>
2024-09-12 15:32:22 -04:00
pre-commit-ci[bot]andpre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> 22dc864d60 [pre-commit.ci] pre-commit autoupdate (#2000)
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.6.3 → v0.6.4](https://github.com/astral-sh/ruff-pre-commit/compare/v0.6.3...v0.6.4)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2024-09-10 12:22:54 +01:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> 9d2f46ce4e chore(deps): bump the actions group with 2 updates (#1999)
Bumps the actions group with 2 updates: [actions/attest-build-provenance](https://github.com/actions/attest-build-provenance) and [peter-evans/create-pull-request](https://github.com/peter-evans/create-pull-request).


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

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

---
updated-dependencies:
- dependency-name: actions/attest-build-provenance
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: actions
- dependency-name: peter-evans/create-pull-request
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: actions
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-09 20:04:37 +01:00
cibuildwheel-bot[bot]andcibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com> b1ed7bb3bc [Bot] Update dependencies (#1993)
Update dependencies

Co-authored-by: cibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com>
2024-09-03 17:16:41 -04:00
Joe RickerbyandMatthieu Darbois ca08f5fbcf Customise merge behaviour depending on option. Fix #1803 (#1984)
Fix for #1803, where the method used for merging the config-settings option - string concatenation - was of little use.

I broke out the TableFmt object into a protocol-like object called OptionFormat, where the formatting and merge rules can be customised more deeply. This is more explicit, and lets us be a bit more precise with how TOML object get converted into the options.

I intend to use the flexibility of the OptionsFormat structure to tackle the remaining abiguity around environment variable quoting, as seen in the xfails in the options_test.py unit test and discussed in #1271.


Co-authored-by: Matthieu Darbois <mayeut@users.noreply.github.com>
2024-09-03 16:05:00 +01:00
pre-commit-ci[bot] 229029e112 [pre-commit.ci] pre-commit autoupdate (#1994) 2024-09-03 07:43:40 +01:00
pre-commit-ci[bot]andpre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> 3294577c17 [pre-commit.ci] pre-commit autoupdate (#1987)
* [pre-commit.ci] pre-commit autoupdate

updates:
- [github.com/astral-sh/ruff-pre-commit: v0.6.1 → v0.6.2](https://github.com/astral-sh/ruff-pre-commit/compare/v0.6.1...v0.6.2)
- [github.com/pre-commit/mirrors-mypy: v1.11.1 → v1.11.2](https://github.com/pre-commit/mirrors-mypy/compare/v1.11.1...v1.11.2)
- [github.com/python-jsonschema/check-jsonschema: 0.29.1 → 0.29.2](https://github.com/python-jsonschema/check-jsonschema/compare/0.29.1...0.29.2)

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

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

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2024-08-27 12:21:14 -04:00
cibuildwheel-bot[bot]andcibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com> 8f51efbc3e [Bot] Update dependencies (#1985)
Update dependencies

Co-authored-by: cibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com>
2024-08-26 10:41:21 -04:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> ebdbb3cbd5 chore(deps): bump actions/attest-build-provenance from 1.4.1 to 1.4.2 in the actions group (#1986)
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.1 to 1.4.2
- [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/310b0a4a3b0b78ef57ecda988ee04b132db73ef8...6149ea5740be74af77f260b9db67e633f6b0a9a1)

---
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-08-26 10:40:32 -04:00
pre-commit-ci[bot]pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>Henry Schreiner
3a30bec9ef [pre-commit.ci] pre-commit autoupdate (#1978)
* [pre-commit.ci] pre-commit autoupdate

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

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

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

* chore: ruff python-version not needed

---------

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-08-21 00:34:31 -04:00
Matthieu Darbois 126b81916d chore(ci): podman is now pre-installed on GHA runners (#1974)
podman is now pre-installed on GHA runners
2024-08-19 11:28:24 -04:00
cibuildwheel-bot[bot]andcibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com> 9abea5b73b [Bot] Update dependencies (#1976)
Update dependencies

Co-authored-by: cibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com>
2024-08-19 11:26:53 -04:00
Matthieu Darbois 170e7aaeb9 fix: TravisCI failures & status (#1970)
* fix: TravisCI failures & status
* Allow failure on s390x
2024-08-15 17:48:24 +02:00
cibuildwheel-bot[bot]andcibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com> 5b570a2451 [Bot] Update dependencies (#1963)
Update dependencies

Co-authored-by: cibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com>
2024-08-14 16:00:33 -04:00
pre-commit-ci[bot]andpre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> ffd7dddcc7 [pre-commit.ci] pre-commit autoupdate (#1967)
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.5.6 → v0.5.7](https://github.com/astral-sh/ruff-pre-commit/compare/v0.5.6...v0.5.7)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2024-08-14 16:00:02 -04:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> b0b13d3a16 chore(deps): bump actions/attest-build-provenance from 1.4.0 to 1.4.1 in the actions group (#1964)
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.0 to 1.4.1
- [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/210c1913531870065f03ce1f9440dd87bc0938cd...310b0a4a3b0b78ef57ecda988ee04b132db73ef8)

---
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-08-14 15:59:47 -04:00
Matthieu Darbois b1781e4606 fix: AppVeyor CI tests & sample (#1971) 2024-08-14 15:57:17 -04:00
Henry Schreinerandmayeut 3580374b18 fix: support empty CIBW_PLATFORM (#1969)
* fix: support empty CIBW_PLATFORM

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

* fix: support empty CIBW_PLATFORM

* Add test

---------

Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>
Co-authored-by: mayeut <mayeut@users.noreply.github.com>
2024-08-14 15:56:06 -04:00
cibuildwheel-bot[bot]andcibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com> c6dd39bd83 [Bot] Update dependencies (#1954)
Update dependencies

Co-authored-by: cibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com>
2024-08-07 16:08:57 -04:00
pre-commit-ci[bot]andpre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> dd8fe86308 [pre-commit.ci] pre-commit autoupdate (#1958)
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.5.5 → v0.5.6](https://github.com/astral-sh/ruff-pre-commit/compare/v0.5.5...v0.5.6)
- [github.com/pre-commit/mirrors-mypy: v1.11.0 → v1.11.1](https://github.com/pre-commit/mirrors-mypy/compare/v1.11.0...v1.11.1)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2024-08-07 16:07:39 -04:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> 2e12f05d5e chore(deps): bump actions/attest-build-provenance from 1.3.3 to 1.4.0 in the actions group (#1956)
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.3.3 to 1.4.0
- [Release notes](https://github.com/actions/attest-build-provenance/releases)
- [Changelog](https://github.com/actions/attest-build-provenance/blob/main/RELEASE.md)
- [Commits](https://github.com/actions/attest-build-provenance/compare/5e9cb68e95676991667494a6a4e59b8a2f13e1d0...210c1913531870065f03ce1f9440dd87bc0938cd)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-07 16:07:28 -04:00
73 changed files with 1217 additions and 627 deletions
+2
View File
@@ -4,6 +4,8 @@ set -o xtrace
if [ "$(uname -s)" == "Darwin" ]; then
sudo softwareupdate --install-rosetta --agree-to-license
else
docker run --rm --privileged docker.io/tonistiigi/binfmt:latest --install all
fi
$PYTHON --version
+2
View File
@@ -17,6 +17,7 @@ linux_x86_task:
memory: 8G
install_pre_requirements_script:
- docker run --rm --privileged docker.io/tonistiigi/binfmt:latest --install all
- apt install -y python3-venv python-is-python3
<<: *RUN_TESTS
@@ -30,6 +31,7 @@ linux_aarch64_task:
memory: 4G
install_pre_requirements_script:
- docker run --rm --privileged docker.io/tonistiigi/binfmt:latest --install all
- apt install -y python3-venv python-is-python3
<<: *RUN_TESTS
+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@5e9cb68e95676991667494a6a4e59b8a2f13e1d0 # v1.3.3
uses: actions/attest-build-provenance@1c608d11d69870c2092266b3f9a6f3abbf17002c # v1.4.3
with:
subject-path: "dist/cibuildwheel-*"
- uses: pypa/gh-action-pypi-publish@release/v1
with:
attestations: true
+9 -17
View File
@@ -38,7 +38,7 @@ jobs:
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-13, macos-14]
python_version: ['3.12']
python_version: ['3.13']
include:
- os: ubuntu-latest
python_version: '3.8'
@@ -49,19 +49,9 @@ jobs:
name: Install Python ${{ matrix.python_version }}
with:
python-version: ${{ matrix.python_version }}
allow-prereleases: true
- uses: yezz123/setup-uv@v4
# Install podman on this CI instance for podman tests on linux
# Snippet from: https://github.com/redhat-actions/podman-login/blob/main/.github/workflows/example.yml
- name: Install latest podman
if: runner.os == 'Linux'
run: |
. /etc/os-release
echo "deb https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/xUbuntu_${VERSION_ID}/ /" | sudo tee /etc/apt/sources.list.d/devel:kubic:libcontainers:stable.list
curl -sSfL "https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/xUbuntu_${VERSION_ID}/Release.key" | sudo apt-key add -
sudo apt-get update
sudo apt-get -y install podman
- uses: astral-sh/setup-uv@v3
# free some space to prevent reaching GHA disk space limits
- name: Clean docker images
@@ -70,6 +60,11 @@ jobs:
docker system prune -a -f
df -h
# for oci_container unit tests
- name: Set up QEMU
if: runner.os == 'Linux'
uses: docker/setup-qemu-action@v3
- name: Install dependencies
run: |
uv pip install --system ".[test]"
@@ -115,7 +110,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
@@ -168,10 +163,7 @@ jobs:
run: python -m pip install ".[test,uv]"
- name: Set up QEMU
id: qemu
uses: docker/setup-qemu-action@v3
with:
platforms: all
- name: Run the emulation tests
run: pytest --run-emulation ${{ matrix.arch }} test/test_emulation.py
+12 -12
View File
@@ -20,6 +20,16 @@ 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
@@ -33,18 +43,9 @@ 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@v6
uses: peter-evans/create-pull-request@v7
with:
commit-message: Update dependencies
title: '[Bot] Update dependencies'
@@ -53,7 +54,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
+1
View File
@@ -15,6 +15,7 @@ linux:
PYTEST_ADDOPTS: -k "unit_test or test_0_basic" --suppress-no-test-exit-code
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 ./bin/run_tests.py
+3 -3
View File
@@ -14,14 +14,14 @@ repos:
- id: trailing-whitespace
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.5.5
rev: v0.6.8
hooks:
- id: ruff
args: ["--fix", "--show-fixes"]
- id: ruff-format
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.11.0
rev: v1.11.2
hooks:
- id: mypy
name: mypy 3.8 on cibuildwheel/
@@ -77,7 +77,7 @@ repos:
- repo: https://github.com/python-jsonschema/check-jsonschema
rev: 0.29.1
rev: 0.29.3
hooks:
- id: check-dependabot
- id: check-github-actions
+14 -2
View File
@@ -20,6 +20,14 @@ jobs:
group: edge
virt: vm
env: PYTHON=python
# docker is outdated in the arm64-graviton2 vm focal image (19.x)
# we need to upgrade to get >= 24.0
addons:
apt:
sources:
- sourceline: 'deb https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable'
packages:
- docker-ce docker-ce-cli containerd.io
- name: Linux | ppc64le | Python 3.9
python: 3.9
@@ -44,11 +52,13 @@ jobs:
python: 3.9
services: docker
arch: s390x
allow_failure: True
env: PYTHON=python
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 ".[dev]" pytest-custom-exit-code
- $PYTHON -m pip install -e ".[test]" pytest-custom-exit-code
script: |
# travis_wait disable the output while waiting
@@ -56,5 +66,7 @@ script: |
(while true; do echo "travis_keep_alive"; sleep 300; done) &
SPINNER_PID=$!
disown
$PYTHON ./bin/run_tests.py --num-processes 2
result=0
$PYTHON ./bin/run_tests.py --num-processes 2 || result=1
kill -9 ${SPINNER_PID}
test ${result} -eq 0
+5 -5
View File
@@ -1,10 +1,10 @@
This is a summary of the host Python versions and platforms covered by the different CI platforms:
| | 3.8 | 3.9 | 3.10 | 3.11 | 3.12 |
|---------|----------------------------------------------|-----------|-----------|---------|--------------------------------------|
| Linux | AppVeyor¹ / Azure Pipelines / GitHub Actions | Travis CI | Cirrus CI | | CircleCI¹ / GitHub Actions / GitLab¹ |
| macOS | AppVeyor¹ / Azure Pipelines | | Cirrus CI | GitLab¹ | CircleCI¹ / GitHub Actions |
| Windows | AppVeyor¹ / Azure Pipelines | Travis CI | Cirrus CI | | GitHub Actions / GitLab¹ |
| | 3.8 | 3.9 | 3.10 | 3.11 | 3.12 |
|---------|----------------------------------|-----------|-----------|---------|--------------------------------------------------|
| Linux | Azure Pipelines / GitHub Actions | Travis CI | Cirrus CI | | AppVeyor¹ / CircleCI¹ / GitHub Actions / GitLab¹ |
| macOS | Azure Pipelines | | Cirrus CI | GitLab¹ | AppVeyor¹ /CircleCI¹ / GitHub Actions |
| Windows | Azure Pipelines | Travis CI | Cirrus CI | | AppVeyor¹ / GitHub Actions / GitLab¹ |
> ¹ Runs a reduced set of tests to reduce CI load
+53 -56
View File
@@ -22,20 +22,20 @@ 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.13³ | ✅ | ✅ | ✅ | ✅ | ✅² | ✅ | ✅ | ✅ | ✅ | ✅ | 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 |
| | 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 | 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 |
<sup>¹ PyPy is only supported for manylinux wheels.</sup><br>
<sup>² Windows arm64 support is experimental.</sup><br>
@@ -94,7 +94,7 @@ jobs:
- uses: actions/setup-python@v5
- name: Install cibuildwheel
run: python -m pip install cibuildwheel==2.20.0
run: python -m pip install cibuildwheel==2.21.2
- name: Build wheels
run: python -m cibuildwheel --output-dir wheelhouse
@@ -161,8 +161,8 @@ Here are some repos that use cibuildwheel.
| [scikit-learn][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | The machine learning library. A complex but clean config using many of cibuildwheel's features to build a large project with Cython and C++ extensions. |
| [pytorch-fairseq][] | ![github icon][] | ![apple icon][] ![linux icon][] | Facebook AI Research Sequence-to-Sequence Toolkit written in Python. |
| [NumPy][] | ![github icon][] ![travisci icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | The fundamental package for scientific computing with Python. |
| [Tornado][] | ![github icon][] | ![linux icon][] ![apple icon][] ![windows icon][] | Tornado is a Python web framework and asynchronous networking library. Uses stable ABI for a small C extension. |
| [duckdb][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | DuckDB is an analytical in-process SQL database management system |
| [Tornado][] | ![github icon][] | ![linux icon][] ![apple icon][] ![windows icon][] | Tornado is a Python web framework and asynchronous networking library. Uses stable ABI for a small C extension. |
| [NCNN][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | ncnn is a high-performance neural network inference framework optimized for the mobile platform |
| [Matplotlib][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | The venerable Matplotlib, a Python library with C++ portions |
| [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. |
@@ -172,8 +172,8 @@ Here are some repos that use cibuildwheel.
[scikit-learn]: https://github.com/scikit-learn/scikit-learn
[pytorch-fairseq]: https://github.com/facebookresearch/fairseq
[NumPy]: https://github.com/numpy/numpy
[Tornado]: https://github.com/tornadoweb/tornado
[duckdb]: https://github.com/duckdb/duckdb
[Tornado]: https://github.com/tornadoweb/tornado
[NCNN]: https://github.com/Tencent/ncnn
[Matplotlib]: https://github.com/matplotlib/matplotlib
[Prophet]: https://github.com/facebook/prophet
@@ -211,8 +211,42 @@ Changelog
<!-- this section was generated by bin/update_readme_changelog.py -- do not edit manually -->
### 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_
- ⚠️ 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)
### v2.20.0
_4 August 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)
@@ -223,6 +257,8 @@ Changelog
### 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)
@@ -232,45 +268,6 @@ Changelog
- 📚 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
- 🐛 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
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)
### v2.18.1
- 🌟 Add free-threaded Linux and Windows builds for 3.13. New identifiers `cp313t-*`, new option `CIBW_FREE_THREADED_SUPPORT`/`tool.cibuildwheel.free-threaded-support` required to opt-in. [See the docs](https://cibuildwheel.pypa.io/en/stable/options/#free-threaded-support) for more information. (#1831)
- ✨ The `container-engine` is now a build (non-global) option. (#1792)
- 🛠 The build backend for cibuildwheel is now hatchling. (#1297)
- 🛠 Significant improvements and modernization to our noxfile. (#1823)
- 🛠 Use pylint's new GitHub Actions reporter instead of a custom matcher. (#1823)
- 🛠 Unpin virtualenv updates for Python 3.7+ (#1830)
- 🐛 Fix running linux tests from Windows or macOS ARM. (#1788)
- 📚 Fix our documentation build. (#1821)
<!-- END bin/update_readme_changelog.py -->
---
+14 -11
View File
@@ -1,26 +1,29 @@
environment:
matrix:
- APPVEYOR_BUILD_WORKER_IMAGE: Ubuntu
APPVEYOR_JOB_NAME: "python38-x64-ubuntu"
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
APPVEYOR_JOB_NAME: "python38-x64-vs2015"
- APPVEYOR_BUILD_WORKER_IMAGE: macos
APPVEYOR_JOB_NAME: "python38-x64-macos"
- APPVEYOR_BUILD_WORKER_IMAGE: Ubuntu2204
APPVEYOR_JOB_NAME: "python312-x64-ubuntu"
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022
APPVEYOR_JOB_NAME: "python312-x64-vs2022"
- APPVEYOR_BUILD_WORKER_IMAGE: macos-sonoma
APPVEYOR_JOB_NAME: "python312-x64-macos"
stack: python 3.8
stack: python 3.12
build: off
init:
- cmd: set PATH=C:\Python38;C:\Python38\Scripts;%PATH%
- ps: |
$BRANCH = if ($env:APPVEYOR_PULL_REQUEST_HEAD_REPO_BRANCH) { $env:APPVEYOR_PULL_REQUEST_HEAD_REPO_BRANCH } else { $env:APPVEYOR_REPO_BRANCH }
if (-not ($BRANCH -eq 'main' -or $BRANCH.ToLower().StartsWith('appveyor-'))) {
$env:PYTEST_ADDOPTS='-k "unit_test or test_0_basic" --suppress-no-test-exit-code'
$env:PYTEST_ADDOPTS = '-k "unit_test or test_0_basic" --suppress-no-test-exit-code'
}
if ($IsLinux) {
docker run --rm --privileged docker.io/tonistiigi/binfmt:latest --install all
}
python -m pip install -U pip
install: python -m pip install -e ".[dev]" pytest-custom-exit-code
install:
- python -m pip install -U pip
- python -m pip install -e ".[dev]" pytest-custom-exit-code
# the '-u' flag is required so the output is in the correct order.
# See https://github.com/pypa/cibuildwheel/pull/24 for more info.
+1
View File
@@ -13,6 +13,7 @@ jobs:
inputs:
versionSpec: '3.8'
- bash: |
docker run --rm --privileged docker.io/tonistiigi/binfmt:latest --install all
python -m pip install -e ".[dev]"
python ./bin/run_tests.py
+3
View File
@@ -137,6 +137,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
+1 -1
View File
@@ -28,7 +28,7 @@ if __name__ == "__main__":
# unit tests
unit_test_args = [sys.executable, "-m", "pytest", "unit_test"]
if sys.platform.startswith("linux"):
if sys.platform.startswith("linux") and os.environ.get("CIBW_PLATFORM", "linux") == "linux":
# run the docker unit tests only on Linux
unit_test_args += ["--run-docker"]
+1
View File
@@ -65,6 +65,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()
+1 -1
View File
@@ -1,3 +1,3 @@
from __future__ import annotations
__version__ = "2.20.0"
__version__ = "2.21.2"
+1 -2
View File
@@ -240,7 +240,7 @@ def _compute_platform_auto() -> PlatformName:
def _compute_platform(args: CommandLineArguments) -> PlatformName:
platform_option_value = args.platform or os.environ.get("CIBW_PLATFORM", "auto")
platform_option_value = args.platform or os.environ.get("CIBW_PLATFORM", "") or "auto"
if args.only and args.platform is not None:
msg = "--platform cannot be specified with --only, it is computed from --only"
@@ -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
+8 -6
View File
@@ -37,6 +37,7 @@ class Architecture(Enum):
aarch64 = "aarch64"
ppc64le = "ppc64le"
s390x = "s390x"
armv7l = "armv7l"
# mac archs
universal2 = "universal2"
@@ -64,7 +65,9 @@ class Architecture(Enum):
if arch_str == "auto":
result |= Architecture.auto_archs(platform=platform)
elif arch_str == "native":
result.add(Architecture(platform_module.machine()))
native_arch = Architecture.native_arch(platform=platform)
if native_arch:
result.add(native_arch)
elif arch_str == "all":
result |= Architecture.all_archs(platform=platform)
elif arch_str == "auto64":
@@ -130,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},
@@ -138,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(
+6
View File
@@ -58,3 +58,9 @@ class AlreadyBuiltWheelError(FatalError):
)
super().__init__(message)
self.return_code = 6
class OCIEngineTooOldError(FatalError):
def __init__(self, message: str) -> None:
super().__init__(message)
self.return_code = 7
+15 -5
View File
@@ -14,7 +14,7 @@ from . import errors
from ._compat.typing import assert_never
from .architecture import Architecture
from .logger import log
from .oci_container import OCIContainer, OCIContainerEngineConfig
from .oci_container import OCIContainer, OCIContainerEngineConfig, OCIPlatform
from .options import BuildOptions, Options
from .typing import PathOrStr
from .util import (
@@ -29,6 +29,15 @@ from .util import (
unwrap,
)
ARCHITECTURE_OCI_PLATFORM_MAP = {
Architecture.x86_64: OCIPlatform.AMD64,
Architecture.i686: OCIPlatform.i386,
Architecture.aarch64: OCIPlatform.ARM64,
Architecture.ppc64le: OCIPlatform.PPC64LE,
Architecture.s390x: OCIPlatform.S390X,
Architecture.armv7l: OCIPlatform.ARMV7,
}
@dataclass(frozen=True)
class PythonConfiguration:
@@ -196,6 +205,8 @@ def build_in_container(
dependency_constraint_flags: list[PathOrStr] = []
log.step("Setting up build environment...")
if build_options.dependency_constraints:
constraints_file = build_options.dependency_constraints.get_for_python_version(
config.version
@@ -205,8 +216,6 @@ def build_in_container(
container.copy_into(constraints_file, container_constraints_file)
dependency_constraint_flags = ["-c", container_constraints_file]
log.step("Setting up build environment...")
env = container.get_environment()
env["PIP_DISABLE_PIP_VERSION_CHECK"] = "1"
env["PIP_ROOT_USER_ACTION"] = "ignore"
@@ -337,7 +346,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"]
@@ -446,10 +455,11 @@ def build(options: Options, tmp_path: Path) -> None: # noqa: ARG001
log.step(f"Starting container image {build_step.container_image}...")
print(f"info: This container will host the build for {', '.join(ids_to_build)}...")
architecture = Architecture(build_step.platform_tag.split("_", 1)[1])
with OCIContainer(
image=build_step.container_image,
enforce_32_bit=build_step.platform_tag.endswith("i686"),
oci_platform=ARCHITECTURE_OCI_PLATFORM_MAP[architecture],
cwd=container_project_path,
engine=build_step.container_engine,
) as container:
+2 -1
View File
@@ -27,7 +27,8 @@ PLATFORM_IDENTIFIER_DESCRIPTIONS: Final[dict[str, str]] = {
"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",
+10 -9
View File
@@ -193,6 +193,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 +205,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]
@@ -294,10 +297,10 @@ def setup_python(
# Set MACOSX_DEPLOYMENT_TARGET, if the user didn't set it.
# For arm64, the minimal deployment target is 11.0.
# On x86_64 (or universal2), use 10.9 as a default.
# CPython 3.13 needs 10.13.
# CPython 3.12.6+ needs 10.13.
if config_is_arm64:
default_target = "11.0"
elif Version(python_configuration.version) >= Version("3.13"):
elif Version(python_configuration.version) >= Version("3.12"):
default_target = "10.13"
elif python_configuration.identifier.startswith("pp") and Version(
python_configuration.version
@@ -415,9 +418,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"
+128 -38
View File
@@ -8,18 +8,23 @@ import shlex
import shutil
import subprocess
import sys
import textwrap
import typing
import uuid
from collections.abc import Mapping, Sequence
from dataclasses import dataclass, field
from enum import Enum
from pathlib import Path, PurePath, PurePosixPath
from types import TracebackType
from typing import IO, Dict, Literal
from ._compat.typing import Self
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,
@@ -29,6 +34,16 @@ from .util import (
ContainerEngineName = Literal["docker", "podman"]
# Order of the enum matters for tests. 386 shall appear before amd64.
class OCIPlatform(Enum):
i386 = "linux/386"
AMD64 = "linux/amd64"
ARMV7 = "linux/arm/v7"
ARM64 = "linux/arm64"
PPC64LE = "linux/ppc64le"
S390X = "linux/s390x"
@dataclass(frozen=True)
class OCIContainerEngineConfig:
name: ContainerEngineName
@@ -56,6 +71,15 @@ class OCIContainerEngineConfig:
disable_host_mount = (
strtobool(disable_host_mount_options[-1]) if disable_host_mount_options else False
)
if "--platform" in create_args or any(arg.startswith("--platform=") for arg in create_args):
msg = "Using '--platform' in 'container-engine::create_args' is deprecated. It will be ignored."
log.warning(msg)
if "--platform" in create_args:
index = create_args.index("--platform")
create_args.pop(index)
create_args.pop(index)
else:
create_args = [arg for arg in create_args if not arg.startswith("--platform=")]
return OCIContainerEngineConfig(
name=name, create_args=tuple(create_args), disable_host_mount=disable_host_mount
@@ -75,6 +99,52 @@ class OCIContainerEngineConfig:
DEFAULT_ENGINE = OCIContainerEngineConfig("docker")
def _check_engine_version(engine: OCIContainerEngineConfig) -> None:
try:
version_string = call(engine.name, "version", "-f", "{{json .}}", capture_stdout=True)
version_info = json.loads(version_string.strip())
if engine.name == "docker":
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":
# podman uses the same version string for "Version" & "ApiVersion"
client_version = FlexibleVersion(version_info["Client"]["Version"])
if "Server" in version_info:
server_version = FlexibleVersion(version_info["Server"]["Version"])
else:
server_version = client_version
# --platform support was introduced in v3
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 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:
"""
An object that represents a running OCI (e.g. Docker) container.
@@ -108,7 +178,7 @@ class OCIContainer:
self,
*,
image: str,
enforce_32_bit: bool = False,
oci_platform: OCIPlatform,
cwd: PathOrStr | None = None,
engine: OCIContainerEngineConfig = DEFAULT_ENGINE,
):
@@ -117,14 +187,48 @@ class OCIContainer:
raise ValueError(msg)
self.image = image
self.enforce_32_bit = enforce_32_bit
self.oci_platform = oci_platform
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:
oci_platform = self.oci_platform
# we need '--pull=always' otherwise some images with the wrong platform get re-used (e.g. 386 image for amd64)
# c.f. https://github.com/moby/moby/issues/48197#issuecomment-2282802313
pull = "always"
try:
image_platform = call(
self.engine.name,
"image",
"inspect",
self.image,
"--format",
(
"{{.Os}}/{{.Architecture}}/{{.Variant}}"
if len(oci_platform.value.split("/")) == 3
else "{{.Os}}/{{.Architecture}}"
),
capture_stdout=True,
).strip()
if image_platform == oci_platform.value:
# in case the correct image is already present, don't pull
# this allows to run local only images
pull = "never"
except subprocess.CalledProcessError:
pass
return f"--platform={oci_platform.value}", f"--pull={pull}"
def __enter__(self) -> Self:
self.name = f"cibuildwheel-{uuid.uuid4()}"
_check_engine_version(self.engine)
# work-around for Travis-CI PPC64le Docker runs since 2021:
# this avoids network splits
# https://github.com/pypa/cibuildwheel/issues/904
@@ -133,15 +237,28 @@ class OCIContainer:
if detect_ci_provider() == CIProvider.travis_ci and platform.machine() == "ppc64le":
network_args = ["--network=host"]
platform_args = self._get_platform_args()
simulate_32_bit = False
if self.enforce_32_bit:
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
container_machine = call(
self.engine.name, "run", "--rm", self.image, "uname", "-m", capture_stdout=True
).strip()
simulate_32_bit = container_machine != "i686"
run_cmd = [self.engine.name, "run", "--rm"]
ctr_cmd = ["uname", "-m"]
try:
container_machine = call(
*run_cmd, *platform_args, self.image, *ctr_cmd, capture_stdout=True
).strip()
except subprocess.CalledProcessError:
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()
simulate_32_bit = container_machine not in {"i686", "armv7l", "armv8l"}
shell_args = ["linux32", "/bin/bash"] if simulate_32_bit else ["/bin/bash"]
@@ -155,6 +272,7 @@ class OCIContainer:
"--interactive",
*(["--volume=/:/host"] if not self.engine.disable_host_mount else []),
*network_args,
*platform_args,
*self.engine.create_args,
self.image,
*shell_args,
@@ -221,15 +339,10 @@ class OCIContainer:
self.name = None
def copy_into(self, from_path: Path, to_path: PurePath) -> None:
# `docker cp` causes 'no space left on device' error when
# a container is running and the host filesystem is
# mounted. https://github.com/moby/moby/issues/38995
# Use `docker exec` instead.
if from_path.is_dir():
self.call(["mkdir", "-p", to_path])
subprocess.run(
f"tar cf - . | {self.engine.name} exec -i {self.name} tar --no-same-owner -xC {shell_quote(to_path)} -f -",
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,
@@ -264,30 +377,7 @@ class OCIContainer:
def copy_out(self, from_path: PurePath, to_path: Path) -> None:
# note: we assume from_path is a dir
to_path.mkdir(parents=True, exist_ok=True)
if self.engine.name == "podman":
subprocess.run(
[
self.engine.name,
"cp",
f"{self.name}:{from_path}/.",
str(to_path),
],
check=True,
cwd=to_path,
)
elif self.engine.name == "docker":
# There is a bug in docker that prevents a simple 'cp' invocation
# from working https://github.com/moby/moby/issues/38995
command = f"{self.engine.name} exec -i {self.name} tar -cC {shell_quote(from_path)} -f - . | tar -xf -"
subprocess.run(
command,
shell=True,
check=True,
cwd=to_path,
)
else:
raise KeyError(self.engine.name)
call(self.engine.name, "cp", f"{self.name}:{from_path}/.", to_path)
def glob(self, path: PurePosixPath, pattern: str) -> list[PurePosixPath]:
glob_pattern = path.joinpath(pattern)
+182 -97
View File
@@ -9,15 +9,15 @@ import enum
import functools
import shlex
import textwrap
from collections.abc import Callable, Generator, Iterable, Iterator, Set
from collections.abc import Generator, Iterable, Set
from pathlib import Path
from typing import Any, Literal, Mapping, Sequence, TypedDict, Union # noqa: TID251
from typing import Any, Literal, Mapping, Sequence, Union # noqa: TID251
from packaging.specifiers import SpecifierSet
from . import errors
from ._compat import tomllib
from ._compat.typing import NotRequired, assert_never
from ._compat.typing import assert_never
from .architecture import Architecture
from .environment import EnvironmentParseError, ParsedEnvironment, parse_environment
from .logger import log
@@ -118,13 +118,16 @@ class BuildOptions:
return self.globals.architectures
Setting = Union[Mapping[str, str], Sequence[str], str, int, bool]
SettingLeaf = Union[str, int, bool]
SettingList = Sequence[SettingLeaf]
SettingTable = Mapping[str, Union[SettingLeaf, SettingList]]
SettingValue = Union[SettingTable, SettingList, SettingLeaf]
@dataclasses.dataclass(frozen=True)
class Override:
select_pattern: str
options: dict[str, Setting]
options: dict[str, SettingValue]
inherit: dict[str, InheritRule]
@@ -137,22 +140,123 @@ DISALLOWED_OPTIONS = {
}
class TableFmt(TypedDict):
# a format string, used with '.format', with `k` and `v` parameters
# e.g. "{k}={v}"
item: str
# the string that is inserted between items
# e.g. " "
sep: str
# a quoting function that, if supplied, is called to quote each value
# e.g. shlex.quote
quote: NotRequired[Callable[[str], str]]
class ConfigOptionError(KeyError):
class OptionsReaderError(errors.ConfigurationError):
pass
class OptionFormat:
"""
Base class for option format specifiers. These objects describe how values
can be parsed from rich TOML values and how they're merged together.
"""
class NotSupported(Exception):
pass
def format_list(self, value: SettingList) -> str: # noqa: ARG002
raise OptionFormat.NotSupported
def format_table(self, table: SettingTable) -> str: # noqa: ARG002
raise OptionFormat.NotSupported
def merge_values(self, before: str, after: str) -> str: # noqa: ARG002
raise OptionFormat.NotSupported
class ListFormat(OptionFormat):
"""
A format that joins lists with a separator.
"""
def __init__(self, sep: str) -> None:
self.sep = sep
def format_list(self, value: SettingList) -> str:
return self.sep.join(str(v) for v in value)
def merge_values(self, before: str, after: str) -> str:
return f"{before}{self.sep}{after}"
class ShlexTableFormat(OptionFormat):
"""
The standard table format uses shlex.quote to quote values and shlex.split
to unquote and split them. When merging values, keys in before are
replaced by keys in after.
"""
def __init__(self, sep: str = " ", pair_sep: str = "=", allow_merge: bool = True) -> None:
self.sep = sep
self.pair_sep = pair_sep
self.allow_merge = allow_merge
def format_table(self, table: SettingTable) -> str:
assignments: list[tuple[str, str]] = []
for k, v in table.items():
if shlex.split(k) != [k]:
msg = f"Invalid table key: {k}"
raise OptionsReaderError(msg)
if isinstance(v, str):
assignments.append((k, v))
elif isinstance(v, Sequence):
for inner_v in v:
assignments.append((k, str(inner_v)))
else:
assignments.append((k, str(v)))
return self.sep.join(f"{k}{self.pair_sep}{shlex.quote(v)}" for k, v in assignments)
def merge_values(self, before: str, after: str) -> str:
if not self.allow_merge:
raise OptionFormat.NotSupported
before_dict = self.parse_table(before)
after_dict = self.parse_table(after)
return self.format_table({**before_dict, **after_dict})
def parse_table(self, table: str) -> Mapping[str, str | Sequence[str]]:
assignments: list[tuple[str, str]] = []
for assignment_str in shlex.split(table):
key, sep, value = assignment_str.partition(self.pair_sep)
if not sep:
msg = f"malformed option with value {assignment_str!r}"
raise OptionsReaderError(msg)
assignments.append((key, value))
result: dict[str, str | list[str]] = {}
for key, value in assignments:
if key in result:
existing_value = result[key]
if isinstance(existing_value, list):
result[key] = [*existing_value, value]
else:
result[key] = [existing_value, value]
else:
result[key] = value
return result
class EnvironmentFormat(OptionFormat):
"""
The environment format accepts a table of environment variables, where the
values may contain variables or command substitutions.
"""
def format_table(self, table: SettingTable) -> str:
return " ".join(f'{k}="{v}"' for k, v in table.items())
def merge_values(self, before: str, after: str) -> str:
return f"{before} {after}"
class InheritRule(enum.Enum):
NONE = enum.auto()
APPEND = enum.auto()
@@ -160,10 +264,9 @@ class InheritRule(enum.Enum):
def _resolve_cascade(
*pairs: tuple[Setting | None, InheritRule],
*pairs: tuple[SettingValue | None, InheritRule],
ignore_empty: bool = False,
list_sep: str | None = None,
table_format: TableFmt | None = None,
option_format: OptionFormat | None = None,
) -> str:
"""
Given a cascade of values with inherit rules, resolve them into a single
@@ -186,13 +289,6 @@ def _resolve_cascade(
result: str | None = None
if table_format is not None:
merge_sep = table_format["sep"]
elif list_sep is not None:
merge_sep = list_sep
else:
merge_sep = None
for value, rule in pairs:
if value is None:
continue
@@ -200,14 +296,9 @@ def _resolve_cascade(
if ignore_empty and not value and value is not False:
continue
value_string = _stringify_setting(value, list_sep, table_format)
value_string = _stringify_setting(value, option_format=option_format)
result = _merge_values(
result,
value_string,
rule=rule,
merge_sep=merge_sep,
)
result = _apply_inherit_rule(result, value_string, rule=rule, option_format=option_format)
if result is None:
msg = "a setting should at least have a default value"
@@ -216,8 +307,9 @@ def _resolve_cascade(
return result
# pylint: disable-next=inconsistent-return-statements
def _merge_values(before: str | None, after: str, rule: InheritRule, merge_sep: str | None) -> str:
def _apply_inherit_rule(
before: str | None, after: str, rule: InheritRule, option_format: OptionFormat | None
) -> str:
if rule == InheritRule.NONE:
return after
@@ -230,34 +322,39 @@ def _merge_values(before: str | None, after: str, rule: InheritRule, merge_sep:
# if after is an empty string, we shouldn't add any separator
return before
if not merge_sep:
if not option_format:
msg = f"Don't know how to merge {before!r} and {after!r} with {rule}"
raise ConfigOptionError(msg)
raise OptionsReaderError(msg)
if rule == InheritRule.APPEND:
return f"{before}{merge_sep}{after}"
elif rule == InheritRule.PREPEND:
return f"{after}{merge_sep}{before}"
else:
assert_never(rule)
return option_format.merge_values(before, after)
if rule == InheritRule.PREPEND:
return option_format.merge_values(after, before)
assert_never(rule)
def _stringify_setting(
setting: Setting, list_sep: str | None, table_format: TableFmt | None
setting: SettingValue,
option_format: OptionFormat | None,
) -> str:
if isinstance(setting, Mapping):
if table_format is None:
try:
if option_format is None:
raise OptionFormat.NotSupported
return option_format.format_table(setting)
except OptionFormat.NotSupported:
msg = f"Error converting {setting!r} to a string: this setting doesn't accept a table"
raise ConfigOptionError(msg)
return table_format["sep"].join(
item for k, v in setting.items() for item in _inner_fmt(k, v, table_format)
)
raise OptionsReaderError(msg) from None
if not isinstance(setting, str) and isinstance(setting, Sequence):
if list_sep is None:
try:
if option_format is None:
raise OptionFormat.NotSupported
return option_format.format_list(setting)
except OptionFormat.NotSupported:
msg = f"Error converting {setting!r} to a string: this setting doesn't accept a list"
raise ConfigOptionError(msg)
return list_sep.join(setting)
raise OptionsReaderError(msg) from None
if isinstance(setting, (bool, int)):
return str(setting)
@@ -323,14 +420,14 @@ class OptionsReader:
if config_overrides is not None:
if not isinstance(config_overrides, list):
msg = "'tool.cibuildwheel.overrides' must be a list"
raise ConfigOptionError(msg)
raise OptionsReaderError(msg)
for config_override in config_overrides:
select = config_override.pop("select", None)
if not select:
msg = "'select' must be set in an override"
raise ConfigOptionError(msg)
raise OptionsReaderError(msg)
if isinstance(select, list):
select = " ".join(select)
@@ -340,7 +437,7 @@ class OptionsReader:
i in {"none", "append", "prepend"} for i in inherit.values()
):
msg = "'inherit' must be a dict containing only {'none', 'append', 'prepend'} values"
raise ConfigOptionError(msg)
raise OptionsReaderError(msg)
inherit_enum = {k: InheritRule[v.upper()] for k, v in inherit.items()}
@@ -358,7 +455,7 @@ class OptionsReader:
matches = difflib.get_close_matches(name, allowed_option_names, 1, 0.7)
if matches:
msg += f" Perhaps you meant {matches[0]!r}?"
raise ConfigOptionError(msg)
raise OptionsReaderError(msg)
def _validate_platform_option(self, name: str) -> None:
"""
@@ -368,7 +465,7 @@ class OptionsReader:
disallowed_platform_options = self.disallow.get(self.platform, set())
if name in disallowed_platform_options:
msg = f"{name!r} is not allowed in {disallowed_platform_options}"
raise ConfigOptionError(msg)
raise OptionsReaderError(msg)
allowed_option_names = self.default_options.keys() | self.default_platform_options.keys()
@@ -377,7 +474,7 @@ class OptionsReader:
matches = difflib.get_close_matches(name, allowed_option_names, 1, 0.7)
if matches:
msg += f" Perhaps you meant {matches[0]!r}?"
raise ConfigOptionError(msg)
raise OptionsReaderError(msg)
def _load_file(self, filename: Path) -> tuple[dict[str, Any], dict[str, Any]]:
"""
@@ -412,8 +509,7 @@ class OptionsReader:
name: str,
*,
env_plat: bool = True,
list_sep: str | None = None,
table_format: TableFmt | None = None,
option_format: OptionFormat | None = None,
ignore_empty: bool = False,
) -> str:
"""
@@ -429,7 +525,7 @@ class OptionsReader:
if name not in self.default_options and name not in self.default_platform_options:
msg = f"{name!r} must be in cibuildwheel/resources/defaults.toml file to be accessed."
raise ConfigOptionError(msg)
raise OptionsReaderError(msg)
# Environment variable form
envvar = f"CIBW_{name.upper().replace('-', '_')}"
@@ -449,26 +545,10 @@ class OptionsReader:
(self.env.get(envvar), InheritRule.NONE),
(self.env.get(plat_envvar) if env_plat else None, InheritRule.NONE),
ignore_empty=ignore_empty,
list_sep=list_sep,
table_format=table_format,
option_format=option_format,
)
def _inner_fmt(k: str, v: Any, table: TableFmt) -> Iterator[str]:
quote_function = table.get("quote", lambda a: a)
if isinstance(v, list):
for inner_v in v:
qv = quote_function(inner_v)
yield table["item"].format(k=k, v=qv)
elif isinstance(v, bool):
qv = quote_function(str(v))
yield table["item"].format(k=k, v=qv)
else:
qv = quote_function(v)
yield table["item"].format(k=k, v=qv)
class Options:
def __init__(
self,
@@ -513,9 +593,11 @@ class Options:
package_dir = args.package_dir
output_dir = args.output_dir
build_config = self.reader.get("build", env_plat=False, list_sep=" ") or "*"
skip_config = self.reader.get("skip", env_plat=False, list_sep=" ")
test_skip = self.reader.get("test-skip", env_plat=False, list_sep=" ")
build_config = (
self.reader.get("build", env_plat=False, option_format=ListFormat(sep=" ")) or "*"
)
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=" "))
free_threaded_support = strtobool(
self.reader.get("free-threaded-support", env_plat=False, ignore_empty=True)
@@ -534,7 +616,7 @@ class Options:
)
requires_python = None if requires_python_str is None else SpecifierSet(requires_python_str)
archs_config_str = args.archs or self.reader.get("archs", list_sep=" ")
archs_config_str = args.archs or self.reader.get("archs", option_format=ListFormat(sep=" "))
architectures = Architecture.parse_config(archs_config_str, platform=self.platform)
# Process `--only`
@@ -569,30 +651,33 @@ class Options:
"""
with self.reader.identifier(identifier):
before_all = self.reader.get("before-all", list_sep=" && ")
before_all = self.reader.get("before-all", option_format=ListFormat(sep=" && "))
environment_config = self.reader.get(
"environment", table_format={"item": '{k}="{v}"', "sep": " "}
environment_config = self.reader.get("environment", option_format=EnvironmentFormat())
environment_pass = self.reader.get(
"environment-pass", option_format=ListFormat(sep=" ")
).split()
before_build = self.reader.get("before-build", option_format=ListFormat(sep=" && "))
repair_command = self.reader.get(
"repair-wheel-command", option_format=ListFormat(sep=" && ")
)
environment_pass = self.reader.get("environment-pass", list_sep=" ").split()
before_build = self.reader.get("before-build", list_sep=" && ")
repair_command = self.reader.get("repair-wheel-command", list_sep=" && ")
config_settings = self.reader.get(
"config-settings",
table_format={"item": "{k}={v}", "sep": " ", "quote": shlex.quote},
"config-settings", option_format=ShlexTableFormat(sep=" ", pair_sep="=")
)
dependency_versions = self.reader.get("dependency-versions")
test_command = self.reader.get("test-command", list_sep=" && ")
before_test = self.reader.get("before-test", list_sep=" && ")
test_requires = self.reader.get("test-requires", list_sep=" ").split()
test_extras = self.reader.get("test-extras", list_sep=",")
test_command = self.reader.get("test-command", option_format=ListFormat(sep=" && "))
before_test = self.reader.get("before-test", option_format=ListFormat(sep=" && "))
test_requires = self.reader.get(
"test-requires", option_format=ListFormat(sep=" ")
).split()
test_extras = self.reader.get("test-extras", option_format=ListFormat(sep=","))
build_verbosity_str = self.reader.get("build-verbosity")
build_frontend_str = self.reader.get(
"build-frontend",
env_plat=False,
table_format={"item": "{k}:{v}", "sep": "; ", "quote": shlex.quote},
option_format=ShlexTableFormat(sep="; ", pair_sep=":", allow_merge=False),
)
build_frontend: BuildFrontendConfig | None
if not build_frontend_str or build_frontend_str == "default":
@@ -674,7 +759,7 @@ class Options:
container_engine_str = self.reader.get(
"container-engine",
table_format={"item": "{k}:{v}", "sep": "; ", "quote": shlex.quote},
option_format=ShlexTableFormat(sep="; ", pair_sep=":", allow_merge=False),
)
try:
+30 -21
View File
@@ -102,6 +102,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 +129,22 @@ 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.4/python-3.12.4-macos11.pkg" },
{ identifier = "cp312-macosx_arm64", version = "3.12", url = "https://www.python.org/ftp/python/3.12.4/python-3.12.4-macos11.pkg" },
{ identifier = "cp312-macosx_universal2", version = "3.12", url = "https://www.python.org/ftp/python/3.12.4/python-3.12.4-macos11.pkg" },
{ identifier = "cp313-macosx_x86_64", version = "3.13", url = "https://www.python.org/ftp/python/3.13.0/python-3.13.0rc1-macos11.pkg" },
{ identifier = "cp313-macosx_arm64", version = "3.13", url = "https://www.python.org/ftp/python/3.13.0/python-3.13.0rc1-macos11.pkg" },
{ identifier = "cp313-macosx_universal2", version = "3.13", url = "https://www.python.org/ftp/python/3.13.0/python-3.13.0rc1-macos11.pkg" },
{ identifier = "cp313t-macosx_x86_64", version = "3.13", url = "https://www.python.org/ftp/python/3.13.0/python-3.13.0rc1-macos11.pkg" },
{ identifier = "cp313t-macosx_arm64", version = "3.13", url = "https://www.python.org/ftp/python/3.13.0/python-3.13.0rc1-macos11.pkg" },
{ identifier = "cp313t-macosx_universal2", version = "3.13", url = "https://www.python.org/ftp/python/3.13.0/python-3.13.0rc1-macos11.pkg" },
{ identifier = "cp312-macosx_x86_64", version = "3.12", url = "https://www.python.org/ftp/python/3.12.7/python-3.12.7-macos11.pkg" },
{ identifier = "cp312-macosx_arm64", version = "3.12", url = "https://www.python.org/ftp/python/3.12.7/python-3.12.7-macos11.pkg" },
{ identifier = "cp312-macosx_universal2", version = "3.12", url = "https://www.python.org/ftp/python/3.12.7/python-3.12.7-macos11.pkg" },
{ identifier = "cp313-macosx_x86_64", version = "3.13", url = "https://www.python.org/ftp/python/3.13.0/python-3.13.0rc3-macos11.pkg" },
{ identifier = "cp313-macosx_arm64", version = "3.13", url = "https://www.python.org/ftp/python/3.13.0/python-3.13.0rc3-macos11.pkg" },
{ identifier = "cp313-macosx_universal2", version = "3.13", url = "https://www.python.org/ftp/python/3.13.0/python-3.13.0rc3-macos11.pkg" },
{ identifier = "cp313t-macosx_x86_64", version = "3.13", url = "https://www.python.org/ftp/python/3.13.0/python-3.13.0rc3-macos11.pkg" },
{ identifier = "cp313t-macosx_arm64", version = "3.13", url = "https://www.python.org/ftp/python/3.13.0/python-3.13.0rc3-macos11.pkg" },
{ identifier = "cp313t-macosx_universal2", version = "3.13", url = "https://www.python.org/ftp/python/3.13.0/python-3.13.0rc3-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.16-macos_x86_64.tar.bz2" },
{ identifier = "pp310-macosx_arm64", version = "3.10", url = "https://downloads.python.org/pypy/pypy3.10-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" },
]
[windows]
@@ -152,22 +161,22 @@ 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.4", arch = "32" },
{ identifier = "cp312-win_amd64", version = "3.12.4", arch = "64" },
{ identifier = "cp313-win32", version = "3.13.0-rc1", arch = "32" },
{ identifier = "cp313t-win32", version = "3.13.0-rc1", arch = "32" },
{ identifier = "cp313-win_amd64", version = "3.13.0-rc1", arch = "64" },
{ identifier = "cp313t-win_amd64", version = "3.13.0-rc1", arch = "64" },
{ identifier = "cp312-win32", version = "3.12.7", arch = "32" },
{ identifier = "cp312-win_amd64", version = "3.12.7", arch = "64" },
{ identifier = "cp313-win32", version = "3.13.0-rc3", arch = "32" },
{ identifier = "cp313t-win32", version = "3.13.0-rc3", arch = "32" },
{ identifier = "cp313-win_amd64", version = "3.13.0-rc3", arch = "64" },
{ identifier = "cp313t-win_amd64", version = "3.13.0-rc3", 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.4", arch = "ARM64" },
{ identifier = "cp313-win_arm64", version = "3.13.0-rc1", arch = "ARM64" },
{ identifier = "cp313t-win_arm64", version = "3.13.0-rc1", arch = "ARM64" },
{ identifier = "cp312-win_arm64", version = "3.12.7", arch = "ARM64" },
{ identifier = "cp313-win_arm64", version = "3.13.0-rc3", arch = "ARM64" },
{ identifier = "cp313t-win_arm64", version = "3.13.0-rc3", 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.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" },
]
[pyodide]
@@ -312,6 +312,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",
@@ -542,6 +547,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"
},
@@ -630,6 +638,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"
},
@@ -2,15 +2,15 @@
# nox -s update_constraints
annotated-types==0.7.0
# via pydantic
anyio==4.4.0
anyio==4.6.0
# via httpx
auditwheel-emscripten==0.0.16
# via pyodide-build
build==1.2.1
build==1.2.2
# via
# -r .nox/update_constraints/tmp/constraints-pyodide.in
# pyodide-build
certifi==2024.7.4
certifi==2024.8.30
# via
# httpcore
# httpx
@@ -21,19 +21,19 @@ click==8.1.7
# via typer
cloudpickle==3.0.0
# via loky
cmake==3.30.1
cmake==3.30.4
# via pyodide-build
distlib==0.3.8
# via virtualenv
filelock==3.15.4
filelock==3.16.1
# via virtualenv
h11==0.14.0
# via httpcore
httpcore==1.0.5
httpcore==1.0.6
# via httpx
httpx==0.27.0
httpx==0.27.2
# via unearth
idna==3.7
idna==3.10
# via
# anyio
# httpx
@@ -54,13 +54,13 @@ packaging==24.1
# unearth
pip==24.2
# via -r .nox/update_constraints/tmp/constraints-pyodide.in
platformdirs==4.2.2
platformdirs==4.3.6
# via virtualenv
pydantic==2.8.2
pydantic==2.9.2
# via
# pyodide-build
# pyodide-lock
pydantic-core==2.20.1
pydantic-core==2.23.4
# via pydantic
pygments==2.18.0
# via rich
@@ -72,15 +72,15 @@ pyodide-cli==0.2.4
# pyodide-build
pyodide-lock==0.1.0a6
# via pyodide-build
pyproject-hooks==1.1.0
pyproject-hooks==1.2.0
# via build
pyyaml==6.0.1
pyyaml==6.0.2
# via pyodide-build
requests==2.32.3
# via pyodide-build
resolvelib==1.0.1
# via pyodide-build
rich==13.7.1
rich==13.9.1
# via
# pyodide-build
# pyodide-cli
@@ -95,29 +95,29 @@ sniffio==1.3.1
# via
# anyio
# httpx
typer==0.12.3
typer==0.12.5
# via
# auditwheel-emscripten
# pyodide-build
# pyodide-cli
types-requests==2.32.0.20240712
types-requests==2.32.0.20240914
# via pyodide-build
typing-extensions==4.12.2
# via
# pydantic
# pydantic-core
# typer
unearth==0.16.1
unearth==0.17.2
# via pyodide-build
urllib3==2.2.2
urllib3==2.2.3
# via
# requests
# types-requests
virtualenv==20.26.3
virtualenv==20.26.6
# via
# build
# pyodide-build
wheel==0.43.0
wheel==0.44.0
# via
# auditwheel-emscripten
# pyodide-build
@@ -2,15 +2,15 @@
# nox -s update_constraints
altgraph==0.17.4
# via macholib
build==1.2.1
build==1.2.2
# via -r cibuildwheel/resources/constraints.in
delocate==0.11.0
delocate==0.12.0
# via -r cibuildwheel/resources/constraints.in
distlib==0.3.8
# via virtualenv
filelock==3.15.4
filelock==3.16.1
# via virtualenv
importlib-metadata==8.2.0
importlib-metadata==8.5.0
# via build
macholib==1.16.3
# via delocate
@@ -20,15 +20,15 @@ packaging==24.1
# delocate
pip==24.2
# via -r cibuildwheel/resources/constraints.in
platformdirs==4.2.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.0.2
# via build
typing-extensions==4.12.2
# via delocate
virtualenv==20.26.3
virtualenv==20.26.6
# via -r cibuildwheel/resources/constraints.in
zipp==3.19.2
zipp==3.20.2
# via importlib-metadata
@@ -2,13 +2,13 @@
# nox -s update_constraints
altgraph==0.17.4
# via macholib
build==1.2.1
build==1.2.2
# via -r cibuildwheel/resources/constraints.in
delocate==0.11.0
delocate==0.12.0
# via -r cibuildwheel/resources/constraints.in
distlib==0.3.8
# via virtualenv
filelock==3.15.4
filelock==3.16.1
# via virtualenv
macholib==1.16.3
# via delocate
@@ -18,11 +18,11 @@ packaging==24.1
# delocate
pip==24.2
# via -r cibuildwheel/resources/constraints.in
platformdirs==4.2.2
platformdirs==4.3.6
# via virtualenv
pyproject-hooks==1.1.0
pyproject-hooks==1.2.0
# via build
typing-extensions==4.12.2
# via delocate
virtualenv==20.26.3
virtualenv==20.26.6
# via -r cibuildwheel/resources/constraints.in
@@ -2,13 +2,13 @@
# nox -s update_constraints
altgraph==0.17.4
# via macholib
build==1.2.1
build==1.2.2
# via -r cibuildwheel/resources/constraints.in
delocate==0.11.0
delocate==0.12.0
# via -r cibuildwheel/resources/constraints.in
distlib==0.3.8
# via virtualenv
filelock==3.15.4
filelock==3.16.1
# via virtualenv
macholib==1.16.3
# via delocate
@@ -18,11 +18,11 @@ packaging==24.1
# delocate
pip==24.2
# via -r cibuildwheel/resources/constraints.in
platformdirs==4.2.2
platformdirs==4.3.6
# via virtualenv
pyproject-hooks==1.1.0
pyproject-hooks==1.2.0
# via build
typing-extensions==4.12.2
# via delocate
virtualenv==20.26.3
virtualenv==20.26.6
# via -r cibuildwheel/resources/constraints.in
@@ -2,13 +2,13 @@
# nox -s update_constraints
altgraph==0.17.4
# via macholib
build==1.2.1
build==1.2.2
# via -r cibuildwheel/resources/constraints.in
delocate==0.11.0
delocate==0.12.0
# via -r cibuildwheel/resources/constraints.in
distlib==0.3.8
# via virtualenv
filelock==3.15.4
filelock==3.16.1
# via virtualenv
macholib==1.16.3
# via delocate
@@ -18,11 +18,11 @@ packaging==24.1
# delocate
pip==24.2
# via -r cibuildwheel/resources/constraints.in
platformdirs==4.2.2
platformdirs==4.3.6
# via virtualenv
pyproject-hooks==1.1.0
pyproject-hooks==1.2.0
# via build
typing-extensions==4.12.2
# via delocate
virtualenv==20.26.3
virtualenv==20.26.6
# via -r cibuildwheel/resources/constraints.in
@@ -4,7 +4,7 @@ altgraph==0.17.4
# via macholib
build==1.1.1
# via -r cibuildwheel/resources/constraints.in
delocate==0.11.0
delocate==0.12.0
# via -r cibuildwheel/resources/constraints.in
distlib==0.3.8
# 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.3
virtualenv==20.26.6
# via -r cibuildwheel/resources/constraints.in
zipp==3.15.0
# via importlib-metadata
@@ -2,15 +2,15 @@
# nox -s update_constraints
altgraph==0.17.4
# via macholib
build==1.2.1
build==1.2.2
# via -r cibuildwheel/resources/constraints.in
delocate==0.11.0
delocate==0.12.0
# via -r cibuildwheel/resources/constraints.in
distlib==0.3.8
# via virtualenv
filelock==3.15.4
filelock==3.16.1
# via virtualenv
importlib-metadata==8.2.0
importlib-metadata==8.5.0
# via build
macholib==1.16.3
# via delocate
@@ -20,15 +20,15 @@ packaging==24.1
# delocate
pip==24.2
# via -r cibuildwheel/resources/constraints.in
platformdirs==4.2.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.0.2
# via build
typing-extensions==4.12.2
# via delocate
virtualenv==20.26.3
virtualenv==20.26.6
# via -r cibuildwheel/resources/constraints.in
zipp==3.19.2
zipp==3.20.2
# via importlib-metadata
@@ -2,15 +2,15 @@
# nox -s update_constraints
altgraph==0.17.4
# via macholib
build==1.2.1
build==1.2.2
# via -r cibuildwheel/resources/constraints.in
delocate==0.11.0
delocate==0.12.0
# via -r cibuildwheel/resources/constraints.in
distlib==0.3.8
# via virtualenv
filelock==3.15.4
filelock==3.16.1
# via virtualenv
importlib-metadata==8.2.0
importlib-metadata==8.5.0
# via build
macholib==1.16.3
# via delocate
@@ -20,15 +20,15 @@ packaging==24.1
# delocate
pip==24.2
# via -r cibuildwheel/resources/constraints.in
platformdirs==4.2.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.0.2
# via build
typing-extensions==4.12.2
# via delocate
virtualenv==20.26.3
virtualenv==20.26.6
# via -r cibuildwheel/resources/constraints.in
zipp==3.19.2
zipp==3.20.2
# via importlib-metadata
+6 -6
View File
@@ -2,13 +2,13 @@
# nox -s update_constraints
altgraph==0.17.4
# via macholib
build==1.2.1
build==1.2.2
# via -r cibuildwheel/resources/constraints.in
delocate==0.11.0
delocate==0.12.0
# via -r cibuildwheel/resources/constraints.in
distlib==0.3.8
# via virtualenv
filelock==3.15.4
filelock==3.16.1
# via virtualenv
macholib==1.16.3
# via delocate
@@ -18,11 +18,11 @@ packaging==24.1
# delocate
pip==24.2
# via -r cibuildwheel/resources/constraints.in
platformdirs==4.2.2
platformdirs==4.3.6
# via virtualenv
pyproject-hooks==1.1.0
pyproject-hooks==1.2.0
# via build
typing-extensions==4.12.2
# via delocate
virtualenv==20.26.3
virtualenv==20.26.6
# via -r cibuildwheel/resources/constraints.in
+1
View File
@@ -37,6 +37,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]
+1 -1
View File
@@ -1,2 +1,2 @@
url = "https://nodejs.org/dist/"
v20 = "v20.16.0"
v20 = "v20.17.0"
+27 -24
View File
@@ -1,54 +1,57 @@
[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.08.03-1
manylinux2014 = quay.io/pypa/manylinux2014_x86_64:2024.10.01-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.08.03-1
musllinux_1_1 = quay.io/pypa/musllinux_1_1_x86_64:2024.08.03-1
musllinux_1_2 = quay.io/pypa/musllinux_1_2_x86_64:2024.08.03-1
manylinux_2_28 = quay.io/pypa/manylinux_2_28_x86_64:2024.10.01-1
musllinux_1_1 = quay.io/pypa/musllinux_1_1_x86_64:2024.10.01-1
musllinux_1_2 = quay.io/pypa/musllinux_1_2_x86_64:2024.10.01-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.08.03-1
manylinux2014 = quay.io/pypa/manylinux2014_i686:2024.10.01-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.08.03-1
musllinux_1_2 = quay.io/pypa/musllinux_1_2_i686:2024.08.03-1
musllinux_1_1 = quay.io/pypa/musllinux_1_1_i686:2024.10.01-1
musllinux_1_2 = quay.io/pypa/musllinux_1_2_i686:2024.10.01-1
[pypy_x86_64]
manylinux2010 = quay.io/pypa/manylinux2010_x86_64:2022-08-05-4535177
manylinux2014 = quay.io/pypa/manylinux2014_x86_64:2024.08.03-1
manylinux2014 = quay.io/pypa/manylinux2014_x86_64:2024.10.01-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.08.03-1
manylinux_2_28 = quay.io/pypa/manylinux_2_28_x86_64:2024.10.01-1
[pypy_i686]
manylinux2010 = quay.io/pypa/manylinux2010_i686:2022-08-05-4535177
manylinux2014 = quay.io/pypa/manylinux2014_i686:2024.08.03-1
manylinux2014 = quay.io/pypa/manylinux2014_i686:2024.10.01-1
manylinux_2_24 = quay.io/pypa/manylinux_2_24_i686:2022-12-26-0d38463
[aarch64]
manylinux2014 = quay.io/pypa/manylinux2014_aarch64:2024.08.03-1
manylinux2014 = quay.io/pypa/manylinux2014_aarch64:2024.10.01-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.08.03-1
musllinux_1_1 = quay.io/pypa/musllinux_1_1_aarch64:2024.08.03-1
musllinux_1_2 = quay.io/pypa/musllinux_1_2_aarch64:2024.08.03-1
manylinux_2_28 = quay.io/pypa/manylinux_2_28_aarch64:2024.10.01-1
musllinux_1_1 = quay.io/pypa/musllinux_1_1_aarch64:2024.10.01-1
musllinux_1_2 = quay.io/pypa/musllinux_1_2_aarch64:2024.10.01-1
[ppc64le]
manylinux2014 = quay.io/pypa/manylinux2014_ppc64le:2024.08.03-1
manylinux2014 = quay.io/pypa/manylinux2014_ppc64le:2024.10.01-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.08.03-1
musllinux_1_1 = quay.io/pypa/musllinux_1_1_ppc64le:2024.08.03-1
musllinux_1_2 = quay.io/pypa/musllinux_1_2_ppc64le:2024.08.03-1
manylinux_2_28 = quay.io/pypa/manylinux_2_28_ppc64le:2024.10.01-1
musllinux_1_1 = quay.io/pypa/musllinux_1_1_ppc64le:2024.10.01-1
musllinux_1_2 = quay.io/pypa/musllinux_1_2_ppc64le:2024.10.01-1
[s390x]
manylinux2014 = quay.io/pypa/manylinux2014_s390x:2024.08.03-1
manylinux2014 = quay.io/pypa/manylinux2014_s390x:2024.10.01-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.08.03-1
musllinux_1_1 = quay.io/pypa/musllinux_1_1_s390x:2024.08.03-1
musllinux_1_2 = quay.io/pypa/musllinux_1_2_s390x:2024.08.03-1
manylinux_2_28 = quay.io/pypa/manylinux_2_28_s390x:2024.10.01-1
musllinux_1_1 = quay.io/pypa/musllinux_1_1_s390x:2024.10.01-1
musllinux_1_2 = quay.io/pypa/musllinux_1_2_s390x:2024.10.01-1
[pypy_aarch64]
manylinux2014 = quay.io/pypa/manylinux2014_aarch64:2024.08.03-1
manylinux2014 = quay.io/pypa/manylinux2014_aarch64:2024.10.01-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.08.03-1
manylinux_2_28 = quay.io/pypa/manylinux_2_28_aarch64:2024.10.01-1
[armv7l]
musllinux_1_2 = quay.io/pypa/musllinux_1_2_armv7l:2024.10.01-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.3", url = "https://github.com/pypa/get-virtualenv/blob/20.26.3/public/virtualenv.pyz?raw=true" }
default = { version = "20.26.6", url = "https://github.com/pypa/get-virtualenv/blob/20.26.6/public/virtualenv.pyz?raw=true" }
+50 -1
View File
@@ -19,7 +19,7 @@ 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
@@ -83,6 +83,7 @@ MUSLLINUX_ARCHS: Final[tuple[str, ...]] = (
"aarch64",
"ppc64le",
"s390x",
"armv7l",
)
DEFAULT_CIBW_CACHE_PATH: Final[Path] = user_cache_path(appname="cibuildwheel", appauthor="pypa")
@@ -899,3 +900,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
+13 -10
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...")
@@ -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
+42
View File
@@ -4,8 +4,42 @@ title: Changelog
# Changelog
### 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_
- ⚠️ 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)
### v2.20.0
_4 August 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)
@@ -16,6 +50,8 @@ title: Changelog
### 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)
@@ -28,6 +64,8 @@ title: Changelog
### 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)
@@ -37,6 +75,8 @@ title: Changelog
### 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)
@@ -55,6 +95,8 @@ See the [release post](https://iscinumpy.dev/post/cibuildwheel-2-19-0/) for more
### v2.18.1
_20 May 2024_
- 🌟 Add free-threaded Linux and Windows builds for 3.13. New identifiers `cp313t-*`, new option `CIBW_FREE_THREADED_SUPPORT`/`tool.cibuildwheel.free-threaded-support` required to opt-in. [See the docs](https://cibuildwheel.pypa.io/en/stable/options/#free-threaded-support) for more information. (#1831)
- ✨ The `container-engine` is now a build (non-global) option. (#1792)
- 🛠 The build backend for cibuildwheel is now hatchling. (#1297)
+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,
+3 -3
View File
@@ -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.20.0
uses: pypa/cibuildwheel@v2.21.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.20.0
cibuildwheel==2.21.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:
@@ -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.20.0 --output-dir wheelhouse
pipx run cibuildwheel==2.21.2 --output-dir wheelhouse
pipx run twine upload wheelhouse/*.whl
```
+39 -33
View File
@@ -288,20 +288,20 @@ 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-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-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-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-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-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-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_aarch64<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-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 |
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).
@@ -475,7 +475,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`
@@ -1157,25 +1157,31 @@ 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_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) |
<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`, 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.
@@ -1599,7 +1605,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 +1616,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.20.0
run: pipx run cibuildwheel==2.21.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.20.0
run: python -m pip install cibuildwheel==2.21.2
- name: Build wheels
run: python -m cibuildwheel --output-dir wheelhouse
+18 -18
View File
@@ -11,8 +11,8 @@ title: Working examples
| [scikit-learn][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | The machine learning library. A complex but clean config using many of cibuildwheel's features to build a large project with Cython and C++ extensions. |
| [pytorch-fairseq][] | ![github icon][] | ![apple icon][] ![linux icon][] | Facebook AI Research Sequence-to-Sequence Toolkit written in Python. |
| [NumPy][] | ![github icon][] ![travisci icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | The fundamental package for scientific computing with Python. |
| [Tornado][] | ![github icon][] | ![linux icon][] ![apple icon][] ![windows icon][] | Tornado is a Python web framework and asynchronous networking library. Uses stable ABI for a small C extension. |
| [duckdb][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | DuckDB is an analytical in-process SQL database management system |
| [Tornado][] | ![github icon][] | ![linux icon][] ![apple icon][] ![windows icon][] | Tornado is a Python web framework and asynchronous networking library. Uses stable ABI for a small C extension. |
| [NCNN][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | ncnn is a high-performance neural network inference framework optimized for the mobile platform |
| [Matplotlib][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | The venerable Matplotlib, a Python library with C++ portions |
| [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. |
@@ -41,8 +41,8 @@ title: Working examples
| [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 |
| [vispy][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Main repository for Vispy |
| [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. |
| [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 |
@@ -55,9 +55,9 @@ title: Working examples
| [Wrapt][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | A Python module for decorators, wrappers and monkey patching. |
| [envd][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | A machine learning development environment build tool |
| [OpenColorIO][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | A color management framework for visual effects and animation. |
| [SimpleJSON][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | simplejson is a simple, fast, extensible JSON encoder/decoder for Python |
| [aioquic][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | QUIC and HTTP/3 implementation in Python |
| [Psycopg 3][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | A modern implementation of a PostgreSQL adapter for Python |
| [aioquic][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | QUIC and HTTP/3 implementation in Python |
| [SimpleJSON][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | simplejson is a simple, fast, extensible JSON encoder/decoder for Python |
| [ruptures][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Extensive Cython + NumPy [pyproject.toml](https://github.com/deepcharles/ruptures/blob/master/pyproject.toml) example. |
| [OpenTimelineIO][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Open Source API and interchange format for editorial timeline information. |
| [PyTables][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | A Python package to manage extremely large amounts of data |
@@ -86,31 +86,31 @@ title: Working examples
| [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. |
| [Python-WebRTC][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | a Python extension that provides bindings to WebRTC M92 |
| [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 |
| [pybase64][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Fast Base64 encoding/decoding in Python |
| [Imagecodecs (fork)][] | ![azurepipelines icon][] | ![apple icon][] ![linux icon][] | Over 20 external dependencies in compiled libraries, custom docker image, `libomp`, `openblas` and `install_name_tool` for macOS. |
| [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. |
| [Confluent client for Kafka][] | ![travisci icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | setup in `tools/wheels/build-wheels.bat` |
| [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. |
| [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 |
| [Confluent client for Kafka][] | ![travisci icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | setup in `tools/wheels/build-wheels.bat` |
| [pyjet][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | The interface between FastJet and NumPy |
| [ril][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | A python binding to Rust Imaging library using maturin and Pyo3, utilizes Github Action cache to improve speed. Builds abi3 wheels. |
| [GSD][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Cython and NumPy project with 64-bit wheels. |
| [SiPM][] | ![github icon][] | ![apple icon][] ![linux icon][] | High performance library for SiPM detectors simulation using C++17, OpenMP and AVX2 intrinsics. |
| [GSD][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Cython and NumPy project with 64-bit wheels. |
| [aalink][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Async Python interface for Ableton Link. |
| [CorrectionLib][] | ![github icon][] | ![apple icon][] ![linux icon][] | Structured JSON powered correction library for HEP, designed for the CMS experiment at CERN. |
| [xmlstarlet][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Python 3.6+ CFFI bindings with true MSVC build. |
@@ -121,8 +121,8 @@ title: Working examples
[scikit-learn]: https://github.com/scikit-learn/scikit-learn
[pytorch-fairseq]: https://github.com/facebookresearch/fairseq
[NumPy]: https://github.com/numpy/numpy
[Tornado]: https://github.com/tornadoweb/tornado
[duckdb]: https://github.com/duckdb/duckdb
[Tornado]: https://github.com/tornadoweb/tornado
[NCNN]: https://github.com/Tencent/ncnn
[Matplotlib]: https://github.com/matplotlib/matplotlib
[Prophet]: https://github.com/facebook/prophet
@@ -151,8 +151,8 @@ title: Working examples
[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
[vispy]: https://github.com/vispy/vispy
[CTranslate2]: https://github.com/OpenNMT/CTranslate2
[coverage.py]: https://github.com/nedbat/coveragepy
[PyCryptodome]: https://github.com/Legrandin/pycryptodome
@@ -165,9 +165,9 @@ title: Working examples
[Wrapt]: https://github.com/GrahamDumpleton/wrapt
[envd]: https://github.com/tensorchord/envd
[OpenColorIO]: https://github.com/AcademySoftwareFoundation/OpenColorIO
[SimpleJSON]: https://github.com/simplejson/simplejson
[aioquic]: https://github.com/aiortc/aioquic
[Psycopg 3]: https://github.com/psycopg/psycopg
[aioquic]: https://github.com/aiortc/aioquic
[SimpleJSON]: https://github.com/simplejson/simplejson
[ruptures]: https://github.com/deepcharles/ruptures
[OpenTimelineIO]: https://github.com/AcademySoftwareFoundation/OpenTimelineIO
[PyTables]: https://github.com/PyTables/PyTables
@@ -196,31 +196,31 @@ title: Working examples
[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
[Python-WebRTC]: https://github.com/MarshalX/python-webrtc
[power-grid-model]: https://github.com/PowerGridModel/power-grid-model
[Python-WebRTC]: https://github.com/MarshalX/python-webrtc
[pybase64]: https://github.com/mayeut/pybase64
[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
[Confluent client for Kafka]: https://github.com/confluentinc/confluent-kafka-python
[clang-format]: https://github.com/ssciwr/clang-format-wheel
[etebase-py]: https://github.com/etesync/etebase-py
[cf-units]: https://github.com/SciTools/cf-units
[ninja]: https://github.com/scikit-build/ninja-python-distributions
[numpythia]: https://github.com/scikit-hep/numpythia
[Confluent client for Kafka]: https://github.com/confluentinc/confluent-kafka-python
[pyjet]: https://github.com/scikit-hep/pyjet
[ril]: https://github.com/Cryptex-github/ril-py
[GSD]: https://github.com/glotzerlab/gsd
[SiPM]: https://github.com/EdoPro98/SimSiPM
[GSD]: https://github.com/glotzerlab/gsd
[aalink]: https://github.com/artfwo/aalink
[CorrectionLib]: https://github.com/cms-nanoAOD/correctionlib
[xmlstarlet]: https://github.com/dimitern/xmlstarlet
+8 -11
View File
@@ -1,18 +1,15 @@
environment:
matrix:
- APPVEYOR_BUILD_WORKER_IMAGE: Ubuntu
APPVEYOR_JOB_NAME: "python37-x64-ubuntu"
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
APPVEYOR_JOB_NAME: "python37-x64-vs2015"
- APPVEYOR_BUILD_WORKER_IMAGE: macos
APPVEYOR_JOB_NAME: "python37-x64-macos"
- APPVEYOR_BUILD_WORKER_IMAGE: Ubuntu2204
APPVEYOR_JOB_NAME: "linux-x64"
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022
APPVEYOR_JOB_NAME: "windows-x64"
- APPVEYOR_BUILD_WORKER_IMAGE: macos-sonoma
APPVEYOR_JOB_NAME: "macos-x64"
stack: python 3.7
stack: python 3.12
init:
- cmd: set PATH=C:\Python37;C:\Python37\Scripts;%PATH%
install: python -m pip install cibuildwheel==2.20.0
install: python -m pip install cibuildwheel==2.21.2
build_script: python -m cibuildwheel --output-dir wheelhouse
+3 -3
View File
@@ -6,7 +6,7 @@ jobs:
- bash: |
set -o errexit
python3 -m pip install --upgrade pip
pip3 install cibuildwheel==2.20.0
pip3 install cibuildwheel==2.21.2
displayName: Install dependencies
- bash: cibuildwheel --output-dir wheelhouse .
displayName: Build wheels
@@ -20,7 +20,7 @@ jobs:
- bash: |
set -o errexit
python3 -m pip install --upgrade pip
python3 -m pip install cibuildwheel==2.20.0
python3 -m pip install cibuildwheel==2.21.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.20.0
pip install cibuildwheel==2.21.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.20.0
python3 -m pip install --user cibuildwheel==2.21.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.20.0
python3 -m pip install --user cibuildwheel==2.21.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.20.0
pip3 install cibuildwheel==2.21.2
cibuildwheel --output-dir wheelhouse
- store_artifacts:
path: wheelhouse/
+1 -1
View File
@@ -1,6 +1,6 @@
build_and_store_wheels: &BUILD_AND_STORE_WHEELS
install_cibuildwheel_script:
- python -m pip install cibuildwheel==2.20.0
- python -m pip install cibuildwheel==2.21.2
run_cibuildwheel_script:
- cibuildwheel
wheels_artifacts:
+1 -1
View File
@@ -1,6 +1,6 @@
build_and_store_wheels: &BUILD_AND_STORE_WHEELS
install_cibuildwheel_script:
- python -m pip install cibuildwheel==2.20.0
- python -m pip install cibuildwheel==2.21.2
run_cibuildwheel_script:
- cibuildwheel
wheels_artifacts:
+1 -1
View File
@@ -23,7 +23,7 @@ jobs:
- uses: actions/checkout@v4
- name: Build wheels
uses: pypa/cibuildwheel@v2.20.0
uses: pypa/cibuildwheel@v2.21.2
- uses: actions/upload-artifact@v4
with:
+1 -1
View File
@@ -15,7 +15,7 @@ jobs:
- uses: actions/checkout@v4
- name: Build wheels
uses: pypa/cibuildwheel@v2.20.0
uses: pypa/cibuildwheel@v2.21.2
# env:
# CIBW_SOME_OPTION: value
# ...
+1 -1
View File
@@ -21,7 +21,7 @@ jobs:
platforms: all
- name: Build wheels
uses: pypa/cibuildwheel@v2.20.0
uses: pypa/cibuildwheel@v2.21.2
env:
# configure cibuildwheel to build native archs ('auto'), and some
# emulated ones
+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.20.0
- python -m pip install cibuildwheel==2.21.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.20.0
- py -m pip install cibuildwheel==2.21.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.20.0
- python3 -m pip install cibuildwheel==2.21.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.20.0
- python -m pip install cibuildwheel==2.21.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.20.0
- python3 -m pip install cibuildwheel==2.21.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.20.0
- python3 -m pip install cibuildwheel==2.21.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.20.0 twine
install: python3 -m pip install cibuildwheel==2.21.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.20.0 twine
install: python3 -m pip install cibuildwheel==2.21.2 twine
script: python3 -m cibuildwheel --output-dir wheelhouse
after_success: python3 -m twine upload --skip-existing wheelhouse/*.whl
+7 -5
View File
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
[project]
name = "cibuildwheel"
version = "2.20.0"
version = "2.21.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",
]
@@ -64,9 +65,9 @@ dev = [
]
docs = [
"jinja2>=3.1.2",
"mkdocs-include-markdown-plugin==2.8.0",
"mkdocs-include-markdown-plugin==6.2.2",
"mkdocs-macros-plugin",
"mkdocs==1.3.1",
"mkdocs==1.6.1",
"pymdown-extensions",
]
test = [
@@ -184,10 +185,8 @@ messages_control.disable = [
]
[tool.ruff]
target-version = "py38"
line-length = 100
[tool.ruff.lint]
extend-select = [
"B", # flake8-bugbear
@@ -241,3 +240,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
+2 -2
View File
@@ -37,7 +37,7 @@ def build_frontend_env_nouv(request: pytest.FixtureRequest) -> dict[str, str]:
return {"CIBW_BUILD_FRONTEND": frontend}
@pytest.fixture()
@pytest.fixture
def build_frontend_env(build_frontend_env_nouv: dict[str, str]) -> dict[str, str]:
frontend = build_frontend_env_nouv["CIBW_BUILD_FRONTEND"]
if frontend != "build" or platform == "pyodide" or find_uv() is None:
@@ -46,7 +46,7 @@ def build_frontend_env(build_frontend_env_nouv: dict[str, str]) -> dict[str, str
return {"CIBW_BUILD_FRONTEND": "build[uv]"}
@pytest.fixture()
@pytest.fixture
def docker_cleanup() -> Generator[None, None, None]:
def get_images() -> set[str]:
if detect_ci_provider() is None or platform != "linux":
+2 -4
View File
@@ -21,7 +21,7 @@ def test_podman(tmp_path, capfd, request):
actual_wheels = utils.cibuildwheel_run(
project_dir,
add_env={
"CIBW_ARCHS": "x86_64",
"CIBW_ARCHS": "native",
"CIBW_BEFORE_ALL": "echo 'test log statement from before-all'",
"CIBW_CONTAINER_ENGINE": "podman",
},
@@ -29,9 +29,7 @@ def test_podman(tmp_path, capfd, request):
)
# check that the expected wheels are produced
expected_wheels = [
w for w in utils.expected_wheels("spam", "0.1.0", single_python=True) if "x86_64" in w
]
expected_wheels = utils.expected_wheels("spam", "0.1.0", single_python=True, single_arch=True)
assert set(actual_wheels) == set(expected_wheels)
# check that stdout is bring passed-though from container correctly
+4 -1
View File
@@ -6,7 +6,7 @@ import textwrap
import pytest
from cibuildwheel.util import CIBW_CACHE_PATH
from cibuildwheel.util import CIBW_CACHE_PATH, CIProvider, detect_ci_provider
from . import test_projects, utils
@@ -49,6 +49,9 @@ def test_pyodide_build(tmp_path, use_pyproject_toml):
if not shutil.which("python3.12"):
pytest.skip("Python 3.12 not installed")
if detect_ci_provider() == CIProvider.travis_ci:
pytest.skip("Python 3.12 is just a non-working pyenv shim")
if use_pyproject_toml:
basic_project.files["pyproject.toml"] = textwrap.dedent(
"""
+23 -20
View File
@@ -23,15 +23,14 @@ EMULATED_ARCHS: Final[list[str]] = sorted(
)
SINGLE_PYTHON_VERSION: Final[tuple[int, int]] = (3, 12)
platform: str
if "CIBW_PLATFORM" in os.environ:
platform = os.environ["CIBW_PLATFORM"]
platform = os.environ.get("CIBW_PLATFORM", "")
if platform:
pass
elif sys.platform.startswith("linux"):
platform = "linux"
elif sys.platform.startswith("darwin"):
platform = "macos"
elif sys.platform in ["win32", "cygwin"]:
elif sys.platform.startswith(("win32", "cygwin")):
platform = "windows"
else:
msg = f"Unsupported platform {sys.platform!r}"
@@ -171,7 +170,9 @@ def expected_wheels(
machine_arch = "aarch64"
if manylinux_versions is None:
if machine_arch == "x86_64":
if machine_arch == "armv7l":
manylinux_versions = []
elif machine_arch == "x86_64":
manylinux_versions = [
"manylinux_2_5",
"manylinux1",
@@ -275,25 +276,27 @@ def expected_wheels(
platform_tags = ["win32", "win_amd64"]
elif platform == "macos":
if python_abi_tag.startswith("pp"):
if python_abi_tag.startswith(("pp37", "pp38")):
min_macosx = macosx_deployment_target
else:
min_macosx = _floor_macosx(macosx_deployment_target, "10.15")
elif python_abi_tag.startswith("cp"):
if python_abi_tag.startswith(("cp36", "cp37", "cp38", "cp39", "cp310", "cp311")):
min_macosx = macosx_deployment_target
else:
min_macosx = _floor_macosx(macosx_deployment_target, "10.13")
else:
min_macosx = macosx_deployment_target
if machine_arch == "arm64":
arm64_macosx = _floor_macosx(macosx_deployment_target, "11.0")
arm64_macosx = _floor_macosx(min_macosx, "11.0")
platform_tags = [f'macosx_{arm64_macosx.replace(".", "_")}_arm64']
else:
if python_abi_tag.startswith("pp") and not python_abi_tag.startswith(
("pp37", "pp38")
):
pypy_macosx = _floor_macosx(macosx_deployment_target, "10.15")
platform_tags = [f'macosx_{pypy_macosx.replace(".", "_")}_x86_64']
elif python_abi_tag.startswith("cp313"):
pypy_macosx = _floor_macosx(macosx_deployment_target, "10.13")
platform_tags = [f'macosx_{pypy_macosx.replace(".", "_")}_x86_64']
else:
platform_tags = [f'macosx_{macosx_deployment_target.replace(".", "_")}_x86_64']
platform_tags = [f'macosx_{min_macosx.replace(".", "_")}_x86_64']
if include_universal2:
platform_tags.append(
f'macosx_{macosx_deployment_target.replace(".", "_")}_universal2',
)
platform_tags.append(f'macosx_{min_macosx.replace(".", "_")}_universal2')
else:
msg = f"Unsupported platform {platform!r}"
raise Exception(msg)
+1 -1
View File
@@ -19,7 +19,7 @@ def pytest_addoption(parser):
)
@pytest.fixture()
@pytest.fixture
def fake_package_dir(tmp_path, monkeypatch):
"""
Monkey-patch enough for the main() function to run
+3 -3
View File
@@ -47,7 +47,7 @@ def mock_protection(monkeypatch):
@pytest.fixture(autouse=True)
def fake_package_dir_autouse(fake_package_dir): # noqa: ARG001
def fake_package_dir_autouse(fake_package_dir):
pass
@@ -60,7 +60,7 @@ def disable_print_wheels(monkeypatch):
monkeypatch.setattr(util, "print_new_wheels", empty_cm)
@pytest.fixture()
@pytest.fixture
def allow_empty(monkeypatch, fake_package_dir):
monkeypatch.setattr(sys, "argv", [*fake_package_dir, "--allow-empty"])
@@ -81,7 +81,7 @@ def platform(request, monkeypatch):
return platform_value
@pytest.fixture()
@pytest.fixture
def intercepted_build_args(monkeypatch):
intercepted = ArgsInterceptor()
+2 -1
View File
@@ -10,7 +10,7 @@ from cibuildwheel.architecture import Architecture
from ..conftest import MOCK_PACKAGE_DIR
@pytest.mark.parametrize("option_value", [None, "auto"])
@pytest.mark.parametrize("option_value", [None, "auto", ""])
def test_platform_unset_or_auto(monkeypatch, intercepted_build_args, option_value):
if option_value is None:
monkeypatch.delenv("CIBW_PLATFORM", raising=False)
@@ -179,6 +179,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 == {
+245 -26
View File
@@ -6,14 +6,23 @@ import platform
import random
import shutil
import subprocess
import sys
import textwrap
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
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
@@ -28,6 +37,14 @@ elif pm in {"aarch64", "arm64"}:
DEFAULT_IMAGE = DEFAULT_IMAGE_TEMPLATE.format(machine="aarch64")
else:
DEFAULT_IMAGE = ""
DEFAULT_OCI_PLATFORM = {
"AMD64": OCIPlatform.AMD64,
"x86_64": OCIPlatform.AMD64,
"ppc64le": OCIPlatform.PPC64LE,
"s390x": OCIPlatform.S390X,
"aarch64": OCIPlatform.ARM64,
"arm64": OCIPlatform.ARM64,
}[pm]
PODMAN = OCIContainerEngineConfig(name="podman")
@@ -63,24 +80,32 @@ def container_engine(request):
def test_simple(container_engine):
with OCIContainer(engine=container_engine, image=DEFAULT_IMAGE) as container:
with OCIContainer(
engine=container_engine, image=DEFAULT_IMAGE, oci_platform=DEFAULT_OCI_PLATFORM
) as container:
assert container.call(["echo", "hello"], capture_output=True) == "hello\n"
def test_no_lf(container_engine):
with OCIContainer(engine=container_engine, image=DEFAULT_IMAGE) as container:
with OCIContainer(
engine=container_engine, image=DEFAULT_IMAGE, oci_platform=DEFAULT_OCI_PLATFORM
) as container:
assert container.call(["printf", "hello"], capture_output=True) == "hello"
def test_debug_info(container_engine):
container = OCIContainer(engine=container_engine, image=DEFAULT_IMAGE)
container = OCIContainer(
engine=container_engine, image=DEFAULT_IMAGE, oci_platform=DEFAULT_OCI_PLATFORM
)
print(container.debug_info())
with container:
pass
def test_environment(container_engine):
with OCIContainer(engine=container_engine, image=DEFAULT_IMAGE) as container:
with OCIContainer(
engine=container_engine, image=DEFAULT_IMAGE, oci_platform=DEFAULT_OCI_PLATFORM
) as container:
assert (
container.call(
["sh", "-c", "echo $TEST_VAR"], env={"TEST_VAR": "1"}, capture_output=True
@@ -92,7 +117,9 @@ def test_environment(container_engine):
def test_environment_pass(container_engine, monkeypatch):
monkeypatch.setenv("CIBUILDWHEEL", "1")
monkeypatch.setenv("SOURCE_DATE_EPOCH", "1489957071")
with OCIContainer(engine=container_engine, image=DEFAULT_IMAGE) as container:
with OCIContainer(
engine=container_engine, image=DEFAULT_IMAGE, oci_platform=DEFAULT_OCI_PLATFORM
) as container:
assert container.call(["sh", "-c", "echo $CIBUILDWHEEL"], capture_output=True) == "1\n"
assert (
container.call(["sh", "-c", "echo $SOURCE_DATE_EPOCH"], capture_output=True)
@@ -102,14 +129,23 @@ def test_environment_pass(container_engine, monkeypatch):
def test_cwd(container_engine):
with OCIContainer(
engine=container_engine, image=DEFAULT_IMAGE, cwd="/cibuildwheel/working_directory"
engine=container_engine,
image=DEFAULT_IMAGE,
oci_platform=DEFAULT_OCI_PLATFORM,
cwd="/cibuildwheel/working_directory",
) as container:
assert container.call(["pwd"], capture_output=True) == "/cibuildwheel/working_directory\n"
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):
with OCIContainer(engine=container_engine, image=DEFAULT_IMAGE) as container:
with OCIContainer(
engine=container_engine, image=DEFAULT_IMAGE, oci_platform=DEFAULT_OCI_PLATFORM
) as container:
docker_containers_listing = subprocess.run(
f"{container.engine.name} container ls",
shell=True,
@@ -141,7 +177,9 @@ def test_large_environment(container_engine):
"d": "0" * long_env_var_length,
}
with OCIContainer(engine=container_engine, image=DEFAULT_IMAGE) as container:
with OCIContainer(
engine=container_engine, image=DEFAULT_IMAGE, oci_platform=DEFAULT_OCI_PLATFORM
) as container:
# check the length of d
assert (
container.call(["sh", "-c", "echo ${#d}"], env=large_environment, capture_output=True)
@@ -150,7 +188,9 @@ def test_large_environment(container_engine):
def test_binary_output(container_engine):
with OCIContainer(engine=container_engine, image=DEFAULT_IMAGE) as container:
with OCIContainer(
engine=container_engine, image=DEFAULT_IMAGE, oci_platform=DEFAULT_OCI_PLATFORM
) as container:
# note: the below embedded snippets are in python2
# check that we can pass though arbitrary binary data without erroring
@@ -200,7 +240,9 @@ def test_binary_output(container_engine):
def test_file_operation(tmp_path: Path, container_engine):
with OCIContainer(engine=container_engine, image=DEFAULT_IMAGE) as container:
with OCIContainer(
engine=container_engine, image=DEFAULT_IMAGE, oci_platform=DEFAULT_OCI_PLATFORM
) as container:
# test copying a file in
test_binary_data = bytes(random.randrange(256) for _ in range(1000))
original_test_file = tmp_path / "test.dat"
@@ -210,12 +252,17 @@ 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):
with OCIContainer(engine=container_engine, image=DEFAULT_IMAGE) as container:
with OCIContainer(
engine=container_engine, image=DEFAULT_IMAGE, oci_platform=DEFAULT_OCI_PLATFORM
) as container:
test_binary_data = bytes(random.randrange(256) for _ in range(1000))
original_test_file = tmp_path / "test.dat"
original_test_file.write_bytes(test_binary_data)
@@ -230,6 +277,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")
@@ -240,11 +293,18 @@ 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):
with OCIContainer(engine=container_engine, image=DEFAULT_IMAGE) as container:
with OCIContainer(
engine=container_engine, image=DEFAULT_IMAGE, oci_platform=DEFAULT_OCI_PLATFORM
) as container:
assignment = EnvironmentAssignmentBash("TEST=$(echo 42)")
assert assignment.evaluated_value({}, container.environment_executor) == "42"
@@ -252,6 +312,8 @@ def test_environment_executor(container_engine):
def test_podman_vfs(tmp_path: Path, monkeypatch, container_engine):
if container_engine.name != "podman":
pytest.skip("only runs with podman")
if sys.platform.startswith("darwin"):
pytest.skip("Skipping test because podman on this platform does not support vfs")
# create the VFS configuration
vfs_path = tmp_path / "podman_vfs"
@@ -309,7 +371,9 @@ def test_podman_vfs(tmp_path: Path, monkeypatch, container_engine):
monkeypatch.setenv("CONTAINERS_CONF", str(vfs_containers_conf_fpath))
monkeypatch.setenv("CONTAINERS_STORAGE_CONF", str(vfs_containers_storage_conf_fpath))
with OCIContainer(engine=PODMAN, image=DEFAULT_IMAGE) as container:
with OCIContainer(
engine=PODMAN, image=DEFAULT_IMAGE, oci_platform=DEFAULT_OCI_PLATFORM
) as container:
# test running a command
assert container.call(["echo", "hello"], capture_output=True) == "hello\n"
@@ -346,6 +410,7 @@ def test_create_args_volume(tmp_path: Path, container_engine):
with OCIContainer(
engine=container_engine,
image=DEFAULT_IMAGE,
oci_platform=DEFAULT_OCI_PLATFORM,
) as container:
assert container.call(["cat", "/test_mount/test_file.txt"], capture_output=True) == "1234"
@@ -388,24 +453,47 @@ def test_create_args_volume(tmp_path: Path, container_engine):
"docker",
("--some-option=value; with; semicolons", "--another-option"),
),
(
"docker; create_args: --platform=linux/amd64",
"docker",
(),
),
(
"podman; create_args: --platform=linux/amd64",
"podman",
(),
),
(
"docker; create_args: --platform linux/amd64",
"docker",
(),
),
(
"podman; create_args: --platform linux/amd64",
"podman",
(),
),
],
)
def test_parse_engine_config(config, name, create_args):
def test_parse_engine_config(config, name, create_args, capsys):
engine_config = OCIContainerEngineConfig.from_config_string(config)
assert engine_config.name == name
assert engine_config.create_args == create_args
if "--platform" in config:
captured = capsys.readouterr()
assert (
"Using '--platform' in 'container-engine::create_args' is deprecated. It will be ignored."
in captured.err
)
@pytest.mark.skipif(pm != "x86_64", reason="Only runs on x86_64")
@pytest.mark.parametrize(
("image", "shell_args"),
[
(DEFAULT_IMAGE_TEMPLATE.format(machine="i686"), ["/bin/bash"]),
(DEFAULT_IMAGE_TEMPLATE.format(machine="x86_64"), ["linux32", "/bin/bash"]),
],
)
def test_enforce_32_bit(container_engine, image, shell_args):
with OCIContainer(engine=container_engine, image=image, enforce_32_bit=True) as container:
def test_enforce_32_bit(container_engine):
with OCIContainer(
engine=container_engine,
image=DEFAULT_IMAGE_TEMPLATE.format(machine="i686"),
oci_platform=OCIPlatform.i386,
) as container:
assert container.call(["uname", "-m"], capture_output=True).strip() == "i686"
container_args = subprocess.run(
f"{container.engine.name} inspect -f '{{{{json .Args }}}}' {container.name}",
@@ -414,7 +502,7 @@ def test_enforce_32_bit(container_engine, image, shell_args):
stdout=subprocess.PIPE,
text=True,
).stdout
assert json.loads(container_args) == shell_args
assert json.loads(container_args) == ["/bin/bash"]
@pytest.mark.parametrize(
@@ -428,16 +516,147 @@ def test_enforce_32_bit(container_engine, image, shell_args):
def test_disable_host_mount(tmp_path: Path, container_engine, config, should_have_host_mount):
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"):
pytest.skip("Skipping test because docker on this platform does not support host mounts")
engine = OCIContainerEngineConfig.from_config_string(config.format(name=container_engine.name))
sentinel_file = tmp_path / "sentinel"
sentinel_file.write_text("12345")
with OCIContainer(engine=engine, image=DEFAULT_IMAGE) as container:
with OCIContainer(
engine=engine, image=DEFAULT_IMAGE, oci_platform=DEFAULT_OCI_PLATFORM
) as container:
host_mount_path = "/host" + str(sentinel_file)
if should_have_host_mount:
assert container.call(["cat", host_mount_path], capture_output=True) == "12345"
else:
with pytest.raises(subprocess.CalledProcessError):
container.call(["cat", host_mount_path], capture_output=True)
@pytest.mark.parametrize("platform", list(OCIPlatform))
def test_local_image(container_engine, platform, tmp_path: Path):
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={platform.value}", remote_image],
check=True,
)
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
@pytest.mark.parametrize("platform", list(OCIPlatform))
def test_multiarch_image(container_engine, platform):
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")
with OCIContainer(
engine=container_engine, image="debian:12-slim", oci_platform=platform
) as container:
output = container.call(["uname", "-m"], capture_output=True)
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.strip() in output_map_kernel[platform]
output = container.call(["dpkg", "--print-architecture"], capture_output=True)
output_map_dpkg = {
OCIPlatform.i386: "i386",
OCIPlatform.AMD64: "amd64",
OCIPlatform.ARMV7: "armhf",
OCIPlatform.ARM64: "arm64",
OCIPlatform.PPC64LE: "ppc64el",
OCIPlatform.S390X: "s390x",
}
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)
+13 -12
View File
@@ -12,6 +12,7 @@ import pytest
from cibuildwheel import linux, util
from cibuildwheel.__main__ import main
from cibuildwheel.oci_container import OCIPlatform
ALL_IDS = {
"cp36",
@@ -29,7 +30,7 @@ ALL_IDS = {
}
@pytest.fixture()
@pytest.fixture
def mock_build_container(monkeypatch):
def fail_on_call(*args, **kwargs):
msg = "This should never be called"
@@ -73,7 +74,7 @@ def test_build_default_launches(monkeypatch):
kwargs = build_in_container.call_args_list[0][1]
assert "quay.io/pypa/manylinux2014_x86_64" in kwargs["container"]["image"]
assert kwargs["container"]["cwd"] == PurePosixPath("/project")
assert not kwargs["container"]["enforce_32_bit"]
assert kwargs["container"]["oci_platform"] == OCIPlatform.AMD64
identifiers = {x.identifier for x in kwargs["platform_configs"]}
assert identifiers == {f"{x}-manylinux_x86_64" for x in ALL_IDS}
@@ -81,7 +82,7 @@ def test_build_default_launches(monkeypatch):
kwargs = build_in_container.call_args_list[1][1]
assert "quay.io/pypa/manylinux2014_i686" in kwargs["container"]["image"]
assert kwargs["container"]["cwd"] == PurePosixPath("/project")
assert kwargs["container"]["enforce_32_bit"]
assert kwargs["container"]["oci_platform"] == OCIPlatform.i386
identifiers = {x.identifier for x in kwargs["platform_configs"]}
assert identifiers == {f"{x}-manylinux_i686" for x in ALL_IDS}
@@ -89,7 +90,7 @@ def test_build_default_launches(monkeypatch):
kwargs = build_in_container.call_args_list[2][1]
assert "quay.io/pypa/musllinux_1_2_x86_64" in kwargs["container"]["image"]
assert kwargs["container"]["cwd"] == PurePosixPath("/project")
assert not kwargs["container"]["enforce_32_bit"]
assert kwargs["container"]["oci_platform"] == OCIPlatform.AMD64
identifiers = {x.identifier for x in kwargs["platform_configs"]}
assert identifiers == {
@@ -99,7 +100,7 @@ def test_build_default_launches(monkeypatch):
kwargs = build_in_container.call_args_list[3][1]
assert "quay.io/pypa/musllinux_1_2_i686" in kwargs["container"]["image"]
assert kwargs["container"]["cwd"] == PurePosixPath("/project")
assert kwargs["container"]["enforce_32_bit"]
assert kwargs["container"]["oci_platform"] == OCIPlatform.i386
identifiers = {x.identifier for x in kwargs["platform_configs"]}
assert identifiers == {f"{x}-musllinux_i686" for x in ALL_IDS if "pp" not in x}
@@ -142,7 +143,7 @@ before-all = "true"
kwargs = build_in_container.call_args_list[0][1]
assert "quay.io/pypa/manylinux2014_x86_64" in kwargs["container"]["image"]
assert kwargs["container"]["cwd"] == PurePosixPath("/project")
assert not kwargs["container"]["enforce_32_bit"]
assert kwargs["container"]["oci_platform"] == OCIPlatform.AMD64
identifiers = {x.identifier for x in kwargs["platform_configs"]}
assert identifiers == {"cp36-manylinux_x86_64"}
@@ -151,7 +152,7 @@ before-all = "true"
kwargs = build_in_container.call_args_list[1][1]
assert "quay.io/pypa/manylinux2014_x86_64" in kwargs["container"]["image"]
assert kwargs["container"]["cwd"] == PurePosixPath("/project")
assert not kwargs["container"]["enforce_32_bit"]
assert kwargs["container"]["oci_platform"] == OCIPlatform.AMD64
identifiers = {x.identifier for x in kwargs["platform_configs"]}
assert identifiers == {
@@ -164,7 +165,7 @@ before-all = "true"
kwargs = build_in_container.call_args_list[2][1]
assert "quay.io/pypa/manylinux_2_28_x86_64" in kwargs["container"]["image"]
assert kwargs["container"]["cwd"] == PurePosixPath("/project")
assert not kwargs["container"]["enforce_32_bit"]
assert kwargs["container"]["oci_platform"] == OCIPlatform.AMD64
identifiers = {x.identifier for x in kwargs["platform_configs"]}
assert identifiers == {
f"{x}-manylinux_x86_64"
@@ -174,7 +175,7 @@ before-all = "true"
kwargs = build_in_container.call_args_list[3][1]
assert "quay.io/pypa/manylinux2014_i686" in kwargs["container"]["image"]
assert kwargs["container"]["cwd"] == PurePosixPath("/project")
assert kwargs["container"]["enforce_32_bit"]
assert kwargs["container"]["oci_platform"] == OCIPlatform.i386
identifiers = {x.identifier for x in kwargs["platform_configs"]}
assert identifiers == {f"{x}-manylinux_i686" for x in ALL_IDS}
@@ -182,7 +183,7 @@ before-all = "true"
kwargs = build_in_container.call_args_list[4][1]
assert "quay.io/pypa/musllinux_1_1_x86_64" in kwargs["container"]["image"]
assert kwargs["container"]["cwd"] == PurePosixPath("/project")
assert not kwargs["container"]["enforce_32_bit"]
assert kwargs["container"]["oci_platform"] == OCIPlatform.AMD64
identifiers = {x.identifier for x in kwargs["platform_configs"]}
assert identifiers == {
@@ -192,7 +193,7 @@ before-all = "true"
kwargs = build_in_container.call_args_list[5][1]
assert "quay.io/pypa/musllinux_1_2_x86_64" in kwargs["container"]["image"]
assert kwargs["container"]["cwd"] == PurePosixPath("/project")
assert not kwargs["container"]["enforce_32_bit"]
assert kwargs["container"]["oci_platform"] == OCIPlatform.AMD64
identifiers = {x.identifier for x in kwargs["platform_configs"]}
assert identifiers == {
f"{x}-musllinux_x86_64" for x in ALL_IDS - {"cp36", "cp37", "cp38", "cp39"} if "pp" not in x
@@ -201,7 +202,7 @@ before-all = "true"
kwargs = build_in_container.call_args_list[6][1]
assert "quay.io/pypa/musllinux_1_2_i686" in kwargs["container"]["image"]
assert kwargs["container"]["cwd"] == PurePosixPath("/project")
assert kwargs["container"]["enforce_32_bit"]
assert kwargs["container"]["oci_platform"] == OCIPlatform.i386
identifiers = {x.identifier for x in kwargs["platform_configs"]}
assert identifiers == {f"{x}-musllinux_i686" for x in ALL_IDS if "pp" not in x}
+1 -2
View File
@@ -10,7 +10,6 @@ import pytest
from cibuildwheel import errors
from cibuildwheel.__main__ import get_build_identifiers, get_platform_module
from cibuildwheel.bashlex_eval import local_environment_executor
from cibuildwheel.environment import parse_environment
from cibuildwheel.options import (
CommandLineArguments,
Options,
@@ -66,7 +65,7 @@ def test_options_1(tmp_path, monkeypatch):
default_build_options = options.build_options(identifier=None)
assert default_build_options.environment == parse_environment('FOO="BAR"')
assert default_build_options.environment.as_dictionary(prev_environment={}) == {"FOO": "BAR"}
all_pinned_container_images = _get_pinned_container_images()
pinned_x86_64_container_image = all_pinned_container_images["x86_64"]
+71 -53
View File
@@ -4,7 +4,15 @@ from pathlib import Path
import pytest
from cibuildwheel.options import ConfigOptionError, InheritRule, OptionsReader, _resolve_cascade
from cibuildwheel.options import (
EnvironmentFormat,
InheritRule,
ListFormat,
OptionsReader,
OptionsReaderError,
ShlexTableFormat,
_resolve_cascade,
)
PYPROJECT_1 = """
[tool.cibuildwheel]
@@ -37,42 +45,32 @@ def test_simple_settings(tmp_path, platform, fname):
options_reader = OptionsReader(config_file_path, platform=platform, env={})
assert options_reader.get("build", env_plat=False, list_sep=" ") == "cp39*"
assert options_reader.get("build", option_format=ListFormat(" "), env_plat=False) == "cp39*"
assert options_reader.get("test-command") == "pyproject"
assert options_reader.get("archs", list_sep=" ") == "auto"
assert options_reader.get("archs", option_format=ListFormat(" ")) == "auto"
assert (
options_reader.get("test-requires", list_sep=" ")
options_reader.get("test-requires", option_format=ListFormat(" "))
== {"windows": "something", "macos": "else", "linux": "other many"}[platform]
)
# Also testing options for support for both lists and tables
assert (
options_reader.get("environment", table_format={"item": '{k}="{v}"', "sep": " "})
options_reader.get("environment", option_format=EnvironmentFormat())
== 'THING="OTHER" FOO="BAR"'
)
assert (
options_reader.get(
"environment", list_sep="x", table_format={"item": '{k}="{v}"', "sep": " "}
)
== 'THING="OTHER" FOO="BAR"'
)
assert options_reader.get("test-extras", list_sep=",") == "one,two"
assert (
options_reader.get(
"test-extras", list_sep=",", table_format={"item": '{k}="{v}"', "sep": " "}
)
== "one,two"
)
assert options_reader.get("test-extras", option_format=ListFormat(",")) == "one,two"
assert options_reader.get("manylinux-x86_64-image") == "manylinux1"
assert options_reader.get("manylinux-i686-image") == "manylinux2014"
with pytest.raises(ConfigOptionError):
options_reader.get("environment", list_sep=" ")
with pytest.raises(OptionsReaderError):
# fails because the option is a table and the option_format only works with lists
options_reader.get("environment", option_format=ListFormat(" "))
with pytest.raises(ConfigOptionError):
options_reader.get("test-extras", table_format={"item": '{k}="{v}"', "sep": " "})
with pytest.raises(OptionsReaderError):
# fails because the option is a list and the option_format only works with tables
options_reader.get("test-extras", option_format=ShlexTableFormat())
def test_envvar_override(tmp_path, platform):
@@ -91,14 +89,14 @@ def test_envvar_override(tmp_path, platform):
},
)
assert options_reader.get("archs", list_sep=" ") == "auto"
assert options_reader.get("archs", option_format=ListFormat(" ")) == "auto"
assert options_reader.get("build", list_sep=" ") == "cp38*"
assert options_reader.get("build") == "cp38*"
assert options_reader.get("manylinux-x86_64-image") == "manylinux_2_24"
assert options_reader.get("manylinux-i686-image") == "manylinux2014"
assert (
options_reader.get("test-requires", list_sep=" ")
options_reader.get("test-requires", option_format=ListFormat(" "))
== {"windows": "docs", "macos": "docs", "linux": "scod"}[platform]
)
assert options_reader.get("test-command") == "mytest"
@@ -174,7 +172,7 @@ repairs-wheel-command = "repair-project-linux"
"""
)
with pytest.raises(ConfigOptionError) as excinfo:
with pytest.raises(OptionsReaderError) as excinfo:
OptionsReader(pyproject_toml, platform="linux", env={})
assert "repair-wheel-command" in str(excinfo.value)
@@ -191,7 +189,7 @@ repair_wheel_command = "repair-project-linux"
"""
)
with pytest.raises(ConfigOptionError) as excinfo:
with pytest.raises(OptionsReaderError) as excinfo:
OptionsReader(pyproject_toml, platform="linux", env={})
assert "repair-wheel-command" in str(excinfo.value)
@@ -205,7 +203,7 @@ def test_unexpected_table(tmp_path):
repair-wheel-command = "repair-project-linux"
"""
)
with pytest.raises(ConfigOptionError):
with pytest.raises(OptionsReaderError):
OptionsReader(pyproject_toml, platform="linux", env={})
@@ -219,8 +217,8 @@ build = ["1", "2"]
)
options_reader = OptionsReader(pyproject_toml, platform="linux", env={})
assert options_reader.get("build", list_sep=", ") == "1, 2"
with pytest.raises(ConfigOptionError):
assert options_reader.get("build", option_format=ListFormat(", ")) == "1, 2"
with pytest.raises(OptionsReaderError):
options_reader.get("build")
@@ -234,7 +232,7 @@ manylinux-x86_64-image = "manylinux1"
)
disallow = {"windows": {"manylinux-x86_64-image"}}
OptionsReader(pyproject_toml, platform="linux", disallow=disallow, env={})
with pytest.raises(ConfigOptionError):
with pytest.raises(OptionsReaderError):
OptionsReader(pyproject_toml, platform="windows", disallow=disallow, env={})
@@ -305,7 +303,7 @@ def test_resolve_cascade_merge_list(ignore_empty, rule):
(["b1", "b2"], rule),
(None, InheritRule.NONE),
ignore_empty=ignore_empty,
list_sep=" ",
option_format=ListFormat(" "),
)
if not ignore_empty:
@@ -326,24 +324,34 @@ def test_resolve_cascade_merge_dict(rule):
(None, InheritRule.NONE),
({"value": "override"}, rule),
(None, InheritRule.NONE),
table_format={"item": "{k}={v}", "sep": " "},
option_format=ShlexTableFormat(),
)
if rule == InheritRule.PREPEND:
assert answer == "value=override value=a1 base=b1"
assert answer == "value=a1 base=b1"
elif rule == InheritRule.NONE:
assert answer == "value=override"
elif rule == InheritRule.APPEND:
assert answer == "value=a1 base=b1 value=override"
assert answer == "value=override base=b1"
def test_resolve_cascade_merge_strings():
answer = _resolve_cascade(
("value=a1 base=b1", InheritRule.NONE),
("value=override", InheritRule.APPEND),
option_format=ShlexTableFormat(),
)
assert answer == "value=override base=b1"
def test_resolve_cascade_merge_different_types():
answer = _resolve_cascade(
({"value": "a1", "base": "b1"}, InheritRule.NONE),
("value=a1 base=b1", InheritRule.NONE),
({"value": "override"}, InheritRule.APPEND),
table_format={"item": "{k}={v}", "sep": " "},
("extra_string_var=c1", InheritRule.APPEND),
option_format=ShlexTableFormat(),
)
assert answer == "value=a1 base=b1 value=override"
assert answer == "value=override base=b1 extra_string_var=c1"
PYPROJECT_2 = """
@@ -387,28 +395,28 @@ def test_pyproject_2(tmp_path, platform):
pyproject_toml.write_text(PYPROJECT_2)
options_reader = OptionsReader(config_file_path=pyproject_toml, platform=platform, env={})
assert options_reader.get("test-command", list_sep=" && ") == "pyproject"
assert options_reader.get("test-command", option_format=ListFormat(" && ")) == "pyproject"
with options_reader.identifier("random"):
assert options_reader.get("test-command", list_sep=" && ") == "pyproject"
assert options_reader.get("test-command", option_format=ListFormat(" && ")) == "pyproject"
with options_reader.identifier("cp37-something"):
assert (
options_reader.get("test-command", list_sep=" && ")
options_reader.get("test-command", option_format=ListFormat(" && "))
== "pyproject-override && override2 && pyproject"
)
assert (
options_reader.get("environment", table_format={"item": '{k}="{v}"', "sep": " "})
options_reader.get("environment", option_format=EnvironmentFormat())
== 'FOO="BAR" HAM="EGGS" FOO="BAZ" PYTHON="MONTY"'
)
with options_reader.identifier("cp37-final"):
assert (
options_reader.get("test-command", list_sep=" && ")
options_reader.get("test-command", option_format=ListFormat(" && "))
== "extra-prepend && pyproject-override && override2 && pyproject && pyproject-finalize && finalize2 && extra-finalize"
)
assert (
options_reader.get("environment", table_format={"item": '{k}="{v}"', "sep": " "})
options_reader.get("environment", option_format=EnvironmentFormat())
== 'FOO="BAR" HAM="EGGS" FOO="BAZ" PYTHON="MONTY"'
)
@@ -426,7 +434,7 @@ test-command = "pyproject-override"
"""
)
with pytest.raises(ConfigOptionError):
with pytest.raises(OptionsReaderError):
OptionsReader(config_file_path=pyproject_toml, platform=platform, env={})
@@ -442,8 +450,8 @@ other = ["two", "three"]
options_reader = OptionsReader(config_file_path=pyproject_toml, platform="linux", env={})
assert (
options_reader.get("config-settings", table_format={"item": '{k}="{v}"', "sep": " "})
== 'example="one" other="two" other="three"'
options_reader.get("config-settings", option_format=ShlexTableFormat(pair_sep="=", sep=" "))
== "example=one other=two other=three"
)
@@ -458,10 +466,8 @@ def test_pip_config_settings(tmp_path):
options_reader = OptionsReader(config_file_path=pyproject_toml, platform="linux", env={})
assert (
options_reader.get(
"config-settings", table_format={"item": "--config-settings='{k}=\"{v}\"'", "sep": " "}
)
== "--config-settings='--build-option=\"--use-mypyc\"'"
options_reader.get("config-settings", option_format=ShlexTableFormat(sep=" ", pair_sep="="))
== "--build-option=--use-mypyc"
)
@@ -471,12 +477,16 @@ def test_overrides_inherit(tmp_path):
"""\
[tool.cibuildwheel]
before-all = ["before-all"]
config-settings = {key1="value1", key2="value2", empty=""}
[[tool.cibuildwheel.overrides]]
select = "cp37*"
inherit.before-all = "append"
before-all = ["override1"]
inherit.config-settings = "append"
config-settings = {key3="value3", key2="override2"}
[[tool.cibuildwheel.overrides]]
select = "cp37*"
inherit.before-all = "prepend"
@@ -486,9 +496,17 @@ before-all = ["override2"]
options_reader = OptionsReader(config_file_path=pyproject_toml, platform="linux", env={})
with options_reader.identifier("cp38-something"):
assert options_reader.get("before-all", list_sep=" && ") == "before-all"
assert options_reader.get("before-all", option_format=ListFormat(" && ")) == "before-all"
assert (
options_reader.get("config-settings", option_format=ShlexTableFormat())
== "key1=value1 key2=value2 empty=''"
)
with options_reader.identifier("cp37-something"):
assert (
options_reader.get("before-all", list_sep=" && ")
options_reader.get("before-all", option_format=ListFormat(" && "))
== "override2 && before-all && override1"
)
assert (
options_reader.get("config-settings", option_format=ShlexTableFormat())
== "key1=value1 key2=override2 empty='' key3=value3"
)
+15
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,
@@ -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")